內置應用升級失敗
ROM內置應用通過網絡升級後,應用運行crash,異常日誌顯示一些類、資源文件找不到
java.lang.ClassNotFoundException: Didn't find class
java.lang.NoClassDefFoundError: Failed resolution of
分析
命令過濾log,發現各組件升級安裝過程一切正常
grep -r "dex2oat\|ActivityManagerService\|re-install\|dexopt\|Cdevice\|app包名" *
再次復現查看進程號,發現升級前後進程號沒有變換,意味着AMS沒有回收舊的進程,進程內存沒有加載進來新得apk資源
ps | grep app包名
升級都會殺死原先的進程,沒有殺死是爲什麼?命令查看進程的oom_adj值
cat proce/app進程號/oom_adj
lowmemorykiller根據oom_adj對進程進行管理,策略如下
所以是因爲內置app的application中加了android:persistent="true",導致進程與os的生命週期一直,不被任何組件殺死回收,即便是異常crash、root下kill 命令也不會對內存重的資源重新加載,除非reboot重啓才能讓升級包的apk資源加載到進程中
命令查看app是否使用了該屬性
dumpsys package app包名
關於android:persistent="true"
該屬性只對rom內置應用起作用
副作用比較大,一定要慎用
例如:
1.加了該屬性的app隨系統啓動非常早,如果在app的application中做了網絡請求操作(如域名下發),但此時網絡都還沒有就緒,如果沒有其他的補救措施,就只能升級系統
2.如果app不夠穩定,出現crash,AMS會立馬啓動該app,將陷入crash---啓動的死循環
在系統啓動之時,AMS的systemReady()會加載所有persistent爲true的應用。
persistent應用會頑固地運行於系統之中,從系統一啓動,一直到系統關機。
爲了保證這種持久性,persistent應用必須能夠在異常出現時,自動重新啓動。在Android裏是這樣實現的。每個ActivityThread 中會有一個專門和AMS通信的binder實體——final ApplicationThread mAppThread。這個實體在AMS中對應的代理接口爲IApplicationThread。
當AMS執行到attachApplicationLocked()時,會針對目標用戶進程的IApplicationThread接口,註冊一個 binder訃告監聽器,一旦日後用戶進程意外掛掉,AMS就能在第一時間感知到,並採取相應的措施。如果AMS發現意外掛掉的應用是 persistent的,它會嘗試重新啓動這個應用。