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

所以要理解去记。 带几个疑问去看代码,才能真的记下来,不要死记方法,知道核心点就行。
梳理问题
- 系统是怎么判断进程是否存在的?
- 那系统是怎么启动一个新的进程的?
- 系统启动进程后,是怎么把我们要的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
发现进程没启动的时候,会构建Socke
t 和这里链接,反射构建了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
进行页面生命周期启动。