「这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战」。
Launcher应用Activity启动流程(初始篇)
从前述 应用进程启动流程分析(客户端篇)和应用进程启动流程分析(服务端篇)中,我们以Launcher应用进程的启动流程,描述了应用进程的FORK和启动流程,那么接下来我们接着前两篇继续分析一下Launcher应用Activity启动流程。
在分析ActivityThread的main函数之前,我们有必要先整理一下ActivityThread类的基本结构,如下:
classDiagram
ClientTransactionHandler <|-- ActivityThread
Handler <|-- H
ActivityThread *-- H
ActivityThread *-- AppBindData
ActivityThread *-- ActivityClientRecord
ActivityThread *-- ApplicationThread
IApplicationThread *-- Stub
Stub <|-- ApplicationThread
<<abstract>> ClientTransactionHandler
<<interface>> Stub
class ActivityThread {
+main(String[] args) void
-attach(boolean system, long startSeq) void
-installContentProviders(Context context, List<ProviderInfo> providers) void
-handleBindApplication(AppBindData data) void
+handleLaunchActivity(ActivityClientRecord, PendingTransactionActions, Intent) Activity
}
class ClientTransactionHandler {
#scheduleTransaction(ClientTransaction transaction) void
}
class H {
+handleMessage(Message msg) void
}
从这边可以看到,ActivityThread类继承自ClientTransactionHandler抽象类,且包含有四个内部类,其中
- H类继承自Handler,其重写了Handler的handleMessage函数
- ApplicationThread类继承自IAppliactionThread.Stub对象,使用Binder通信传递数据
- AppBindData保存有应用进程的一些基本信息
接下来,我们继续分析ActivityThread的main函数具体做了什么
public static void main(String[] args) {
// ......
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
// ......
}
在ActivityThread的main函数中主要初始化ActivityThread对象并调用其attach函数。
不过,在分析attach函数之前,首先我们要先确认一下其第二个参数startSeq具体是什么?
ActivityThread的attach函数的第二个参数startSeq表示什么
追踪这个startSeq参数值,可以看到,其在ActivityThread的main函数,通过传入参数args中包含"seq="字串的对应参数值
public static void main(String[] args) {
// ......
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()));
}
}
}
// ......
}
而main函数的args是根据进程启动过程中传递的参数,说到进程启动的流程,服务端的参数数据是通过zygote的socket从客户端传递过来的,因此,追溯到客户端的代码可知
ProcessList.java
boolean startProcessLocked(......) {
// ......
final long startSeq = app.startSeq = ++mProcStartSeqCounter;
// ......
mPendingStarts.put(startSeq, app);
// ......
final Process.ProcessStartResult startResult = startProcess(hostingRecord,
entryPoint, app,
uid, gids, runtimeFlags, zygotePolicyFlags, mountExternal, seInfo,
requiredAbi, instructionSet, invokeWith, startTime);
// ......
}
private Process.ProcessStartResult startProcess(......) {
// ......
// 注意最后一个参数
startResult = Process.start(......, new String[]{PROC_START_SEQ_IDENT + app.startSeq});
// ......
}
ZygoteProcess.java
private Process.ProcessStartResult startViaZygote(args[......]
@Nullable String[] extraArgs)
throws ZygoteStartFailedEx {
// ......
if (extraArgs != null) {
Collections.addAll(argsForZygote, extraArgs);
}
// ......
return zygoteSendArgsAndGetResult(......, argsForZygote);
// ......
}
因此,上述ActivityThread对象的attach函数中传递的startSeq参数的数值是从进程启动过程中,在ProcessList对象中生成的一个索引值,这个索引值和对应的进程启动包含Activity信息的ProcessRecord对象生成<key, value>,并保存在ProcessList的mPendingStarts参数对象中
ActivityThread的attach函数运行
此后,我们来看一下ActivityThread的attach函数具体做了哪些操作
final ApplicationThread mAppThread = new ApplicationThread();
private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mSystemThread = system;
// 传入参数false
if (!system) {
// ......
// 获取对应的ActivityManagerService对象
final IActivityManager mgr = ActivityManager.getService();
try {
// 调用AMS的attachApplication函数
mgr.attachApplication(mAppThread, startSeq);
}
// ......
// Watch for getting close to heap limit.
// 监听当前的堆内存信息,及时回收内存空间
BinderInternal.addGcWatcher(new Runnable() {
@Override public void run() {
// ......
}
});
}
// ......
ViewRootImpl.ConfigChangedCallback configChangedCallback
= (Configuration globalConfig) -> {
// ......
};
ViewRootImpl.addConfigCallback(configChangedCallback);
}
在这个函数中主要调用AMS的attachApplication函数,注,此处还添加了一个堆内存信息监听,用作及时释放和回收对应的内存空间
ActivityManagerService.java
public final void attachApplication(IApplicationThread thread, long startSeq) {
// ......
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
Binder.restoreCallingIdentity(origId);
}
}
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
// ......
// 可以看到,此处直接从ProcessList的mPendingStarts参数对象中获取key为startReq对应的ProcessReocrd对象
// 当然,此处是Launcher应用对应的启动Activity的信息
// It's possible that process called attachApplication before we got a chance to
// update the internal state.
if (app == null && startSeq > 0) {
final ProcessRecord pending = mProcessList.mPendingStarts.get(startSeq);
if (pending != null && pending.startUid == callingUid && pending.startSeq == startSeq
&& mProcessList.handleProcessStartedLocked(pending, pid, pending
.isUsingWrapper(),
startSeq, true)) {
app = pending;
}
}
// ......
// 获取当前的应用中包含的所有的ContentProvider信息
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
// ......
final BackupRecord backupTarget = mBackupTargets.get(app.userId);
try {
// ......
ApplicationInfo appInfo = instr != null ? instr.mTargetInfo : app.info;
app.compat = compatibilityInfoForPackage(appInfo);
// ......
mAtmInternal.preBindApplication(app.getWindowProcessController());
final ActiveInstrumentation instr2 = app.getActiveInstrumentation();
if (mPlatformCompat != null) {
mPlatformCompat.resetReporting(app.info);
}
final ProviderInfoList providerList = ProviderInfoList.fromList(providers);
// ......
thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
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.mDisabledCompatChanges);
// Make app active after binding application or client may be running requests (e.g
// starting activities) before it is ready.
// 注意,ProcessRecord对象的makeActive函数会将当前的ApplicationThread对象设置给ProcessRecord
// 此处在后续的分析中会用到
app.makeActive(thread, mProcessStats);
// ......
}
// See if the top visible activity is waiting to run in this process...
if (normalMode) {
try {
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
// ...... 本篇将只讨论Activity的启动流程,后续的服务,广播等启动暂不做分析
return true;
}
从这边可以看到,最终会
- 调用到此处的ApplicationThread对象的bindApplication函数, 来启动整个Application
- 此后会通过调用ActivityTaskManagerService.LocalService对象的attachApplication函数来启动Activity,进入Activity的整个声明周期