该文章解说下 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()时调用的, 其过程整顿如下:
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">
总结
- 对 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() 流程简略整顿:
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();