软件测试之SDK开发(ios)——signal捕获

signal是一种软中断信号,提供异步事件处理机制。signal是进程间相互传递信息的一种粗糙方法,使用场景如下:

  • 进程终止
  • 终端交互
  • 编程错误或硬件错误相关,系统遇到不可恢复的错误时触发崩溃机制让程序退出,比如:除0,内存写入错误等。

这里我们主要考虑系统遇到不可恢复的错误即Crash时,信号相关的应用。此类致命signal有很多,简单列举如下:

SIGABRT–程序中止命令中止信号
SIGALRM–程序超时信号
SIGFPE–程序浮点异常信号
SIGILL–程序非法指令信号
SIGHUP–程序终端中止信号
SIGINT–程序键盘中断信号
SIGKILL–程序结束接收中止信号
SIGTERM–程序kill中止信号
SIGSTOP–程序键盘中止信号
SIGSEGV–程序无效内存中止信号
SIGBUS–程序内存字节未对齐中止信号
SIGPIPE–程序Socket发送失败中止信号

signal的捕获可以使用signal函数,将signal抛给处理函数进行处理,通过signal 的name 和线程的callStackSymbols等信息即可定位该signal发生的场景。如下所示:

void SignalHandler(int sig)
{
    // See https://stackoverflow.com/questions/40631334/how-to-intercept-exc-bad-instruction-when-unwrapping-nil.
    NSString *name = @"Unknown signal";
    switch (sig) {
        case SIGHUP:{
            name = @"SIGHUP";
        }
            break;
        case SIGINT:{
            name = @"SIGINT";
        }
            break;
        case SIGQUIT:{
            name = @"SIGQUIT";
        }
            break;
        case SIGILL:{
            name = @"SIGILL";
        }
            break;
        case SIGTRAP:{
            name = @"SIGTRAP";
        }
            break;
        case SIGABRT:{
            name = @"SIGABRT";
        }
            break;
#ifdef SIGPOLL
        case SIGPOLL:{
            name = @"SIGPOLL";
        }
            break;
#endif
        case SIGEMT:{
            name = @"SIGEMT";
        }
            break;
        case SIGFPE:{
            name = @"SIGFPE";
        }
            break;
        case SIGKILL:{
            name = @"SIGKILL";
        }
            break;
        case SIGBUS:{
            name = @"SIGBUS";
        }
            break;
        case SIGSEGV:{
            name = @"SIGSEGV";
        }
            break;
        case SIGSYS:{
            name = @"SIGSYS";
        }
            break;
        case SIGPIPE:{
            name = @"SIGPIPE";
        }
            break;
        case SIGALRM:{
            name = @"SIGALRM";
        }
            break;
        case SIGTERM:{
            name = @"SIGTERM";
        }
            break;
        case SIGURG:{
            name = @"SIGURG";
        }
            break;
        case SIGSTOP:{
            name = @"SIGSTOP";
        }
            break;
        case SIGTSTP:{
            name = @"SIGTSTP";
        }
            break;
        case SIGCONT:{
            name = @"SIGCONT";
        }
            break;
        case SIGCHLD:{
            name = @"SIGCHLD";
        }
            break;
        case SIGTTIN:{
            name = @"SIGTTIN";
        }
            break;
        case SIGTTOU:{
            name = @"SIGTTOU";
        }
            break;
#ifdef SIGIO
        case SIGIO:{
            name = @"SIGIO";
        }
            break;
#endif
        case SIGXCPU:{
            name = @"SIGXCPU";
        }
            break;
        case SIGXFSZ:{
            name = @"SIGXFSZ";
        }
            break;
        case SIGVTALRM:{
            name = @"SIGVTALRM";
        }
            break;
        case SIGPROF:{
            name = @"SIGPROF";
        }
            break;
#ifdef SIGWINCH
        case SIGWINCH:{
            name = @"SIGWINCH";
        }
            break;
#endif
#ifdef SIGINFO
        case SIGINFO:{
            name = @"SIGINFO";
        }
            break;
#endif
        case SIGUSR1:{
            name = @"SIGUSR1";
        }
            break;
        case SIGUSR2:{
            name = @"SIGUSR2";
        }
            break;
        default:{}
            break;
    }

    NSArray *callStackSymbols = [NSThread callStackSymbols];
    NSString *date = [LLTool stringFromDate:[NSDate date]];
    NSDictionary *appInfos = [LLRoute dynamicAppInfos];
    LLCrashSignalModel *signalModel = [[LLCrashSignalModel alloc] initWithName:name stackSymbols:callStackSymbols date:date userIdentity:[LLConfig sharedConfig].userIdentity appInfos:appInfos];
    if ([LLCrashHelper sharedHelper].crashModel) {
        [[LLCrashHelper sharedHelper].crashModel updateAppInfos:[LLRoute appInfos]];
        [[LLCrashHelper sharedHelper].crashModel appendSignalModel:signalModel];
        [[LLStorageManager sharedManager] updateModel:[LLCrashHelper sharedHelper].crashModel complete:^(BOOL result) {
            NSLog(@"Save signal model success");
        } synchronous:YES];
    } else {
        LLCrashModel *model = [[LLCrashModel alloc] initWithName:signalModel.name reason:@"Catch Signal" userInfo:nil stackSymbols:callStackSymbols date:date userIdentity:[LLConfig sharedConfig].userIdentity appInfos:[LLRoute appInfos] launchDate:[NSObject LL_launchDate]];
        [model appendSignalModel:signalModel];
        [LLCrashHelper sharedHelper].crashModel = model;
        [[LLStorageManager sharedManager] saveModel:model complete:^(BOOL result) {
            NSLog(@"Save signal model success");
        } synchronous:YES];
    }
    
    //将crash的有用信息转换成字典
    NSDictionary *crashInfo = [NSDictionary dictionaryWithObjectsAndKeys:name, @"name",
                               @"Catch Signal",@"reason",
                               callStackSymbols,@"stack",nil] ;
    
    [[LLDebugTool sharedTool] uploadBugWithDict:crashInfo exceptionType:CRASH files:nil takeScreenshot:NO complete:^(BOOL result,NSString* zipPath) {
        if(result){
            NSLog(@"上传bug成功");
            [[NSFileManager defaultManager] removeItemAtPath:zipPath error:nil];
        };
        
    } synchronous:YES] ;
}

参考文章:
1、http://www.cocoachina.com/articles/22765
2、https://www.jianshu.com/p/1b804426d212
3、http://www.iosxxx.com/blog/2015-08-29-iosyi-chang-bu-huo.html

你可能感兴趣的:(app测试,软件测试)