一、前言
本文主要講解內容
1、系統啟動zygote、zygote的構造流程、主要做了什么
2、如何創建一個新的進程
3、systemserver的ams創建應用如何建立socket聯系,以及如何收發消息
先簡單提一下開機流程
init.rc -> zygote.rc -> app_main.cpp -> AndroidRuntime.cpp (啟動虛擬機,注冊jni,啟動zygote) -> ZygoteInit.java -> SystemServer進程
其中init是我們系統啟動的第一個進程,正是它通過linux的forck方法,創建我們系統的最重要的進程之一zygote.
zygote的啟動過程以及作用:啟動dalvik虛擬機,加載系統必須的一些資源,啟動framework的systemserver進程。最后等待app請求創建應用進程
zygote在fork一個新的進程時會克隆出和之前zygote幾乎一樣的進程包含zygote的資源,新進程不需要進行初始化操作,只會修改一些必要參數
由于源碼過多,本文的代碼都會精簡要點,最好結合源碼閱讀,源碼基于androidR,各安卓版本代碼可能有小區別但整體不會變化很大
二、啟動流程
2.1、init.rc啟動的地方
關于zygote的rc文件有幾個地方:
./system/core/rootdir/init.zygote32_64.rc
./system/core/rootdir/init.zygote32.rc
./system/core/rootdir/init.zygote64_32.rc
./system/core/rootdir/init.zygote64.rc
他們的32和64分別對應兩個啟動的地方app_process32和app_process64
例如:zygote64_32.rc,那么它以app_process64為主,app_process32為輔,它兩都會啟動,也就是有兩個zygote進程
./system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
上面就是開始啟動zygote的地方,不管是啟動32/64,都比較類似,執行手機里的/system/bin/app_process它對應的地方
2.2、app_main init主入口
app_main.cpp frameworks\base\cmds\app_process 11671 2022/2/23 241
app_main.cpp的main函數就成了入口,它主要做了如下幾個事情:
//1、構建runtime
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
//2、解析運行參數
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
//3、runtime start zygoteinit
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
這里的runtime只是一個調用,實現在
AndroidRuntime.cpp frameworks\base\core\jni
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
//這句日志實際輸出02-21 11:29:59.487 496 496 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<<
//達標className = com.android.internal.os.ZygoteInit
ALOGD(">>>>>> START %s uid %d <<<<<<\n",
className != NULL ? className : "(unknown)", getuid());
//打印關鍵日志boot_progress_start 表示開機過程上層開始
for (size_t i = 0; i < options.size(); ++i) {
if (options[i] == startSystemServer) {
primary_zygote = true;
/* track our progress through the boot sequence */
const int LOG_BOOT_PROGRESS_START = 3000;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
}
1、啟動虛擬機
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
return;
}
onVmCreated(env);
2、注冊JNI
/*
* Register android functions.
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
3、調用ZygoteInit的main函數
//這就是上面備注的className = ZygoteIni
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
2.3、ZygoteInit.java#main zygote入口
public static void main(String argv[]) {
1、加載進程的資源和類(這里可以多線程加載class文件優化開機速度)
preload(bootTimingsTraceLog);
2、創建zygoteServer
zygoteServer = new ZygoteServer(isPrimaryZygote);
if (startSystemServer) {
3、把sokeckname傳進去systemserver中,并開始運行systemserver
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
if (r != null) {
r.run();
return;
}
4、最后開啟loop等待消息
caller = zygoteServer.runSelectLoop(abiList);
}
看一下forkSystemServer中關鍵的兩個地方
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
1、zygote調用forkSystemServer這個native方法創建出系統進程
pid = Zygote.forkSystemServer(
parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.mGids,
parsedArgs.mRuntimeFlags,
null,
parsedArgs.mPermittedCapabilities,
parsedArgs.mEffectiveCapabilities);
2、給應用創建新的進程,走handleSystemServerProcess邏輯
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
}
}
這里下一步就開始啟動我們熟悉的systemserver服務。關于Systemserver就不過多闡述了,它主要啟動了我們整個android系統的各種service
三、zygote創建子進程流程
3.1、調用流程
創建一個應用流程這里就不詳述了,都大同小異,這里直接跟蹤到關鍵點,當我們跟蹤啟動流程跟蹤到
ActivityStack.java frameworks\base\services\core\java\com\android\server\wm
ActivityStack#resumeTopActivityInnerLocked
mStackSupervisor.startSpecificActivity(next, true, false);
startSpecificActivity主要判斷當前應用是否進程已經在運行,會跟蹤改到ActivityTaskManager#startProcessAsync方法
final Message m = PooledLambda.obtainMessage(ActivityManagerInternal::startProcess, mAmInternal, activity.processName, activity.info.applicationInfo, knownToBeDead, isTop, hostingType, activity.intent.getComponent());
即來到ActivityManagerServie#startProcess
public void startProcess(String processName, ApplicationInfo info, boolean knownToBeDead,
boolean isTop, String hostingType, ComponentName hostingName) {
startProcessLocked(processName, info, knownToBeDead, 0 /* intentFlags */,
new HostingRecord(hostingType, hostingName, isTop),
ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE, false /* allowWhileBooting */,
false /* isolated */, true /* keepIfLarge */);
即來到ActivityManagerServie#startProcessLocked - ProcessList#startProcessLocked -
ProcessList.java frameworks\base\services\core\java\com\android\server\am
private Process.ProcessStartResult startProcess(HostingRecord hostingRecord, String entryPoint,
ProcessRecord app, int uid, int[] gids, int runtimeFlags, int zygotePolicyFlags,
int mountExternal, String seInfo, String requiredAbi, String instructionSet,
String invokeWith, long startTime) {
Process.ProcessStartResult startResult;
if (hostingRecord.usesWebviewZygote()) {
startResult = startWebView(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName, app.mDisabledCompatChanges,
new String[]{PROC_START_SEQ_IDENT + app.startSeq});
} else if (hostingRecord.usesAppZygote()) {
final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);
// We can't isolate app data and storage data as parent zygote already did that.
startResult = appZygote.getProcess().start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, app.info.packageName,
/*zygotePolicyFlags=*/ ZYGOTE_POLICY_FLAG_EMPTY, isTopApp,
app.mDisabledCompatChanges, pkgDataInfoMap, whitelistedAppDataInfoMap,
false, false,
new String[]{PROC_START_SEQ_IDENT + app.startSeq});
} else {
//modify for prefork blank process begin
PreForkArgs preforkArgs = new PreForkArgs(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap,
whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
new String[] {PROC_START_SEQ_IDENT + app.startSeq});
startResult = mService.handlePreForkStartProcess(preforkArgs);
if (startResult == null) {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, runtimeFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, app.info.packageName, zygotePolicyFlags,
isTopApp, app.mDisabledCompatChanges, pkgDataInfoMap,
whitelistedAppDataInfoMap, bindMountAppsData, bindMountAppStorageDirs,
new String[]{PROC_START_SEQ_IDENT + app.startSeq});
}
//modify for prefork blank process end
}
}
其中主要是appZygote.getProcess().start這一句,調用棧
ZygoteProcess中start - startViaZygote -
ygoteProces - zygoteSendArgsAndGetResult - attemptZygoteSendArgsAndGetResult
3.2、連接socket發送數據
1、sokeck建立的地方
startViaZygote - openZygoteSocketIfNeeded - attemptConnectionToPrimaryZygote
@GuardedBy("mLock")
private void attemptConnectionToPrimaryZygote() throws IOException {
primaryZygoteState =
ZygoteState.connect(mZygoteSocketAddress, mUsapPoolSocketAddress);
//構建好消息這里發送
maybeSetApiBlacklistExemptions(primaryZygoteState, false);
}
static ZygoteState connect(@NonNull LocalSocketAddress zygoteSocketAddress,
@Nullable LocalSocketAddress usapSocketAddress) {
DataInputStream zygoteInputStream;
BufferedWriter zygoteOutputWriter;
final LocalSocket zygoteSessionSocket = new LocalSocket();
if (zygoteSocketAddress == null) {
throw new IllegalArgumentException("zygoteSocketAddress can't be null");
}
try {
//關鍵點,這里連接上了zygote的socket
zygoteSessionSocket.connect(zygoteSocketAddress);
zygoteInputStream = new DataInputStream(zygoteSessionSocket.getInputStream());
zygoteOutputWriter =
new BufferedWriter(
new OutputStreamWriter(zygoteSessionSocket.getOutputStream()),
Zygote.SOCKET_BUFFER_SIZE);
}
2、通過zygoteState的BufferedWriter,用socket發消息給zygote
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();
// Always read the entire result from the input stream to avoid leaving
// bytes in the stream for future process starts to accidentally stumble
// upon.
Process.ProcessStartResult result = new Process.ProcessStartResult();
result.pid = zygoteInputStream.readInt();
result.usingWrapper = zygoteInputStream.readBoolean();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
上面這段代碼,通過zygoteWriter把消息發給zygote,即發送流程
3.3、接收流程
接著上面的第二部分的ZygoteInit#main函數中,new了一個ZygoteServer
3.3.1 創建socket
ZygoteServer(boolean isPrimaryZygote) {
mUsapPoolEventFD = Zygote.getUsapPoolEventFD();
if (isPrimaryZygote) {
mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
int fileDesc;
// fullSocketName = “ANDROID_SOCKET_” + “zygote";
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
return new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException(
"Error building socket from file descriptor: " + fileDesc, ex);
}
}
3.3.2 sokeck創建后消息發送到了哪里
這里又接著上面的第二部分的ZygoteInit#main函數中第四步zygoteServer.runSelectLoop(abiList);
ZygoteServer創建了socket,runSelectLoop會執行
Runnable runSelectLoop(String abiList) {
while(true) {
try {
ZygoteConnection connection = peers.get(pollIndex);
// while循環到這句話會執行forck操作,進行新的進程的創建
final Runnable command = connection.processOneCommand(this);
// 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 processOneCommand hasn't called "exec".
if (command == null) {
throw new IllegalStateException("command == null");
}
return command;
}
}
}
3.4 創建子進程
ZygoteConnection#processOneCommand
Runnable processOneCommand(ZygoteServer zygoteServer) {
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.mWhitelistedDataInfoList,
parsedArgs.mBindMountAppDataDirs, parsedArgs.mBindMountAppStorageDirs);
//穿件完后給ams回復
return handleChildProc(parsedArgs, childPipeFd, parsedArgs.mStartChildZygote);
}
//Zygote#forkAndSpecialize
static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
boolean isTopApp, String[] pkgDataInfoList, String[] whitelistedDataInfoList,
boolean bindMountAppDataDirs, boolean bindMountAppStorageDirs) {
ZygoteHooks.preFork();
int pid = nativeForkAndSpecialize(
uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
fdsToIgnore, startChildZygote, instructionSet, appDataDir, isTopApp,
pkgDataInfoList, whitelistedDataInfoList, bindMountAppDataDirs,
bindMountAppStorageDirs);
子進程的初始化操作就不詳述了大概說下調用棧
handleChildProc - ZygoteInit.zygoteInit - RuntimeInit.applicationInit - RuntimeInit.findStaticMain
四、寫在最后
本文意在分析zygote的構建,以及如何通過socke構建新的進程。下面說兩個比較常規的問題
為啥系統其它進程都用binder而這里采用socket呢?
首先binder是多線程的,zygote的fork函數是不允許多線程的,不然容易造成死鎖(copy on write)
為啥運行app不新建一個進程而采用zygote fork?
因為應用是獨立運行在dalvik中,他們的進程空間是分開的。如果每個應用都是新建進程,那么zygote加載的系統資源就會重復創建添加浪費系統資源。且zygote孵化也可節約創建的時間。