前面文章讲到了从Launcher启动新应用时,最终通过调用AMS的startActivity方法。那么这次,我们来看一下AMS是怎么启动新应用的Activity的。
Activity启动概述
Activity的启动过程分为两种,一种是根Activity的启动过程,另一种是普通Activity的启动过程,根Activity指的是应用程序启动的第一个Activity,因此根Activity的启动过程一般情况下也可以理解为应用程序的启动过程。普通Activity指的是除了应用程序启动的第一个Activity之外的其他的Activity。这里介绍的是根Activity的启动过程,它和普通Activity的启动过程是有重叠部分的,只不过根Activity的启动过程一般情况下指的就是应用程序的启动过程。
这里,研究根Activity的启动,弄清楚了根Activity的启动,其他Activity启动流程也差不多了。
回顾一下Launcher启动新应用的,我们可以将根Activity的启动分为三个部分。
1、Launcher请求AMS过程。
2、AMS到ApplicationThread的调用过程。
3、ActivityThread启动Activity。
1、Launcher请求AMS过程
第一篇文章就要介绍过Launcher这个特殊的应用程序,它将所有已安装的应用显示在桌面,为进入其他应用提供入口。而Launcher请求AMS的过程,就是从我们在桌面上点击一个应用程序图标开始的。
时序图如下:
这个过程已经介绍过了,这里不再重复叙述了。但是有一个类要注意的是Instrumentation,主要用来监控应用程序和系统的交互,也是因为这个特性可以通过它去达成某种目的。
2、AMS到ApplicationThread的调用过程
首先先看一下这个过程的时序图:
从图中可以看出,涉及的方法比较多,我们重点看一下几个方法。
AMS调用startActivityAsUser了,这个方法多了一个参数userId,AMS会根据这个UserId来确定调用者的权限。
源码frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Override
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
//判断调用者进程是否被隔离
enforceNotIsolatedCaller("startActivity");//1
//检查调用者权限
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivity", null);//2
return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null, null, bOptions, false, userId, null, null,
"startActivityAsUser");
}
注释1处判断调用者进程是否被隔离,如果被隔离则抛出SecurityException异常。
注释2处用于检查调用者是否有权限,如果没有权限也会抛出SecurityException异常。
继续往下调用,看一下ActivityStarter的核心方法startActivity。ActivityStarter是Android 7.0新加入的类,它是加载Activity的控制类,会收集所有的逻辑来决定如何将Intent和Flags转换为Activity,并将Activity和Task以及Stack相关联。
源码frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
TaskRecord inTask) {
int err = ActivityManager.START_SUCCESS;
final Bundle verificationBundle
= options != null ? options.popAppVerificationBundle() : null;
ProcessRecord callerApp = null;
if (caller != null) {//1
//获取Launcher进程
callerApp = mService.getRecordForAppLocked(caller);//2
if (callerApp != null) {
//获取Launcher进程的pid和uid并赋值
callingPid = callerApp.pid;
callingUid = callerApp.info.uid;
} else {
Slog.w(TAG, "Unable to find app for caller " + caller
+ " (pid=" + callingPid + ") when starting: "
+ intent.toString());
err = ActivityManager.START_PERMISSION_DENIED;
}
}
...
//创建即将要启动的Activity的描述类ActivityRecord
ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
mSupervisor, container, options, sourceRecord); //2
if (outActivity != null) {
outActivity[0] = r;//3
}
...
doPendingActivityLaunchesLocked(false);
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
options, inTask, outActivity);//4
}
注释1处判断IApplicationThread类型的caller是否为null,这个caller是方法调用一路传过来的,指向的是Launche进程的ApplicationThread对象。
注释2处调用AMS的getRecordForAppLocked方法得到的是代表Launcher进程的callerApp对象,它是ProcessRecord类型的,ProcessRecord用于描述一个应用程序进程。同样的,ActivityRecord用于描述一个Activity,用来记录一个Activity的所有信息。在注释2处创建ActivityRecord,这个ActivityRecord用于描述即将要启动的Activity,并在注释3处将创建的ActivityRecord赋值给ActivityRecord[]类型的outActivity,这个outActivity会作为注释4处的startActivity方法的参数传递下去。
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
...
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {//1
newTask = true;
//创建新的TaskRecord
result = setTaskFromReuseOrCreateNewTask(
taskToAffiliate, preferredLaunchStackId, topStack);//2
} else if (mSourceRecord != null) {
result = setTaskFromSourceRecord();
} else if (mInTask != null) {
result = setTaskFromInTask();
} else {
setTaskToCurrentTopOrCreateNewTask();
}
...
if (mDoResume) {
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
if (!mTargetStack.isFocusable()
|| (topTaskActivity != null && topTaskActivity.mTaskOverlay
&& mStartActivity != topTaskActivity)) {
...
} else {
if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
mTargetStack.moveToFront("startActivityUnchecked");
}
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);//3
}
} else {
mTargetStack.addRecentActivityLocked(mStartActivity);
}
...
}
startActivityUnchecked方法主要处理栈管理相关的逻辑。
启动根Activity时会将Intent的Flag设置为FLAG_ACTIVITY_NEW_TASK,这样注释1处的条件判断就会满足,接着执行注释2处的setTaskFromReuseOrCreateNewTask方法,其内部会创建一个新的TaskRecord,TaskRecord用来描述一个Activity任务栈,也就是说setTaskFromReuseOrCreateNewTask方法内部会创建一个新的Activity任务栈。
继续调用方法到ActivityStackSupervisor中
源码frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
//获取即将要启动的Activity的所在的应用程序进程
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);//1
r.getStack().setLaunchTime(r);
if (app != null && app.thread != null) {//2
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
mService.mProcessStats);
}
realStartActivityLocked(r, app, andResume, checkConfig);//3
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
}
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
...
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);
...
return true;
}
注释1处获取即将要启动的Activity的所在的应用程序进程。
注释2处判断要启动的Activity的所在应用程序进程已经运行的话,就会调用注释3处的realStartActivityLocked方法,需要注意的是,这个方法的第二个参数是代表要启动的Activity的所在的应用程序进程的ProcessRecord。
在判断启动目标Activity所在的进程是否已经启动上,新版本SDK源码使用Try Catch异常捕捉的方式去做跳转逻辑,如果进程没有启动,便通知zygote fork出一个进程;如果进程已经启动了,直接让ApplicationThread调用scheduleResumeActivity方法。
realStartActivityLocked的 app.thread指的是IApplicationThread,它的实现是ActivityThread的内部类ApplicationThread,其中ApplicationThread继承了IApplicationThread.Stub。app指的是传入的要启动的Activity的所在的应用程序进程,因此,注释1处的代码指的就是要在目标应用程序进程启动Activity。当前代码逻辑运行在AMS所在的进程(SyetemServer进程),通过ApplicationThread来与应用程序进程进行Binder通信,换句话说,ApplicationThread是AMS所在进程(SyetemServer进程)和应用程序进程的通信桥梁,如下图所示。