关于android:HomeLauncher启动

50次阅读

共计 19159 个字符,预计需要花费 48 分钟才能阅读完成。

该文章解说下 Launcher 启动相干常识, 并更正网上某些文章的谬误点.

本篇为鸡生蛋系列第五篇文章, 也即最初篇, 终于能够完结该系列了。

  1. Linux input 零碎数据上报流程
  2. Android InputManager 剖析
  3. AMS startActivity()
  4. activity 显示过程梳理
  5. HomeLauncher 启动

[代码: Android 11]

http://aosp.opersys.com/xref/…

[代码: Android 8.1]

http://aosp.opersys.com/xref/…

startHomeActivityLocked()

搜网上材料, 好些文章说 launcher 启动是在

ActivityManagerService.systemReady() --> startHomeActivityLocked()

时启动的, 那这个对不对呢? 这个其实对, 也不对,(也可能是他们剖析的版本太老了吧)。

说它不对咱们前面点再说, 先简略看下这个流程代码。

AMS(ActivityManagerService) systemReady()是在 SystemServer startOtherServices()时调用的, 其过程整顿如下:

frameworks/base/services/java/com/android/server/SystemServer.java
main(String[] args)
  + new SystemServer().run();
      + startBootstrapServices(t);
      + startCoreServices(t);
      + startOtherServices(t);
          + mActivityManagerService.systemReady(() -> {
                ......// callback 参数会里启动 system ui, 有须要的可关注下
                startSystemUi(context, windowManagerF);
                ......
            )

对于 < Android10 的版本, AMS 的 systemReady()进一步通过 startHomeActivityLocked(), 好些文章认为在此就启动了 launcher

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void systemReady(final Runnable goingCallback, TimingsTraceLog traceLog) {
......
        startHomeActivityLocked(currentUserId, "systemReady");

boolean startHomeActivityLocked(int userId, String reason) {
    ......
    // home intent
    Intent intent = getHomeIntent();
    // 失去该 intent 应该启哪个利用
    ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
    if (aInfo != null) {
            ......
            // 启动该 activity, 前面流程和利用启动流程差不多, 就不说了
            mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);

具体的代码解说可网上搜下相干文章, 网上有很多,
好,

<big>完!</big>

可是 …

事件真的完了吗?

我之前也始终认为是这样的, 我想着他人都写了一大堆这类文章, 多我一个也没啥意思, 所以就想用逆向剖析的办法来看看, 后果这一剖析, 发现有些不对的中央.

逆向剖析

所谓逆向剖析, 就是我假如我不晓得答案, 也不太分明 framework 咋玩的, 从 launcher 的 onCreate()动手, 看能不能失去雷同的后果.

所采纳的办法呢, 也很简略, 也就是打印调用堆栈, 而后看代码持续剖析, 持续打印调用堆栈 …. 反复

具体的说, 安卓 java 层常见的打印堆栈办法有如下几种:

  • Throwable
Log.i(TAG, Log.getStackTraceString(new Throwable()));
  • Exception
Exception e = new Exception("testandroid this is a log");  
e.printStackTrace();  
也即简化为
new Exception("testandroid this is a log").printStackTrace();
  • RuntimeException
RuntimeException callStack = new RuntimeException("callstack:");  
callStack.fillInStackTrace();  
Log.e(TAG, "testandroid this is a log:", callStack);

那咱们就实战一把, 先在 Launcher 里加上 log,
留神:
我实战用的代码为 android8.1 的源码, 因为我目前就只有该平台的开发机.
堆栈也不重要, 看下分析方法就行.

/home/atom/work/code/suiren_master/LINUX/android/packages/apps/Launcher3
@@ -350,6 +350,13 @@ public class Launcher extends BaseActivity
     @Override
     protected void onCreate(Bundle savedInstanceState) {+        RuntimeException callStack = new RuntimeException("callstack:");
+        callStack.fillInStackTrace();
+        Log.e(TAG,"testandroid this is a log:", callStack);

打印出的堆栈如下:

Launcher: testandroid this is a log: 
Launcher: java.lang.RuntimeException: callstack:
Launcher:  at com.android.launcher3.Launcher.onCreate(Launcher.java:354)
Launcher:  at android.app.Activity.performCreate(Activity.java:7082)
Launcher:  at android.app.Activity.performCreate(Activity.java:7073)
Launcher:  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1215)
Launcher:  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2737)
Launcher:  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2862)
Launcher:  at android.app.ActivityThread.-wrap11(Unknown Source:0)
Launcher:  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1595)
Launcher:  at android.os.Handler.dispatchMessage(Handler.java:106)
Launcher:  at android.os.Looper.loop(Looper.java:164)
// ActivityThread.main()函数, 通过 AMS startActivity()章节剖析可晓得其通过 zyogote fork 后会调用该函数
Launcher:  at android.app.ActivityThread.main(ActivityThread.java:6524)
Launcher:  at java.lang.reflect.Method.invoke(Native Method)
Launcher:  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
Launcher:  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

