之前几篇文章,我们分析了从init进程到zygote进程,再到systemServer进程的启动流程。我们在systemServer进程的结尾说到了将要开始启动桌面。这篇文章我们就接着systemServer的结尾开始从启动桌面讲起。另外之前我们分析zygote进程的时候有分析到zygote进程中会启动一个localSocket,那个socket会监听是否其他进程连接socket,如果socket有链接,zygote进程会被唤醒进行后面的处理,这里其实就是在创建进程的时候会链接到socket,所以本文后半部分我们会通过从AMS启动一个新进程来看下整个进程创建的流程,同时也对zygote创建进程的代码进行分析。好了,话不多说,我们先开始看桌面进程的启动流程。
# 启动桌面进程
之前在分析systemServer的时候分析到AMS的systemReady方法,在这个方法里面会开始启动桌面,调用的方法是startHomeActivityLocked,我们就从这个方法讲起,看下这个方法:
```java
boolean startHomeActivityLocked(int userId, String reason) {
..........
// 获取主界面的intent
Intent intent = getHomeIntent();
// 获取home activity的ActivityInfo
ActivityInfo aInfo = resolveActivityInfo(intent, STOCK_PM_FLAGS, userId);
if (aInfo != null) {
intent.setComponent(new ComponentName(aInfo.applicationInfo.packageName, aInfo.name));
// Don't do this if the home app is currently being
// instrumented.
// new一个ActivityInfo
aInfo = new ActivityInfo(aInfo);
// 设置ApplicationInfo这个对象
aInfo.applicationInfo = getAppInfoForUser(aInfo.applicationInfo, userId);
// 看看AMS中ProcessRecord集合中有没有这个进程
ProcessRecord app = getProcessRecordLocked(aInfo.processName,
aInfo.applicationInfo.uid, true);
// 主界面第一次启动,AMS的ProcessRecord集合中肯定没有,所以会进这个分支
if (app == null || app.instr == null) {
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
final int resolvedUserId = UserHandle.getUserId(aInfo.applicationInfo.uid);
// For ANR debugging to verify if the user activity is the one that actually
// launched.
final String myReason = reason + ":" + userId + ":" + resolvedUserId;
// 继续调用
mActivityStarter.startHomeActivityLocked(intent, aInfo, myReason);
}
} else {
Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());
}
return true;
}
```
这个方法首先调用getHomeIntent来获得intent:
```java
Intent getHomeIntent() {
Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
// <category android:name="android.intent.category.HOME" />
// pkms会找minifest的这个包
intent.addCategory(Intent.CATEGORY_HOME);
}
return intent;
}
```
这个方法主要是设置action和category,这里的mTopAction值默认是android.intent.action.MAIN,这个不用多说。之后category值是android.intent.category.HOME,之后packaManager会根据这些值找到桌面的minifest。我们回到startHomeActivityLocked方法。
接着会调用resolveActivityInfo方法来获取intent对象的包:
```java
private ActivityInfo resolveActivityInfo(Intent intent, int flags, int userId) {
ActivityInfo ai = null;
ComponentName comp = intent.getComponent();
try {
if (comp != null) {
// Factory test.
ai = AppGlobals.getPackageManager().getActivityInfo(comp, flags, userId);
} else { // 正常应该会这里,PKMS会解析
ResolveInfo info = AppGlobals.getPackageManager().resolveIntent(
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
flags, userId);
if (info != null) {
ai = info.activityInfo;
}
}
} catch (RemoteException e) {
// ignore
}
return ai;
}
```
这里可以看到首先获取下ComponentName,开始的话这个会是空,所以下面会进入else分支,else分支里面会通过PackageManager来解析intent,解析出的结果会返回ResolveInfo对象,之后把ResolveInfo对象封装到ActivityInfo对象中。这里PackageManager的解析就进入详细说了,会有专门分析packageManager的文章来讲解PackageManager,这里就跳过了。我们返回到startHomeActivityLocked方法中。
返回ActivityInfo对象后,如果不为空,那么从ActivityInfo对象中取出包名和类名封装为ComponentName。之后我们看到从ActivityInfo中取出applicationInfo对象,这个对象可以理解为PackageManager解析包的minifest后封装的对象。下面可以看到获得applicationInfo后,就需要获得启动进程的ProcessRecord了,调用getProcessRecordLocked方法:
```java
final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {
if (uid == SYSTEM_UID) {
// The system gets to run in any process. If there are multiple
// processes with the same uid, just pick the first (this
// should never happen).
SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(processName);
if (procs == null) return null;
final int procCount = procs.size();
for (int i = 0; i < procCount; i++) {
final int procUid = procs.keyAt(i);
if (UserHandle.isApp(procUid) || !UserHandle.isSameUser(procUid, uid)) {
// Don't use an app process or different user process for system component.
continue;
}
return procs.valueAt(i);
}
}
// 从map中获取ProcessRecord
ProcessRecord proc = mProcessNames.get(processName, uid);
if (false && proc != null && !keepIfLarge
&& proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY
&& proc.lastCachedPss >= 4000) {
// Turn this condition on to cause killing to happen regularly, for testing.
if (proc.baseProcessTracker != null) {
proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss);
}
proc.kill(Long.toString(proc.lastCachedPss) + "k from cached", true);
} else if (proc != null && !keepIfLarge
&& mLastMemoryLevel > ProcessStats.ADJ_MEM_FACTOR_NORMAL
&& proc.setProcState >= ActivityManager.PROCESS_STATE_CACHED_EMPTY) {
if (DEBUG_PSS) Slog.d(TAG_PSS, "May not keep " + proc + ": pss=" + proc.lastCachedPss);
if (proc.lastCachedPss >= mProcessList.getCachedRestoreThresholdKb()) {
if (proc.baseProcessTracker != null) {
proc.baseProcessTracker.reportCachedKill(proc.pkgList, proc.lastCachedPss);
}
proc.kill(Long.toString(proc.lastCachedPss) + "k from cached", true);
}
}
return proc;
}
```
这个方法我们在AMS分析的文章中分析过,他会从AMS保存的当前运行的map对象mProcessNames中获取和这个进程名对应的ProcessRecord返回。由于现在是第一次启动桌面进程,那么肯定返回的是空,所以我们看到startHomeActivityLocked方法中,会调用ActivityStarter的startHomeActivityLocked方法来继续启动桌面进程。我们进入这个方法:
```java
// 启动主界面
void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
// 把当前home的stack移动到顶部
mSupervisor.moveHomeStackTaskToTop(reason);
// 启动桌面Activity
mLastHomeActivityStartResult = startActivityLocked(null /*caller*/, intent,
null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/,
null /*voiceSession*/, null /*voiceInteractor*/, null /*resultTo*/,
null /*resultWho*/, 0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/,
null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/,
0 /*startFlags*/, null /*options*/, false /*ignoreTargetSecurity*/,
false /*componentSpecified*/, mLastHomeActivityStartRecord /*outActivity*/,
null /*container*/, null /*inTask*/, "startHomeActivity: " + reason);
if (mSupervisor.inResumeTopActivity) {
// 这里默认是false,如果正常执行完也是false。如果进入这里执行了,由于是true,scheduleResumeTopActivities方法
// 里面还会判断,true的话就不会继续往下执行,所以不影响
// If we are in resume section already, home activity will be initialized, but not
// resumed (to avoid recursive resume) and will stay that way until something pokes it
// again. We need to schedule another resume.
mSupervisor.scheduleResumeTopActivities();
}
}
```
这个方法不算长,他里面调用了几个方法。首先调用ActivityStackSupervisor的moveHomeStackTaskToTop方法:
```java
boolean moveHomeStackTaskToTop(String reason) {
// 把home的task移动到最前面
mHomeStack.moveHomeStackTaskToTop();
// 获得桌面的顶部activity
final ActivityRecord top = getHomeActivity();
if (top == null) {
return false;
}
// 把这个桌面stack,task都放到对应位置的顶部
moveFocusableActivityStackToFrontLocked(top, reason);
return true;
}
```
之前看过我们AMS分析的同学对这些方法不会感到太陌生,虽然桌面进程作为一个特殊的进程,AMS把和他相关的对象单独拿出来处理,但是处理的套路和其他进程都是一样的。这个首先把桌面进程的stack移动到最前端,调用moveHomeStackTaskToTop方法:
```java
void moveHomeStackTaskToTop() {
final int top = mTaskHistory.size() - 1;
for (int taskNdx = top; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
if (task.taskType == HOME_ACTIVITY_TYPE) {
if (DEBUG_TASKS || DEBUG_STACK) Slog.d(TAG_STACK,
"moveHomeStackTaskToTop: moving " + task);
mTaskHistory.remove(taskNdx);
mTaskHistory.add(top, task);
updateTaskMovement(task, true);
return;
}
}
}
```
这里会遍历mTaskHistory集合,取出代表桌面类型的TaskRecord,把这个TaskRecord移动到最顶端。这里对于任务栈TaskRecord的概念就不解释了,不太清楚的同学可以去看看我们AMS分析的文章[AMS源码分析(一)](https://liqi.site/archives/ams%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%E4%B8%80)。好了,我们返回moveHomeStackTaskToTop方法。
接着调用getHomeActivity获取桌面任务栈中顶部的Activity:
```java
ActivityRecord getHomeActivity() {
return getHomeActivityForUser(mCurrentUser);
}
ActivityRecord getHomeActivityForUser(int userId) {
final ArrayList<TaskRecord> tasks = mHomeStack.getAllTasks();
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = tasks.get(taskNdx);
// 找到桌面stack中的桌面task
if (task.isHomeTask()) {
final ArrayList<ActivityRecord> activities = task.mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
// 获取顶部Activity
final ActivityRecord r = activities.get(activityNdx);
// 如果是桌面Activity,并且是同一个userId,返回这个Activity
if (r.isHomeActivity()
&& ((userId == UserHandle.USER_ALL) || (r.userId == userId))) {
return r;
}
}
}
}
return null;
}
```
这里最终会调用到getHomeActivityForUser方法。方法中从ActivityStack中取出桌面所在的TaskRecord,然后从上往下取得显示在前台的那个Activity返回。我们回到moveHomeStackTaskToTop方法中,最后调用moveFocusableActivityStackToFrontLocked方法,这个方法我们在分析AMS的时候已经分析过了,这里不展开分析了,这个方法主要就是把这个Activity关联的ActivityStack,TaskRecord都显示到前台。
我们回到startHomeActivityLocked方法。前面分析的这些如果在第一次启动的情况下,Launcher进程其实都是找不到的,所以上面执行的这些最后都是返回空,等于什么都没有执行。不管桌面进程现在有没有存在,接下来都会执行startActivityLocked方法,这个方法就是启动Activity的方法,AMS中已经详细的的分析过了,进程如果已经存在的话,会显示这个进程中的Activity,如果进程不存在则先启动进程,然后启动进程中的Activity,这个就不多说了。
在上面startActivityLocked方法中,启动过程中会调用到resumeTopActivityUncheckedLocked方法,我们看一眼这个方法:
```java
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
if (mStackSupervisor.inResumeTopActivity) {
// Don't even start recursing.
return false;
}
boolean result = false;
try {
// Protect against recursion.
mStackSupervisor.inResumeTopActivity = true;
// 继续执行prev启动
result = resumeTopActivityInnerLocked(prev, options);
} finally {
mStackSupervisor.inResumeTopActivity = false;
}
// When resuming the top activity, it may be necessary to pause the top activity (for
// example, returning to the lock screen. We suppress the normal pause logic in
// {@link #resumeTopActivityUncheckedLocked}, since the top activity is resumed at the end.
// We call the {@link ActivityStackSupervisor#checkReadyForSleepLocked} again here to ensure
// any necessary pause logic occurs.
mStackSupervisor.checkReadyForSleepLocked();
return result;
}
```
这个方法中可以看到,如果mStackSupervisor.inResumeTopActivity这个值是true,就会返回了,他的意思是当前已经在启动一个Activity了,所以本次启动不能继续进行。如果遇到这种情况的话,启动Launcher就要稍等下了,所以在startHomeActivityLocked方法中,最后会判断如果是这种情况的话,会调用ActivityStackSupervisor的scheduleResumeTopActivities方法,方法如下:
```java
final void scheduleResumeTopActivities() {
if (!mHandler.hasMessages(RESUME_TOP_ACTIVITY_MSG)) {
mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
}
}
```
这个方法会发送Hander的RESUME_TOP_ACTIVITY_MSG消息:
```java
case RESUME_TOP_ACTIVITY_MSG: {
synchronized (mService) {
resumeFocusedStackTopActivityLocked();
}
```
这里可以看到hander中调用resumeFocusedStackTopActivityLocked是一个同步方法,这里由于锁是mService,如果在他之前已经在启动了一个activity或者已经持有这个锁在做其他事情了,那么现在启动Launcher就会阻塞在这里,等其他地方完成了事情后再调用resumeFocusedStackTopActivityLocked方法,继续启动桌面的Activity,这个方法这里就不跟进了,在AMS的文章那里已经有过分析了。
至此,桌面进程就正常启动了,接下去就是android启动后的流程了,系统的启动流程到这里也就结束了。 这里再次进入了AMS,可见AMS确实是很重要的,从系统启动就开始参与工作,一直伴随着系统的整个生命周期。我们经常见到AMS中的方法命名为xxLocked,刚开始接触的时候还不是非常理解,但是在阅读AMS的代码过程中,遇到类似上面启动Launcher过程中判断当前方法到底是不是线程安全的时候,方法的命令确实代理我们分析代码很好的帮助,通过代码的命令可以快速的知道当前方法会不会阻塞,从而理解系统执行的流程,可以看到良好的命令规范对一个开发者来说也是一个基本功的体现。
好了,启动桌面的流程就分析到这里了,到这里android启动的任务也就基本完成了。之后也就是android启动后的正常流程了。接下来,本文后半部分会分析一个进程的创建过程,即是对之前init进程中遗留的通过socket来创建进行流程的一个补全,也是对之前AMS中分析启动Activity时如果该Activity所在的进程不存在的时候,进程是如何创建的分析流程,所以下面我们就开始分析一个进程的创建过程。
# 新进程的创建
之前在在分析AMS的文章中,我们有分析到在启动一个Activity的时候,有可能这个Activity所在的进程还不存在,所以需要先创建一个进程,然后再启动这个Activity。当初我们跳过了进程创建的流程,直接分析了后面启动Activity的流程,所以下面我们就从AMS中请求创建进程开始说起。
首先我们回到AMS中,我们看到ActivityManagerService的startProcessLocked方法,具体AMS是怎么走到这个方法的,请从
[AMS源码分析(一)](https://liqi.site/admin/index.html#/posts/write?postId=54)这篇文章开始的AMS分析看起。我们看下这个方法:
```java
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
.............
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
............
}
```
这里我们看到会调用Process的start方法:
```java
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
return zygoteProcess.start(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}
```
这里继续调用ZygoteProcess的start方法:
```java
public final Process.ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, 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方法:
```java
private Process.ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String invokeWith,
String[] extraArgs)
throws ZygoteStartFailedEx {
// 封装进程参数
ArrayList<String> argsForZygote = new ArrayList<String>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {
argsForZygote.add("--enable-jni-logging");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
argsForZygote.add("--enable-safemode");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_JDWP) != 0) {
argsForZygote.add("--enable-jdwp");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
argsForZygote.add("--enable-checkjni");
}
if ((debugFlags & Zygote.DEBUG_GENERATE_DEBUG_INFO) != 0) {
argsForZygote.add("--generate-debug-info");
}
if ((debugFlags & Zygote.DEBUG_ALWAYS_JIT) != 0) {
argsForZygote.add("--always-jit");
}
if ((debugFlags & Zygote.DEBUG_NATIVE_DEBUGGABLE) != 0) {
argsForZygote.add("--native-debuggable");
}
if ((debugFlags & Zygote.DEBUG_JAVA_DEBUGGABLE) != 0) {
argsForZygote.add("--java-debuggable");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
argsForZygote.add("--enable-assert");
}
if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
argsForZygote.add("--mount-external-default");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
argsForZygote.add("--mount-external-read");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
argsForZygote.add("--mount-external-write");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
}
if (instructionSet != null) {
argsForZygote.add("--instruction-set=" + instructionSet);
}
if (appDataDir != null) {
argsForZygote.add("--app-data-dir=" + appDataDir);
}
if (invokeWith != null) {
argsForZygote.add("--invoke-with");
argsForZygote.add(invokeWith);
}
argsForZygote.add(processClass);
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
// 以上封装一系列进程启动时的参数,下面继续调用zygoteSendArgsAndGetResult方法
synchronized(mLock) {
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
```
这个方法前面都是封装一些参数,我们先不管,最后一句zygoteSendArgsAndGetResult方法是最终的调用。这个方法有2个参数,第一个参数是一个ZygoteState对象,他封装了一些和socket相关的对象,第二个参数是具体需要传的参数。我们看下第一个创建ZygoteState对象的方法openZygoteSocketIfNeeded:
```java
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
// 这里connect里面方法connect会唤醒runSelectLoop方法中socket的poll阻塞的代码
// mSocket是zygote,在Process类加载时候会初始化ZygoteProcess,从而给mSocket赋值
primaryZygoteState = ZygoteState.connect(mSocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
}
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
// The primary zygote didn't match. Try the secondary.
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
}
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}
```
这个方法里面开始对socket请求连接了。这里我们看到有两部分相似的内容,还记得之前我们在分析zygote进程的时候说过,在64位系统的时候,可能会创建两个zygote进程,一个是64位的zygote,另一个32位的兼容zygote。这里会首先通过判断abi,即应用二进制接口是否相同来判断是哪个zygote。abi一般我们在开发中用到so的时候,会在不同目录下面放入适配的so文件,比如像armeabi-v7a,arm64-v8a等等,这些就代表了不同体系架构下的执行文件,这里会通过这个字符串来判断是哪个zygote。
不管是哪个zygote,最终都会调用ZygoteState的connect方法,我们看下这个方法:
```java
public static ZygoteState connect(String socketAddress) throws IOException {
DataInputStream zygoteInputStream = null;
BufferedWriter zygoteWriter = null;
// 这个LocalSocket下面调用了connect方法后,对应的LocalServerSocket的accept方法就是他了
final LocalSocket zygoteSocket = new LocalSocket();
try {
// 与zygote那里建立连接,调用到LocalServerSocket那里
zygoteSocket.connect(new LocalSocketAddress(socketAddress,
LocalSocketAddress.Namespace.RESERVED));
// new输入流
zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
// new输出流
zygoteWriter = new BufferedWriter(new OutputStreamWriter(
zygoteSocket.getOutputStream()), 256);
} catch (IOException ex) {
try {
zygoteSocket.close();
} catch (IOException ignore) {
}
throw ex;
}
String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
Log.i("Zygote", "Process: zygote socket " + socketAddress + " opened, supported ABIS: "
+ abiListString);
return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
Arrays.asList(abiListString.split(",")));
}
```
这个方法首先声明了三个对象,DataInputStream,BufferedWriter和LocalSocket。DataInputStream是输入流,BufferedWriter是输出流,这两个分别保存着socket通信过程中,读取和写入的数据,下面会new出这两个对象的实例。
之后会创建一个LocalSocket,通过他的connect方法和对应的socket进行连接。对应的socket是什么,LocalSocketAddress就封装了这个对应的socket,他的第一个参数mSocket是ZygoteProcess类初始化时候传入的,由于ZygoteProcess类是在Process类初始化时候创建的,而Process类是在zygote进程初始化时候预加载的类,所以这个时候ZygoteProcess类已经初始化好了,我们看到在Process类中创建ZygoteProcess的代码:
```java
public static final String ZYGOTE_SOCKET = "zygote";
public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";
public static final ZygoteProcess zygoteProcess =
new ZygoteProcess(ZYGOTE_SOCKET, SECONDARY_ZYGOTE_SOCKET);
public ZygoteProcess(String primarySocket, String secondarySocket) {
mSocket = primarySocket;
mSecondarySocket = secondarySocket;
}
```
通过以上代码我们可以看到,mSocket变量的值是zygote。我们回到connect方法中,创建LocalSocketAddress类的第一个参数就是zygote,第二个参数RESERVED是个枚举类:
```java
public enum Namespace {
/** A socket in the Linux abstract namespace */
ABSTRACT(0),
/**
* A socket in the Android reserved namespace in /dev/socket.
* Only the init process may create a socket here.
*/
RESERVED(1),
/**
* A socket named with a normal filesystem path.
*/
FILESYSTEM(2);
/** The id matches with a #define in include/cutils/sockets.h */
private int id;
Namespace (int id) {
this.id = id;
}
/**
* @return int constant shared with native code
*/
/*package*/ int getId() {
return id;
}
}
```
这里可以看出,他的值是1。这个值有什么用呢,我们接着看代码,后面就可以知道。我们还是回到ZygoteProcess的connect方法,LocalSocketAddress对象创建好了,接着调用LocalSocket的connect方法,我们跟进去看下:
```java
public void connect(LocalSocketAddress endpoint) throws IOException {
synchronized (this) {
if (isConnected) {
throw new IOException("already connected");
}
implCreateIfNeeded();
impl.connect(endpoint, 0);
isConnected = true;
isBound = true;
}
}
```
这个方法里面首先会调用implCreateIfNeeded这个方法来创建一个LocalSocketImpl对象实例,接着会调用LocalSocketImpl的connect方法,这里调用方法传入的第一个参数是前面创建的LocalSocketAddress对象,第二个参数是0。我们继续跟进这个connect方法:
```java
protected void connect(LocalSocketAddress address, int timeout)
throws IOException
{
if (fd == null) {
throw new IOException("socket not created");
}
// 这个native方法,准备connect
connectLocal(fd, address.getName(), address.getNamespace().getId());
}
```
这个方法中会调用一个native的方法connectLocal,这个方法有三个参数,第一个参数是socket的文件描述符,第二个和第三个参数是之前创建LocalSocketAddress对象时候的参数,他们的值分别是zygote和枚举类的值1。我们看下这个native方法:
```c++
// android_net_LocalSocketImpl.cpp
static void socket_connect_local(JNIEnv *env, jobject object,
jobject fileDescriptor, jstring name, jint namespaceId)
{
int ret;
int fd;
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (env->ExceptionCheck()) {
return;
}
ScopedUtfChars nameUtf8(env, name);
// 继续发起连接
// nameUtf8参数zyfote
// 这里namespaceId的值是ANDROID_SOCKET_NAMESPACE_ABSTRACT(0),
// ANDROID_SOCKET_NAMESPACE_RESERVED(1),ANDROID_SOCKET_NAMESPACE_FILESYSTEM(2)
// 下面这个方法在socket_local_client_unix.c
ret = socket_local_client_connect(
fd,
nameUtf8.c_str(),
namespaceId,
SOCK_STREAM);
if (ret < 0) {
jniThrowIOException(env, errno);
return;
}
}
```
这个方法在文件frameworks/base/core/jni/android_net_LocalSocketImpl.cpp中,我们看到这会继续调用socket_local_client_connect方法,参数还是之前的三个,多了一个socket的类型SOCK_STREAM,这个是stream socket类型的,之前在分析init进程的时候有过解释,我们就可以把他理解为tcpip类型的socket。我们继续看socket_local_client_connect方法:
```c++
int socket_local_client_connect(int fd, const char *name, int namespaceId,
int type UNUSED)
{
struct sockaddr_un addr;
socklen_t alen;
int err;
// 继续调用
err = socket_make_sockaddr_un(name, namespaceId, &addr, &alen);
if (err < 0) {
goto error;
}
// 进行连接
if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {
goto error;
}
return fd;
error:
return -1;
}
```
这个方法里面主要有两个步骤。第一个步骤是调用socket_make_sockaddr_un获取socket的地址。根据我们之前分析init进程时候的介绍,一般我们理解socket都是网络间的通信,但是他也可以用于进程间的通信。对于网络间的通信,地址我们都比较熟悉,主要是指ip地址,那么对于本地的进程间通信,这里的地址其实是指一个文件,我们可以理解为这个文件就是一个中介,不同进程通过将数据发送给这个文件保存,然后这个文件再将数据转发给其他进程,所以这里的socket_make_sockaddr_un方法就是找到socket文件,然后最后通过调用connect方法就可以和在服务端注册的socket连接上了。我们看下socket_make_sockaddr_un这个方法是怎么找socket文件的:
```c++
#define ANDROID_SOCKET_NAMESPACE_RESERVED 1
#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
int socket_make_sockaddr_un(const char *name, int namespaceId,
struct sockaddr_un *p_addr, socklen_t *alen)
{
memset (p_addr, 0, sizeof (*p_addr));
size_t namelen;
................
switch (namespaceId) {
.................
case ANDROID_SOCKET_NAMESPACE_RESERVED:
namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);
/* unix_path_max appears to be missing on linux */
if (namelen > sizeof(*p_addr)
- offsetof(struct sockaddr_un, sun_path) - 1) {
goto error;
}
// ANDROID_RESERVED_SOCKET_PREFIX是/dev/socket/
strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);
// name是zygote
strcat(p_addr->sun_path, name);
// 以上是给p_addr赋值,这个参数上一个方法传入,之后会用这个参数调用connect连接服务端的socket
break;
}
...............
p_addr->sun_family = AF_LOCAL;
*alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
return 0;
error:
return -1;
}
```
这个方法的namespaceId参数,就是之前我们传入的枚举类,他的值是1,代表是一个socket的文件路径,所以进入ANDROID_SOCKET_NAMESPACE_RESERVED这个分支,ANDROID_SOCKET_NAMESPACE_RESERVED是一个宏定义,值是1,这样就和之前创建LocalSocketAddress时候的参数对应起来了,那时候枚举类参数就是用在这里寻找具体的socket文件的,我们继续看这里的代码。这里还有一个宏定义变量ANDROID_RESERVED_SOCKET_PREFIX,他的值是/dev/socket/,而这个方法的参数name是zygote,所以最后给p_addr->sun_path赋值的值就是/dev/socket/zygote,这个就是socket文件所在的路径。这个文件还记得是在哪里创建的吗,我们再简单回顾下这个文件创建的地方。
在init进程启动之后,会解析init.rc文件,这个文件里面都是些初始化的命令,在解析start zygote命令的时候就会触发service.cpp的Start方法,在Start方法里会根据socket命令解析出的DescriptorInfo对象,调用他的CreateAndPublish方法,我们就再看下CreateAndPublish这个方法,有关init进程怎么会调用到这里的流程就不详细说了,在分析init进程的文章里面已经有过详细的分析了,如果不太了解的同学可以参考这篇文章[android启动之init进程](https://liqi.site/archives/android%E5%90%AF%E5%8A%A8%E4%B9%8Binit%E8%BF%9B%E7%A8%8B#fkxMYJKW),我们现在还是先再看下CreateAndPublish方法:
```c++
void DescriptorInfo::CreateAndPublish(const std::string& globalContext) const {
// Create
const std::string& contextStr = context_.empty() ? globalContext : context_;
// 创建socket,返回fd小于0,return
// 这里create方法最终会创建/dev/socket/zygote文件
int fd = Create(contextStr);
if (fd < 0) return;
// Publish
std::string publishedName = key() + name_;
std::for_each(publishedName.begin(), publishedName.end(),
[] (char& c) { c = isalnum(c) ? c : '_'; });
std::string val = android::base::StringPrintf("%d", fd);
// 添加这个socket到环境变量,key为ANDROID_SOCKET_ENV_PREFIX_zygote,val为fd
add_environment(publishedName.c_str(), val.c_str());
// make sure we don't close on exec
// 设置这个文件被执行后,不会关闭
fcntl(fd, F_SETFD, 0);
}
```
这个方法会调用Create方法来创建socket的文件,成功的话会返回文件描述符fd,之后会以publishedName为名字,把这个fd注册到环境变量中,publishedName的值是ANDROID_SOCKET_zygote,之后再zygote进程中会对这个文件进程监听,也就是监听是否有其他进程对这个socket进行连接,这个之前分析zygote的时候也有说过,我们等会在回顾看一下,这里先在看下Create方法:
```c++
int SocketInfo::Create(const std::string& context) const {
int flags = ((type() == "stream" ? SOCK_STREAM :
(type() == "dgram" ? SOCK_DGRAM :
SOCK_SEQPACKET)));
// create_socket会创建/dev/socket/zygote这个文件
return create_socket(name().c_str(), flags, perm(), uid(), gid(), context.c_str());
}
```
这个方法会继续调用create_socket方法,这个方法的第一个参数是从init.rc文件中socket命令解析出来的,如下:
```c++
socket zygote stream 660 root system
```
这里socket的命令就是zygote,这里也不展开说了,之前也分析过,可以去看分析的文章。我们继续看create_socket方法:
```c++
int create_socket(const char *name, int type, mode_t perm, uid_t uid,
gid_t gid, const char *socketcon)
{
.........
struct sockaddr_un addr;
// 地址初始化为0
memset(&addr, 0 , sizeof(addr));
// 表示是域套接字,进程间通信
addr.sun_family = AF_UNIX;
// 设备文件路径/dev/socket/zygote赋值给addr.sun_path
snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
name);
...............
int ret = bind(fd, (struct sockaddr *) &addr, sizeof (addr));
...................
}
```
可以看到这里结构体sockaddr_un就是代表socket地址的对象,这里给他的sun_path字段赋值ANDROID_SOCKET_DIR/name,ANDROID_SOCKET_DIR的值是/dev/socket,name是zygote,所以这里文件的路径就是/dev/socket/zygote,最后通过一个系统调用的bind方法会创建这里路径的文件,bind方法最终会走到操作系统底层的系统调用方法,这里就不跟进了,总之socket的文件我们看到了在init进程这里就以后创建了,我们回到ZygoteProcess类中。
经过上面一系列的socket分析,我们回到ZygoteProcess的startViaZygote方法中,我们前面说到这个方法最后会调用zygoteSendArgsAndGetResult方法,这个方法的第一个参数ZygoteState,就是我们上面分析的通过连接上socket后创建的,上面我们已经分析了找到这个socket的地址,接着就会通过LocalSocket的connect进行连接了,连接会唤醒zygote,但是这次唤醒不会创建一个新进程,这次链接仅仅把这个LocalSocket添加到zygote中,后面还会进行一次通信,这次通信会把需要创建进程的参数发给socket,这样socket才会真正创建一个进程。接下来我们先看下zygoteSendArgsAndGetResult这个方法,这个就是AMS这里会把新进程参数通知socket从而再次唤醒zygote进程:
```java
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
try {
int sz = args.size();
// 遍历启动进程时候的参数,如果有换行,不允许
for (int i = 0; i < sz; i++) {
if (args.get(i).indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx("embedded newlines not allowed");
}
}
// 获取链接socket的写包装流
final BufferedWriter writer = zygoteState.writer;
// 获取链接socket的读包装流
final DataInputStream inputStream = zygoteState.inputStream;
// 写启动参数
writer.write(Integer.toString(args.size()));
// 写入换行
writer.newLine();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg);
writer.newLine();
}
writer.flush(); // 唤醒zygoteServer那里的socket
// Should there be a timeout on this?
// 创建新进程的返回对象
Process.ProcessStartResult result = new Process.ProcessStartResult();
// Always read the entire result from the input stream to avoid leaving
// bytes in the stream for future process starts to accidentally stumble
// upon.
// 获得新进程的pid
result.pid = inputStream.readInt();
result.usingWrapper = inputStream.readBoolean();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}
```
这个方法的逻辑比较简单,开始会遍历前面传过来的所有参数,然后把参数写入前面连接到zygote那里的LocalSocket的输出流,最后调用输出流的flush方法就会唤醒阻塞在zygote那里的socket了,zygote那里在接收到这里发送的创建新进程的数据后,就会fork出一个新进程了,这个过程我们等下在看。当新进程全部创建完毕后,最后还会回到AMS的这个方法里来,这里继续执行后面的代码。这里会创建一个ProcessStartResult对象,这个对象封装了新进程的pid,最后返回这个对象。
新进程创建后,就是后续的AMS步骤的,比如继续启动一个Activity等,这个之前分析AMS的时候都分析过了,也就不多说了。这样一个新进程创建的流程也就执行完毕了,好了,AMS这里的流程都走完了,我们回到zygote那里在看下具体创建进程的过程。
# zygote创建新进程
我们在zygote进程的时候分析过在获得socket文件后,会通过poll方法监听者socket是否有链接,我们下面的流程就会走到监听socket的地方,我们回到ZygoteServer的runSelectLoop方法:
```java
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
// 把之前创建的socket文件描述符加入到数组
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
// 有多少socket就创建几个数组,每个socket都会被监听,一旦有信息了,socket就会执行相关任务
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
// 监听这些文件描述符
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
// 一旦有数据可读了,就会走到这里。如果i==0,说明是第一个
// 第一个就是zygote的socket的文件描述符,所以说明是新创建进程的命令
// 那么就加入一个文件描述符继续监听
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
// 到这里说明是第一个文件描述符有可读数据,肯定是创建新进程的命令
// 正常来说Process.start方法调用后,会调用到connect来触发这里
// 之后会往数据流中写输入,会触发else的
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
// 如果走到这里,说明是一个已经创建的进程有数据可能
// 那么就触发这个进程的初始化方法
boolean done = peers.get(i).runOnce(this);
// 新进程完成初始化了,清除掉之前的保存
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}
```
这个方法在之前分析zygote的文章中也已经详细分析过了,具体可以参考[android启动之zygote进程](https://liqi.site/archives/android%E5%90%AF%E5%8A%A8%E4%B9%8Bzygote%E8%BF%9B%E7%A8%8B。这里fds是一个文件描述符的集合,在之前分析这个方法的时候,我们说到过如果是第一次这个文件描述符中的数据有变化的话,会创建一个ZygoteConnection对象把这个对象加入到ZygoteConnection集合中,同时监听的文件描述符数量也增加一个,所以当AMS那里往socket发送数据的时候,如果文件描述符集合的数量大于1个了,说明就不是一个链接命令了,是AMS向socket发送数据了,所以这个方法会取出上次加入的ZygoteConnection对象,并调用它的runOnce方法,我们看下这个方法:
```java
boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
// 读取参数
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
Log.w(TAG, "IOException on command socket " + ex.getMessage());
closeSocket();
return true;
}
// 参数是空的话,关闭socket
if (args == null) {
// EOF reached.
closeSocket();
return true;
}
.............
try {
// 解析参数
parsedArgs = new Arguments(args);
...........
// 继续启动新进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
parsedArgs.appDataDir);
} catch (ErrnoException ex) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} catch (IllegalArgumentException ex) {
logAndPrintError(newStderr, "Invalid zygote arguments", ex);
} catch (ZygoteSecurityException ex) {
logAndPrintError(newStderr,
"Zygote security policy prevents request: ", ex);
}
}
```
这个方法我们分两段来讲,这里是第一段。首先会调用readArgumentList方法解析从ZygoteProcess类的zygoteSendArgsAndGetResult方法那里写入的参数,封装为一个string数组,这个方法比较简单这里就不贴出代码了,主要就是从localSocket的输入流中读出数据,然后保存到args数组中。接着就调用forkAndSpecialize方法开始创建进程了:
```java
public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
int[] fdsToIgnore, String instructionSet, String appDataDir) {
VM_HOOKS.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
int pid = nativeForkAndSpecialize(
uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
fdsToIgnore, instructionSet, appDataDir);
// Enable tracing as soon as possible for the child process.
// 返回0,表示是子进程,返回>0是zygote
if (pid == 0) {
Trace.setTracingEnabled(true);
// Note that this event ends at the end of handleChildProc,
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
}
VM_HOOKS.postForkCommon();
return pid;
}
```
这个方法中由于要fork出一个线程,为了线程安全考虑,所以开始会调用VM_HOOKS.preFork()停止zygote的子线程,使fork的时候是单线程的状态,这个之前分析zygote时候也说过了,preFork方法也分析过,这里就提一下。之后就调用nativeForkAndSpecialize开始创建新进程,创建完毕后再调用VM_HOOKS.postForkCommon()回复zygote进程之前的状态,比如恢复之前停止的子线程,这个也不用多说。我们看下nativeForkAndSpecialize方法:
```c++
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
jint debug_flags, jobjectArray rlimits,
jint mount_external, jstring se_info, jstring se_name,
jintArray fdsToClose,
jintArray fdsToIgnore,
jstring instructionSet, jstring appDataDir) {
.................
return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
rlimits, capabilities, capabilities, mount_external, se_info,
se_name, false, fdsToClose, fdsToIgnore, instructionSet, appDataDir);
}
```
这个方法最后会调用ForkAndSpecializeCommon来创建新的进程,这个方法也在这篇文章[android启动之zygote进程](https://liqi.site/archives/android%E5%90%AF%E5%8A%A8%E4%B9%8Bzygote%E8%BF%9B%E7%A8%8B)里分析过了,这里也不多说了。这里fork后,父进程和子进程分别会返回至前面调用处,我们回到前面runOnce方法,看后半段代码:
```java
try {
if (pid == 0) { // 走到这里是fork出的子进程
// in child
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
// 执行子进程
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
// should never get here, the child is expected to either
// throw Zygote.MethodAndArgsCaller or exec().
return true;
} else { // 这里是zygote进程,pid是子进程的pid
// in parent...pid of < 0 means failure
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
// 返回父进程
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
```
这里有2个分支,pid为0代表是新进程,所以就是需要创建的进程。另一个分支就是父进程,即zygote进程了。我们先看父进程的处理,会调用handleParentProc方法:
```java
private boolean handleParentProc(int pid,
FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {
// 这里pid>0是子进程的
if (pid > 0) {
// 把子进程的gid设置为peer当初创建时候的组id,即和zygote是一组的
setChildPgid(pid);
}
..............
try {
// 这是zygote进程,需要写入AMS那里请求的localSocket的输出流
mSocketOutStream.writeInt(pid);
mSocketOutStream.writeBoolean(usingWrapper);
} catch (IOException ex) {
Log.e(TAG, "Error writing to command socket", ex);
return true;
}
return false;
}
```
父进程的处理也很简单,由于子进程是父进程fork出来的,所以先调用setChildPgid方法把子进程和父进程设置为同一组。方法的最后把子进程的pid写入AMS那里请求的localSocket的输出流中,这里AMS就可以拿到新创建的子进程pid,后面会封装成ProcessStartResult对象返回给AMS,这个在上面说过了,就不多说了,父进程主要就是需要把创建进程的pid返回给AMS,我们回去看子进程处理的方法。
子进程由于是从zygote中fork出来的,所以需要先关闭mServerSocket,这个是zygote作为一个服务端socket用的,子进程不需要这个所以先关闭。之后调用handleChildProc方法执行子进程的流程:
```java
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws Zygote.MethodAndArgsCaller {
closeSocket();
................
// 设置进程名
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}
// End of the postFork event.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
} else {
// 一般新进程会走这里,最终会调用到经常入口函数main
ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
```
首先调用closeSocket方法关闭AMS向socket发送连接请求时候保存的localSocket,之后会根据解析出的进程名设置给新进程。之后参数中如果invokeWith非空,说明是一个使用特殊启动命令启动的新进程,这个我们在之前也解释过,有时候我们需要再启动过程中执行一些命令,会使用命令行调用的方式来启动一个新进程,这个时候invokeWith这个参数就是非空的,所以会走if分支,我们正常启动这个参数为空,所以我们一般都会走else分支。ZygoteInit.zygoteInit这个方法最终会调用到ActiviyThread的main方法,从而进行进程的初始化,接着就是启动Activity的流程了。ZygoteInit.zygoteInit方法的分析也请参考[android启动之SystemServer进程](https://liqi.site/archives/a-n-d-r-o-i-d-qi-dong-zhi-z-y-g-o-t-e-jin-cheng--er-)这篇文章。
至此,一个新进程的创建就完成了,我们之前分析android启动过程中,遗留的一些问题在这篇文章里,也就都说完了。整个android的启动流程,我们也分了好几篇文章来讲,虽然讲了很多,但是里面还是有许多的细节可以深入分析,我们把主要的流程基本都分析过了,具体同学对哪部分有兴趣的话,可以深入去研究,我们这篇文章就到这里了,最后我们看下从AMS开始到进程创建的流程图。

android桌面的启动和进程的创建流程