亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS監控筆記之啟動crash

2019-10-21 18:41:09
字體:
來源:轉載
供稿:網友

前言

相較于正常的崩潰問題,啟動crash造成的損失要遠遠大得多。正常來說,如果有足夠強健的構建發布系統,大多數時候能在版本上線之前及時發現問題并且修復,但是仍然存在小概率的線上意外。啟動crash一般同時具備損害嚴重以及難以捕獲兩大特點

啟動過程

從應用圖標被用戶點擊開始,直到應用可以開始響應發生了很多事情。正常來說,盡管我們希望crash監控工具啟動的盡可能早,但接入方往往總是等到launch事件之后才能啟動工具,而在這個時間之前發生的崩潰就是啟動crash,下面列出了在應用直到launch時,存在的可能發生啟動crash的階段:

ios,crash監控,crash,分析

其中initialize的順序可能在更早,但總是會在load和launch之間。從圖中來說,如果我們想要監控啟動crash,那么開始監控的時間點必須要放到load階段,才能保證最好的監控效果

如何監控

最簡單的方式是不管接入方愿不愿意啟動crash監控,我們在load方法中直接啟動監控功能。但是這樣的做法會讓應用面臨四個風險點:

  • 類似A/B的線上開關方案失去了對監控工具的控制能力
  • crash監控啟動存在崩潰問題,這將導致應用完全癱瘓
  • load階段類未加載完畢,啟動工具過程的遞歸加載引發的崩潰無法監控

綜合這些風險點,啟動crash監控的方案應該滿足這些條件:

  • 啟動過程不依賴類,避免遞歸加載造成的crash
  • 一旦過程發生crash,能夠保證日志記錄的安全性

最終得出監控的流程圖:

ios,crash監控,crash,分析

不依賴類

不依賴類意味著監控工具需要使用C接口來實現功能,雖然比較麻煩,但由于runtime的機制決定了所有方法調用最終要以objc_msgSend函數作為入口,因此如果能夠hook掉這個函數并且實現一個調用棧結構,將所有調用入棧記錄,那么追蹤方法調用就不是難事。fishhook提供了hook掉函數的能力:

__unused static id (*orig_objc_msgSend)(id, SEL, ...);__attribute__((__naked__)) static void hook_Objc_msgSend() { /// save stack data /// push msgSend /// resume stack data  /// call origin msgSend  /// save stack data /// pop msgSend /// resume stack data}void observe_Objc_msgSend() { struct rebinding msgSend_rebinding = { "objc_msgSend", hook_Objc_msgSend, (void *)&orig_objc_msgSend }; rebind_symbols((struct rebinding[1]){msgSend_rebinding}, 1);}

實現msgSend

__naked__修飾的函數告訴編譯器在函數調用的時候不使用棧保存參數信息,同時函數返回地址會被保存到LR寄存器上。由于msgSend本身就是用這個修飾符的,因此在記錄函數調用的出入棧操作中,必須保證能夠保存以及還原寄存器數據。msgSend利用x0 - x9的寄存器存儲參數信息,可以手動使用sp寄存器來存儲和還原這些參數信息:

/// 保存寄存器參數信息#define save() /__asm volatile ( / "stp x8, x9, [sp, #-16]!/n" / "stp x6, x7, [sp, #-16]!/n" / "stp x4, x5, [sp, #-16]!/n" / "stp x2, x3, [sp, #-16]!/n" / "stp x0, x1, [sp, #-16]!/n");/// 還原寄存器參數信息#define resume() /__asm volatile ( / "ldp x0, x1, [sp], #16/n" / "ldp x2, x3, [sp], #16/n" / "ldp x4, x5, [sp], #16/n" / "ldp x6, x7, [sp], #16/n" / "ldp x8, x9, [sp], #16/n" ); /// 函數調用,value傳入函數地址#define call(b, value) / __asm volatile ("stp x8, x9, [sp, #-16]!/n"); / __asm volatile ("mov x12, %0/n" :: "r"(value)); / __asm volatile ("ldp x8, x9, [sp], #16/n"); / __asm volatile (#b " x12/n");/// msgSend必須使用匯編實現__attribute__((__naked__)) static void hook_Objc_msgSend() { save() __asm volatile ("mov x2, lr/n"); __asm volatile ("mov x3, x4/n");  call(blr, &push_msgSend) resume() call(blr, orig_objc_msgSend)  save() call(blr, &pop_msgSend)  __asm volatile ("mov lr, x0/n"); resume() __asm volatile ("ret/n");}

日志記錄

常規的I/O處理不能保證crash發生的數據安全,因此mmap是最適合用于此場景的方案。mmap能保證即便是應用發生了不可抗拒的崩潰時,也能完成將文件寫入IO的工作。另外我們只需記錄class和selector的調用棧信息,在不存在遞歸算法的情況下,只需要很小的內存使用就能記錄這些數據:

time_t ts = time(NULL);const char *filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingString: [NSString stringWithFormat: @"%d", ts]].UTF8String;unsigned char *buffer = NULL;int fileDescriptor = open(filePath, O_RDWR, 0);buffer = (unsigned char *)mmap(NULL, MB * 4, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fileDescriptor, 0);

