该文章讲解下Launcher启动相关知识,并更正网上某些文章的错误点.
本篇为鸡生蛋系列第五篇文章, 也即最后篇, 终于可以结束该系列了。
[代码: 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();
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。