问题引入
在新平台开发过程中,测试同学一直抱怨在进入Launcher前,屏幕会黑屏闪现一下,大概2-3s,随后才进入,影响用户体验。刚开始没有特别关注,以为是启动Activity 过程中加载东西太多,导致窗体渲染有点慢。经过后续分析,原来另有原因,而且其中涉及好几个知识点。这里mark 一下。(在另一个平台上,出现了一个“平板正在启动中”的显示,产品同学很想拿掉或者替换,那么我们可以实现了?看完这篇就有答案了)

发现问题
抓取开机打印,查看一下在进入Launcher前后,系统做了什么:

12-17 15:22:57.358   507   507 I ActivityManager: System now ready
12-17 15:22:58.702   507   561 I ActivityManager: Start proc 938:com.android.tv.settings/1000 for top-activity {com.android.tv.settings/com.android.tv.settings.system.FallbackHome}
12-17 15:23:01.076   507   554 E ActivityManager: ams finishBooting.
12-17 15:23:01.078   507   554 I ActivityManager: User 0 state changed from BOOTING to RUNNING_LOCKED
12-17 15:23:01.118   507   554 D ActivityManager: Started unlocking user 0
12-17 15:23:01.118   507   554 D ActivityManager: Unlocking user 0 progress 0
12-17 15:23:01.118   507   554 D ActivityManager: Unlocking user 0 progress 5
12-17 15:23:01.869   507   551 I ActivityManager: User 0 state changed from RUNNING_LOCKED to RUNNING_UNLOCKING
12-17 15:23:01.870   507   551 D ActivityManager: Unlocking user 0 progress 20
12-17 15:23:06.422   507   560 I ActivityManager: User 0 state changed from RUNNING_UNLOCKING to RUNNING_UNLOCKED
12-17 15:23:06.456   507   560 I ActivityManager: Posting BOOT_COMPLETED user #0
12-17 15:23:06.602   507   561 I ActivityManager: Start proc 1274:com.funshion.ottedu/u0a26 for top-activity {com.funshion.ottedu/com.bestv.ott.home.HomeActivity}

发现在启动我们Launcher应用(com.funshion.ottedu)前,还启动了一个{com.android.tv.settings/com.android.tv.settings.system.FallbackHome}组件,而且是在解锁屏幕之前就启动了。

FallbackHome
经过查找发现原生设置中设有directBootAware 属性,且FallbackHome 带有android.intent.category.HOME特性,但是优先级很低(-1000)
packages/apps/Settings/AndroidManifest.xml

