Zygote Fork App流程解析
涉及的源码如下
platform/frameworks/base/core/java/com/android/internal/os/ZygoteServer.java zygote进程启动时,负责创建socket服务端,循环等待来自system server进程(AMS发出)的fork请求
platform/frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java socket连接,处理接收到的socket指令
core/java/android/os/ZygoteProcess.java 客户端发送fork app的请求类
services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
services/core/java/com/android/server/wm/TaskFragment.java
ZygoteServer
ZygoteServer.runSelectLoop()
if (pollIndex == 0) {
// Zygote server socket
// 客户端发送给zygote socket的请求,会创建一个连接,并且加入监听列表
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
socketFDs.add(newPeer.getFileDescriptor());
} else if (pollIndex < usapPoolEventFDIndex) {
// Session socket accepted from the Zygote server socket
// 处理客户端发送的socket消息
try {
ZygoteConnection connection = peers.get(pollIndex);
boolean multipleForksOK = !isUsapPoolEnabled()
&& ZygoteHooks.isIndefiniteThreadSuspensionSafe();
// 核心的代码在这里,会执行fork,fork成功,mIsForkChild会置为true并且command != null
final Runnable command =
connection.processCommand(this, multipleForksOK);
// TODO (chriswailes): Is this extra check necessary?
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");
}
// 对应ZygoteInit.main()的最后一条语句
return command;
}
ZygoteConnection
Socket连接封装成ZygoteConnection用于处理客户端发送的相关命令并返回相应的响应信息。
ZygoteConnection.processCommand()
核心的函数,主要为解析参数,执行fork。关键代码如下:
if (parsedArgs.mInvokeWith != null || parsedArgs.mStartChildZygote
|| !multipleOK || peer.getUid() != Process.SYSTEM_UID) {
// Continue using old code for now. TODO: Handle these cases in the other path.
// 这是特殊应用(详见之前的分析文章)进程的fork流程,普通app走不到,暂不分析
pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.mGids, parsedArgs.mRuntimeFlags, rlimits,
parsedArgs.mMountExternal, parsedArgs.mSeInfo, parsedArgs.mNiceName,
fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir,
parsedArgs.mIsTopApp, parsedArgs.mPkgDataInfoList,
parsedArgs.mAllowlistedDataInfoList, parsedArgs.mBindMountAppDataDirs,
parsedArgs.mBindMountAppStorageDirs);
try {
if (pid == 0) {
// in child
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
return handleChildProc(parsedArgs, childPipeFd,
parsedArgs.mStartChildZygote);
} else {
// In the parent. A pid < 0 indicates a failure and will be handled in
// handleParentProc.
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, serverPipeFd);
return null;
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
} else {
// 普通App的fork
ZygoteHooks.preFork();
// childMain -> specializeAppProcess -> ZygoteInit.init()
Runnable result = Zygote.forkSimpleApps(argBuffer,
zygoteServer.getZygoteSocketFileDescriptor(),
peer.getUid(), Zygote.minChildUid(peer), parsedArgs.mNiceName);
if (result == null) { // 父进程
// parent; we finished some number of forks. Result is Boolean.
// We already did the equivalent of handleParentProc().
ZygoteHooks.postForkCommon();
// argBuffer contains a command not understood by forksimpleApps.
continue;
} else {
// child; result is a Runnable. 子进程
zygoteServer.setForkChild();
Zygote.setAppProcessName(parsedArgs, TAG); // ??? Necessary?
return result;
}
}
对于普通App,关注Zygote.forkSimpleApps
及其之后的流程即可。至此服务端的分析结束。客户端的分析与服务端不同,主要使用逆向分析方式,从ZygoteProcess发送socket请求开始,一层一层往上分析。
ZygoteProcess.java
创建了ZygoteServer对应的4个客户端socket连接,调用链为:
start
public final Process.ProcessStartResult start(@NonNull final String processClass,
final String niceName,
int uid, int gid, @Nullable int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
@Nullable String seInfo,
@NonNull String abi,
@Nullable String instructionSet,
@Nullable String appDataDir,
@Nullable String invokeWith,
@Nullable String packageName,
int zygotePolicyFlags,
boolean isTopApp,
@Nullable long[] disabledCompatChanges,
@Nullable Map<String, Pair<String, Long>>
pkgDataInfoMap,
@Nullable Map<String, Pair<String, Long>>
allowlistedDataInfoList,
boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] zygoteArgs) {
// TODO (chriswailes): Is there a better place to check this value?
if (fetchUsapPoolEnabledPropWithMinInterval()) {
informZygotesOfUsapPoolStatus();
}
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
pkgDataInfoMap, allowlistedDataInfoList, bindMountAppsData,
bindMountAppStorageDirs, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
startViaZygote
封装参数,调用zygoteSendArgsAndGetResult
zygoteSendArgsAndGetResult
关键代码如下:
// 向服务端发送请求,得到pid
if (shouldAttemptUsapLaunch(zygotePolicyFlags, args)) {
try {
// 写入usap socket
return attemptUsapSendArgsAndGetResult(zygoteState, msgStr);
} catch (IOException ex) {
// If there was an IOException using the USAP pool we will log the error and
// attempt to start the process through the Zygote.
Log.e(LOG_TAG, "IO Exception while communicating with USAP pool - "
+ ex.getMessage());
}
}
// 写入zygote socket
return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr);
Process.java
内部创建了一个静态的ZygoteProcess实例ZYGOTE_PROCESS。其start()方法,即调用ZygoteProcess的start方法
ProcessList.java
ProcessList.startProcessLocked()
AMS.LocalService
@Override
public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,
boolean isTop, String hostingType, ComponentName hostingName) {
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "startProcess:"
+ processName);
}
synchronized (ActivityManagerService.this) {
// If the process is known as top app, set a hint so when the process is
// started, the top priority can be applied immediately to avoid cpu being
// preempted by other processes before attaching the process of top app.
startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
new HostingRecord(hostingType, hostingName, isTop),
ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,
false /* isolated */);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}
从上面的代码可知,fork操作其实只能在单线程中执行
AMS及ATMS
ATMS.startProcessAsync
void startProcessAsync(ActivityRecord activity, boolean knownToBeDead, boolean isTop,
String hostingType) {
try {
if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "dispatchingStartProcess:"
+ activity.processName);
}
// Post message to start process to avoid possible deadlock of calling into AMS with the
// ATMS lock held.
final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess,
mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead,
isTop, hostingType, activity.intent.getComponent());
mH.sendMessage(m);
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
}
ActivityTaskSupervisor.startSpecificActivity
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());
}
r.notifyUnknownVisibilityLaunchedForKeyguardTransition();
final boolean isTop = andResume && r.isTopRunningActivity();
// 启动进程
mService.startProcessAsync(r, knownToBeDead, isTop,
isTop ? HostingRecord.HOSTING_TYPE_TOP_ACTIVITY
: HostingRecord.HOSTING_TYPE_ACTIVITY);
}
前面的调用链:
TaskFragment.resumeTopActivity() <- Task.resumeTopActivityInnerLocked <- Task.resumeTopActivityUncheckedLocked
太深了,方法比较复杂,AMS这块又搞了个ATMS,后面再分析。
本文永久链接: [https://www.ieclipse.cn/2022/10/30/Android/fwk/zygote_fork_app/](https://www.ieclipse.cn/2022/10/30/Android/fwk/zygote_fork_app/) 未经允许,禁止转载,如有问题,请在我的博客原始页面提交评论。