自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

iOS App 后臺任務(wù)的坑

移動開發(fā)
大多數(shù) iOS App 在進(jìn)入后臺之后都會將一些關(guān)鍵任務(wù)封裝到 Background Task 里,否則程序在若干秒之后就會被系統(tǒng) Suspend。啟動 Background Task 之后,可以獲得 3 分鐘繼續(xù)執(zhí)行代碼的時(shí)間。

大多數(shù) iOS App 在進(jìn)入后臺之后都會將一些關(guān)鍵任務(wù)封裝到 Background Task 里,否則程序在若干秒之后就會被系統(tǒng) Suspend。啟動 Background Task 之后,可以獲得 3 分鐘繼續(xù)執(zhí)行代碼的時(shí)間。

最近在調(diào)查 Messenger 的 Background Crash 問題,最后都追蹤到和 Background Task 相關(guān),和大家分享下一些要點(diǎn)。

iOS App 后臺任務(wù)的坑

Crash 信號

一般 App 都有自己的 crash 日志采集工具,這類工具一般有三個(gè)問題。第一是在工具啟動之前的 crash 日志無法捕捉,第二是如果 App 啟動閃退日志無法上傳,第三是一些特殊場景的系統(tǒng)強(qiáng)殺無法捕捉 crash 信號。

  • 解決第一個(gè)問題,只要將工具的執(zhí)行時(shí)間盡可能提前,或者確保之前的代碼及可能簡單可靠。
  • 解決第二個(gè)問題,可以采用我之前分享過的,使用 NSURLSession 的 background mode。
  • 解決第三個(gè)問題,需要依賴于 Apple 自己的 crash 信號,這也是很多開發(fā)團(tuán)隊(duì)所忽視的一點(diǎn)。

Apple 也有自己的 crash 日志采集,不過基于用戶隱私的考慮,這個(gè) crash 日志并不可靠,主要存在以下幾方面的缺陷:

  • 用戶需同意上傳并分享數(shù)據(jù),據(jù)聞,同意比例不足 20%,所以無法準(zhǔn)確確定某個(gè) crash 的實(shí)際影響面。
  • crash 日志工具簡陋,通過 Xcode -> Organizer 打開,選中 App 就能從 Apple 后臺下載某個(gè)版本的 crash 日志,無法通過某個(gè)條件做篩選,比如你不能過濾出所有 SIGKILL 的日志。
  • 日志不全,Apple 按照自己的規(guī)則呈現(xiàn) crash 樣本,一個(gè) App 實(shí)際線上的 crash 非常之多,但 Apple 列出的 crash 樣本只有數(shù)十個(gè),規(guī)則不明。
  • crash 日志只保存一周,一周刷新一次,所有比較明智的做法是寫個(gè)腳本同步下來,上傳到自己的后臺。

Background Task 花式 crash

Background Task 的 API 及其簡單,begin 和 end 之間的代碼全部進(jìn)入 Background Task 的范疇。但簡單的代碼隱藏著不小的風(fēng)險(xiǎn),下面列出三個(gè)比較容易出現(xiàn)的 crash。而且這三個(gè) crash 都是客戶端自帶的 crash 采集工具無法捕捉的,只能通過 Apple 的 crash 日志獲得信號。原因很簡單,這些 crash 發(fā)生的時(shí)候 app 一般處于 suspend 狀態(tài),根本沒有機(jī)會執(zhí)行任何代碼,系統(tǒng)直接發(fā)送 SIGKILL 信號后就將 app 強(qiáng)殺,并生成一個(gè)系統(tǒng)日志,一個(gè)只能 Apple 訪問的日志,還得用戶先同意上傳分享。

0xdead10cc

這個(gè) crash 日志一般長這樣:

 

  1. Exception Type:  EXC_CRASH (SIGKILL)  
  2. Exception Codes: 0x0000000000000000, 0x0000000000000000  
  3. Exception Note:  EXC_CORPSE_NOTIFY  
  4. Termination Reason: Namespace SPRINGBOARD, Code 0xdead10cc  
  5. Termination Description: SPRINGBOARD, com.xxx.xxx was task-suspended with locked system file 

原因我之前介紹過,當(dāng)你的 App 有 Extension,而且 Extension 存在和 Host App 共享數(shù)據(jù)的需求,一般做法會將 db 文件放入 shared container 目錄下,此時(shí)你的 App 就有大概率會發(fā)生這種 crash。

