.hhtml
#import <UIKit/UIKit.h> @interface UncaughtExceptionHandler : NSObject{ BOOL dismissed; } @end void HandleException(NSException *exception); void SignalHandler(int signal); void YunInstallUncaughtExceptionHandler(void);
.m 數組
#import "YunUncaughtExceptionHandler.h" #include <libkern/OSAtomic.h> #include <execinfo.h> NSString * const YunUncaughtExceptionHandlerSignalExceptionName = @"YunUncaughtExceptionHandlerSignalExceptionName"; NSString * const YunUncaughtExceptionHandlerSignalKey = @"YunUncaughtExceptionHandlerSignalKey"; NSString * const YunUncaughtExceptionHandlerAddressesKey = @"YunUncaughtExceptionHandlerAddressesKey"; //volatile的做用是做爲指令關鍵字,確保本條指令不會因編譯器的優化而省略,且要求每次直接讀值。 //當前處理的異常個數 volatile int32_t YunUncaughtExceptionCount = 0; //最大可以處理的異常個數 const int32_t YunUncaughtExceptionMaximum = 10; const NSInteger YunUncaughtExceptionHandlerSkipAddressCount = 4; const NSInteger YunUncaughtExceptionHandlerReportAddressCount = 5; @implementation UncaughtExceptionHandler //回溯, 追蹤 + (NSArray *)backtrace { // backtrace函數用於獲取堆棧的地址信息, // backtrace_symbols函數把堆棧地址翻譯成咱們易識別的字符串, // backtrace_symbols_fd函數則把字符串堆棧信息輸出到文件中 void* callstack[128]; int frames = backtrace(callstack, 128); char **strs = backtrace_symbols(callstack, frames); int i; NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames]; for ( i = YunUncaughtExceptionHandlerSkipAddressCount; i < YunUncaughtExceptionHandlerSkipAddressCount + YunUncaughtExceptionHandlerReportAddressCount; i++) { [backtrace addObject:[NSString stringWithUTF8String:strs[i]]]; } free(strs); return backtrace; } - (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex { if (anIndex == 0) { dismissed = YES; } } - (void)validateAndSaveCriticalApplicationData { } //錯誤日誌開始發送到服務器 - (void)handleException:(NSException *)exception { [self validateAndSaveCriticalApplicationData]; // UIAlertView *alert = // [[UIAlertView alloc] // initWithTitle:NSLocalizedString(@"Unhandled exception", nil) // message:[NSString stringWithFormat:NSLocalizedString( // @"You can try to continue but the application may be unstable.\n\n" // @"Debug details follow:\n%@\n%@", nil), // [exception reason], // [[exception userInfo] objectForKey:YunUncaughtExceptionHandlerAddressesKey]] // delegate:self // cancelButtonTitle:NSLocalizedString(@"Quit", nil) // otherButtonTitles:NSLocalizedString(@"Continue", nil), nil]; // [alert show]; NSString *errorStr = [NSString stringWithFormat:NSLocalizedString( @"error info details follow:%@%@", nil), [exception reason], [[exception userInfo] objectForKey:YunUncaughtExceptionHandlerAddressesKey]] ; if(errorStr) { [self sendErrorMsg]; } NSLog(@"捕獲的異常:error:%@",errorStr); //當接收到異常處理消息時,讓程序開始runloop,防止程序死亡 CFRunLoopRef runLoop = CFRunLoopGetCurrent(); CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop); while (!dismissed) { for (NSString *mode in (__bridge NSArray *)allModes) { CFRunLoopRunInMode((__bridge CFStringRef)mode, 0.001, false); } } CFRelease(allModes); NSSetUncaughtExceptionHandler(NULL); signal(SIGABRT, SIG_DFL); signal(SIGILL, SIG_DFL); signal(SIGSEGV, SIG_DFL); signal(SIGFPE, SIG_DFL); signal(SIGBUS, SIG_DFL); signal(SIGPIPE, SIG_DFL); if ([[exception name] isEqual:YunUncaughtExceptionHandlerSignalExceptionName]) {
//若是我想程序發一個SIGINT函數,能夠使用kill函數 kill(getpid(),SIGINT)。getpid()得到了當前運行的程序id,此時就發送了SIGINT信號給該進程 kill(getpid(), [[[exception userInfo] objectForKey:YunUncaughtExceptionHandlerSignalKey] intValue]); }else{
//拋出異常,並致使崩潰 [exception raise]; } } -(void)sendErrorMsg { // [fetchQueue setGLDelegate:self.gldelegate]; } @end /** 異常回調函數 */ void HandleException(NSException *exception){ //OSAtomicIncrement32:一個自增函數,在庫<libkern/OSAtomic.h>中,是線程安全的; int32_t exceptionCount = OSAtomicIncrement32(&YunUncaughtExceptionCount); if (exceptionCount > YunUncaughtExceptionMaximum) { return; } NSArray *callStack = [UncaughtExceptionHandler backtrace]; NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]]; [userInfo setObject:callStack forKey:YunUncaughtExceptionHandlerAddressesKey]; [[[UncaughtExceptionHandler alloc] init] performSelectorOnMainThread:@selector(handleException:) withObject: [NSException exceptionWithName:[exception name] reason:[exception reason] userInfo:userInfo] waitUntilDone:YES]; } /** 捕獲信號後的回調函數 */ void SignalHandler(int signal) { int32_t exceptionCount = OSAtomicIncrement32(&YunUncaughtExceptionCount); if (exceptionCount > YunUncaughtExceptionMaximum) { return; } NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithObject:[NSNumber numberWithInt:signal] forKey:YunUncaughtExceptionHandlerSignalKey]; NSArray *callStack = [UncaughtExceptionHandler backtrace]; [userInfo setObject:callStack forKey:YunUncaughtExceptionHandlerAddressesKey]; [[[UncaughtExceptionHandler alloc] init] performSelectorOnMainThread:@selector(handleException:) withObject: [NSException exceptionWithName:YunUncaughtExceptionHandlerSignalExceptionName reason: [NSString stringWithFormat: NSLocalizedString(@"Signal %d was raised.", nil), signal] userInfo: [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:signal] forKey:YunUncaughtExceptionHandlerSignalKey]] waitUntilDone:YES]; } //begain void YunInstallUncaughtExceptionHandler(void) { //崩潰報告系統會用NSSetUncaughtExceptionHandler方法設置全局的 異常處理器。 NSSetUncaughtExceptionHandler(&HandleException); signal(SIGABRT, SignalHandler); signal(SIGILL, SignalHandler); signal(SIGSEGV, SignalHandler); signal(SIGFPE, SignalHandler); signal(SIGBUS, SignalHandler); signal(SIGPIPE, SignalHandler); } /* SIGABRT--程序停止命令停止信號 SIGALRM--程序超時信號 SIGFPE--程序浮點異常信號 SIGILL--程序非法指令信號 SIGHUP--程序終端停止信號 SIGINT--程序鍵盤中斷信號 SIGKILL--程序結束接收停止信號 SIGTERM--程序kill停止信號 SIGSTOP--程序鍵盤停止信號 SIGSEGV--程序無效內存停止信號 SIGBUS--程序內存字節未對齊停止信號 SIGPIPE--程序Socket發送失敗停止信號 */
關於 Signal 的介紹安全