前言
本文主要从Android系统开机启动角度解答“我的应用是什么时候启动的”
Android系统开机
我们先看下谷歌官方的图,我们今天的重点就是讲讲怎么应用在开机过程中如何启动的。
从AMS说起
我们知道System server 会启动很多系统服务,其中AMS是android系统服务中很重要的一个,我们今天的主角就是它。
下面代码截取自system server的run方法,里面按照重要程度和先后顺序,执行了三个启动系统服务的方法,
// Start services.
try {
traceBeginAndSlog("StartServices");
startBootstrapServices(); // AMS 构造函数在这里执行
startCoreServices();
startOtherServices(); // AMS 的system Ready 在这里执行
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
我们重点关注的就是AMS的systemReady方法,应用的启动也是从这里开始。
AMS.systemReady
最先启动的应用,AMS的systemReady函数中,systemserver传入的callback中包含2个应用程序的启动,我们看下代码:
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
traceBeginAndSlog("StartCarServiceHelperService");
mSystemServiceManager.startService(CAR_SERVICE_HELPER_SERVICE_CLASS);
traceEnd();
}
traceBeginAndSlog("StartSystemUI");
try {
startSystemUi(context, windowManagerF);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
traceEnd();
如果是android 车载版本就会启动carservice app,还会启动systemui app,毫无疑问,我们目前看到的这是最早启动的两个应用。 接下来会启动常驻应用,也就是所谓的persistent app,当然在目前这个阶段,并不是所有的常驻应用都会被启动,再没有user unlock之前,我们启动的是包含DIRECT_BOOT_AWARE flag的应用。
// Only start up encryption-aware persistent apps; once user is
// unlocked we'll come back around and start unaware apps
startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
第一个launcher
Android 系统启动的第一个Activity也是第一个桌面是com.android.settings/.FallbackHome,
重点是这个桌面的优先级是-1000,这也为了后面的桌面出现铺平了道路。
<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>
启动桌面调用函数如下:
startHomeActivityLocked(currentUserId, "systemReady");
流程简单来说就是在AMS systemReady函数中去启动桌面的时候,这时候还没有user unlcok,在derectboot模式下查询到的是FallbackHome,这时候我们就把他拉起来了,如果开机动画已经结束,这时候桌面上显示的是“android 正在启动”,可以参考下面时序图
真正的home
真正的home启动其实比较复杂,这里面涉及到复杂的开机流程,FallbackHome是源头,FallbackHome activity启动之后,在FallbackHome的OnResume阶段,会调用到ActivityThread类的handleResumeActivity()方法,handleResumeActivity()方法会往消息队列中增加一个IdelHandler。
Looper.myQueue().addIdleHandler(new Idler());
settings 消息队列空闲时会执行这个idleHandler,最终会调用到AMS端,执行checkFinishBootingLocked函数,触发后续的开机流程。
这个流程比较复杂,会执行关闭开机动画,user unlock,启动桌面,启动非derect boot flag常驻应用,发送开机广播。
这部分比较复杂,直接上图吧:
启动顺序总结
- CarService和SystemUI
- Derect Boot Flag 常驻应用,如settings,android:directBootAware="true",android:persistent="true"
- FallbackHome,“假桌面”
- 桌面,非derect boot flag常驻应用,接收开机广播启动的应用
在上面的顺序中,最后一条的内容里面,这些应用启动时间比较相近,启动的也比较多,通常这个阶段系统负载会很高,后续有时间讲一下开机自启动应用治理。