前言
前面我們?cè)?Android 系統(tǒng)啟動(dòng) - init 進(jìn)程 中提到,init 進(jìn)程在解析完 init.rc 腳本后,會(huì)啟動(dòng) Zygote 進(jìn)程。具體來講,Zygote 是以服務(wù)(service)的形式配置在 init.rc 中,其對(duì)應(yīng)的可執(zhí)行文件為 /system/bin/app_processXX。init 進(jìn)程會(huì)通過 fork
為每個(gè)服務(wù)創(chuàng)建一個(gè)獨(dú)立的進(jìn)程。對(duì)于 Zygote 來說, /system/bin/app_processXX 就會(huì)被啟動(dòng),然后該進(jìn)程內(nèi)部最終會(huì)通過 AppRuntime.start
真正啟動(dòng) Zygote 進(jìn)程。
接下來,我們就來分析下 Zygote 具體的啟動(dòng)過程:
Zygote 啟動(dòng)過程
我們先來看下啟動(dòng) Zygote 服務(wù)源碼:
framework/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
···
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
}
···
}
看到調(diào)用的是 runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
,看到 "com.android.internal.os.ZygoteInit"
這種包名形式,就大概知道 runtime.start
該函數(shù)內(nèi)部應(yīng)該會(huì)通過 JNI 來調(diào)用 Java 層的類了。究竟是不是,我們進(jìn)入看一下:
frameworks/base/core/jni/AndroidRuntime.cpp
/*
* Start the Android runtime. This involves starting the virtual machine
* and calling the "static void main(String[] args)" method in the class
* named by "className".
*
* Passes the main function two arguments, the class name and the specified
* options string.
*/
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
···
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
// 創(chuàng)建 Java 虛擬機(jī)
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
// JNI 方法注冊(cè)
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
/*
* We want to call main() with a String array with arguments in it.
* At present we have two arguments, the class name and an option string.
* Create an array to hold them.
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
// 相當(dāng)于 strArray= new String[options.size() + 1];
stringClass = env->FindClass("java/lang/String");
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
// 相當(dāng)于 strArray[0] = "com.android.internal.os.ZygoteInit"
classNameStr = env->NewStringUTF(className);
env->SetObjectArrayElement(strArray, 0, classNameStr);
// 等價(jià) strArray[1] = "start-system-server";
// strArray[2] = "--abi-list=xxx";
// 其中xxx為系統(tǒng)響應(yīng)的cpu架構(gòu)類型,比如arm64-v8a.
for (size_t i = 0; i < options.size(); ++i) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
assert(optionsStr != NULL);
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
// 將"com.android.internal.os.ZygoteInit"轉(zhuǎn)換為"com/android/internal/os/ZygoteInit"
char* slashClassName = toSlashClassName(className);
// 找到類 "com/android/internal/os/ZygoteInit"
jclass startClass = env->FindClass(slashClassName);
···
// 找到類 "com/android/internal/os/ZygoteInit"的靜態(tài)方法main(String[])
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
···
// 調(diào)用 ZygoteInit.main(String[])
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
//釋放相應(yīng)對(duì)象的內(nèi)存空間
free(slashClassName);
ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
}
該方法主要就是啟動(dòng) Android 運(yùn)行時(shí),主要做了兩件事:創(chuàng)建虛擬機(jī) startVm
和 注冊(cè) JNI 方法 startReg
并啟動(dòng) ZygoteInit.main
函數(shù)。
到這里,Zygote 服務(wù)進(jìn)程通過 JNI 反射調(diào)用 Java 層代碼,正式將 Android 運(yùn)行環(huán)境從 c++ 層轉(zhuǎn)移到 Java 層。Zygote 進(jìn)程也同時(shí)成為 Android 系統(tǒng)第一個(gè) Java 進(jìn)程。
那我們接下來看看 ZygoteInit.main
函數(shù)源碼:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
try {
// 開啟DDMS功能
RuntimeInit.enableDdms();
···
// 為Zygote注冊(cè)Socket
registerZygoteSocket(socketName);
···
// 預(yù)加載類和資源
preload();
···
// Do an initial gc to clean up after startup
// GC 釋放資源
gcAndFinalize();
···
if (startSystemServer) {
// 啟動(dòng) SystemServer 進(jìn)程
startSystemServer(abiList, socketName);
}
// 進(jìn)入監(jiān)聽狀態(tài),等待客戶端請(qǐng)求
runSelectLoop(abiList);
// 關(guān)閉Socket
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run(); // 真正啟動(dòng) SystemServer
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
// 關(guān)閉Socket
closeServerSocket();
throw ex;
}
}
可以看到,ZygoteInit.main
方法主要做了四件事:
- 為 Zygote 進(jìn)程注冊(cè)一個(gè)服務(wù)端 Socket:
registerZygoteSocket
; - 預(yù)加載類和資源:
preload
; - 啟動(dòng) SystemServer 進(jìn)程:
startSystemServer
; - 開啟 Socket 監(jiān)聽,等待客戶端請(qǐng)求:
runSelectLoop
下面我們依次分析上述四個(gè)操作:
首先來看下 Zygote 注冊(cè)服務(wù)端 Socket 具體過程:registerZygoteSocket
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static void registerZygoteSocket(String socketName) {
if (sServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
// 從環(huán)境變量中獲取Socket套接字描述符
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); // 設(shè)置文件描述符
sServerSocket = new LocalServerSocket(fd);// 創(chuàng)建Socket的本地服務(wù)端
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
其實(shí)就是從環(huán)境變量中獲取 Socket 套接字文件描述符(此處的 socket 是由 service_start
創(chuàng)建的,并且創(chuàng)建完后會(huì)通過 publish_socket
方法發(fā)布出去,發(fā)布的途徑就是設(shè)置到環(huán)境變量中),然后創(chuàng)建 Socket 本地服務(wù)端。
接下來看下 Zygote 預(yù)加載類和資源的具體過程:preload
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
static void preload() {
Log.d(TAG, "begin preload");
// 預(yù)加載常用類:/system/etc/preloaded-classes
preloadClasses();
// 預(yù)加載資源文件,包含drawable和color資源
preloadResources();
// 預(yù)加載OpenGL
preloadOpenGL();
// 預(yù)加載共享庫(kù):"android","compiler_rt" 和 "jnigraphics"
preloadSharedLibraries();
// 預(yù)加載文本連接符資源
preloadTextResources();
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
// 為了達(dá)到內(nèi)存共享,WebViewFactory 需要進(jìn)行的初始化操作
WebViewFactory.prepareWebViewInZygote();
Log.d(TAG, "end preload");
}
該方法沒有太多好說的,就是預(yù)加載了一些常用類庫(kù)和資源文件等,這樣后續(xù)創(chuàng)建新的虛擬機(jī)進(jìn)程時(shí),直接 fork
Zygote 進(jìn)程,就無需再次預(yù)加載這些資源了,節(jié)省時(shí)間,使虛擬機(jī)能更快啟動(dòng)。
ZygoteInit.main
第三個(gè)主要操作就是啟動(dòng) SystemServer 進(jìn)程,該部分詳細(xì)內(nèi)容請(qǐng)查看:Android 系統(tǒng)啟動(dòng) - SystemServer 進(jìn)程
最后我們來看下 Zygote 進(jìn)程實(shí)現(xiàn)響應(yīng)客戶端請(qǐng)求的具體過程:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
/**
* Runs the zygote process's select loop. Accepts new connections as
* they happen, and reads commands from connections one spawn-request's
* worth at a time.
*
* @throws MethodAndArgsCaller in a child process when a main() should
* be executed.
*/
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
// sServerSocket就是Zygote自己創(chuàng)建的Socket:registerZygoteSocket
// 即 zygote 的 socket 通信服務(wù)端,保存到fds[0
fds.add(sServerSocket.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;
}
try {
// 處理輪詢狀態(tài),當(dāng)pollFds有事件到來時(shí)則往下執(zhí)行,否則阻塞
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
// 采用I/O多路復(fù)用機(jī)制,當(dāng)接收到客戶端發(fā)出連接請(qǐng)求 或者 數(shù)據(jù)處理請(qǐng)求到來,則往下執(zhí)行
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
// 即fds[0],代表的是sServerSocket,意味著有客戶端連接請(qǐng)求,則會(huì)創(chuàng)建ZygoteConnection對(duì)象,并添加到fds。
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
// i>0,說明接收到一個(gè)創(chuàng)建應(yīng)用進(jìn)程的請(qǐng)求,則調(diào)用ZygoteConnection的runOnce函數(shù)來創(chuàng)建一個(gè)新的應(yīng)用程序進(jìn)程。
boolean done = peers.get(i).runOnce();
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}
該方法采用 I/O 多路復(fù)用機(jī)制,高效地實(shí)現(xiàn)了 Zygote 進(jìn)程的 Socket 監(jiān)聽。當(dāng)有客戶端的連接請(qǐng)求或數(shù)據(jù)處理時(shí),則響應(yīng)客戶端請(qǐng)求。特別的,當(dāng)接收到客戶端請(qǐng)求創(chuàng)建應(yīng)用進(jìn)程時(shí),就會(huì)調(diào)用 ZygoteConnection.runOnce
方法創(chuàng)建一個(gè)新的應(yīng)用進(jìn)程,具體的進(jìn)程創(chuàng)建方法,請(qǐng)查看:理解Android進(jìn)程創(chuàng)建流程
至此,Zygote 進(jìn)程的啟動(dòng)流程分析結(jié)束。
總結(jié)
Zygote 進(jìn)程是由 init 進(jìn)程啟動(dòng)的,其對(duì)應(yīng)的可執(zhí)行文件為 /system/bin/app_processXX,其內(nèi)部最終會(huì)通過 AppRuntime.start
方法啟動(dòng) Zygote 進(jìn)程:具體來說,該方法內(nèi)部會(huì)創(chuàng)建 Java 虛擬機(jī)(startVm
) 和 注冊(cè) JNI 本地方法(startReg
),最后通過 JNI 調(diào)用啟動(dòng) Java 層 Zygote 進(jìn)程(ZygoteInit.main
),從而讓 Android 系統(tǒng)正式開啟第一個(gè) Java 進(jìn)程,即 Zygote。
Java 框架層的 Zygote 主要做的就是:創(chuàng)建服務(wù)端 Socket 并進(jìn)行監(jiān)聽(registerZygoteSocket
,runSelectLoop
),預(yù)加載常用類和資源,啟動(dòng) SystemServer 進(jìn)程。