一、概述
Activity的启动过程,涉及到多个进程以及跨进程通信IPC,总体的时序图如下所示,这种情况是打开新应用进程Activity的过程。
二、源码分析过程
1.Activity A 发起startActivity,如下:
会调用到Instrumentation的execStartActivity方法:
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
try {
//这里的调用是一个IPC过程,会调用到 ActivityTaskManagerService 的远程方法
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getOpPackageName(), who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), token,
target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
}
return null;
}
这里我们看到,调用了ActivityTaskManager提供的远程接口,并且传入了一堆参数进去,主要的参数有intent、token、whoThread。intent我们都知道这是表示一个意图,也就是我们想要启动的Activity的信息都包含在这此。后面两个参数咱们等会儿再说。
2.ATMS的内部处理
这一步已经来到了system_server进程。ActivityTaskManagerService继承了IActivityTaskManager.Stub接口,是Binder接口的实现类,作为一个系统服务存在于system_server进程中。
ActivityTaskManagerService会调用到如下方法:
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setUserId(userId) //此处就会把mRequest.mayWait设置为true
.execute();
}
这里obtainStarter会获取ActivityStarter,并执行了ActivityStarter的execute()方法,然后一步步调用,创建了本次将要启动的ActivityRecord:
ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
mSupervisor, checkedOptions, sourceRecord); //创建一个ActivityRecord,这就是将要发起的Activity在AMS中的数据结构
然后进入到比较核心的方法startActivityUnchecked(),如下:
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity, boolean restrictedBgActivity) {
computeLaunchingTaskFlags(); //推测lunchmode,主要目的是当sourceRecord为null的时候,需要|FLAG_ACTIVITY_NEW_TASK
computeSourceStack(); //查看sourceStack的状态,是否是finishing
ActivityRecord reusedActivity = getReusableIntentActivity(); //如果不设置启动模式为FLAG_ACTIVITY_NEW_TASK,此处返回为null
if (dontStart) {
//如果发起发activity是null,并且栈顶里面的activity和将要发起的activity名字相同等等逻辑,才重复使用栈顶activity,且回调newIntent
//一般情况不会走进这里
......
}
boolean newTask = false;
final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null) //taskToAffiliate通常为null
? mSourceRecord.getTaskRecord() : null;
// Should this be considered a new task?
int result = START_SUCCESS;
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true; //表示没有依附的task,所以需要另起一个
result = setTaskFromReuseOrCreateNewTask(taskToAffiliate); //重复使用TaskRecord或者创建一个新的TaskRecord
} else if (mSourceRecord != null) {
result = setTaskFromSourceRecord(); //不设置launchmode,正常情况会走这里
} else if (mInTask != null) {
result = setTaskFromInTask();
} else {
// This not being started from an existing activity, and not part of a new task...
// just put it in the top task, though these days this case should never happen.
result = setTaskToCurrentTopOrCreateNewTask(); //不考虑此种情况
}
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
mOptions);
if (mDoResume) {
......
mRootActivityContainer.resumeFocusedStacksTopActivities(
mTargetStack, mStartActivity, mOptions);
}
mRootActivityContainer.updateUserStack(mStartActivity.mUserId, mTargetStack);
return START_SUCCESS;
}
这一步主要是判定新建的Activity应该归属哪个TaskRecord、ActivityStack,默认情况下会调用setTaskFromSourceRecord()这个方法,即新建的Activity默认是属于发起方Activity所在的TaskRecord。
下一步就是RootActivityContainer的resumeFocusedStacksTopActivities方法,去显示出这个Activity。这个方法又会调用到ActivityStack内部:
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
pausing |= startPausingLocked(userLeaving, false, next, false); //终止当前的activity
......
if (next.attachedToProcess()) {
}else{
mStackSupervisor.startSpecificActivityLocked(next, true, true); //需要重新启动这个activity
}
}
这里就会把当前还在显示的Activity onPause掉。也就是先onpause上一个Activity,然后才会显示下一个Activity。
接着继续调用到了ActivityStackSupervisor里面:
void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);
if (wpc != null && wpc.hasThread()) {
realStartActivityLocked(r, wpc, andResume, checkConfig); //如果对应的进程存在,则去打开activity
return;
}
// Post message to start process to avoid possible deadlock of calling into AMS with the //不存在对应的进程,需要先创建进程
// ATMS lock held.
final Message msg = PooledLambda.obtainMessage(
ActivityManagerInternal::startProcess, mService.mAmInternal, r.processName,
r.info.applicationInfo, knownToBeDead, "activity", r.intent.getComponent());
mService.mH.sendMessage(msg);
}
这里会判断Activity对应的进程是否存在,如果不存在,那么就会给ActivityManagerService发送一条创建新进程的消息。
消息进入到ActivityManagerService:
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
HostingRecord hostingRecord, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
return mProcessList.startProcessLocked(processName, info, knownToBeDead, intentFlags,
hostingRecord, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge,
null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
null /* crashHandler */);
}
ProcessList内部会创建一个AppZygote对象,然后孵化出新的进程:
final String entryPoint = "android.app.ActivityThread";
private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int mountExternal,
String seInfo, String requiredAbi, String instructionSet, String invokeWith,
long startTime) {
final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);
startResult = appZygote.getProcess().start(entryPoint, //这里调用Zygote去创建一个新的进程
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
/*useUsapPool=*/ false,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
}
3.新创建应用进程的处理
一个Android应用进程,它的主程序入口就在ActivityThread,这在上面的 entryPoint = "android.app.ActivityThread"可以找到一些踪迹。
public static void main(String[] args) {
Looper.prepareMainLooper(); //初始化looper
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq); //attach就是把这个新创建的进程关联到AMS中
Looper.loop();
}
private void attach(boolean system, long startSeq) {
final IActivityManager mgr = ActivityManager.getService();
mgr.attachApplication(mAppThread, startSeq); //ApplicationThread是一个Binder接口的本地实现
//这是一次IPC过程,会调用ActivityManagerService服务中对应的方法
}
这里传入的mAppThread类型是ApplicationThread,它是IApplicationThread的Binder接口本地实现类,用来接收AMS等其他进程的信息,具体的接口我们后面讲。
至此,流程又来到了AMS这一边。
4.AMS处理attach信息
ActivityManagerService处理attachApplication的调用,主要是把进程名等信息,通过IApplicationThread给到新创建的应用进程:
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
ProcessRecord app;
app = mPidsSelfLocked.get(pid);
final String processName = app.processName;
final ActiveInstrumentation instr = app.getActiveInstrumentation();
ApplicationInfo appInfo = instr != null ? instr.mTargetInfo : app.info;
thread.bindApplication(processName, appInfo, providers, null, profilerInfo, //这里把进程的信息,通过IApplicationThread这个Binder接口传递给新创建的进程
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions);
app.makeActive(thread, mProcessStats);
}
在执行完bindApplication之后,ActivityManagerService会继续调用到RootActivityContainer里面的方法,找到与此进程相关联的Activity,并打开此Activity:
mStackSupervisor.realStartActivityLocked(activity, app, top == activity /* andResume */, true /* checkConfig */))
boolean realStartActivityLocked(ActivityRecord r, WindowProcessController proc,
boolean andResume, boolean checkConfig) throws RemoteException {
final ClientTransaction clientTransaction = ClientTransaction.obtain(
proc.getThread(), r.appToken);
clientTransaction.addCallback(LaunchActivityItem.obtain(new Intent(r.intent),
System.identityHashCode(r), r.info,
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
r.icicle, r.persistentState, results, newIntents,
dc.isNextTransitionForward(), proc.createProfilerInfoIfNeeded(),
r.assistToken));
mService.getLifecycleManager().scheduleTransaction(clientTransaction);
}
这里的ClientTransaction,具备IPC的能力,通过它内部的IApplicationThread Binder接口,它会把自己作为参数传递给对应要操作的进程。本次的事务处理,ClientTransaction添加了一个LaunchActivityItem,说明这是要显示Activity的意图。
5.应用进程接收信息后的处理
应用进程首先会接收到AMS对bindApplication的回调,接收的位置是在ApplicationThread内部,它是IApplicationThread的本地实现:
private class ApplicationThread extends IApplicationThread.Stub {
public final void bindApplication(String processName, ApplicationInfo appInfo, //这里会接收到来自AMS的绑定信息,主要是processName和ApplicationInfo
List providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation,
boolean isRestrictedBackupMode, boolean persistent, Configuration config,
CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
String buildSerial, AutofillOptions autofillOptions,
ContentCaptureOptions contentCaptureOptions) {
setCoreSettings(coreSettings);
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
......
sendMessage(H.BIND_APPLICATION, data); //给主线程Handler H 发送送一条信息,交由H处理
}
}
class H extends Handler {
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
}
private void handleBindApplication(AppBindData data) {
// send up app name; do this *before* waiting for debugger
Process.setArgV0(data.processName); //进程设置名称
VMRuntime.setProcessPackageName(data.appInfo.packageName); //设置包名
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info); //创建ContextImpl
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance(); //创建mInstrumentation
mInstrumentation.init(this, instrContext, appContext, component,
data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
Application app;
app = data.info.makeApplication(data.restrictedBackupMode, null); //利用反射创建了Manifest文件中对应的Application
mInstrumentation.onCreate(data.instrumentationArgs);
mInstrumentation.callApplicationOnCreate(app); //调用Application的onCreat()方法
}
在这里初始化了Android的上下文环境,同时还初始化了Application,并且回调了Application的onCreat()方法。
然后应用进程会收到ClientTransaction的方法回调:
private class ApplicationThread extends IApplicationThread.Stub {
@Override
public void scheduleTransaction(ClientTransaction transaction) throws RemoteException {
ActivityThread.this.scheduleTransaction(transaction);
}
......
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
if (async) {
msg.setAsynchronous(true);
}
mH.sendMessage(msg);
}
}
在接收到scheduleTransaction的回调之后,还是会把消息给到ApplicationThread的H处理,H会把ClientTransaction这个消息给到TransactionExecutor处理:
public void executeCallbacks(ClientTransaction transaction) {
final List callbacks = transaction.getCallbacks();
for (int i = 0; i < size; ++i) {
final ClientTransactionItem item = callbacks.get(i); //这里的item是LaunchActivityItem
item.execute(mTransactionHandler, token, mPendingActions);
item.postExecute(mTransactionHandler, token, mPendingActions);
}
}
发现TransactionExecutor会去执行ClientTransactionItem 内部的逻辑,这里是LaunchActivityItem:
public class LaunchActivityItem extends ClientTransactionItem {
public void execute(ClientTransactionHandler client, IBinder token,
PendingTransactionActions pendingActions) {
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
ActivityClientRecord r = new ActivityClientRecord(token, mIntent, mIdent, mInfo,
mOverrideConfig, mCompatInfo, mReferrer, mVoiceInteractor, mState, mPersistentState,
mPendingResults, mPendingNewIntents, mIsForward,
mProfilerInfo, client, mAssistToken);
client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
}
这里的client就是ActivityThread,ActivityThread实现了ClientTransactionHandler。于是这里就调用到了ActivityThread的handleLaunchActivity方法,同时把Activity的相关信息封装成了ActivityClientRecord 这个数据结构作为参数传递。
接下来就来到了熟悉的handleLaunchActivity方法:
public Activity handleLaunchActivity(ActivityClientRecord r,
PendingTransactionActions pendingActions, Intent customIntent) {
WindowManagerGlobal.initialize(); //获取WindowManagerService
final Activity a = performLaunchActivity(r, customIntent);
return a;
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ContextImpl appContext = createBaseContextForActivity(r);
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent); //最终是AppComponentFactory利用反射生成Activity
activity.attach(appContext, this, getInstrumentation(), r.token, //activity关联相关的信息,包括创建PhoneWindow
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config,
r.referrer, r.voiceInteractor, window, r.configCallback,
r.assistToken);
mInstrumentation.callActivityOnCreate(activity, r.state); //这里会回调Activity的OnCreate回调方法
}
在回调了OnCreate方法之后,我们的Activity就算创建完毕啦。下一步就是在设置过contentview之后,attach到WMS上显示出来了。
三、Q&A
1.Q:一个新的Activity启动过程,生命周期顺序是怎样的?
A:发起方为Activity A,新启动的为Activity B,那么:
A onPause() -> B Application onCreate() -> B onCreate() -> B onStart() ->B onResume() -> A onStop() -> A onDestroy()
2.Q:AMS和APP进程怎么通信?
A:APP想要跟AMS通信,可以通过Android SDK提供的系统类ActivityManager,去获取到Binder的Client端接口,然后向AMS发送消息。
APP想要跟ATMS通信,如最常见的startActivity,同样也是通过Android SDK提供的系统类ActivityTaskManager,获取Binder接口。
AMS想要跟APP通信,是通过IApplicationThread这个Binder接口来完成的。APP在创建的时候,会把自己实现了的IApplicationThread传递给AMS,这样AMS就拿到了对应APP的句柄,通过这个句柄跟APP通信。
3.Q:Activity里面的mToken是什么?有什么作用?
A:mToken的类型是Token,是ActivityRecord的内部成员,也是它的内部类
final IApplicationToken.Stub appToken; // window manager token
static class Token extends IApplicationToken.Stub {
private final WeakReference weakActivity;
private final String name;
Token(ActivityRecord activity, Intent intent) {
weakActivity = new WeakReference<>(activity);
name = intent.getComponent().flattenToShortString();
}
......
}
在ActivityRecord的构造函数内创建的
appToken = new Token(this, _intent);
AMS在执行realStartActivity的调用时,传递给对应的APP。
appToken会被保存在应用进程的ActivityClientRecord和Activity中。并且Token还会被传递给WMS等一些其他服务中去。
可以看出Token代表的是一个唯一的Activity,它是一种可以在不同进程间传递的介质,获取到Token就可以标定这个Activity。
4.Q:Application什么时候创建的?它和Context是什么关系?
A:Application是在应用进程创建后,AMS绑定应用程序时创建的。
它创建后会回调Android系统框架下应用的第一个生命周期函数。
Application继承自ContextWrapper,也就是继承自Context。它因此也拥有Context所定义的,提供整个Android系统环境接口的能力。
但是Application提供上下文的能力不是有它自己实现的,而是由创建Application的时候传入了一个ContextImpl提供。
5.Q: 设置了singleTask模式,启动Activity的时候就会创建新的Task任务栈吗?
A:不一定,如果新启动的Activity的所属的任务栈已经存在,那么就不会创建新的任务栈。
怎么判断这个Activity的所属的任务栈,我们可以简单理解为任务栈名称相同,这就涉及到taskAffinity。
taskAffinity属性默认值就是应用包名。在manifest文件中也可以手动设置这个属性。
Task任务栈中的taskAffinity是UID加上XML中的taskAffinity属性一起组合的,类似于如下:
taskAffinity=10007:com.example.activitytest01
那么也就是说两个不同进程的Activity,虽然设置的taskAffinity属性是一样的,但是它们是属于不同的任务栈。
taskAffinity属性只有在设置了singleTask,新创建Task任务栈的时候才有用。
6.Q:Task任务栈和应用程序的关系
A:TaskRecord是一系列Activity的集合,但这些Activity并不一定属于同一个应用程序。
同一个应用程序,它内部的Activity也可能会属于不同的TaskRecord。
一个Activity,它始终会运行在自己所在的应用进程,但是它可能却存在于另外一个应用进程建立的Task任务栈中。