App 進(jìn)入后臺運(yùn)行 Background Task,end 之后 App 被系統(tǒng) suspend,如果 suspend 之后還存在任何訪問 db 的操作,此時(shí) App 會立馬被系統(tǒng)強(qiáng)殺,這是 Apple 出于保護(hù)數(shù)據(jù)庫文件的完整的考慮。

所以正確的做法是將所有有可能在 App 進(jìn)入后臺之后,還會發(fā)生的 db 操作統(tǒng)統(tǒng)封入 Background Task,以確保安全。這個(gè)代碼寫在 db layer 可能更加合適。

而且 Apple 推薦當(dāng)你想啟動 Background Task 的時(shí)候,其實(shí)并不需要考慮當(dāng)前 App 是出于 foreground 還是 background,即使 App 在前臺啟動 Background Task,也并不會占用進(jìn)入后臺之后 3 分鐘額度,所以放心大膽的把關(guān)鍵代碼放進(jìn) Background Task 吧。

0xbada5e47

當(dāng)你聽從了上面的建議,大大方方的把盡可能多的關(guān)鍵代碼封入 Background Task 后,那么你可能會遇到下面的 crash:

 

  1. Exception Type: EXC_CRASH (SIGKILL)  
  2. Exception Codes: 0x0000000000000000, 0x0000000000000000  
  3. Exception Note: EXC_CORPSE_NOTIFY  
  4. Termination Reason: Namespace ASSERTIOND, Code 0xbada5e47 

同理也是和 Background Task 相關(guān),原因是 Apple 認(rèn)為你啟動了過多的 Background Task,所以要?dú)⒌?。多少算多?幾十個(gè)不多,當(dāng)前的 threshold 是 1000 個(gè),超過 1000 個(gè)才會強(qiáng)殺。如果你的 Background Task 封裝發(fā)生在 db layer,出現(xiàn)大量數(shù)據(jù)過來需要存儲或讀取的時(shí)候,還是有可能會 hit 這個(gè) limit。

另一個(gè) 0xbada5e47 的可能原因是,Background Task 在超時(shí)之后會調(diào)用 expiry handler,無論你有多少個(gè) Background Task,所有 expiry handler 執(zhí)行的時(shí)間不能超過若干秒,一旦超過也會被槍殺。所以在 expiry handler 里面切忌有任何比如 disk io 的耗時(shí)操作。

0x8badf00d

說到 0x8badf00d,大家都很熟悉了,當(dāng)你的主線程卡住的時(shí)間太長,系統(tǒng)的 Watchdog 會將你的 App 強(qiáng)殺,并生成一個(gè)帶有 0x8badf00d 的 crash 日志。

Background Task 其實(shí)也可以 0x8badf00d 的,比如:

 

  1. Exception Type:  EXC_CRASH (SIGKILL)  
  2. Exception Codes: 0x0000000000000000, 0x0000000000000000  
  3. Exception Note:  EXC_CORPSE_NOTIFY  
  4. Termination Reason: Namespace SPRINGBOARD, Code 0x8badf00d 

當(dāng)你的代碼邏輯會產(chǎn)生 leaked Background Task 時(shí),就會出現(xiàn)上面的系統(tǒng)強(qiáng)殺 crash 日志了,什么是 leaked Background Task 呢?看代碼:

  1. - (void)startBgTask 
  2.  self.bgTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ 
  3.    NSLog(@"Expired: %lu", (unsigned long)self.bgTaskID); 
  4.    [[UIApplication sharedApplication] endBackgroundTask:self.bgTaskID]; 
  5.  }]; 
  6.  
  7. - (void)endBgTask 
  8.  [[UIApplication sharedApplication] endBackgroundTask:self.bgTaskID]; 

上面的代碼如果 startBgTask 執(zhí)行兩次,就一定會出現(xiàn) leaked Background Task,因?yàn)?self.bgTaskID 第二次會被賦予一個(gè)新的 ID,之前的 task ID 就丟失了,無法正確調(diào)用 end。

那怎么判斷 0x8badf00d 到底是主線程卡死,還是出現(xiàn)了 leaked Background Task ?很簡單,看主線程的 stack,如果長這樣:

 

  1. Thread 0 Crashed:0    
  2.  
  3. libsystem_kernel.dylib        0x000000018472be08 0x18472b000 + 35921     
  4. libsystem_kernel.dylib        0x000000018472bc80 0x18472b000 + 32002   
  5. CoreFoundation                0x0000000184c6ee40 0x184b81000 + 9744003 
  6. CoreFoundation                0x0000000184c6c908 0x184b81000 + 9648724 
  7. CoreFoundation                0x0000000184b8cda8 0x184b81000 + 485525   
  8. GraphicsServices              0x0000000186b6f020 0x186b64000 + 450886    
  9. UIKit                          0x000000018eb6d78c 0x18e850000 + 32664447   
  10. Messenger                      0x0000000103015ee4 0x102ff8000 + 1225968  
  11. libdyld.dylib                  0x000000018461dfc0 0x18461d000 + 4032 

