接上篇: Android系統(tǒng)啟動流程(一)init進(jìn)程的啟動流程
Zygote在英語中是受精卵的意思,從這個名字可以看出,zygote進(jìn)程是用來孵化其他進(jìn)程的,SystemServer和其他應(yīng)用程序進(jìn)程都是由Zygote進(jìn)程所創(chuàng)建的。Zygote是以服務(wù)的形式存在于Android系統(tǒng)中的,是Android系統(tǒng)的一個重要的守護(hù)進(jìn)程,下面我們通過源碼來分析Zygote進(jìn)程的啟動流程。
1.解析Zygote服務(wù)的啟動腳本并啟動app_main
在init進(jìn)程啟動時,會解析Zygote服務(wù)進(jìn)程的啟動腳本并開啟Zygote進(jìn)程,針對不同位數(shù)的操作系統(tǒng),Zygote也分別對應(yīng)不同的啟動腳本,在Android8.0系統(tǒng)的源碼中共有4個啟動腳本,分別是init.zygote32.rc(支持32位系統(tǒng))、init.zygote64.rc(支持64位系統(tǒng))、init.zygote32_64.rc(同時支持32位和64位,但以32位為主)、init.zygote64_32.rc(同時支持32位和64位,但以64位為主),我們以init.zygote32.rc為例來看一下Zygote服務(wù)的腳本源碼:
目錄位置:\system\core\rootdir\init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
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
從上面的代碼可以看出,該服務(wù)的名稱是zygote,路徑為/system/bin/app_process,參數(shù)包含-Xzygote /system/bin --zygote --start-system-server,class的名稱為main。
init進(jìn)程在解析完上面的代碼后,會對zygote服務(wù)進(jìn)行啟動,啟動部分的腳本代碼如下:
源碼位置:\system\core\rootdir\init.rc
on zygote-start && property:ro.crypto.state=unencrypted //在.rc文件中,on表示一個觸發(fā)器,zygote-start是觸發(fā)器的名稱
//當(dāng)該觸發(fā)器被觸發(fā)后,便會執(zhí)行下面的命令
exec_start update_verifier_nonencrypted
start netd
start zygote //啟動zygote服務(wù)
start zygote_secondary
上面的代碼是定義在init.rc中的一個觸發(fā)器,當(dāng)該觸發(fā)器被觸發(fā)后,便會執(zhí)行start zygote這行命令,從而啟動zygote服務(wù),start命令對應(yīng)的函數(shù)為do_start,源碼如下:
源碼路徑:\system\core\init\builtins.cpp
static int do_start(const std::vector<std::string>& args) {
// 1.根據(jù)service的名稱找到該服務(wù)
Service* svc = ServiceManager::GetInstance().FindServiceByName(args[1]);
if (!svc) {
LOG(ERROR) << "do_start: Service " << args[1] << " not found";
return -1;
}
if (!svc->Start()) //2.調(diào)用Start方法開啟該服務(wù)
return -1;
return 0;
}
在注釋1處通過service的名稱來找到zygote這個服務(wù)的實(shí)例,然后再注釋2出調(diào)用Service的Start方法來開啟這個服務(wù),我們來看一下Start方法的源碼:
源碼路徑:\system\core\init\service.cpp
bool Service::Start() {
...
pid_t pid = -1;
if (namespace_flags_) {
pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
} else {
pid = fork(); // 1.通過fork函數(shù)創(chuàng)建zygote子進(jìn)程
}
if (pid == 0) { //pid為0,說明當(dāng)前在子進(jìn)程中
...
if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) { // 2.調(diào)用execve執(zhí)行子進(jìn)程的代碼
PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
}
_exit(127);
}
...
return true;
}
在注釋1處通過fork函數(shù)創(chuàng)建了一個子線程,由于fork函數(shù)是對父進(jìn)程的自我復(fù)制,所以fork函數(shù)會同時在父進(jìn)程和子進(jìn)程中返回,并在父進(jìn)程中返回子進(jìn)程的id,在子進(jìn)程中返回0。
在注釋2處,通過調(diào)用execve函數(shù)來執(zhí)行子進(jìn)程的代碼,從zygote的啟動腳本中可以看到,該服務(wù)的執(zhí)行代碼位于 /system/bin/app_process中,對應(yīng)的文件為app_main.cpp,這樣程序即進(jìn)入了app_main的main方法中。
2.通過AppRuntime啟動Zygote
我們先來看一下app_main.cpp的main方法的源碼:
源碼路徑:\frameworks\base\cmds\app_process\app_main.cpp
int main(int argc, char* const argv[])
{
...
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));// 1.創(chuàng)建AppRuntime實(shí)例
...
while (i < argc) { // 2.循環(huán)遍歷參數(shù)
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) { //當(dāng)參數(shù)為“--zygote”時
zygote = true; //將zygote標(biāo)記變?yōu)閠rue
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) { //當(dāng)參數(shù)為“--start-system-server”時
startSystemServer = true; //將startSystemServer參數(shù)變?yōu)閠rue
} 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;
}
}
if (zygote) {
// 3.如果zygote標(biāo)志為true,則執(zhí)行runtime的start方法
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.");
}
}
在注釋1處創(chuàng)建了一個AppRuntime實(shí)例。
在注釋2處對參數(shù)進(jìn)行循環(huán)遍歷,如果參數(shù)中含有 "--zygote",則將zygote置為true,如果參數(shù)中含有"--start-system-server",則將startSystemServer置為true。
在注釋3處通過調(diào)用runtime的start方法來執(zhí)行ZygoteInit文件中的代碼,并將ZygoteInit的文件路徑作為參數(shù)傳入了start方法,這是一個java文件。start函數(shù)的源碼位于AppRuntime的父類AndroidRuntime中,源碼如下:
源碼路徑:\frameworks\base\core\jni\AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...
JniInvocation jni_invocation;
jni_invocation.Init(NULL);//初始化jni
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) { // 1.啟動java虛擬機(jī)
return;
}
onVmCreated(env);
//主要用于注冊jni函數(shù)
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
...
/* 2.通過jni的方式執(zhí)行ZygoteInit的main方法*/
char* slashClassName = toSlashClassName(className); //將classname中的"."替換為“/”
jclass startClass = env->FindClass(slashClassName);//通過jni的方式加載ZygoteInit的java類
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V"); //找到ZygoteInit的main方法
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);//通過jni的方式調(diào)用ZygoteInit的mian方法
...
}
...
}
由于ZygoteInit文件是由java代碼編寫的,因此我們需要用jni的方法來執(zhí)行ZygoteInit的main方法。
在注釋1處,通過startVm方法創(chuàng)建了java虛擬機(jī)。
在注釋2處,通過執(zhí)行一系列的jni方法,最終調(diào)用了ZygoteInit的main方法。
3.啟動SystemServer并持續(xù)監(jiān)聽?wèi)?yīng)用創(chuàng)建請求。
我們來看一下Zygote的main方法的源碼:
源碼路徑:\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer(); //創(chuàng)建ZygoteServer實(shí)例
...
try {
...
zygoteServer.registerServerSocket(socketName); // 1.注冊ServerSocket
...
if (startSystemServer) {
startSystemServer(abiList, socketName, zygoteServer); // 2.啟動SystemServer
}
Log.i(TAG, "Accepting command socket connections");
zygoteServer.runSelectLoop(abiList); // 3.開啟事件循環(huán),不斷監(jiān)聽新的請求
zygoteServer.closeServerSocket();
} catch (Zygote.MethodAndArgsCaller caller) {
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
zygoteServer.closeServerSocket();
throw ex;
}
}
在main方法中,首先創(chuàng)建了一個ZygoteServer實(shí)例,然后在注釋1處,通過調(diào)用zygoteServer的registerServerSocket方法對ServerSocket進(jìn)行了注冊。
在注釋2處調(diào)用startSystemServer方法開啟了SystemServer進(jìn)程。
在注釋3處通過調(diào)用zygoteServer的runSelectLoop方法開啟了事件循環(huán),這樣zygote進(jìn)程就可以持續(xù)監(jiān)聽新的應(yīng)用進(jìn)程創(chuàng)建請求。
我們先來看一下registerServerSocket方法的源碼:
源碼路徑:\frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
private LocalServerSocket mServerSocket;
void registerServerSocket(String socketName) {
if (mServerSocket == null) {
int fileDesc;
//通過拼接字符串得到最終的Socket名稱,最后的結(jié)果為“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(fullSocketName + " unset or invalid", ex);
}
try {
FileDescriptor fd = new FileDescriptor();//創(chuàng)建文件描述符對象
fd.setInt$(fileDesc);
mServerSocket = new LocalServerSocket(fd);//創(chuàng)建ServerSocket對象
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
在registerServerSocket方法中,首先通過字符串拼接的方式獲得了Socket的名稱,然后根據(jù)這個名稱創(chuàng)建了一個文件描述符對象。基于linux一切都是文件的思想,socket也被看作是一個文件,該文件描述符即用來表示該socket。
然后通過這個文件描述符創(chuàng)建了一個LocalServerSocket對象,通過名稱我們便可以看出,這是一個運(yùn)行于服務(wù)端的socket,它的作用便是用來監(jiān)聽新的應(yīng)用進(jìn)程創(chuàng)建請求。
我們再來看一下runSelectLoop方法:
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
/* 1.開始無限循環(huán),不斷監(jiān)聽新的請求 */
while (true) {
/* 將fds中的數(shù)據(jù)轉(zhuǎn)移到pollFds數(shù)組中 */
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);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {// 2.當(dāng)數(shù)組中沒有未執(zhí)行的任務(wù)時
ZygoteConnection newPeer = acceptCommandPeer(abiList);//不斷進(jìn)行監(jiān)聽,當(dāng)有新請求時便會返回
//將這個連接請求放入數(shù)組中
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done = peers.get(i).runOnce(this);// 3.從peers中去除連接請求并執(zhí)行
if (done) {
//執(zhí)行完成后從數(shù)組中移除
peers.remove(i);
fds.remove(i);
}
}
}
}
}
在runSelectLoop方法中,首先創(chuàng)建了一個FileDescriptor數(shù)組和一個ZygoteConnection數(shù)組,他們用來存儲新接收到的請求。在注釋1處開啟了一個無限循環(huán)來不斷監(jiān)聽新的請求,因此zygote進(jìn)程在android系統(tǒng)的運(yùn)行過程中會一直存在,直到系統(tǒng)關(guān)閉。
在這個無限循環(huán)中,先將fds數(shù)組的數(shù)據(jù)轉(zhuǎn)移到了pollFds數(shù)組中,然后對pollFds數(shù)組進(jìn)行了遍歷,當(dāng)i==0時,說明數(shù)組中所有請求任務(wù)都已經(jīng)執(zhí)行完了,那么調(diào)用acceptCommandPeer方法來獲取新的請求,acceptCommandPeer方法是一個阻塞方法,如果沒有新的連接請求,acceptCommandPeer會一直阻塞,直到有新的連接請求到來時,acceptCommandPeer才會將這個新的請求返回。獲取到新的請求后便將這個請求放入peers和fds數(shù)組中。
當(dāng)i不為0時,說明數(shù)組中還存在未執(zhí)行的請求,則將請求取出并調(diào)用runOnce方法來執(zhí)行這個請求。
我們先來看一下acceptCommandPeer方法的源碼:
private ZygoteConnection acceptCommandPeer(String abiList) {
try {
return createNewConnection(mServerSocket.accept(), abiList);//調(diào)用accept方法等待新的請求
} catch (IOException ex) {
throw new RuntimeException(
"IOException during accept()", ex);
}
}
protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
throws IOException {
return new ZygoteConnection(socket, abiList); //創(chuàng)建ZygoteConnection實(shí)例
}
acceptCommandPeer的源碼非常簡單,就是就是調(diào)用accept方法等待新的請求,該方法會一直阻塞當(dāng)前線程,直到有新的請求到來。
我們再來看一下ZygoteConnection的runOnce方法:
源碼路徑:\frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java
boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {
...
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
parsedArgs.appDataDir);
...
}
runOnce方法的代碼很長,我們只看最關(guān)鍵的一句代碼,即調(diào)用forkAndSpecialize方法創(chuàng)建新的進(jìn)程,該方法最終會調(diào)用native方法來fork新的應(yīng)用程序進(jìn)程。
之前我們講過,zygote進(jìn)程在啟動的時候會創(chuàng)建一個java虛擬機(jī),而我們的應(yīng)用程序進(jìn)程都是由zygote進(jìn)程fork得來的,而fork的本質(zhì)是對父進(jìn)程的自我復(fù)制,因此所有的應(yīng)用程序子進(jìn)程也會獲得一個復(fù)制而來的java虛擬機(jī)副本,這樣便無需在應(yīng)用程序進(jìn)程中單獨(dú)啟動java虛擬機(jī)了。