写在最前面
这篇文章写了一年有余,我前几天哥们问启动流程的时候 。 我信誓旦旦这玩意简单,张口就来。然后嗯啊了半天,什么也没说出来,丢了个大的。 进入了张无忌学太极拳的境界,我已经全部忘记了。

所以要理解去记。 带几个疑问去看代码,才能真的记下来,不要死记方法,知道核心点就行。
梳理问题
- 系统是怎么判断进程是否存在的?
- 那系统是怎么启动一个新的进程的?
- 系统启动进程后,是怎么把我们要的Activity拉起来的?
问题梳理
系统是怎么判断进程是否存在的?
让我们梦回ActivityTaskSupervisor的startSpecificActivity()
js
void startSpecificActivity(ActivityRecord r, boolean andResume, boolean checkConfig) {
// Is this activity's application already running?
final WindowProcessController wpc =
mService.getProcessController(r.processName, r.info.applicationInfo.uid);
boolean knownToBeDead = false;
if (wpc != null && wpc.hasThread()) {
try {
realStartActivityLocked(r, wpc, 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.
knownToBeDead = true;
// Remove the process record so it won't be considered as alive.
mService.mProcessNames.remove(wpc.mName, wpc.mUid);
mService.mProcessMap.remove(wpc.getPid());
//省略部分代码
mService.startProcessAsync(r, knownToBeDead, isTop,
isTop ? HostingRecord.HOSTING_TYPE_TOP_ACTIVITY
: HostingRecord.HOSTING_TYPE_ACTIVITY);
}
我们可以看到 有一句注释 Is this activity's application already running? 其实很简单 就是去 ATMS 根据processName 和uid 去查一下,你的wpc 是否存在 并且你的 ApplicationThread 也存在,就证明你的进程是存在的。 就可以直接启动对应页面。然后 return。
总结一下
看看进程对应的WindowProcessController 和ApplicationThread 是否存在。
那系统是怎么启动一个新的进程的?
我们看到上面代码部分有 调用到 mService.startProcessAsync 这里一路调用下去 会进入ZygoteProcess的 openZygoteSocketIfNeeded 然后调用到 attemptConnectionToPrimaryZygote();
java
@GuardedBy("mLock")
private void attemptConnectionToPrimaryZygote() throws IOException {
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
primaryZygoteState =
ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);
maybeSetApiDenylistExemptions(primaryZygoteState, false);
maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
}
}
这里不要记代码,就知道最后搞了个socket进行了通信。 我们这里要知道和哪里进行了通信。 其实这个是在ZygoteInit 的main 方法里
java
zygoteServer = new ZygoteServer(isPrimaryZygote);
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList);
这里 的zygoteServer.runSelectLoop(abiList) 上面注释 意思就是等待一个字进程来fork 在这里面。不贴代码了,这里主要是根据连接过来的的句柄,然后进行返回一个 Runnable,咱们简单理解就是你socket 一连,这边发现多一个,嘿, 帮你构建一个Runnable 返回回去。
java
final Runnable command =
connection.processCommand(this, multipleForksOK);
if (mIsForkChild) {
// We're in the child. We should always have a command to run at
// this stage if processCommand hasn't called "exec".
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
}
java
//ZygoteConnection
Runnable result = Zygote.forkSimpleApps(argBuffer,
zygoteServer.getZygoteSocketFileDescriptor(),
peer.getUid(), Zygote.minChildUid(peer), parsedArgs.mNiceName);
最后调用到 RunTimeInit.applicationInit(),其实就构建了 反射调用 ActivityThread的 main 方法的一个Runnable 并传入了 参数 "seq=42",这里的42并不是固定值,我只是演示用。 最后返回 Runnable 被执行,反射启动了ActivityThread。
总结一下。
在启动 SystemSerVer的时候,启动了一个死循环,等待Socket的连接, 当我们启动Activity 发现进程没启动的时候,会构建Socket 和这里链接,反射构建了ActivityThread 的main 方法并传入了参数 seq=x。 其实到这里还没有解决第三个问题,怎么启动的Activity,我们放到第三个问题里回答。
系统启动进程后 是怎么把我们要的Activity拉起来的?
ActivityThread的 main 方法部分解析
java
//ActivityThread
final ApplicationThread mAppThread = new ApplicationThread();
public static final String PROC_START_SEQ_IDENT = "seq=";
public static vodi 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()));
}
}
}
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
//省略部分代码。。。
//调用到attachApplication
attachApplication(mAppThread, startSeq);
}
其实上面代码就是把seq 进行了获取,比如我们拿到了42,然后调用 ActivityThread的attch 方法。 调用到了AMS的attachApplication 方法 ,继续调用到了 attachApplicationLocked, 注意 在ActivityThread 里面的 ApplicationThread 是直接构建出来的 ,后面直接作为参数传到了AMS。
java
//AMS
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
ProcessRecord app;
//省略。。
//seq的使用
if (app == null && startSeq > 0) {
final ProcessRecord pending = mProcessList.mPendingStarts.get(startSeq);
if (pending != null && pending.getStartUid() == callingUid
&& pending.getStartSeq() == startSeq
&& mProcessList.handleProcessStartedLocked(pending, pid,
pending.isUsingWrapper(), startSeq, true)) {
app = pending;
}
}
//省略。。
thread.bindApplication(processName, appInfo,
app.sdkSandboxClientAppVolumeUuid, app.sdkSandboxClientAppPackage,
providerList, null, profilerInfo, null, null, null, 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,
app.getStartElapsedTime(), app.getStartUptime());
//省略
//
if (normalMode) {
try {
didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
} catch (Exception e) {
Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
badApp = true;
}
}
}
这里可以根据传入的thread 也就是 我们从ActivityThread ,调用了bindApplication ,回到了ActivitThread ,最终回调了 handleBindApplication(data); 开始了Application的构建。这里不展开拓展。但是这里要看到 AMS到App之间的交互 ,依赖于ApplicationThread。
到这里是Application的构建,那我们要启动的Activity 去哪里了?
其实是在 mAtmInternal.attachApplication 方法里。注意他的参数是app.getWindowProcessController()。 也就是我们之前说如何判断app进程是否存在的抓手。 然后调用到 mRootWindowContainer.attachApplication(wpc); 继续调用RootWindowContainer 内部的, AttachApplicationHelper的process 方法。 process 方法会调用到他自己的 test方法 。该方法里调用到了mTaskSupervisor.realStartActivityLocked() 方法。 这里我们就很熟悉了,然后就是熟悉的构建 ActivityLifecycleItem和 mService.getLifecycleManager().scheduleTransaction(clientTransaction); 推进生命周期,触发对应Activity的生命周期 ,这里不浪费篇幅。
总结一下
在Application 构建以后,会进入 RootWindowContainer 它通过遍历任务栈、筛选符合条件的 Activity,并构建LifeItem进行页面生命周期启动。