实战-Android开机进入Launcher前黑屏问题
问题引入
在新平台开发过程中,测试同学一直抱怨在进入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前黑屏问题相关推荐
- 计算机启动黑屏时间很长,电脑开机启动系统前黑屏很长时间,怎么处理?
进入系统后黑屏处理办法: 首先检查一下是否因为显示器的刷新频率设置过高而导致的,进入安全模式后右击桌面并选择"属性",在打开的窗口中选择"设置"选项卡,单击&q ...
- kernel logo到开机卡通片之间闪现黑屏(android 5.X)
kernel logo到开机动画之间闪现黑屏(android 5.X) 在BootAnimation开始绘图之前,会先做一次clear screen的动作,避免出现前面的图干扰到BootAnimati ...
- android广告视频播放,一种解决android广告视频启播前黑屏的方法与流程
本发明涉及数字视频技术领域,具体的说,是一种解决android广告视频启播前黑屏的方法. 背景技术: 目前,Android系统已经作为普遍的智能电视平台出现在我们面前,为了提升电视平台的运营价值,很多 ...
- 苹果开机是白苹果黑屏_这是苹果应如何回应史诗般的1984年诱饵
苹果开机是白苹果黑屏 As you are reading this, you probably know about Epic Game's lawsuit filing against Apple ...
- android videoview 播放之前短暂黑屏
最近在做视频闪屏页,但是遇到了一个困难 VideoView播放视频的时候会出现黑屏,能够清晰看到黑色的屏幕,很不美观 照惯例,遇到问题先看有没有网友解决过,发现了几篇博客 Android VideoV ...
- windows开机出现GNU GRUB黑屏解决方法记录
windows开机出现GNU GRUB黑屏解决方法记录 电脑情况 我的电脑是组装机,系统为WIN10+UBUNTU16.04, 一块240G固态,一块750G机械硬盘.固态平分为两部分,各120G安装 ...
- 联想笔记本键盘亮屏幕不亮_联想笔记本电脑开机键亮但是黑屏 联想笔记本电脑键盘失灵怎么办...
联想笔记本电脑一直是笔记本电脑行业里的大品牌,非常的受人们欢迎.但是它在使用时也会遇到很多问题,例如联想笔记本电脑开机键亮但是黑屏怎么办?联想笔记本电脑键盘失灵怎么办?所以在联想笔记本选购之前需要了解 ...
- 联想笔记本键盘亮屏幕不亮_联想笔记本电脑开机键亮但是黑屏,联想笔记本电脑键盘失灵怎么办...
联想笔记本电脑一直是笔记本电脑行业的大品牌,深受人们的喜爱.然而,它在使用时也会遇到很多问题,比如如何处理联想笔记本电脑开机键亮但是黑屏?联想笔记本电脑键盘失灵怎么办?因此,在购买联想笔记本之前,我们 ...
- win10计算机打开一直读进度条,win10开机读条后黑屏怎么办_win10开机读条之后黑屏修复方法-win7之家...
在启动win10电脑过程中,总是需要让系统先进行到读条之后才能够正常的进入系统中来,但是近日有些用户的win10电脑在开机进行读条完成之后就出现黑屏的情况,导致电脑无法正常进入系统,那么win10开机 ...
最新文章
- mysql 查询绑定变量_MySQL高级特性——绑定变量
- struts iterator 标签 之 indexId
- linux主机ip数据包抓取,tcpdump和ngrep抓不到本机数据包
- “清华同方同传”By软件:同方易教管理平台 V2.4
- 移远NB-IOT BC28 模组 与自建的UDP服务器通信
- Acer 4750 安装黑苹果_超详细安装黑苹果教程
- 正确的配置Android开发环境-让你的C盘不在爆红
- java gui容器_中国大学MOOC: (GUI容器)容器类java.awt.container的父类是_______。
- 使用python进行数据清洗常用的库_用于格式化和数据清理的便捷Python库
- Three.js 基础之灯光
- 生态学建模:增强回归树(BRT)预测短鳍鳗生存分布和影响因素
- 电脑录音,台式电脑如何录音_怎么电脑录音-win7之家
- 【单镜头反光相机】影调、反差、光比、宽容度;光质(硬光、软光)、硬调、软调、高调、低调、中间调...
- Matlab Mobile手机版获取gps数据和加速度信号融合
- Dota2世界冠军OG被AI碾压,全程人类只推掉两座外塔 | 广东省智能创新协会
- 13个SpringBoot优秀学习项目
- HDU 3853 LOOPS(概率DP)
- 从像素之间谈起:像素游戏的画面增强
- JavaScript 基础学习(三)
- 矩阵寻找目标值的技巧