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