ExceptionHandler.m 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. //
  2. // ExceptionHandler.m
  3. // IBOSS
  4. //
  5. // Created by ssl on 2018/3/2.
  6. // Copyright © 2018年 elongtian. All rights reserved.
  7. //
  8. #import "ExceptionHandler.h"
  9. #include <libkern/OSAtomic.h>
  10. #include <execinfo.h>
  11. NSString * const ExceptionHandlerSignalExceptionName = @"UncaughtExceptionHandlerSignalExceptionName";
  12. NSString * const ExceptionHandlerSignalKey = @"UncaughtExceptionHandlerSignalKey";
  13. NSString * const ExceptionHandlerAddressesKey = @"UncaughtExceptionHandlerAddressesKey";
  14. volatile int32_t UncaughtExceptionCount = 0;
  15. const int32_t UncaughtExceptionMaximum = 10;
  16. const NSInteger ExceptionHandlerSkipAddressCount = 4;
  17. const NSInteger ExceptionHandlerReportAddressCount = 5;
  18. @implementation ExceptionHandler
  19. + (NSArray *)backtrace
  20. {
  21. void * callstack[128];
  22. int frames = backtrace(callstack, 128);
  23. char **strs = backtrace_symbols(callstack, frames);
  24. int i;
  25. NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
  26. for (
  27. i = ExceptionHandlerSkipAddressCount;
  28. i < ExceptionHandlerSkipAddressCount +
  29. ExceptionHandlerReportAddressCount;
  30. i++)
  31. {
  32. [backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
  33. }
  34. free(strs);
  35. return backtrace;
  36. }
  37. - (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex
  38. {
  39. if (anIndex == 0)
  40. {
  41. dismissed = YES;
  42. }
  43. }
  44. - (void)validateAndSaveCriticalApplicationData
  45. {
  46. }
  47. - (void)handleException:(NSException *)exception
  48. {
  49. [self validateAndSaveCriticalApplicationData];
  50. // 找到Documents文件夹路径
  51. NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
  52. NSString *dataFilePath = [documentsPath stringByAppendingPathComponent:IBOSSERROR];
  53. NSFileManager *fileManager = [NSFileManager defaultManager];
  54. BOOL isDir = NO;
  55. // fileExistsAtPath 判断一个文件或目录是否有效,isDirectory判断是否一个目录
  56. BOOL existed = [fileManager fileExistsAtPath:dataFilePath isDirectory:&isDir];
  57. if ( !(isDir == YES && existed == YES) ) {
  58. // 在 Document 目录下创建一个 head 目录
  59. [fileManager createDirectoryAtPath:dataFilePath withIntermediateDirectories:YES attributes:nil error:nil];
  60. }
  61. NSString *str = [exception reason];
  62. //需要知道字符串最终存储的地方,所以需要创建一个路径去存储字符串
  63. NSString *strPath = [dataFilePath stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.log",[self getCurrentTimes]]];
  64. [str writeToFile:strPath atomically:YES encoding:NSUTF8StringEncoding error:nil];
  65. NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
  66. CFRunLoopRef runLoop = CFRunLoopGetCurrent();
  67. CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
  68. while (!dismissed)
  69. {
  70. for (NSString *mode in (__bridge NSArray *)allModes)
  71. {
  72. CFRunLoopRunInMode((CFStringRef)mode, 0.001, false);
  73. }
  74. }
  75. CFRelease(allModes);
  76. NSSetUncaughtExceptionHandler(NULL);
  77. signal(SIGABRT, SIG_DFL);
  78. signal(SIGILL, SIG_DFL);
  79. signal(SIGSEGV, SIG_DFL);
  80. signal(SIGFPE, SIG_DFL);
  81. signal(SIGBUS, SIG_DFL);
  82. signal(SIGPIPE, SIG_DFL);
  83. if ([[exception name] isEqual:ExceptionHandlerSignalExceptionName])
  84. {
  85. kill(getpid(), [[[exception userInfo] objectForKey:ExceptionHandlerSignalKey] intValue]);
  86. }
  87. else
  88. {
  89. [exception raise];
  90. }
  91. }
  92. -(NSString*)getCurrentTimes{
  93. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  94. // ----------设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制
  95. [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
  96. //现在时间,你可以输出来看下是什么格式
  97. NSDate *datenow = [NSDate date];
  98. //----------将nsdate按formatter格式转成nsstring
  99. NSString *currentTimeString = [formatter stringFromDate:datenow];
  100. return currentTimeString;
  101. }
  102. @end
  103. void HandleException(NSException *exception)
  104. {
  105. int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
  106. if (exceptionCount > UncaughtExceptionMaximum)
  107. {
  108. return;
  109. }
  110. NSArray *callStack = [ExceptionHandler backtrace];
  111. NSMutableDictionary *userInfo =
  112. [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]];
  113. [userInfo
  114. setObject:callStack
  115. forKey:ExceptionHandlerAddressesKey];
  116. [[[ExceptionHandler alloc] init]
  117. performSelectorOnMainThread:@selector(handleException:)
  118. withObject:
  119. [NSException
  120. exceptionWithName:[exception name]
  121. reason:[exception reason]
  122. userInfo:userInfo]
  123. waitUntilDone:YES];
  124. }
  125. void SignalHandler(int signal)
  126. {
  127. int32_t exceptionCount = OSAtomicIncrement32(&UncaughtExceptionCount);
  128. if (exceptionCount > UncaughtExceptionMaximum)
  129. {
  130. return;
  131. }
  132. NSMutableDictionary *userInfo =
  133. [NSMutableDictionary
  134. dictionaryWithObject:[NSNumber numberWithInt:signal]
  135. forKey:ExceptionHandlerSignalKey];
  136. NSArray *callStack = [ExceptionHandler backtrace];
  137. [userInfo
  138. setObject:callStack
  139. forKey:ExceptionHandlerAddressesKey];
  140. [[[ExceptionHandler alloc] init]
  141. performSelectorOnMainThread:@selector(handleException:)
  142. withObject:
  143. [NSException
  144. exceptionWithName:ExceptionHandlerSignalExceptionName
  145. reason:
  146. [NSString stringWithFormat:
  147. NSLocalizedString(@"Signal %d was raised.", nil),
  148. signal]
  149. userInfo:
  150. [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:signal] forKey:ExceptionHandlerSignalKey]]
  151. waitUntilDone:YES];
  152. }
  153. void InstallUncaughtExceptionHandler(void){
  154. NSSetUncaughtExceptionHandler(&HandleException);
  155. signal(SIGABRT, SignalHandler);
  156. signal(SIGILL, SignalHandler);
  157. signal(SIGSEGV, SignalHandler);
  158. signal(SIGFPE, SignalHandler);
  159. signal(SIGBUS, SignalHandler);
  160. signal(SIGPIPE, SignalHandler);
  161. }