這個(gè) stack 很經(jīng)典,經(jīng)常會看到,不需要 symbolicate 也能知道是干啥,這是 UI 線程 runloop 處于 idle 狀態(tài)的 stack,在等待 kernel 的 message。表示 UI 線程此時(shí)處于閑置狀態(tài),這種狀態(tài)下的系統(tǒng)強(qiáng)殺大概率是由于 leaked Background Task 導(dǎo)致的。

善用設(shè)備本地的 crash 日志

當(dāng)用戶的手機(jī)遇到 crash,而你既無法重現(xiàn)又在后臺找不到 crash 日志的時(shí)候,此時(shí)你最大的希望就是手機(jī)本地的 crash 日志了。

本地日志位于 Settings -> Privacy -> Analytics -> Analytics Data。打開看下,說不定你所開發(fā)的 App 的 crash 日志,我手機(jī)上微信和支付寶都有好些日志。

日志排序先是按照 App 的名稱,再按日志發(fā)生的日期。

如果調(diào)查內(nèi)存使用過多的 crash,可以查看 JetsamEvent-xxx 開頭的日志。

如果想知道 App 發(fā)生 crash 前系統(tǒng)有哪些異常日志,需要首先在設(shè)備上安裝一個(gè) loggingiOS.mobileconfig 的文件,這個(gè)文件基本上就是讓用戶授權(quán)給你記錄系統(tǒng)行為,用戶在遇到 crash 的時(shí)候,同時(shí)按下兩個(gè)音量鍵 + 電源鍵,松手震動之后,系統(tǒng)會將過去一段時(shí)間的關(guān)鍵日志記錄下來,對于分析一些疑難雜癥很有幫助,這種日志一般為 sysdiagnose_xxx 開頭。

安裝上述 loggingiOS.mobileconfig 文件之后,還有另外一個(gè)好處,Apple 會記錄更多而且更詳細(xì)的 crash 日志了,因?yàn)橛脩羰跈?quán)過,所以 Apple 可以大膽施為了。這類日志的文件名一般為:stacks + appName - date.ips。

如果用戶的設(shè)備能重現(xiàn)你所調(diào)查的問題,還有另一個(gè)簡單高效的辦法,將手機(jī) usb 連接 mac,然后啟動 mac 上的 Console App,就能直觀的看到所有系統(tǒng)關(guān)鍵日志了,比如網(wǎng)絡(luò)異常日志可以查看 nsurlsessiond,定位異常日志查看 locationd,Background Task 異常日志可以查看 assertiond,也可以直接按照你 app 的進(jìn)程名進(jìn)行過濾,查看生命周期以及被強(qiáng)殺的原因。

總結(jié)

以上是最近調(diào)查 Background Task crash 的一些知識點(diǎn)分享,希望對大家有所幫助。

責(zé)任編輯:未麗燕 來源: MrPeak
相關(guān)推薦

2023-11-25 09:30:13

Android后臺任務(wù)

2023-11-27 19:32:25

Android

2022-01-10 09:05:32

Linux后臺命令

2009-06-19 20:38:49

Linux操作系統(tǒng)

2023-04-26 11:59:06

Swift異步編程

2021-10-13 07:30:13

AndroidAlarmManageWorkManager

2023-12-01 08:21:51

開發(fā)者Android組件庫

2011-12-13 20:36:26

Android

2025-04-27 08:40:00

架構(gòu)后臺任務(wù)開發(fā)

2015-08-25 15:58:33

編程集錦

2013-04-12 15:59:33

2015-02-28 09:49:22

lua

2011-08-04 18:48:21

IOS 后臺

2015-11-04 10:15:45

iOS 后臺進(jìn)程監(jiān)聽

2023-08-02 09:29:40

任務(wù)池TaskPool

2024-01-22 08:21:46

APPHomemCount

2017-10-24 13:42:55

流氓App安卓Google

2021-11-23 10:25:35

性能優(yōu)化iOS App 啟動優(yōu)化

2014-05-09 12:59:26

iOS移動互聯(lián)網(wǎng)

2012-01-05 09:19:25

iOSApp應(yīng)用
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號