后果加了第一个 log, 就发现了些问题,

问题 1:
因为咱们代码是有开机向导的, 后果发现要开机向导完结后才调用 Launcher 的 onCreate()

我在 AMS startHomeActivityLocked()也加了 log, systemReady()时的确是有调用到, 然而没有 Launcher 的 onCreate(), 问题 1 之后才有

我先把逆向剖析讲完再回头看这两问题

从下面堆栈看, 利用调到了 ActivityThread.main(), 如果再沿着这个剖析可能就很难了, 这个就须要点背景常识了.
在剖析 AMS startActivity()时咱们晓得, 利用会通过 zygoteProcess.start()申请 zyogote fork 利用,

frameworks/base/core/java/android/os/Process.java
public static final ProcessStartResult start(final String processClass,
                              final String niceName,
                              int uid, int gid, int[] gids,
                              int runtimeFlags, int mountExternal,
                              int targetSdkVersion,
                              ......) {
    // 留神 processClass 为 "android.app.ActivityThread"
    return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}

strat()会进一部调用 startViaZygote(), 咱们调加 启动利用流程调用栈应该在如下中央

frameworks/base/services/core/java/android/os/ZygoteProcess.java
    private Process.ProcessStartResult startViaZygote(final String processClass,....
 
+        RuntimeException callStack = new RuntimeException("callstack:");
+        callStack.fillInStackTrace();
         // 将 niceName 打印进去不便看启动哪个利用
+        Log.e(LOG_TAG, "testandroid this is a log:" + processClass + "niceName:" + niceName + " ", callStack);

其堆栈如下

// com.android.launcher3 启动
ZygoteProcess: testandroid this is a log: android.app.ActivityThread niceName:com.android.launcher3
ZygoteProcess: java.lang.RuntimeException: callstack:
ZygoteProcess:     at android.os.ZygoteProcess.startViaZygote(ZygoteProcess.java:346)
ZygoteProcess:     at android.os.ZygoteProcess.start(ZygoteProcess.java:208)
ZygoteProcess:     at android.os.Process.start(Process.java:462)
ZygoteProcess:     at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:4007)
ZygoteProcess:     at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:3829)
ZygoteProcess:     at com.android.server.am.ActivityManagerService.startProcessLocked(ActivityManagerService.java:3715)
ZygoteProcess:     at com.android.server.am.ActivityStackSupervisor.startSpecificActivityLocked(ActivityStackSupervisor.java:1599)
ZygoteProcess:     at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:2755)
ZygoteProcess:     at com.android.server.am.ActivityStack.resumeTopActivityUncheckedLocked(ActivityStack.java:2268)
ZygoteProcess:     at com.android.server.am.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java:2102)
ZygoteProcess:     at com.android.server.am.ActivityStack.completePauseLocked(ActivityStack.java:1499)
ZygoteProcess:     at com.android.server.am.ActivityStack.activityPausedLocked(ActivityStack.java:1426)
// activityPaused
ZygoteProcess:     at com.android.server.am.ActivityManagerService.activityPaused(ActivityManagerService.java:7691)
// binder 通信, 调用栈断了
ZygoteProcess:     at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:317)
ZygoteProcess:     at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2980)

