異常捕獲上傳服務(wù)器

要接入上海分部的自己的性能統(tǒng)計(jì)和事件統(tǒng)計(jì)的 sdk,在接入之前自己了解下。看到了一套捕獲異常的代碼。

對(duì)于異常分為了兩種,一種是系統(tǒng)拋出的 Exception 異常,iOS 提供了 NSSetUncaughtExceptionHandler 函數(shù)來進(jìn)行捕獲。對(duì)于另一種 Signal 異常需要自己單獨(dú)捕獲處理,最終還是轉(zhuǎn)成 Exception 異常上傳至服務(wù)器。

Signal 信號(hào)類型:

SIGABRT--程序中止命令中止信號(hào)

SIGALRM--程序超時(shí)信號(hào)

SIGFPE--程序浮點(diǎn)異常信號(hào)

SIGILL--程序非法指令信號(hào)

SIGHUP--程序終端中止信號(hào)

SIGINT--程序鍵盤中斷信號(hào)

SIGKILL--程序結(jié)束接收中止信號(hào)

SIGTERM--程序kill中止信號(hào)

SIGSTOP--程序鍵盤中止信號(hào)

SIGSEGV--程序無效內(nèi)存中止信號(hào)

SIGBUS--程序內(nèi)存字節(jié)未對(duì)齊中止信號(hào)

SIGPIPE--程序Socket發(fā)送失敗中止信號(hào)

單獨(dú)創(chuàng)建一個(gè)異常捕獲的類 CaughtExceptionHandler。這個(gè)類在 appFinsh 方法中初始化。

+ (void)initHandler

{

???? NSSetUncaughtExceptionHandler(&HandleException);

???? signal(SIGABRT, SignalHandler);

????? signal(SIGILL, SignalHandler);

????? signal(SIGSEGV, SignalHandler);

????? signal(SIGFPE, SignalHandler);

?????? signal(SIGBUS, SignalHandler);

?????? signal(SIGPIPE, SignalHandler);

}

HandleException 函數(shù)是用來處理系統(tǒng)拋出的 Expcetion 異常。

void HandleException(NSException *exception)

{

? ? ? ? [[[CaughtExceptionHandler alloc] init]? performSelectorOnMainThread:@selector(handleException:) withObject:exception waitUntilDone:YES]; // 主線程執(zhí)行 handleException 方法

}


SignalHandler 捕獲系統(tǒng)發(fā)出的信號(hào)

void SignalHandler(int signal)

{

???? int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount); // 32位并發(fā)的原子操作數(shù)

???? if (exceptionCount > UncaughtExceptionMaximum) {

????????? return;

???? }

??? NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];

? ? NSArray *callStack = [NSThread callStackSymbols]; // 獲取調(diào)用函數(shù)棧

? [userInfo setObject:callStack forKey:CaughtExceptionHandlerAddressesKey];

??? NSException *exception = [NSException exceptionWithName:CaughtExceptionHandlerSignalExceptionName reason:[NSString stringWithFormat:NSLocalizedString(@"Signal %@ was raised.", nil), @(signal)] userInfo:userInfo]; // 將 Signal 信號(hào)轉(zhuǎn)成 NSException 異常傳出

? [[[CaughtExceptionHandler alloc] init] performSelectorOnMainThread:@selector(handleException:) withObject:exception waitUntilDone:YES];

}

handleException 函數(shù)將 Exception 對(duì)象轉(zhuǎn)為字典,通過通知將其帶出。性能處理類接收該類通知通過通知對(duì)象獲取字典,將字典上傳服務(wù)器。

- (void)handleException:(NSException *)exception

{

????? NSTimeInterval crashTime = [[NSDate date] timeIntervalSince1970] * 1000; //毫秒級(jí)

????? NSString *name = [exception name]; //異常名稱

??? ? NSString *reason = [exception reason]; //異常原因

????? NSString *callStackSymbols = [[exception callStackSymbols] componentsJoinedByString:@"\n"];

????? if (callStackSymbols && callStackSymbols.length > 0) {

???????????? NSArray *callStack = [[exception userInfo] objectForKey:UncaughtExceptionHandlerAddressesKey];

???????????? if (callStack.count > 0) {

????????????????? callStackSymbols = [callStack componentsJoinedByString:@"\n"];

???????????? }

????? }

????? NSInteger crashType = 1; //異常類型

????? NSInteger netType = 0; //網(wǎng)絡(luò)類型

????? NSInteger screenType = 1; //橫豎屏

?????? NSString *memoryInfo = [self currentMemoryInfo]; //剩余內(nèi)存

???? ? NSString *pageName = @""; //當(dāng)前頁面路徑

?????? NSMutableDictionary *crashDic = [NSMutableDictionary dictionary];

?????? [crashDic setObject:@(crashTime) forKey:ExceptionTime];

?????? [crashDic setObject:XT_NSSTRING_NOT_NIL(pageName) forKey:ExceptionPageName];

?????? [crashDic setObject:XT_NSSTRING_NOT_NIL(name) forKey:ExceptionName];

?????? [crashDic setObject:XT_NSSTRING_NOT_NIL(reason) forKey:ExceptionReason];

?????? [crashDic setObject:XT_NSSTRING_NOT_NIL(callStackSymbols) forKey:ExceptionStack];

??????? [crashDic setObject:@(crashType) forKey:ExceptionCrashType];

??????? [crashDic setObject:@(netType) forKey:ExceptionNetType];

??????? [crashDic setObject:@(screenType) forKey:ExceptionScreenType];

???????? [crashDic setObject:XT_NSSTRING_NOT_NIL(memoryInfo) forKey:ExceptionMemoryInfo];

???????? NSLog(@"crashCatcher has catch the crash %@, crash Reason is %@, crash Stack is %@", name, reason, callStackSymbols);

//發(fā)送通知

????????? NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];

[notificationCenter postNotificationName:BFCrashCatcherCatchNotification object:nil userInfo:crashDic];

?????? CFRunLoopRef runLoop = CFRunLoopGetCurrent();

?????? CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);

?????? while (!self.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:UncaughtExceptionHandlerSignalExceptionName]) {

????????????????? kill(getpid(), [[[exception userInfo] objectForKey:UncaughtExceptionHandlerSignalKey] intValue]);

?????????? } else {

????????????????? [exception raise];

??????????? }

}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 最近項(xiàng)目上需要對(duì)崩潰信息進(jìn)行處理,要滿足崩潰后及時(shí)捕捉到崩潰信息,當(dāng)應(yīng)用下次打開后再將報(bào)文上傳至服務(wù)器...
    迷失之刃閱讀 4,716評(píng)論 9 8
  • 程序都會(huì)有bug,那么在有bug和異常時(shí)能不能給個(gè)提醒呢,今天咱們來看看這個(gè)問題怎么解決 首先說下基本的NSExc...
    愛吃魚的小灰閱讀 709評(píng)論 1 9
  • 什么是Signal 在計(jì)算機(jī)科學(xué)中,信號(hào)(英語:Signals)是Unix、類Unix以及其他POSIX兼容的操作...
    城市之光閱讀 1,515評(píng)論 0 1
  • 文章目錄 一. 系統(tǒng)Crash 二. 處理signal 下面是一些信號(hào)說明 關(guān)鍵點(diǎn)注意 三. 實(shí)戰(zhàn) 四. Cras...
    MTDeveloper閱讀 1,168評(píng)論 1 2
  • 首先介紹一款工具 定位解析信號(hào)異常上github上搜索DSYMTools,和郵件發(fā)送SKPSMTPMessage ...
    coderK閱讀 733評(píng)論 0 1