原文路徑:關于Android9.0開機黑屏一段時間才加載launcher界面的解決方法
前言
最近做9.0項目,發現開機的時候,會先顯示壁紙一段時間,再去加載launcher,如果壁紙是黑色的,則會導致開機動畫結束后,顯示黑屏一段時間,再看到launcher。
調試抓log
遇到問題,當然就是看開機日志了。一番折騰,找到比較有用的log如下:
20:10:50.453 769 1910 I ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.example.user.myapplication/.FallbackHome} from uid 0 on display 0
20:10:54.376 2029 2029 D FallbackHome: User unlocked and real home found; let's go!
20:10:54.466 769 2207 I ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.google.android.setupwizard/.SetupWizardActivity} from uid 0 on display 0
原來在啟動launcher前,系統先啟動了一個FallbackHome的界面,接著再啟動launcher,這中間差了4秒,這跟現象對上了,即先顯示一段時間的壁紙,再啟動launcher。
FallbackHome
那FallbackHome是什么呢?
FallbackHome是原生setting的一個activity,且配置了DirectBoot mode。launcher啟動的時候會先啟動到這個界面,用戶解鎖后,才會調用finish,結束該界面,從而進入到真正的launcher界面。
若未解鎖就等待ACTION_USER_UNLOCKED廣播后再去啟動Launcher。非DirectBoot模式下的launcher耗時4s就是在等待finishBooting后的系統廣播ACTION_USER_UNLOCKED。
FallbackHome就是應DirectBoot功能而新增的一個頁面,具體DirectBoot功能不在這里贅述,大家可自行了解。
如何解決黑屏
那如何解決掉處于DirectBoot模式下的黑屏呢?
嘗試了多種方案,最終比較完美的方案如下:
通過延長開機動畫,等進入到非DirectBoot模式,再結束開機動畫。
但屏蔽掉關閉開機動畫以及開機動畫服務結束檢測相關代碼:
frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
private void performEnableScreen()方法:
.....
/* 這里屏蔽掉一些代碼
if (!mBootAnimationStopped) {
Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
// stop boot animation
// formerly we would just kill the process, but we now ask it to exit so it
// can choose where to stop the animation.
SystemProperties.set("service.bootanim.exit", "1");
mBootAnimationStopped = true;
}
if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {
if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: Waiting for anim complete");
return;
}
try {
IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
if (surfaceFlinger != null) {
Slog.i(TAG_WM, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
data, null, 0);
data.recycle();
}
} catch (RemoteException ex) {
Slog.e(TAG_WM, "Boot completed: SurfaceFlinger is dead!");
}
*/
....
}
這里屏蔽了系統結束開機動畫的代碼,那么得找一個地方去結束開機動畫,從而啟動launcher。
FallbackHome具備home屬性,launcher也必帶home屬性。那么我們可以通過判斷系統所啟動的應用為Home應用但又不是FallbackHome時,就可以結束開機動畫了。
在如下地方去結束開機動畫:
frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java
private void reportLaunchTimeLocked(final long curTime) {
....
//mnq, 20190819, @ {
//Log.d(TAG, "reportLaunchTimeLocked......" + shortComponentName + " intent" + intent);
if (isHomeIntent(intent) && shortComponentName != null && !shortComponentName.contains("FallbackHome")) {
SystemProperties.set("service.bootanim.exit", "1");
Log.d(TAG, "reportLaunchTimeLocked:real home....." + shortComponentName);
}
//mnq, 20190819, @}
}
如此更改后,開機后,發現系統不會有黑屏的現象,且開機動畫結束后就進入到了launcher界面了。
MTK平臺上,也會有此問題,不夠它會在界面上有一個友好的提示:
Phone is starting....
告知用戶,此時機器正在啟動中。
這個其實一樣,也可以用這個辦法去處理。