这里 onTransactd()是 binder 通信, 所以须要晓得 binder proxy 侧谁调用该 binder 函数, 而后在那儿增加日志

通过搜代码, 还好, 就一个中央, 能够在该中央加上日志

frameworks/base/core/java/android/app/ActivityThread.java
private void handlePauseActivity(IBinder token, boolean finished,....
......
                  // 调用 activityPaused(), 可在此加上日志,
                  ActivityManager.getService().activityPaused(token);

因为两头有 handler 也会导致栈信息断, 对 handler message 这种导致的栈断只能剖析代码看谁在 sendMessage()给它了
具体过程了加的日志就不说了, 其流程为
schedulePauseActivity() --> sendMessage(PAUSE_ACTIVITY_FINISHING/PAUSE_ACTIVITY) --> handlePauseActivity() --> ActivityManager.getService().activityPaused(token);

进一步的堆栈如下:

// 其是通过 ActivityStack.java schedulePauseActivity 调用到了
ActivityManager: testandroid ActivityStack.java schedulePauseActivity java.lang.Throwable
ActivityManager:   at com.android.server.am.ActivityStack.startPausingLocked(ActivityStack.java:1359)
ActivityManager:   at com.android.server.am.ActivityStack.finishActivityLocked(ActivityStack.java:3821)
ActivityManager:   at com.android.server.am.ActivityStack.finishActivityLocked(ActivityStack.java:3763)
ActivityManager:   at com.android.server.am.ActivityStack.requestFinishActivityLocked(ActivityStack.java:3611)
// 谁在调用 finishActivity() ?
ActivityManager:   at com.android.server.am.ActivityManagerService.finishActivity(ActivityManagerService.java:5283)

堆栈的最初为 finishActivity(), 那么谁在调用呢?
调用 finishActivity()的中央也有好几个, 可在各个中央加上代码, 最终是在 Activity.java finish() 调用的
代码如下:

frameworks/base/core/java/android/app/Activity.java
private void finish(int finishTask) {
......
            if (ActivityManager.getService()
                    .finishActivity(mToken, resultCode, resultData, finishTask)) {

堆栈如下:

Activity.java finish()
System.err: java.lang.Exception: testandroid Activity.java finish
System.err:    at android.app.Activity.finish(Activity.java:5562)
System.err:    at android.app.Activity.finish(Activity.java:5600)
System.err:    at com.android.settings.FallbackHome.maybeFinish(FallbackHome.java:129)
System.err:    at com.android.settings.FallbackHome.-wrap0(Unknown Source:0)
System.err:    at com.android.settings.FallbackHome$1.onReceive(FallbackHome.java:106)

至此, 咱们终于看到了, 是在 FallbackHome onReceive() 时调用了 finish(), 而后才把 launcher 启动起来.

那咱们看下代码(剖析看正文):

packages/apps/Settings/src/com/android/settings/FallbackHome.java
protected void onCreate(Bundle savedInstanceState) {
    ......
    // 注册了用户解锁的 receiver
    registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_USER_UNLOCKED));
    // 留神这里的 maybeFinish 并没有调起 launcher
    maybeFinish();}

private BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {// 接到用户解锁, 而后调 maybeFinish()
        maybeFinish();}
};

private void maybeFinish() {// 用户是否解锁, 如果 onCreate()-->maybeFinish()时如果用户没解锁则啥也不做
    if (getSystemService(UserManager.class).isUserUnlocked()) {final Intent homeIntent = new Intent(Intent.ACTION_MAIN)
                .addCategory(Intent.CATEGORY_HOME);
        ......
            Log.d(TAG, "User unlocked and real home found; let's go!");
            getSystemService(PowerManager.class).userActivity(SystemClock.uptimeMillis(), false);
            // 调用 finish 完结本人 activity
            finish();}
    }
}

