背景介紹:客戶給了定制的launcher,要求在設備上啟動他們的launcher,實現過程中出現的問題是 開機引導還沒走完,launcher就會自己彈出來打斷開機引導,按道理來說launcher是在開機引導結束后,由開機引導通過intent啟動才對。看了log之后發現是客戶launcher監聽了BOOT_COMPLETED廣播實現了開機自啟動導致了問題。
??像這種情況,開機引導還沒走完,客戶給的應用就開機自啟動了,肯定是不行的,我們怎么在framework層禁止呢?下面給出一種實際可行的修改方式。
注:Android 每個大版本斷層嚴重,本文章只針對Android 11 ,其它版本不一定適用,讀者需自己斟酌一下。類似的文章還有 Android系統層面限制應用開機自啟動詳解
一、分析過程
?? 做framework層的修改,最好的思路是 找到相關log——>找到相關代碼——>理解相關代碼——>修改相關邏輯實現需求。很多人會走錯路,一遇到問題就直接去搜某個模塊的代碼流程梳理博客來看,結果就是看半天看懵逼了,花了很多時間,結果還是不知道從何下手,浪費時間,原因是Android的代碼調用了太多層,像這種代碼啟動流程平時看看就可以了,但絕對不是一個合理的系統層開發手段。這些都是血淋淋的教訓,切記。 相關日志如下:
BroadcastQueue: Permission Denial: receiving Intent { act=android.intent.action.BOOT_COMPLETED flg=0x89000010 (has extras) } to com.xinjing.hotel/com.mydlna.application.DmpBroadcastReceiver requires ...
??找到這段打印的位置:
frameworks\base\services\core\java\com\android\server\am\BroadcastQueue.javafinal void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {. . . . . .. . . . . .. . . . . .perm = PackageManager.PERMISSION_DENIED;}if (perm != PackageManager.PERMISSION_GRANTED) {Slog.w(TAG, "Permission Denial: receiving "+ r.intent + " to "+ component.flattenToShortString()+ " requires " + requiredPermission+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")");. . . . . .. . . . . .. . . . . .
??看了一下附近的邏輯,BroadcastQueue是負責發送廣播的類,不管是系統還是上層應用發送廣播都會調用到它,這里的意思是com.xinjing.hotel 監聽了BOOT_COMPLETED廣播,給com.xinjing.hotel 發送,那么思路就來了,可不可以在這里做截斷呢?下面看看具體實現。
二、修改
??在代碼如下位置加入注釋//xuhao之間的代碼即可。
frameworks\base\services\core\java\com\android\server\am\BroadcastQueue.javafinal void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {. . . . . .. . . . . .. . . . . .ResolveInfo info = (ResolveInfo)nextReceiver;ComponentName component = new ComponentName(info.activityInfo.applicationInfo.packageName,info.activityInfo.name); //xuhaoif(component.flattenToShortString().contains("com.xinjing.hotel")) {Slog.w(TAG,"component.flattenToShortString "+component.flattenToShortString());Slog.w(TAG,"r.intent.toString "+r.intent.toString());}if(component.flattenToShortString().contains("com.xinjing.hotel")) {if(r.intent.toString().contains("android.intent.action.BOOT_COMPLETED") || r.intent.toString().contains("android.intent.action.MEDIA_MOUNTED") ){Slog.w(TAG,"tongzhouzhixing return");return;}}//xuhao
??上述代碼修改解釋:客戶給的launcher com.xinjing.hotel,開機自啟動監聽了兩個廣播android.intent.action.BOOT_COMPLETED、android.intent.action.MEDIA_MOUNTED,屏蔽掉即可禁止該應用開機自啟動。
三、思維發散
??上述的方案不完美但是可用,完美的方案是開機引導結束后設置一個系統屬性為1,該屬性初始值為0,偽代碼如下:
if(component.flattenToShortString().contains("com.xinjing.hotel")&& persisit.me.xuhao == 0) {if(r.intent.toString().contains("android.intent.action.BOOT_COMPLETED") || r.intent.toString().contains("android.intent.action.MEDIA_MOUNTED") ){Slog.w(TAG,"tongzhouzhixing return");return;}}
??這樣能保證只在開機引導沒完成前對應用有限制,完成后不對應用限制,邏輯得到完善。開發時間急就用上面現成的,不急就完善下。
??這個地方還可以做成讀取配置文件的方式,xml里配置一堆需要禁止開機自啟動的應用,這里讀取xml文件解析,在開機引導沒有完成前對所有xml中的APP做出限制,客戶需求大的話,這樣做最好。