android:directBootAware="true"
<activity android:name=".FallbackHome"android:excludeFromRecents="true"android:label=""android:screenOrientation="nosensor"android:taskAffinity="com.android.settings.FallbackHome"android:theme="@style/FallbackHome"><intent-filter android:priority="-1000"><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.HOME" /><category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
public class FallbackHome extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));maybeFinish();}private BroadcastReceiver mReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {maybeFinish();}};private void maybeFinish() {if (getSystemService(UserManager.class).isUserUnlocked()) {final Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);final ResolveInfo homeInfo = getPackageManager().resolveActivity(homeIntent, 0);if (Objects.equals(getPackageName(), homeInfo.activityInfo.packageName)) {if (UserManager.isSplitSystemUser()&& UserHandle.myUserId() == UserHandle.USER_SYSTEM) {// This avoids the situation where the system user has no home activity after// SUW and this activity continues to throw out warnings. See b/28870689.return;}Log.d(TAG, "User unlocked but no home; let's hope someone enables one soon?");mHandler.sendEmptyMessageDelayed(0, 500);} else {Log.d(TAG, "User unlocked and real home found; let's go!");getSystemService(PowerManager.class).userActivity(SystemClock.uptimeMillis(), false);finish();}}}private Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {maybeFinish();}};
}

FallbackHome 的代码很简单,简单界面显示“平台正在启动中”,随后一直等待用户解锁的广播,接收到之后判断是否有新的Launcher可用,并结束自己使命。准确来说它只是一个过渡界面。
新平台出现黑屏的原因是里面延时2s 才显示Fallbakhome的界面,当我们正要显示FallbackHome界面时,此时接收到系统解锁(系统没有设置ping 密码,不需解锁直接进系统)便出现了黑屏一下的现象

那么有两种方案解决我们的问题,后面会详细补充。

directBootAware
Direct Boot Mode—是AndroidN 引入的新特性, 设备启动后进入,直到用户解锁(unlock)设备此阶段结束的一种模式。应用程序可以在用户锁屏阶段启动,并处理应用程序的部分逻辑。Direct Boot Mode和正常模式下最大的不同是使用一种新的存储空间:Device protected storage。

Android亮屏流程
这是一个比较复杂且繁琐的过程,这里给出几个关键文件和函数,感兴趣的朋友可以自己查看源码(后续可能会单独写一篇博文分享一下):

frameworks/base/services/java/com/android/server/SystemServer.java
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
//AMS systemReady
public systemReady() {Slog.i(TAG, "System now ready");//在这里会拉起FallbackHome startHomeActivityLocked(currentUserId, "systemReady");
}frameworks/base/core/java/android/app/ActivityThread.java
//resume阶段handleResumeActivity方法里面在加载完window之后将自己实现的Idlehandler添加到自己的消息队列里面。
handleLaunchActivity{Looper.myQueue().addIdleHandler(new Idler());
}
//这里调用到AMS的activityIdle,开启亮屏流程
MessageQueue.IdleHandler {am.activityIdle(a.token, a.createdConfig, stopProfiling);
}
//activityIdle 最后调用到的是ActivityStackSuperVisor里面的activityIdleInternalLocked。
//会报告启动时间结束,还有就是检查是否是还在开机阶段然后结束开机流程。意思就是桌面都已经拿到焦点显示好了,开机动画可以退役了。
ActivityRecord activityIdleInternalLocked() {if (isFocusedStack(r.getStack()) || fromTimeout) {booting = checkFinishBootingLocked();}
}
private boolean checkFinishBootingLocked() {mService.postFinishBooting(booting, enableScreen);//这里调用到AMS里面去了
}
//回到AMS
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
void postFinishBooting(boolean finishBooting, boolean enableScreen) {mHandler.sendMessage(mHandler.obtainMessage(FINISH_BOOTING_MSG,finishBooting ? 1 : 0, enableScreen ? 1 : 0));}case FINISH_BOOTING_MSG: {if (msg.arg1 != 0) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");finishBooting();Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}if (msg.arg2 != 0) {enableScreenAfterBoot();}break;}//发送亮屏请求
void enableScreenAfterBoot() {mWindowManager.enableScreenAfterBoot();}frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java//亮屏处理
public void enableScreenIfNeeded() {synchronized (mWindowMap) {enableScreenIfNeededLocked();mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30 * 1000);//超时时间30s}}
void enableScreenIfNeededLocked() {mH.sendEmptyMessage(H.ENABLE_SCREEN);}private void performEnableScreen() {if (!mBootAnimationStopped) {//这里设置属性可以关闭开机动画SystemProperties.set("service.bootanim.exit", "1");mBootAnimationStopped = true;}mActivityManager.bootAnimationComplete();//这里有回到AMSmPolicy.enableScreenAfterBoot();
}
//再次回到AMS
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java//亮屏之后通知AMS后续的操作public void bootAnimationComplete() {finishBooting();}
//系统的第一个应用启动起来,窗口准备完毕,介绍开机动画,并发送开机广播都在这里
final void finishBooting() {mUserController.sendBootCompleted()//在这里会发生解锁广播之类
}frameworks/base/services/core/java/com/android/server/am/UserController.java
void sendBootCompleted(IIntentReceiver resultTo) {finishUserBoot(uss, resultTo);
}
private void finishUserBoot(UserState uss, IIntentReceiver resultTo) {}
void finishUserUnlocked(final UserState uss) {final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED);mInjector.sendPreBootBroadcast(userId, quiet,() -> finishUserUnlockedCompleted(uss));
}

比较凌乱,没有画图,后续再慢慢详细分析,不关注的朋友可以忽略。

解决方案
1.部分平台没有显示黑屏,而是显示“平板正在启动中”之类的,咱们可以直接修改FallbackHome的界面,修改成你想要的效果。当然你可以拿掉FallbackHome这个界面。但是前提是你需要自己实现一个带
directBootAware属性应用,且具有android.intent.category.HOME 特性的Activity。否则系统将起不来。因为系统无法亮屏

2.延时开机动画,等自己的Launcher起来之后,再杀掉开机动画。
这里直接给出patch.

diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 9c8b7ef..e1c4e14 100755
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -1161,19 +1161,25 @@ bool BootAnimation::android()glDeleteTextures(1, &mAndroid[1].name);return false;}
-void BootAnimation::checkExit() {// Allow surface flinger to gracefully request shutdownchar value[PROPERTY_VALUE_MAX];
+    char value1[PROPERTY_VALUE_MAX];
+    char value2[PROPERTY_VALUE_MAX];property_get(EXIT_PROP_NAME, value, "0");
+    property_get("service.launcher.visible", value1, "0");
+    property_get("service.launcher.create", value2, "0");ALOGI("service.bootanim.exit : %s", value);
+    ALOGI("service.launcher.visible : %s", value1);
+    ALOGI("service.launcher.create : %s", value2);int exitnow = atoi(value);
-    if (exitnow) {+    if (exitnow && (atoi(value1)||atoi(value2))) {+        ALOGI("checkExit really exit");
+        property_set("service.boot.complete", "1");requestExit();mCallbacks->shutdown();}}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4b98d02..b83f733 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3485,12 +3485,12 @@ public class WindowManagerService extends IWindowManager.Stub}private boolean checkBootAnimationCompleteLocked() {-        if (SystemService.isRunning(BOOT_ANIMATION_SERVICE)) {+        if (!mDisplayEnabled) {mH.removeMessages(H.CHECK_IF_BOOT_ANIMATION_FINISHED);mH.sendEmptyMessageDelayed(H.CHECK_IF_BOOT_ANIMATION_FINISHED,BOOT_ANIMATION_POLL_INTERVAL);if (DEBUG_BOOT) Slog.i(TAG_WM, "checkBootAnimationComplete: Waiting for anim complete");
-            return false;
+            return mBootAnimationStopped;}if (DEBUG_BOOT) Slog.i(TAG_WM, "checkBootAnimationComplete: Animation complete!");return true;
--

为什么需要修改WindowManagerService 里面的checkBootAnimationCompleteLocked。这里会一直等开机动画结束,才会想AMS 发送bootAnimationComplete。没有接收到解锁广播,FallbakHome 会一直运行。(WMS 也有个超时机制,30s)。

同样都带有HOME,为什么首先找到的是FallbackHome
想必你可能有这个疑问,这里也是有猫腻的,这是因为:
解锁之前queryIntentActivitiesInternal(),查找HomeIntent,只能匹配到 FallbackHome(与priority无关)。

android/content/pm/PackageUserState.java
public boolean isMatch(ComponentInfo componentInfo, int flags) {final boolean isSystemApp = componentInfo.applicationInfo.isSystemApp();final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;if (!isAvailable(flags)&& !(isSystemApp && matchUninstalled)) return false;if (!isEnabled(componentInfo, flags)) return false;if ((flags & MATCH_SYSTEM_ONLY) != 0) {if (!isSystemApp) {return false;}}final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)&& !componentInfo.directBootAware;final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)&& componentInfo.directBootAware;return matchesUnaware || matchesAware;}

这里就不再继续展开了,关键代码已贴上,自己去RFSC吧。

实战-Android开机进入Launcher前黑屏问题相关推荐

  1. 计算机启动黑屏时间很长,电脑开机启动系统前黑屏很长时间,怎么处理?

    进入系统后黑屏处理办法: 首先检查一下是否因为显示器的刷新频率设置过高而导致的,进入安全模式后右击桌面并选择"属性",在打开的窗口中选择"设置"选项卡,单击&q ...

  2. kernel logo到开机卡通片之间闪现黑屏(android 5.X)

    kernel logo到开机动画之间闪现黑屏(android 5.X) 在BootAnimation开始绘图之前,会先做一次clear screen的动作,避免出现前面的图干扰到BootAnimati ...

  3. android广告视频播放,一种解决android广告视频启播前黑屏的方法与流程

    本发明涉及数字视频技术领域,具体的说,是一种解决android广告视频启播前黑屏的方法. 背景技术: 目前,Android系统已经作为普遍的智能电视平台出现在我们面前,为了提升电视平台的运营价值,很多 ...

  4. 苹果开机是白苹果黑屏_这是苹果应如何回应史诗般的1984年诱饵

    苹果开机是白苹果黑屏 As you are reading this, you probably know about Epic Game's lawsuit filing against Apple ...

  5. android videoview 播放之前短暂黑屏

    最近在做视频闪屏页,但是遇到了一个困难 VideoView播放视频的时候会出现黑屏,能够清晰看到黑色的屏幕,很不美观 照惯例,遇到问题先看有没有网友解决过,发现了几篇博客 Android VideoV ...

  6. windows开机出现GNU GRUB黑屏解决方法记录

    windows开机出现GNU GRUB黑屏解决方法记录 电脑情况 我的电脑是组装机,系统为WIN10+UBUNTU16.04, 一块240G固态,一块750G机械硬盘.固态平分为两部分,各120G安装 ...

  7. 联想笔记本键盘亮屏幕不亮_联想笔记本电脑开机键亮但是黑屏 联想笔记本电脑键盘失灵怎么办...

    联想笔记本电脑一直是笔记本电脑行业里的大品牌,非常的受人们欢迎.但是它在使用时也会遇到很多问题,例如联想笔记本电脑开机键亮但是黑屏怎么办?联想笔记本电脑键盘失灵怎么办?所以在联想笔记本选购之前需要了解 ...

  8. 联想笔记本键盘亮屏幕不亮_联想笔记本电脑开机键亮但是黑屏,联想笔记本电脑键盘失灵怎么办...

    联想笔记本电脑一直是笔记本电脑行业的大品牌,深受人们的喜爱.然而,它在使用时也会遇到很多问题,比如如何处理联想笔记本电脑开机键亮但是黑屏?联想笔记本电脑键盘失灵怎么办?因此,在购买联想笔记本之前,我们 ...

  9. win10计算机打开一直读进度条,win10开机读条后黑屏怎么办_win10开机读条之后黑屏修复方法-win7之家...

    在启动win10电脑过程中,总是需要让系统先进行到读条之后才能够正常的进入系统中来,但是近日有些用户的win10电脑在开机进行读条完成之后就出现黑屏的情况,导致电脑无法正常进入系统,那么win10开机 ...

最新文章

  1. mysql 查询绑定变量_MySQL高级特性——绑定变量
  2. struts iterator 标签 之 indexId
  3. linux主机ip数据包抓取,tcpdump和ngrep抓不到本机数据包
  4. “清华同方同传”By软件:同方易教管理平台 V2.4
  5. 移远NB-IOT BC28 模组 与自建的UDP服务器通信
  6. Acer 4750 安装黑苹果_超详细安装黑苹果教程
  7. 正确的配置Android开发环境-让你的C盘不在爆红
  8. java gui容器_中国大学MOOC: (GUI容器)容器类java.awt.container的父类是_______。
  9. 使用python进行数据清洗常用的库_用于格式化和数据清理的便捷Python库
  10. Three.js 基础之灯光
  11. 生态学建模:增强回归树(BRT)预测短鳍鳗生存分布和影响因素
  12. 电脑录音,台式电脑如何录音_怎么电脑录音-win7之家
  13. 【单镜头反光相机】影调、反差、光比、宽容度;光质(硬光、软光)、硬调、软调、高调、低调、中间调...
  14. Matlab Mobile手机版获取gps数据和加速度信号融合
  15. Dota2世界冠军OG被AI碾压,全程人类只推掉两座外塔 | 广东省智能创新协会
  16. 13个SpringBoot优秀学习项目
  17. HDU 3853 LOOPS(概率DP)
  18. 从像素之间谈起:像素游戏的画面增强
  19. JavaScript 基础学习(三)
  20. 矩阵寻找目标值的技巧

热门文章

  1. iframe之父子页面通信
  2. 斑能不能彻底去掉_脸上的斑真的能完全去掉么
  3. Python基础+数据科学入门(六)类
  4. vscode开发微信小程序插件
  5. 10年IT老兵跳槽到银行1年后的体会
  6. 【论文阅读】GA-RPN:Region Proposal by Guided Anchoring
  7. 2010最新《怪物史瑞克4/怪物史莱克4》DVD中英双字
  8. 支持组播的流媒体服务器,VLC 搭建流媒体服务器
  9. linux 删除文件夹中所有文件命令行,Linux中使用命令行删除文件夹
  10. React弹出框(简易版)