前言
Activity 启动过程文章系列会按阶段拆开分析。上一篇已经讲完 Zygote 如何 fork 出新的应用进程;本文只聚焦 ActivityThread 初始化阶段:新进程如何进入主线程、如何把 ApplicationThread 注册给 AMS,以及应用侧如何完成 bindApplication 和 Application 初始化。
启动流程梳理:
- Activity 启动流程(一)—— Launcher 阶段
- Activity 启动流程(二)—— AMS 处理阶段
- Activity 启动流程(三)—— 应用程序进程启动阶段
- Activity 启动流程(四)—— ActivityThread 初始化阶段
- Activity 启动流程(五)—— Activity 启动阶段
代码基于 android-14.0.0_r9。
1. 一句话总览
这一阶段的核心是:新应用进程从 ActivityThread.main() 进入主线程世界,创建 ActivityThread,把 ApplicationThread 通过 attachApplication() 注册给 AMS;AMS 再通过 bindApplication() 把应用绑定数据回送给客户端,最终由 handleBindApplication() 完成 Instrumentation、Application、ContentProvider 等应用级初始化。
主链路如下:
ActivityThread.main()→ActivityThread.attach(false, startSeq)→ActivityManagerService.attachApplication()→attachApplicationLocked()→ApplicationThread.bindApplication()→ActivityThread.handleBindApplication()→LoadedApk.makeApplication()→installContentProviders()→Instrumentation.callApplicationOnCreate()
flowchart LR
A[ActivityThread.main]
B[prepareMainLooper]
C[new ActivityThread]
D[attach false startSeq]
E[AMS.attachApplication]
F[thread.bindApplication]
G[H.BIND_APPLICATION]
H[handleBindApplication]
I[makeApplication]
J[installContentProviders / Application.onCreate]
A --> B --> C --> D --> E --> F --> G --> H --> I --> J
这条链路结束时,应用进程已经完成了主线程、ApplicationThread、Application 以及 Provider 的基础初始化,但 Activity 本身还没有真正 launch。
2. ActivityThread 初始化阶段源码分析
2.1 进程入口:从 ActivityThread.main() 进入应用主线程
新进程在 Java 世界的入口是 ActivityThread.main():
// frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
...
Looper.prepareMainLooper();
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
}
这里有三个关键信号:
- 应用主线程的
Looper在这里建立。 ActivityThread在这里被创建,它会成为客户端世界的核心调度者。startSeq被从启动参数里解析出来,用来和 system_server 的那次进程启动请求对上。
也就是说,到 main() 为止,系统刚把“一个新进程”变成“一个拥有主线程消息循环的 Android 应用进程”。
2.2 注册到 AMS:attach() 把 ApplicationThread 暴露给 system_server
ActivityThread 创建好之后,马上进入 attach(false, startSeq):
// frameworks/base/core/java/android/app/ActivityThread.java
private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mConfigurationController = new ConfigurationController(this);
mSystemThread = system;
mStartSeq = startSeq;
if (!system) {
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>", UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManager.getService();
try {
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
...
}
}
这里最重要的是 mgr.attachApplication(mAppThread, startSeq)。它说明新进程启动后做的第一件系统交互,不是启动 Activity,而是先把 ApplicationThread 这个 Binder 入口 注册给 AMS。
这样 system_server 后续才有能力反向回调这个应用进程,例如 bindApplication()、调度事务、分发生命周期等。
2.3 system_server 侧绑定:AMS 先认可这条进程,再回调 bindApplication()
AMS 收到 attachApplication() 后,先把这个进程和之前的启动记录对上:
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
public final void attachApplication(IApplicationThread thread, long startSeq) {
if (thread == null) {
throw new SecurityException("Invalid application interface");
}
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
Binder.restoreCallingIdentity(origId);
}
}
在 attachApplicationLocked() 里,真正关键的是 thread.bindApplication(...):
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...
thread.bindApplication(processName, appInfo, providerList,
instr2.mClass, profilerInfo, instr2.mArguments,
instr2.mWatcher, instr2.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.getCompat(), getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions,
app.getDisabledCompatChanges(), serializedSystemFontMap);
...
synchronized (mProcLock) {
app.makeActive(thread, mProcessStats);
}
...
}
这说明 AMS 在这一阶段主要做两件事:
- 确认这条新进程确实是刚刚启动出来的那条进程;
- 把应用绑定数据回送给客户端,并把
thread记录到ProcessRecord/WindowProcessController里。
也就是说,AMS 在这里做的是“进程接入”和“应用绑定”,还不是“Activity launch”。
2.4 客户端绑定:bindApplication() 只是发消息,真正初始化在 handleBindApplication()
IApplicationThread 在客户端的实现就是 ActivityThread.ApplicationThread。它收到 bindApplication() 后,不会立刻在 Binder 线程里做重活,而是转成主线程消息:
// frameworks/base/core/java/android/app/ActivityThread.java
public final void bindApplication(String processName, ApplicationInfo appInfo,
ProviderInfoList providerList, 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, long[] disabledCompatChanges,
SharedMemory serializedSystemFontMap) {
...
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providerList.getList();
...
sendMessage(H.BIND_APPLICATION, data);
}
真正的初始化发生在 handleBindApplication():
// frameworks/base/core/java/android/app/ActivityThread.java
private void handleBindApplication(AppBindData data) {
...
mBoundApplication = data;
mConfigurationController.setConfiguration(data.config);
mConfigurationController.setCompatConfiguration(data.config);
...
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
...
if (ii != null) {
initInstrumentation(ii, data, appContext);
} else {
mInstrumentation = new Instrumentation();
mInstrumentation.basicInit(this);
}
...
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
}
}
mInstrumentation.onCreate(data.instrumentationArgs);
mInstrumentation.callApplicationOnCreate(app);
...
}
这一层才是本文真正的终点。因为它把应用进程初始化需要的基础对象都建立起来了:
ContextImplInstrumentationApplicationContentProvider
到这里为止,可以说 “应用进程已经准备好运行应用代码了”,但还不能说 “目标 Activity 已经启动完了”。
3. 关键设计点
3.1 ActivityThread.main() 建立的是应用主线程世界
上一篇只是把进程 fork 出来;ActivityThread.main() 才真正把它变成一个能跑 Android 组件生命周期的应用进程。Looper.prepareMainLooper() 和 Looper.loop() 是这一切的基础。
3.2 ApplicationThread 是客户端暴露给 AMS 的 Binder 门面
attachApplication(mAppThread, startSeq) 的意义,不是立刻启动 Activity,而是先把客户端的回调入口交给 system_server。没有这一步,后续的 bindApplication()、事务调度都无从谈起。
3.3 bindApplication() 是应用级初始化网关,不是 Activity 启动网关
handleBindApplication() 初始化的是 Application、Instrumentation、Provider 和配置环境。它负责把应用“跑起来”,但不负责把具体 Activity “拉起来”。这正是它和下一篇的边界。
5. 总结
ActivityThread 初始化阶段的本质,是 把“刚被 fork 出来的 Linux 进程”变成“已经接入 system_server、完成应用级初始化的 Android 应用进程”。
当 handleBindApplication() 执行完,Application、Instrumentation 和 Provider 都已经准备好了。接下来 system_server 才会继续把等待中的 Activity 启动事务发给客户端,这就是下一篇的起点。