buffer就是我們寫入數據的緩沖區,為了保證調用棧的信息準確,每次調用函數信息出入棧的時候,都需要更新緩沖區的數據。一個可行的方式是每個調用記錄添加一個@符號前綴,總是保存最后一個調用記錄的此符號下標,出棧時清除該下標之后的所有數據即可

static inline void push_msgSend(id _self, Class _cls, SEL _cmd, uintptr_t lr) { _lastIdx = _length; buffer[_lastIdx] = '@'; ......}static inline void pop_msgSend(id _self, SEL _cmd, uintptr_t lr) { ...... buffer[_lastIdx] = '/0'; _length = _lastIdx; size_t idx = _lastIdx - 1;  while (idx >= 0) { if (buffer[idx] == '@') {  _lastIdx = idx;  break; } idx--; }}

清空日志

由于msgSend的調用非常頻繁,這種監控方案并不適合長時間啟動,因此需要在某個時機關閉監控。由于正常的崩潰監控啟動時也可能會存在crash,監聽becomeActive通知來關閉功能是最合適的選擇,因為此時已經過了launch啟動崩潰監控工具的階段,可以保證該工具本身是正常使用的:

[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(closeMsgSendObserve) name: UIApplicationDidBecomeActiveNotification object: nil];- (void)closeMsgSendObserve { close(fileDescriptor); munmap(buffer, MB * 4); [[NSFileManager defaultManager] removeItemAtPath: _logPath error: nil];}

回滾

當需要回滾時,說明已經發生了啟動crash,此時根據日志內容,也有不同的處理方式:

日志文件是空文件

這種情況是最危險的情況,如果日志文件為空,說明文件已經建立,但是還沒有產生任何方法調用。很有可能在fishhook的處理過程中存在crash,此時應該直接關閉監控方案,即便不是它的原因,并且快速增發版本

日志文件不為空

如果日志文件不為空,說明成功的監控到了crash,此時應該同步上傳日志文件,快速反饋到業務方及時止損。首先止損手段都應該采用同步的方式,保證應用能夠繼續運行,根據情況不同,止損的回滾方式包括以下:

  1. 如果crash發生在并不干擾正常業務執行的功能組件中,可以通過A/B線上開關關閉對應的功能,前提是功能組件使用開關控制
  2. 崩潰處代碼已經干擾正常業務執行,但是錯誤代碼短,可以嘗試通過服務器下發patch包動態修復錯誤代碼,但是patch包要提防引入其他問題
  3. 在A/B Test和patch包都無法解決問題的情況下,假如項目采用了合理的組件化設計,通過路由轉發來使用h5完成應用的正常運行
  4. 缺少動態修復的手段且crash不干擾正常業務執行,考慮停止一切插件、輔助組件運行
  5. 缺少動態修復的手段,包括1, 2, 3的方案??煽紤]通過第三方越獄市場提供逆向包,提示用戶下載安裝
  6. 缺少動態修復的手段,包括1, 2, 3的方案。增發版本快速止損,使用Test Flight分批次快速讓用戶恢復使用

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VEVB武林網的支持。


