「这是我参与2022首次更文挑战的第25天,活动详情查看:2022首次更文挑战」。
应用进程启动流程分析
在此前的Launcher应用进程启动流程中,我们分析过,Launcher应用进程的启动的前序,接下来这篇文章,我们将分析一下,应用进程启动流程。我们将继续以Launcher应用进程作为主要分析的目标。
前篇中,我们分析到,Launcher应用进程启动的最终会调用到ProcessList.java文件的startProcess函数,并最终通过Process.java文件的start函数启动进程,如下我们将接着流程分析。
public static ProcessStartResult start(@NonNull final String processClass,
@Nullable 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>>
whitelistedDataInfoMap,
boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] zygoteArgs) {
return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, packageName,
zygotePolicyFlags, isTopApp, disabledCompatChanges,
pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
bindMountAppStorageDirs, zygoteArgs);
}
当然,在梳理整个流程的时候,我们有必要对其传入参数进行整理一下
// 注:此处参数信息通过日志打印和代码追踪得到
第一个参数processClass的定义在ProcessList.java文件中的startProcessLocked函数中,其值为"android.app.ActivityThread"
第二个参数niceName为当前所需要启动的进程名称,此处为Launcher应用进程名称"com.android.launcher3"
第三、四、五个参数,为对应的uid、uid和gids
第六个参数runtimeFlags为运行时的flags
第七个参数mountExternal为
第八个参数targetSdkVersion为对应的SDK版本
第九个参数seInfo是进程所具有的selinux权限相关的信息
第十个参数abi为系统所对应的abi信息,此处为
第十一个参数instructionSet为null
第十二个参数appDataDir为对应的data数据存放的地址
第十三个参数invokeWith为null
第十四个参数packageName为所需要启动应用的包名,此处为Launcher应用进程名称"com.android.launcher3"
第十五个参数zygotePolicyFlags的值在AMS调用startProcess函数时传入的Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE
第十六个参数isTopApp为false
第十七个参数disabledCompatChanges为应用中的信息
第十八个参数pkgDataInfoMap为对应的应用的MAP对象,此处为launcher3应用的对应信息
第十九个参数whitelistedDataInfoMap为对应的空数据
第二十个参数bindMountAppsData为true
第二十一个参数bindMountAppStorageDirs为false
第二十二个参数zygoteArgs表明的startReq=20
此后,调用的是ZYGOTE_PROCESS的start函数
// 从名字来看,我们也知道这边肯定跟ZYGOTE进程有关系
public static final ZygoteProcess ZYGOTE_PROCESS = new ZygoteProcess();
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>>
whitelistedDataInfoMap,
boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] zygoteArgs) {
// .......
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
runtimeFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/ false,
packageName, zygotePolicyFlags, isTopApp, disabledCompatChanges,
pkgDataInfoMap, whitelistedDataInfoMap, bindMountAppsData,
bindMountAppStorageDirs, zygoteArgs);
}
// ...... catch exception log delete
}
private Process.ProcessStartResult startViaZygote(@NonNull final String processClass,
@Nullable final String niceName,
final int uid, final int gid,
@Nullable final int[] gids,
int runtimeFlags, int mountExternal,
int targetSdkVersion,
@Nullable String seInfo,
@NonNull String abi,
@Nullable String instructionSet,
@Nullable String appDataDir,
@Nullable String invokeWith,
boolean startChildZygote,
@Nullable String packageName,
int zygotePolicyFlags,
boolean isTopApp,
@Nullable long[] disabledCompatChanges,
@Nullable Map<String, Pair<String, Long>>
pkgDataInfoMap,
@Nullable Map<String, Pair<String, Long>>
whitelistedDataInfoMap,
boolean bindMountAppsData,
boolean bindMountAppStorageDirs,
@Nullable String[] extraArgs)
throws ZygoteStartFailedEx {
// ...... 此处主要是配置所需要启动的Process的参数argsForZygote,此处不做赘述,主要是生成argsForZygote参数
synchronized(mLock) {
// The USAP pool can not be used if the application will not use the systems graphics
// driver. If that driver is requested use the Zygote application start path.
// 最终,通过zygoteSendArgsAndGetResult函数来跟zygote通信,此处是如何实现跟zygote通信的呢?
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),
zygotePolicyFlags,
argsForZygote);
}
}
通过如上的代码可知,在最终,会通过zygoteSendArgsAndGetResult函数来跟zygote通信的,具体如何通信的,我们需要看下其第一个参数openZygoteSocketIfNeeded(abi)
打开和zygote之间的通信链路
首先先来分析下openZygoteSocketIfNeeded函数是如何打开zygote通信链路的吧
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
try {
// 尝试连接到primary zygote
attemptConnectionToPrimaryZygote();
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
// ......
}
// ......
}
// 尝试连接对应的primary zygote socket
@GuardedBy("mLock")
private void attemptConnectionToPrimaryZygote() throws IOException {
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
// socket通信连接
primaryZygoteState =
ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);
maybeSetApiBlacklistExemptions(primaryZygoteState, false);
maybeSetHiddenApiAccessLogSampleRate(primaryZygoteState);
}
}
// mZygoteSocketAddress是一个名称为zygote的socket链接地址
mZygoteSocketAddress = new LocalSocketAddress(Zygote.PRIMARY_SOCKET_NAME, LocalSocketAddress.Namespace.RESERVED);
public static final String PRIMARY_SOCKET_NAME = "zygote";
// 使用mZygoteSocketAddress链接地址连接后返回对应的ZygoteState对象
static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress,
@Nullable LocalSocketAddress usapSocketAddress)
throws IOException {
// ......
try {
// 连接socket服务器
zygoteSessionSocket.connect(zygoteSocketAddress);
zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());
// 写入和传递socket数据
zygoteOutputWriter =
new BufferedWriter(new OutputStreamWriter(zygoteSessionSocket.getOutputStream()), Zygote.SOCKET_BUFFER_SIZE);
}
// catch exception中关闭socket通信
// 初始化ZygoteState对象
return new ZygoteState(zygoteSocketAddress, usapSocketAddress, zygoteSessionSocket, zygoteInputStream, zygoteOutputWriter, getAbiList(zygoteOutputWriter, zygoteInputStream));
}
此处会跟名称为zygote的一个socket建立连接关系。还记得在zygote启动中分析过,其对应的配置文件中有一个socket的名称就是zygote么?
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
......
socket zygote stream 660 root system
......
在解析配置文件的过程中,会将这个socket服务端初始化,等待连接
而此处,我们就会作为服务端直接跟zygote服务端进行连接,连接成功后,将能够直接进行通信
通过zygote分裂出对应进程
通过zygoteSendArgsAndGetResult函数
private Process.ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, int zygotePolicyFlags, @NonNull ArrayList<String> args)
throws ZygoteStartFailedEx {
// ...... 参数判空操作代码省略
// 参数重定义
String msgStr = args.size() + "\n" + String.join("\n", args) + "\n";
// ......功能无关代码省略
// 继续调用函数
return attemptZygoteSendArgsAndGetResult(zygoteState, msgStr);
}
private Process.ProcessStartResult attemptZygoteSendArgsAndGetResult(
ZygoteState zygoteState, String msgStr) throws ZygoteStartFailedEx {
try {
final BufferedWriter zygoteWriter = zygoteState.mZygoteOutputWriter;
final DataInputStream zygoteInputStream = zygoteState.mZygoteInputStream;
// 写入对应的参数
zygoteWriter.write(msgStr);
zygoteWriter.flush();
// 获取ZYGOTE进程运行结束后对应的返回结果
Process.ProcessStartResult result = new Process.ProcessStartResult();
result.pid = zygoteInputStream.readInt();
result.usingWrapper = zygoteInputStream.readBoolean();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
}
// ...... catch exception code delete
}
如上代码,通过对应的参数传递给zygote服务侧,然后从服务端侧获取到对应的运行结果,此处包含对应的初始化进程pid和usingWrapper参数