根Activity启动过程深刻剖析(上)
2023-10-23 19:54:40
根Activity启动过程深刻剖析(上)
在几个月前我写了《Android深入四大组件(一)应用程序启动过程(前篇)》和《Android深入四大组件(一)应用程序启动过程(后篇)》这两篇文章,它们都是基于Android 7.0,当我开始阅读Android 8.0源码时发现应用程序(根Activity)启动过程照Android 7.0没有太大变化,所以,根Activity启动过程仍然基于前三篇为基础进行讲解。
接下来我来分析它们是如何协调执行根Activity启动过程的,以及这里面还涉及的Activity启动动画和启动主题。
根Activity启动过程的前半部分由Launcher进程触发,从Launcher到ActivityManagerService服务, 再到ActivityThread, 后半部分基本和Android 7.0应用程序启动流程一致, ActivityThread通过Instrumentation回调AMS启动Activity,Instrumentation转发AMS回调至ActivityThread并解析AndroidManifest.xml开始启动Activity。
来看看ActivityManagerService是如何触发Instrumentation回调,同时启动ActivityThread的。
这个类是根Activity启动过程中关键的一个变量, 我们来看下它是个什么东西。
Instrumentation是一个系统级服务, 我们可以利用Instrumentation来启动指定Activity, 而这个Instrumentation实际上是AMS赋予我们操作ActivityThread的能力, 在前几篇文章中, 当ActivityThread在Main函数中的loop()方法中调用ActivityThread的attachApplication方法时, 参数中的Instrumentation对象会被传给attachApplication方法的另一个参数ApplicationThread.AppBindData中。
在ActivityThread的attachApplication方法中对Instrumentation做了两次set操作, 将ApplicationThread对象和Binder对象赋予了Instrumentation中的ApplicationThread和Binder属性。 由于Instrumenttion不是一个静态的类,需要创建对象, 而且它是一个系统级服务, 我们可以通过Context.getSystemService方法和"instrumentation"标识得到一个Instrumentation实例。
知道了上述信息之后, 我们再看看attachApplication方法中的另外一个方法instrumentation.init, 这里有一段注释:
The root application has been started. This is where the
process actually enters in attachApplication. For a normal
process, the application and bindApplication methods will
have already been called when this method returns.
这里, ActivityThread已经完成应用程序(根Activity)的启动, 在这个阶段, ActivityThread已经调用了bindApplication方法, 在这个方法中, 会和ActivityManagerService进行RPC, 也就是Instrumentation.execStartActivity方法, 也就是这里所说的instrumentation.init()。
同样, 在instrumentation.init()方法中有一段注释:
This function is used by anyone who is in the same process
as an application (typically would be system ui, etc) to tell
the process that it's now okay to go ahead and start.
再往init方法里看, 这里找到了启动应用程序入口的入口。
Binder binder = sDefaultBinder;
if (!binder.isBinderAlive()) {
if (DEBUG_MESSAGES) {
Log.w(TAG, "Instrumentation binder (1) went away, app will not " +
"be launched.");
}
try {
// 0: BinderProxy.DeathRecipient
mInstrumentationBinder.unlinkToDeath(this, 0);
} catch (RemoteException e) {
Log.w(TAG, "RemoteException calling unlinkToDeath: " + e);
}
return;
}
mInstrumentationBinder = null;
ApplicationThread application = null;
try {
application = AppThread.asInterface(binder);
application.instrumentationStarted(this);
if (DEBUG_MESSAGES) {
Log.w(TAG, "Instrumentation now started.");
}
} catch (RemoteException e) {
if (DEBUG_MESSAGES) {
Log.w(TAG, "RemoteException calling instrumentationStarted: " + e);
}
try {
// 0: BinderProxy.DeathRecipient
mInstrumentationBinder.unlinkToDeath(this, 0);
} catch (RemoteException e1) {
Log.w(TAG, "RemoteException calling unlinkToDeath: " + e1);
}
return;
}
application.scheduleLaunchActivity(new ActivityClientRecord(activity,
binder, false, instrumentation),
mInstrumentation.mProfilerProxy);
再看ActivityThread的attachApplication方法中的else语句, 也就是当AMS绑定的对象和ActivityThread当前实例不匹配时的操作, 这里, ActivityThread启动应用程序, 然后通过instrumentation.execStartActivity发送请求, 并且Instrumentation.execStartActivity是Instrumentation对象的关键方法。
在Instrumentation.execStartActivity方法中, 先向ApplicationThread发送ApplicationThread.scheduleLaunchActivity, 然后创建ActivityClientRecord对象, 再启动Instrumentation的Binder对象。
if (mBinder != null && sDefaultBinder.isBinderAlive()) {
scheduleLaunchActivity(new ActivityClientRecord(activity,
sDefaultBinder, false, instrumentation),
instrumentation.mProfilerProxy);
}
if (isInstrumenting()) {
startBinderTracking();
}
然后ActivityClientRecord被传入了ApplicationThread.scheduleLaunchActivity中, 并且该方法中调用了一个关键方法performLaunchActivity, 再看ActivityClientRecord对象, 在该对象中包含了一系列数据,比如intent、binder、运行模式、是否可执行、进程信息和仪表信息等。
在performLaunchActivity方法中, 有两段关键代码如下:
IBinder token = mH.sendMessageAtTime(mCallback,
RealTimeClock.MillisClock.getInstance().uptimeMillis()
+ (component == null
? mLaunchTimeOms : mAnimationOms));
...
mInstrumentation->launchActivity(token, null);
在performLaunchActivity方法中, ActivityManagerService回调Instrumentation对象, 并且这个Instrumentation对象已经被ActivityThread赋予了可操作ApplicationThread的能力, 在Instrumentation对象中, 当收到ActivityManagerService的回调后, 调用一个函数:
public void launchActivity(IBinder token, IVoiceInteractor starter) {
AppThread appThread = AppThread.current();
// To prevent the dispatch of the resume intent from being
// overlooked, mDidBindView has to be set before invoking the method
// below that receives the return value from the app thread.
mDidBindView = true;
try {
appThread.scheduleLaunchActivity(token);
} catch (RemoteException ex) {
throw new RuntimeException("Couldn't schedule launch: " + ex);
}
}
这里, ActivityManagerService的回调函数是launchActivity方法, 这个方法是Instrumentation的公共接口, 这个方法调用scheduleLaunchActivity方法, scheduleLaunchActivity方法中调用attachApplication方法, 调用attachApplication方法后, 就进入了ActivityThread.handleLaunchActivity方法, handleLaunchActivity方法将创建一个H对象, 并通过H对象发送一个消息到handleLaunchActivity方法, 并且这个handleLaunchActivity方法就是ActivityThread的handleLaunchActivity, 再看ActivityThread的handleLaunchActivity方法如下:
public final void handleLaunchActivity(ActivityClientRecord r,
Activity... activities) {
// set before calling application callbacks, for instrumentation
mLaunchingActivity = r;
if (r != null) {
String processName =
mAppThread.asBinder().getProcessName();
r.processName = processName;
}
// TODO(b/26042302): avoid allocating this instance per activity
mLaunchingActivityContainer = new ActivityContainer(activities, r.activityInfo.windowLayout);
}
在该方法中, 有一个变量mLaunchingActivityContainer, 该变量是ActivityContainer类型的, 它有一个叫做addActivityContainer方法。 现在, ActivityThread已经完成应用程序(根Activity)的启动, Instrumentation调用ActivityContainer对象的addActivityContainer方法, 创建ActivityActivity, 并将Activity添加到Container中, 接下来会调用performLaunchActivity方法, 这个方法中有一段关键的代码:
mInstrumentation->callActivityOnCreate(r.token, icicle);
这段代码将调用Instrumentation对象的callActivityOnCreate方法, 而callActivityOnCreate方法中会通过ActivityManagerService的回调调用attachApplication方法, 也就是在Instrumentation对象中的attachApplication方法。 在该方法中有两段关键代码:
// TODO: re-enable this once bug 2496596 is fixed.
// try {
// r.activity.attach(r.application, r.activityInfo, token, null, null,
// r.loadedApk, r.app, r