Activity启动过程中你所不知道的细节
在安卓面试过程中,经常被问到以下几个问题:
1、Activity的生命周期
2、Activity启动后到页面展现出来的过程
3、应用启动过程
其实这些问题都可以在Activity的启动过程中(应用启动其实也是Activity启动的一个分支)寻找到答案,下面就让我们来探究下Activity启动过程到底经历了什么东西吧。
核心流程
先上一张核心的流程图:
![](https://img.haomeiwen.com/i2362099/89e242ae16220aa3.png)
由上图可知,Activity启动涉及到应用层、framework层两个部分,应用层的交互主要由Instrumentation类承担,作为与framework层通讯的入口管理类,framework层主要涉及ActivityManager对全局Activity栈相关的管理、Application进程的管理以及最终ApplicationThread对Activity生命周期的调度。
整个过程涉及了两次AIDL跨进程通讯,第一次是从startActivity发起方的进程切换到系统进程,调用入口代码位于类ActivityManager中:
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
在系统进程中完成了Intent flag等数据处理以及Activity栈、TaskRecord的管理,然后再次使用AIDL跨进程调用,切换到应用进程完成Activity的创建及相关生命周期方法的回调。所以,要理清楚Activity的启动过程主要就是要理清楚framework层的代码流程,这时就需要去分析framework层的源码了,sdk里面是不包含framework层的代码的,需要翻墙查看:https://android.googlesource.com/platform/frameworks/base/+refs,笔者这边分析的是android-cts-7.1_r20 tag的代码,不同版本的代码可能会有细微的差异。
Framework源码分析
首先从最开始的地方也就是ActivityManagerService开始(代码地址:https://android.googlesource.com/platform/frameworks/base/+/android-cts-7.1_r20/services/core/java/com/android/server/am/ActivityManagerService.java)
public class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
...
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
final int startActivity(Intent intent, ActivityStackSupervisor.ActivityContainer container) {
enforceNotIsolatedCaller("ActivityContainer.startActivity");
final int userId = mUserController.handleIncomingUser(Binder.getCallingPid(),
Binder.getCallingUid(), mStackSupervisor.mCurrentUser, false,
ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
// TODO: Switch to user app stacks here.
String mimeType = intent.getType();
final Uri data = intent.getData();
if (mimeType == null && data != null && "content".equals(data.getScheme())) {
mimeType = getProviderMimeType(data, userId);
}
container.checkEmbeddedAllowedInner(userId, intent, mimeType);
intent.addFlags(FORCE_NEW_TASK_FLAGS);
return mActivityStarter.startActivityMayWait(null, -1, null, intent, mimeType, null, null, null,
null, 0, 0, null, null, null, null, false, userId, container, null);
}
@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");
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivity", null);
// TODO: Switch to user app stacks here.
return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null, null, bOptions, false, userId, null, null);
}
...
}
由上述代码片段可以看出几点:ActivityManager继承了IActivityManager.Stub,熟悉AIDL的同学应该一眼就能看出这是AIDL的特点;startActivity最终由mActivityStarter执行,然后顺着代码一步步往下分析即可。
最终经过一系列方法调用:ActivityStarter#startActivityUnchecked->
ActivityStackSupervisor#resumeFocusedStackTopActivityLocked->
ActivityStack#resumeTopActivityUncheckedLocked->
ActivityStack#resumeTopActivityInnerLocked->
ActivityStackSupervisor#startSpecificActivityLocked->
ApplicationThread#schedule*完成了Activity的启动过程。(有兴趣的同学可以从ActivityManagerService类开始一步步分析下去。)
其中,我们只需要分析核心类ActivityStack、ActivityStackSupervisor、ApplicationThread即可。
首先看ActivityStack#resumeTopActivityInnerLocked方法
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
···
// We need to start pausing the current activity so the top one can be resumed...
final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, dontWaitForPause);
if (mResumedActivity != null) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Pausing " + mResumedActivity);
pausing |= startPausingLocked(userLeaving, false, next, dontWaitForPause);
}
···
mStackSupervisor.startSpecificActivityLocked(next, true, true);
···
}
由上述代码片段可知,Activity启动之前,必须先pause当前Activity,这里最终也会调用到ApplicationThread里面的方法,具体就不细说了。
然后再看ActivityStackSupervisor#startSpecificActivityLocked方法,最终发现同样是调用到了app.thread中的调度方法,这也是整个过程的第二次AIDL跨进程调用。
public final class ActivityStackSupervisor implements DisplayListener {
...
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.task.stack.setLaunchTime(r);
if (app != null && app.thread != null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
// Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a
// separate apk in the process.
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
mService.mProcessStats);
}
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
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);
...
}
...
}
最后看ApplicationThread#scheduleLaunchActivity方法(注意ApplicationThread是ActivityThread的内部类哦)
// we use token to identify this activity without having to send the
// activity itself back to the activity manager. (matters more with ipc)
@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
int procState, Bundle state, PersistableBundle persistentState,
List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
...
sendMessage(H.LAUNCH_ACTIVITY, r);
}
这里就是采用message机制的地方,通过message机制通知Handler H(也是ActivityThread的内部类)完成了Activity的启动(大家可以思考下为什么这里用了message机制,笔者认为message机制主要是可以确保应用层Activity启动的过程都是在主线程中完成的)
后续的代码片段如下:
Handler H:
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
} break;
}
...
}
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
Activity a = performLaunchActivity(r, customIntent);
...
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
...
}
//创建Activity并通过Instrumentation调用Activity的onCreate方法
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
...
mInstrumentation.callActivityOnCreate(activity, r.state);
....
}
final void handleResumeActivity(IBinder token,
boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
...
r = performResumeActivity(token, clearHide, reason);
...
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
...
if (a.mVisibleFromClient && !a.mWindowAdded) {
a.mWindowAdded = true;
wm.addView(decor, l);
}
}
由上面的代码片段可知Activity启动顺序为onCreate->onResume->DecorView绘制。
综上所述可以得知Activity启动生命周期为:
Activity source onPause->Activity target onCreate->Activity target onResume->页面绘制(onStop的调用周期没有找到就不列了)
最初的问题1,2也就有了答案了。
至于问题3,首先要明确的是,Android的桌面其实也是一个Activity,应用启动其实也是startActivity的过程,唯一的区别在于此时应用进程还未创建,回到ActivityStackSupervisor#startSpecificActivityLocked方法可以发现,应用启动的分支就在此处,当应用进程不存在时,会创建一个新的进程。
public final class ActivityStackSupervisor implements DisplayListener {
...
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.task.stack.setLaunchTime(r);
if (app != null && app.thread != null) {
try {
if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) {
// Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a
// separate apk in the process.
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
mService.mProcessStats);
}
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
}
除了应用进程的创建,应用启动过程的区别还包括ActivityThread的创建、向ActivityManagerService绑定新建的ApplicationThread、创建UI Thread等操作,然后就是MainActivity的启动过程与上述情况一至,具体流程就不详细列举了。
总结
通过上述framework层代码的分析,我们大致了解了Activity启动的过程,其中笔者最重要的还是最开始的流程图,我们主要需要了解整体的工作原理,对于代码细节没必要死抠。
整体看下来,AIDL跨进程通讯贯穿了整个Acitivity的生命周期,这其实也是Android系统整体的一个设计思路:通过一系列framework层的ManagerService来实现和管理各种应用功能,相当于C/S架构,这些service相当于服务端,对于我们应用开发者只暴露基础的接口,具体实现封装在framework层可以随时升级替换,应用层通过AIDL向“服务端”发起请求获取各种基础功能服务。