这时候事件进一步明了了,
FallbackHome onReceive() 接到用户解锁播送时调用了 finish(), 本人的 activity 退出时才把 launcher 启动

那 startHomeActivityLocked() 是不是在 Launcher 启动时就齐全没作用呢?

发现有日志:

ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher} from uid 0

而后找到代码所在中央, 通过打印堆栈发现其实是有调用的.

ActivityManager: ActivityStarter.java testandroid this is a log:
ActivityManager: java.lang.RuntimeException: callstack:
ActivityManager:   at com.android.server.am.ActivityStarter.startActivity(ActivityStarter.java:331)
ActivityManager:   at com.android.server.am.ActivityStarter.startActivityLocked(ActivityStarter.java:283)
ActivityManager:   at com.android.server.am.ActivityStarter.startHomeActivityLocked(ActivityStarter.java:655)
ActivityManager:   at com.android.server.am.ActivityManagerService.startHomeActivityLocked(ActivityManagerService.java:4241)
ActivityManager:   at com.android.server.am.ActivityStackSupervisor.resumeHomeStackTask(ActivityStackSupervisor.java:781)
ActivityManager:   at com.android.server.am.ActivityStack.resumeTopActivityInNextFocusableStack(ActivityStack.java:2779)
ActivityManager:   at com.android.server.am.ActivityStack.resumeTopActivityInnerLocked(ActivityStack.java:2326)
ActivityManager:   at com.android.server.am.ActivityStack.resumeTopActivityUncheckedLocked(ActivityStack.java:2268)
ActivityManager:   at com.android.server.am.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java:2107)
ActivityManager:   at com.android.server.am.ActivityStackSupervisor.resumeFocusedStackTopActivityLocked(ActivityStackSupervisor.java:2091)
ActivityManager:   at com.android.server.am.ActivityStack.finishCurrentActivityLocked(ActivityStack.java:3943)
ActivityManager:   at com.android.server.am.ActivityStack.completePauseLocked(ActivityStack.java:1458)
ActivityManager:   at com.android.server.am.ActivityStack.activityPausedLocked(ActivityStack.java:1426)
ActivityManager:   at com.android.server.am.ActivityManagerService.activityPaused(ActivityManagerService.java:7686)
ActivityManager:   at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:317)
ActivityManager:   at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2980)

Provision

让咱们回到问题 1

因为咱们代码是有开机向导的, 后果发现要开机向导完结后才调用 Launcher 的 onCreate()

Android 默认的开机向导为 Provision, 其代码也很简略, 次要为
设置一些数据库值 –> 把本人 disable, 之后 home intent 时就不会找到本人了 –> 完结本人

packages/apps/Provision/src/com/android/provision/DefaultActivity.java
protected void onCreate(Bundle icicle) {
    ......
    Settings.Global.putInt(getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1);
    Settings.Secure.putInt(getContentResolver(), Settings.Secure.USER_SETUP_COMPLETE, 1);
    Settings.Secure.putInt(getContentResolver(), Settings.Secure.TV_USER_SETUP_COMPLETE, 1);

    // remove this activity from the package manager.
    // disable 该 activity
    PackageManager pm = getPackageManager();
    ComponentName name = new ComponentName(this, DefaultActivity.class);
    pm.setComponentEnabledSetting(name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP);

    // terminate the activity.
    // 完结该 activity
    finish();}

HOME intent 优先级问题

AMS systemReady() –> startHomeActivityLocked() 时获取到的为 FallbackHome