注:相關教程知識閱讀請移步到IOS開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
欧美国产日韩一区二区在线观看| 精品国产老师黑色丝袜高跟鞋| 久久成人精品电影| 亚洲天堂男人天堂女人天堂| 国产99久久精品一区二区 夜夜躁日日躁| 丝袜美腿亚洲一区二区| 国产成人97精品免费看片| 国产欧美精品一区二区三区-老狼| 亚洲国产精品福利| 成人一区二区电影| 欧美电影免费观看大全| 亚洲午夜精品久久久久久性色| 日韩中文字幕不卡视频| 日韩欧美精品免费在线| 欧美日韩美女在线观看| 亚洲va久久久噜噜噜久久天堂| 久久夜色撩人精品| 欧美网站在线观看| 成人免费淫片视频软件| 色青青草原桃花久久综合| 综合国产在线视频| 国产精品人成电影在线观看| 中文字幕久精品免费视频| 久久91超碰青草是什么| 欧美精品少妇videofree| 亚洲午夜国产成人av电影男同| 98视频在线噜噜噜国产| 亚洲qvod图片区电影| 亚洲日本成人网| 国模叶桐国产精品一区| 国产成人精品免高潮费视频| 亚洲福利视频专区| 热re99久久精品国产66热| 亚洲人成电影在线播放| 久久国产精品亚洲| 中文字幕日韩精品在线观看| 久久久这里只有精品视频| 日韩成人在线网站| 久久久国产视频| 亚州成人av在线| 国产欧美日韩中文字幕| 亚洲欧美综合精品久久成人| 亚洲欧洲一区二区三区在线观看| 91av视频在线观看| 97国产精品视频| 欧美电影在线播放| 欧美一级淫片丝袜脚交| 亚洲精品美女视频| 清纯唯美日韩制服另类| 欧美日韩成人在线播放| 日本精品久久久| 91性高湖久久久久久久久_久久99| 亚洲成人av在线播放| 国模精品一区二区三区色天香| 国产97在线观看| 日韩精品在线免费播放| 日韩中文在线中文网三级| 国产精品精品视频| 国产精品无码专区在线观看| 国产精品成人久久久久| 人人做人人澡人人爽欧美| 国产精品爽黄69天堂a| 久久99久久亚洲国产| 久久精品视频播放| 97视频在线观看亚洲| 国产成人涩涩涩视频在线观看| 日韩天堂在线视频| 久久视频国产精品免费视频在线| 成人a视频在线观看| 91久久精品在线| 亚洲a∨日韩av高清在线观看| 97超级碰碰碰久久久| 91经典在线视频| 91高清免费视频| 成人黄色影片在线| 中文字幕视频在线免费欧美日韩综合在线看| 日韩少妇与小伙激情| 久久久久五月天| 欧美在线性视频| 国产精品一区二区三区在线播放| 成人亲热视频网站| 九色91av视频| 中文字幕自拍vr一区二区三区| 国产欧美在线看| 欧美一级在线播放| 中文字幕精品视频| 欧美性20hd另类| 欧美日韩国产在线看| 国产自摸综合网| 欧美激情精品久久久久久黑人| 欧美日韩国内自拍| 91精品免费看| 91av在线国产| 欧美国产视频一区二区| 欧美大荫蒂xxx| 国产精品永久在线| 丝袜情趣国产精品| 国产精品亚洲片夜色在线| 69久久夜色精品国产69| 日韩在线观看精品| 欧美丰满少妇xxxxx做受| 91久久夜色精品国产网站| 国产精品免费一区二区三区都可以| 7m第一福利500精品视频| 欧美乱人伦中文字幕在线| 久久精品免费播放| 中文字幕亚洲二区| 日韩欧美在线免费观看| 亚洲欧美中文另类| 国产国产精品人在线视| 欧美性猛交99久久久久99按摩| 久久精品视频在线播放| 日韩电影免费在线观看中文字幕| 午夜剧场成人观在线视频免费观看| 日韩av在线精品| 91高清免费视频| 国产成人精品视频| 最好看的2019年中文视频| 最近2019好看的中文字幕免费| 国产精品视频久| 亚洲欧美在线第一页| 精品久久久久久中文字幕| 国产成人精品999| 欧美一区二区影院| 久久这里只有精品99| 欧美激情精品久久久久久黑人| 国产精品嫩草视频| 国产91久久婷婷一区二区| 国产精品草莓在线免费观看| 国产香蕉一区二区三区在线视频| 亚洲第一男人天堂| 91成人免费观看网站| 亚洲国产精品一区二区久| 热99精品里视频精品| 国产精品久久久久久久久久新婚| 国产精品视频色| 国语自产精品视频在免费| 国产一区av在线| 日韩动漫免费观看电视剧高清| 亚洲免费人成在线视频观看| 亚洲成人a**站| 国产激情久久久| 国产成人啪精品视频免费网| 欧美一级片一区| 欧美日韩亚洲一区二| 亚洲色图五月天| 日韩视频在线免费| 欧美成人黑人xx视频免费观看| 国产小视频91| 国产午夜精品全部视频播放| 国产日韩精品视频| 欧美综合在线观看| 日产精品99久久久久久| 日韩中文字幕视频| 久久久精品视频成人| 色黄久久久久久| 成人www视频在线观看| 国产精品7m视频| 7777精品久久久久久| 在线成人一区二区| 欧美一级视频一区二区| 92国产精品久久久久首页| 欧美激情精品久久久久久变态| 精品动漫一区二区三区|