该文章解说下Launcher启动相干常识,并更正网上某些文章的谬误点.
本篇为鸡生蛋系列第五篇文章, 也即最初篇, 终于能够完结该系列了。
- Linux input零碎数据上报流程
- Android InputManager剖析
- AMS startActivity()
- activity显示过程梳理
- 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()时调用的, 其过程整顿如下:
<code class="java">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
<code class="java">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
<code class="java">Log.i(TAG, Log.getStackTraceString(new Throwable()));
- Exception
<code class="java">Exception e = new Exception("testandroid this is a log"); e.printStackTrace(); 也即简化为 new Exception("testandroid this is a log").printStackTrace();
- RuntimeException
<code class="java">RuntimeException callStack = new RuntimeException("callstack: "); callStack.fillInStackTrace(); Log.e(TAG, "testandroid this is a log: ", callStack);
那咱们就实战一把, 先在Launcher里加上log,
留神:
我实战用的代码为android8.1的源码, 因为我目前就只有该平台的开发机.
堆栈也不重要, 看下分析方法就行.
<code class="diff">/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);
打印出的堆栈如下:
<code class="txt">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利用,
<code class="java">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(), 咱们调加启动利用流程调用栈应该在如下中央
<code class="diff">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函数, 而后在那儿增加日志
通过搜代码,还好,就一个中央, 能够在该中央加上日志
<code class="java">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);
进一步的堆栈如下:
<code class="txt">// 其是通过 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() 调用的
代码如下:
<code class="java">frameworks/base/core/java/android/app/Activity.java private void finish(int finishTask) { ...... if (ActivityManager.getService() .finishActivity(mToken, resultCode, resultData, finishTask)) {
堆栈如下:
<code class="txt">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启动起来.
那咱们看下代码(剖析看正文):
<code class="java">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
而后找到代码所在中央,通过打印堆栈发现其实是有调用的.
<code class="txt">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时就不会找到本人了 –> 完结本人
<code class="java">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
<code class="java">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
可是看了其优先级设置,
<code class="xml">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()流程如下:
<code class="java">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()之后可简略看看调查过程和正文, 因为代码老是变,也没多大意义, 次要的是提下前面的调查结果和发现了 间接启动 这么个对我来说的新货色.
<code class="java">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才有机会匹配上.
<code class="xml">packages/apps/Settings/AndroidManifest.xml <application android:label="@string/settings_label" ...// FallbackHome 所在的设置反对间接启动 android:directBootAware="true">
总结
- 对home intent的响应是有优先级的, 所以AMS systemReady()调用 start home时并不一定会启动launcher, 当其它优先级的home activity响应完后才有可能是 launcher
- 一般说来, launcher启动是在, settings FallbackHome 监听到解锁后调用finish() 完结本人时,才把launcher启动起来
- 因为 settings 反对 间接启动, launcher 不反对, 所以未解锁时launcher不会匹配到home intent.
- 一些home intent的优先级
package activity | 优先级 |
---|---|
com.android.settings CryptKeeper | 10 |
com.android.provision DefaultActivity | 3 |
com.android.launcher3 Launcher | 默认 |
com.android.settings FallbackHome | -1000 |
- Android 11 AMS systemRead() startHomeOnDisplay() 流程简略整顿:
<code class="java">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();