博客同步至github博客:Zygote進程啓動流程
使用到的相關源碼:https://github.com/JesusYoung/AndroidResourceCode9.0/tree/master
基於Android 9.0
1、Zygote進程
Zygote是在init進程啓動時創建的,它又稱爲孵化器,它可以通過fork(複製進程)的形式來創建應用程序進程和SystemServer進程,並且,Zygote進程在啓動的時候會創建DVM或者ART,因此通過fork而創建的應用程序進程和SystemServer進程可以在內部獲取一個DVM或者ART的實例副本;
2、Zygote進程啓動流程
2.1、Init進程調用
2.1.1、解析配置參數
Init進程啓動之後,解析init.rc配置文件,執行其配置,其中有啓動Zygote進程的參數配置,在app_main.cpp的main()方法中,先解析參數,例如在前面解析.rc文件時添加的參數“–zygote、----start-system-server”等,初始化各種標識位;
int main(int argc, char* const argv[]) {
...
++i; // Skip unused "parent dir" argument.
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;
}
}
...
}
2.1.2、啓動Dalvik虛擬機
接着判斷className是否爲空,在Zygote模式下,調用maybeCreateDalvikCache()函數創建Dalvik虛擬機緩存,添加啓動systemServer的參數標識;
int main(int argc, char* const argv[]) {
...
if (!className.isEmpty()) {
...
} else {
// We're in zygote mode.
maybeCreateDalvikCache();
if (startSystemServer) {
args.add(String8("start-system-server"));
}
char prop[PROP_VALUE_MAX];
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.", ABI_LIST_PROPERTY);
return 11;
}
String8 abiFlag("--abi-list=");
abiFlag.append(prop);
args.add(abiFlag);
// In zygote mode, pass all remaining arguments to the zygote main() method.
// 在Zygote模式下,將剩餘的參數全部傳遞過去
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
...
}
2.2、啓動Zygote
2.2.1、創建AppRunTime對象
在main()函數中創建了AppRunTime對象,AppRunTime對象繼承自AndroidRunTime類;
int main(int argc, char* const argv[]) {
...
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
...
}
class AppRuntime : public AndroidRuntime {
public:
AppRuntime(char* argBlockStart, const size_t argBlockLength)
: AndroidRuntime(argBlockStart, argBlockLength) , mClass(NULL) {
}
...
}
2.2.2、AppRunTime啓動Zygote
隨後調用AppRunTime類的start()方法來啓動Zygote進程,在前面判斷中得知zygote參數爲true;
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
...
}
AppRunTime類繼承自AndroidRunTime類,AppRunTime類並沒有重載start()方法,所以這裏執行的是AndroidRunnTime類的start()方法;
2.2.3、註冊JNI
首先會初始化一些環境rootDir等,然後會啓動虛擬機,調用startReg()函數向虛擬機註冊Android Native方法;
拿到前面傳入的類名,即com.android.internal.os.ZygoteInit,通過JNI調用其main()方法,因爲此處爲C代碼,而ZygoteInit爲Java類,所以調用時需要使用JNI方式去調用,此時,正式從C層進入Java層;
class AppRuntime : public AndroidRuntime {}
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote) {
...
// 啓動虛擬機
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
...
// 向虛擬機註冊Android Native方法
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
...
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
...
} else {
// 找到main()方法
jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V");
if (startMeth == NULL) {
...
} else {
// 調用ZygoteInit類的main()方法
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
...
}
2.2.4、啓動進入Java層Zygote
Zygote進程啓動,在ZygoteInit的main()方法中,通過調用ZygoteHooks類的startZygoteNoThreadCreation()函數來拋出異常,標識Zygote進程已經啓動;
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
// Mark zygote start. This ensures that thread creation will throw
// an error.
ZygoteHooks.startZygoteNoThreadCreation();
...
}
2.3、創建Zygote進程Socket
2.3.1、創建服務端socket
在ZygoteInit的main()函數中,創建了ZygoteServer對象,作爲Zygote進程的socket通信的服務端,名爲zygote,用來接收SystemServer進程向Zygote進程發來的請求,例如AMS向Zygote進程請求創建新應用等,接着調用runSelectLoop()來等待SystemServer進程發來的請求;
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
...
try {
...
zygoteServer.registerServerSocketFromEnv(socketName);
...
caller = zygoteServer.runSelectLoop(abiList);
}
...
if (caller != null) {
caller.run();
}
}
// ZygoteServer
void registerServerSocketFromEnv(String socketName) {
if (mServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
mServerSocket = new LocalServerSocket(fd);
mCloseSocketFd = true;
} catch (IOException ex) {
throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
2.3.2、執行客戶端請求
輪詢客戶端Socket消息,當客戶端有新消息到來時,創建一個新的連接去執行客戶端發來的請求,例如AMS請求創建新的進程;
新建一個peers列表,用於存儲每個客戶端的連接,將fd數據轉存到poolFds中,遍歷,當i=0時表示有客戶端與服務端連接成功,此時執行acceptCommandPeer()方法拿到新的連接,並將其存入到peers集合中,當i>0時,表示客戶端在向服務端傳輸數據,從peers中拿出與客戶端的連接,執行processOneCommand()函數得到一個Runnable對象,如果是fork子進程並且任務不爲null則返回該Runnable對象,在main()函數中,如果該對象不爲空,就去執行其run()方法;
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
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;
}
...
for (int i = pollFds.length - 1; i >= 0; --i) {
...
if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
try {
ZygoteConnection connection = peers.get(i);
final Runnable command = connection.processOneCommand(this);
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;
} else {
// We're in the server - we should never have any commands to run.
if (command != null) {
throw new IllegalStateException("command != null");
}
// We don't know whether the remote side of the socket was closed or
// not until we attempt to read from it from processOneCommand. This shows up as
// a regular POLLIN event in our regular processing loop.
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(i);
fds.remove(i);
}
}
}
...
}
}
}
}
執行processOneCommand()方法時,創建fork子進程的Runnable對象,如果是在父進程中,則返回null,子進程中則會返回fork子進程的Runnable對象,去執行fork操作,並且清除掉fork過來的父進程中的socket信息;
Runnable processOneCommand(ZygoteServer zygoteServer) {
...
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.runtimeFlags, rlimits, parsedArgs.mountExternal,
parsedArgs.seInfo, parsedArgs.niceName, fdsToClose,
fdsToIgnore, parsedArgs.startChildZygote,
parsedArgs.instructionSet, parsedArgs.appDataDir);
try {
if (pid == 0) {
// in child
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
return handleChildProc(parsedArgs, descriptors, childPipeFd, parsedArgs.startChildZygote);
} else {
// In the parent. A pid < 0 indicates a failure and will be handled in
// handleParentProc.
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
...
}
2.4、啓動SystemServer
Zygote進程啓動後,執行ZygoteInit類的main()方法,啓動會調用forkSystemServer()方法去通過fork自身的方式去創建SystemServer進程;
public static void main(String argv[]) {
...
try {
...
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, socketName, 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;
}
}
...
}
...
}