1

该文章讲解下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 CryptKeeper10
com.android.provision DefaultActivity3
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();

Atom
26 声望30 粉丝

带着问题看code