boolean startHomeActivityLocked(int userId, String reason) {
    // 取得 home intent
    Intent intent = getHomeIntent();
    //  失去该 intent 应该启哪个利用
    ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
    if (aInfo != null) {
    ......
            mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);

日志(零碎里还有别的响应 home 的 activity, 这里就没列出了, 次要看这三个):

ActivityManager: startHomeActivityLocked ?? act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.settings/.FallbackHome
// 开机向导设置完之后 DefaultActivity 会禁用, 之后启机不会再匹配上
ActivityManager: startHomeActivityLocked ?? act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.provision/.DefaultActivity
ActivityManager: startHomeActivityLocked ?? act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher

可是看了其优先级设置,

packages/apps/Settings/AndroidManifest.xml
<activity android:name=".FallbackHome"
    ...... // FallbackHome 优先级 -1000
    <intent-filter android:priority="-1000">

packages/apps/Provision/AndroidManifest.xml
<activity android:name="DefaultActivity"
......// DefaultActivity 优先级 3
    <intent-filter android:priority="3">

FallbackHome 优先级 -1000, 为最小
DefaultActivity 优先级 3
Launcher3 没有设置

实践上来说, 有开机向导时, 应该 DefaultActivity 匹配上, 之后重启应该是 Launcher3 匹配上,
那么为啥 systemReady()时为 FallbackHome, 或者说为啥老是 FallbackHome 先匹配上?
按理来说其优先级最低, 应该最初匹配上才对啊.

resolveActivityInfo()流程如下:

resolveActivityInfo() / ActivityManagerService.java
  + AppGlobals.getPackageManager().resolveIntent()
      + resolveIntent() / PackageManagerService.java 
          + resolveIntentInternal()
              + queryIntentActivitiesInternal() // 查问所有符合条件的 activities
              |   + result = filterIfNotSystemUser(mActivities.queryIntent(.....))
              |       + super.queryIntent(....) / class ActivityIntentResolver
              |           + buildResolveList(....firstTypeCut, finalList, userId); / IntentResolver.java
              + chooseBestActivity() // 抉择最好的那个

在下面流程中, 会先查问出所有符合条件的 activities, 而后选出最好的那个, 有须要的能够在这儿查看选取规定.
本认为是 chooseBestActivity()时 DefaultActivity/Launcher3 不是最好的, 加上 log 确认原来在 queryIntentActivitiesInternal() 时最开始就只有 FallbackHome

间接启动

buildResolveList()之后可简略看看调查过程和正文, 因为代码老是变, 也没多大意义, 次要的是提下前面的调查结果和发现了 间接启动 这么个对我来说的新货色.

frameworks/base/services/core/java/com/android/server/IntentResolver.java
private void buildResolveList(Intent intent, FastImmutableArraySet<String> categories,
        boolean debug, boolean defaultOnly, String resolvedType, String scheme,
        F[] src, List<R> dest, int userId) {
        ......
        match = filter.match(action, resolvedType, scheme, data, categories, TAG);
        if (match >= 0) {
            // 关上这里的日志发现其实最后时 FallbackHome DefaultActivity Launcher 都有 match 的
            if (debug) Slog.v(TAG, "Filter matched!  match=0x" +
                    Integer.toHexString(match) + "hasDefault="
                    + filter.hasCategory(Intent.CATEGORY_DEFAULT));
            if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {
                // 然而后两者返回的为 null
                final R oneResult = newResult(filter, match, userId);
                if (oneResult != null) {
                    // 如果不为 null 才退出到 dest 里
                    dest.add(oneResult);

newResult 对于 activity intent 来说实现在
PackageManagerService.java
......
final class ActivityIntentResolver
        extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {

    protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info,
            int match, int userId) {if (!sUserManager.exists(userId)) return null;
        // 这里返回为 null, 因为 DefaultActivity 设置后会把本人禁用, 所以重启时他没匹配上倒也能够了解,
        // 可是为啥起机后 Launcher 也在 FallbackHome 后匹配上呢? 能够持续考察
        if (!mSettings.isEnabledAndMatchLPr(info.activity.info, mFlags, userId)) {return null;}

frameworks/base/services/core/java/com/android/server/pm/Settings.java
boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {final PackageSetting ps = mPackages.get(componentInfo.packageName);
    if (ps == null) return false;

    final PackageUserState userState = ps.readUserState(userId);
    // 这里反回 false
    return userState.isMatch(componentInfo, flags);
}

frameworks/base/core/java/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;
    // Enable 判断
    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;
    // 对 Launcher 来说, 这里起机时刚开始反回 false, 之后返回 true
    return matchesUnaware || matchesAware;
}

看到最初 DIRECT_BOOT_UNAWARE DIRECT_BOOT_AWARE componentInfo.directBootAwar 这是啥呢?

这个其实就是对间接启动利用判断,

间接启动材料可看:
https://developer.android.goo…
简略说就是未解锁时能够运行的程序, 比如说未解锁拍照.

FallbackHome 所在的设置是有反对间接启动, Launcher 不反对, 所以 FallbackHome 总是会先匹配, 解锁后 Launcher 才有机会匹配上.

packages/apps/Settings/AndroidManifest.xml
<application android:label="@string/settings_label"
        ...// FallbackHome 所在的设置反对间接启动      
         android:directBootAware="true">

总结

  1. 对 home intent 的响应是有优先级的, 所以 AMS systemReady()调用 start home 时并不一定会启动 launcher, 当其它优先级的 home activity 响应完后才有可能是 launcher
  2. 一般说来, launcher 启动是在, settings FallbackHome 监听到解锁后调用 finish() 完结本人时, 才把 launcher 启动起来
  3. 因为 settings 反对 间接启动, launcher 不反对, 所以未解锁时 launcher 不会匹配到 home intent.
  4. 一些 home intent 的优先级
package activity 优先级
com.android.settings CryptKeeper 10
com.android.provision DefaultActivity 3
com.android.launcher3 Launcher 默认
com.android.settings FallbackHome -1000
  1. Android 11 AMS systemRead() startHomeOnDisplay() 流程简略整顿:
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public void systemReady(final Runnable goingCallback, @NonNull TimingsTraceAndSlog t) {
  + // goingCallback 回调, 这里会启动 systemui
  | if (goingCallback != null) goingCallback.run();
  + // start user
  | mSystemServiceManager.startUser(t, currentUserId);
  + // 启动 persistent 利用
  | startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
  + // 启动所有屏的 Home, 
  | mAtmInternal.startHomeOnAllDisplays(currentUserId, "systemReady");
  | // mAtmInternal 为 ActivityTaskManagerInternal 类型, 其最终实现在
  | // ActivityTaskManagerService.java
  + // final class LocalService extends ActivityTaskManagerInternal
      + mRootWindowContainer.startHomeOnDisplay(...) / ActivityTaskManagerService.java
          + startHomeOnTaskDisplayArea(...) / RootWindowContainer.java
              + if (taskDisplayArea == getDefaultTaskDisplayArea()) {|     homeIntent = mService.getHomeIntent();
              |     // 失去默认屏 home intent 的 activity
              |     aInfo = resolveHomeActivity(userId, homeIntent);
              | } else if (shouldPlaceSecondaryHomeOnDisplayArea(taskDisplayArea)) {
              |     // 失去第二个屏 home intent 的 activity
              |     Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, taskDisplayArea);
              +
              + mService.getActivityStartController().startHomeActivity(...)
                  +
                  | ActivityStartController.java
                  | void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason,
                  |         TaskDisplayArea taskDisplayArea) {...
                  |      // 多屏相干, 启动到哪个屏设置
                  |     final int displayId = taskDisplayArea.getDisplayId();
                  |     options.setLaunchDisplayId(displayId);
                  |     options.setLaunchTaskDisplayArea(taskDisplayArea.mRemoteToken
                  |             .toWindowContainerToken());
                  |     ......
                  | 
                  |     mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity:" + reason)
                  |             .setOutActivity(tmpOutRecord)
                  |             .setCallingUid(0)
                  |             .setActivityInfo(aInfo)
                  |             .setActivityOptions(options.toBundle())
                  +             .execute();

正文完
 0