概述
轉載請註明出處:https://blog.csdn.net/wangzaieee/article/details/85003806
init進程是用戶空間的第一個進程,而zygote進程則是第一個java進程。zygote進程是init進程的子進程,init進程通過解析rc文件,運行了zygote進程。
zygote是Android系統中一個相當重要的進程,它的主要功能就是執行Android應用程序。在Android系統中運行新的應用,如同卵子受精分裂一樣,需要跟Zygote進程(擁有應用程序運行時所需要的各種元素和條件,如:虛擬機等)結合才能執行。
Zygote進程
zygote進程運行時,會初始化Art(或者Dalvik)虛擬機,並啓動它。Android的應用程序是由Java編寫的,它們不能直接以本地進程的形式運行在linux上,只能運行在虛擬機中。並且,每個應用程序都運行在各自的虛擬機中,如果應用程序每次運行都要重新初始化並啓動虛擬機,這個過程會耗費相當長時間。因此,在Android中,應用程序運行前,zygote進程通過共享已運行的虛擬機的代碼與內存信息,縮短應用程序運行所耗費的時間。並且,它會事先將應用程序要使用的Android Framework中的類和資源加載到內存中,並組織形成所用資源的鏈接信息。新運行的Android應用程序在使用所需資源時不必每次重新形成資源的鏈接信息,這回節省大量時間,提高程序運行速度。
那麼,在Linux系統中創建並運行一個進程,與在Android系統中通過zygote來創建並運行一個應用程序,兩者究竟有何不同呢?
以下圖片均參考自《Android框架揭祕》一書(實在不想自己畫了 0.0)
如上圖所示,父進程A調用fork()函數創建新的子進程A’。新創建的進程A’共享父進程的內存結構信息與庫連接信息(COW 寫時拷貝技術)。而後子進程A’調用exec(‘B’),將新進程B的代碼加載到內存中。此時,將重新分配內存(因爲之前是共享的),以便運行被裝載的B程序,接着形成新的庫連接信息,以供B進程單獨使用。
如上圖所示,zygote進程調用fork()函數創建出zygote’子進程,子進程zygote’ 共享父進程zygote的代碼區與鏈接信息。注意,新的Android應用程序A 並非通過exec() 來重新裝載已有進程的代碼區,而是動態的加載到複製的虛擬機上(虛擬空間的複製,物理空間還是同一個)。而後,zygote’進程將執行流程交給應用程序A類的方法,Android應用程序開始運行。新生成的應用程序A會使用已有zygote進程的庫與資源的鏈接信息,所以運行速度很快。
如上圖所示,zygote啓動後,初始化並運行art(或者dalvik)虛擬機,而後將需要的類與資源加載到內存中。隨後調用fork()創建出zygote’子進程,接着zygote’子進程動態加載並運行Android應用程序A。運行的應用程序A會使用zygote已經初始化並啓動運行的虛擬機代碼,通過使用已記載至內存中的類與資源來加快運行速度。
COW (Copy on write)
在創建新進程後,新進程會共享父進程的內存空間,即新的子進程會複製所有與父進程內存空間相關的信息並使用它。COW就是針對內存複製的一種技術。一般來說,複製內存的開銷非常大,因此創建的子進程在引用父進程的內存空間時,不要進行復制,而要直接共享父進程的內存空間。而當需要修改共享內存中的信息時,子進程纔會將父進程中相關的內存信息複製到自身的內存空間,並進行修改,這就是COW(Copy on write)技術。
在fork之後exec之前兩個進程用的是相同的物理空間(內存區),子進程的代碼段、數據段、堆棧都是指向父進程的物理空間,也就是說,兩者的虛擬空間不同,但其對應的物理空間是同一個。
Zygote進程源碼分析
由app_process運行ZygoteInit class
zygote由java編寫而成,不能直接由init進程啓動運行。若想執行zygote類,必須先創建虛擬機,然後在虛擬機上運行ZygoteInit類。執行這一任務的就是app_process程序。
下面我們開始分析zygote進程的啓動流程:
/system/core/rootdir/init.rc
import /init.$(ro.zygote).rc
如果是64位系統,$(ro.zygote)的值爲"zygote64"
/system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
...
class main
user root
socket zygote stream 660 root system //創建/dev/socket/zygote套接字
...
init進程解析上面的init.zygote64.rc
文件後,會執行/system/bin/app_process64
進程,並且生成了/dev/socket/zygote
套接字,ZygoteInit會用該套接字來接收AMS發來的創建新應用程序的請求。
init進程分析並執行rc文件流程可以看看我的上一篇文章Init進程的啓動流程。
app_process64程序的main函數入口如下:
frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
......
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
......
// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
......
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
}
......
}
......
if (zygote) {
//zygote進程
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
//普通java進程
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
}
}
如果是zygote進程就走ZygoteInit
代碼,如果是普通java進程就走RuntimeInit
代碼,例如常用的am
命令,/system/bin/am
實際上是一個shell腳本,查看裏面的代碼可知是通過app_process來啓動普通java進程,然後和AMS進行通信。
frameworks/base/core/jni/AndroidRuntime.cpp
//AppRuntime繼承自AndroidRuntime
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
/* start the virtual machine */
JniInvocation jni_invocation;
// ① 加載指定的虛擬機的庫(art或者dalvik)
jni_invocation.Init(NULL);
JNIEnv* env;
// ② 創建java虛擬機
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
// ③ 註冊JNI函數
if (startReg(env) < 0) {
return;
}
......
// ④ 正式進入java的世界,調用ZygoteInit.java的main方法
jclass startClass = env->FindClass(slashClassName);
......
jmethodID startMeth = env->GetStaticMethodID(startClass, "main","([Ljava/lang/String;)V");
......
env->CallStaticVoidMethod(startClass, startMeth, strArray);
......
}
①: 加載虛擬機的庫(art或者dalvik),並且函數指針指向庫對應的函數(如:JNI_CreateJavaVM函數)
libnativehelper/JniInvocation.cpp
bool JniInvocation::Init(const char* library) {
//獲取要加載庫的名稱
library = GetLibrary(library, buffer);
//動態加載對應的虛擬機庫
handle_ = dlopen(library, RTLD_NOW);
......
//JNI_CreateJavaVM_函數指針指向虛擬機庫中的JNI_CreateJavaVM函數
if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
"JNI_CreateJavaVM")) {
return false;
}
.......
return true;
}
GetLibraray()
函數獲取動態庫的名稱(libart.so或者libdalvik .so),dlopen()
函數動態加載虛擬機庫,RTLD_NOW
表示返回之前立即鏈接所有未定位的符號,FindSysmbol()
函數指針指向對應的函數。
libnativehelper/JniInvocation.cpp
static const char* kLibrarySystemProperty = "persist.sys.dalvik.vm.lib.2";
static const char* kDebuggableSystemProperty = "ro.debuggable";
static const char* kDebuggableFallback = "0"; // Not debuggable.
static const char* kLibraryFallback = "libart.so";
const char* JniInvocation::GetLibrary(const char* library, char* buffer) {
char debuggable[PROPERTY_VALUE_MAX];
//獲取"ro.debuggable"的屬性值
property_get(kDebuggableSystemProperty, debuggable,kDebuggableFallback);
if (strcmp(debuggable, "1") != 0) {
//如果不是debug設備,library的值爲"libart.so"
library = kLibraryFallback;
} else {
//如果是debug設備,library的值爲"persisit.sys.dalvik.vm.lib.2"的屬性值
property_get(kLibrarySystemProperty, buffer, kLibraryFallback);
}
return library;
}
②: 創建java虛擬機
frameworks/base/core/jni/AndroidRuntime.cpp
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
JavaVMInitArgs initArgs;
......
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();
initArgs.nOptions = mOptions.size();
initArgs.ignoreUnrecognized = JNI_FALSE;
......
//創建java虛擬機
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
return -1;
}
return 0;
}
JNI_CreateJavaVM()
是JniInvocation.cpp中的函數,會調用到①中所說的JNI_CreateJavaVM_()
函數指針,最後調用到相應虛擬機動態庫中的JNI_CreateJavaVM()
函數,創建對應的虛擬機。initArgs
表示傳入的虛擬機參數。
③: 註冊JNI本地函數
我們先來熟悉一下幾個數據結構:
frameworks/base/core/jni/AndroidRuntime.cpp
#define REG_JNI(name) { name }
struct RegJNIRec {
int (*mProc)(JNIEnv*);
};
......
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
......
};
gRegJNI
是RegJNIRec
結構體數組,然後數組通過REG_JNI
宏定義初始化。例如gRegJNI第一個元素的初始化,等同於:
gRegJNI[0] = {register_com_android_internal_os_RuntimeInit};
那麼gRegJNI[0]中RegJNIRec
結構體的mProc
函數指針就指向上面的函數register_com_android_internal_os_RuntimeInit
,數組中的其它元素也同理。下面我們繼續分析JNI本地函數的註冊。
frameworks/base/core/jni/AndroidRuntime.cpp
int AndroidRuntime::startReg(JNIEnv* env)
{
......
//註冊JNI本地函數,將gRegJNI數組傳入
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
return -1;
}
......
return 0;
}
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
//遍歷執行gRegJNI數組中元素的mProc函數
//(mProc是函數指針,數組初始化的時候已經指向指定的函數)
for (size_t i = 0; i < count; i++) {
if (array[i].mProc(env) < 0) {
return -1;
}
}
return 0;
}
startReg
會調用register_jni_procs
遍歷調用gRegJNI數組中的mProc
函數,以第一個元素爲例,gRegJNI[0].mProc(env)
由上面的分析可知調用的實際是register_com_android_internal_os_RuntimeInit(env)
函數。
frameworks/base/core/jni/AndroidRuntime.cpp
int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
{
const JNINativeMethod methods[] = {
{ "nativeFinishInit", "()V",
(void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
......
};
//最後會調用到(*env)->RegisterNative()註冊
return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
methods, NELEM(methods));
}
用上面的代碼可知,nativeFinishInit
函數映射了com_android_internal_os_RuntimeInit_nativeFinishInit
函數,當java調用nativeFinishInit
函數時,實際會調用到c/c++中的com_android_internal_os_RuntimeInit_nativeFinishInit
函數。有讀者可能會問,java調用jni函數時,虛擬機會自動映射,爲什麼要自己映射呢?如果jni函數比較少,這麼做確實可行,但是我們可以看到gRegJNI數組是很龐大的,需要映射的函數也很多,如果全部交給虛擬機映射,會大大降低虛擬機的執行性能,所以我們提前註冊JNI函數,虛擬機就可以直接找到對應的函數進行調用。
④: 通過反射調用ZygoteInit.java的main函數,正式進入java的世界。env->FindClass
獲取ZygoteInit類的類型,env->GetStaticMethodID
獲取函數main的函數id,env->CallStaticVoidMethod
調用ZygoteInit.java的靜態函數main。
ZygoteInit類的功能
至此,我們已經創建好了虛擬機,並且將ZygoteInit類裝載到了虛擬機。接下來,ZygoteInit類將會被運行,那麼ZygoteInit類具體有哪些功能呢?大致概括爲如下幾點:
- 綁定套接字,用來接收新Android應用程序運行請求
- 預加載Android Application Framework 使用的類與資源
- 啓動並運行SystemServer
- 處理新Android應用程序運行請求
ZygoteInit的main函數:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
......
try{
boolean startSystemServer = false;
String socketName = "zygote";//套接字默認名稱zygote
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
}
......
}
// ① 綁定/dev/socket/zygote套接字,用來接收Android應用程序運行請求
zygoteServer.registerServerSocketFromEnv(socketName);
......
if (!enableLazyPreload) {
......
// ② 預加載類與資源
preload(bootTimingsTraceLog);
......
}
......
if (startSystemServer) {
// ③ fork出system_server子進程
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
// ③ {@code r == null}表示是父進程(zygote),{@code r != null}在子進程(system_server)
if (r != null) {
// ③ 如果是子進程(system_server)就執行run()方法,並返回,父進程(zygote)就繼續往下執行
r.run();
return;
}
}
Log.i(TAG, "Accepting command socket connections");
// ④ 這輪詢會在zygote進程中無限循環,而fork出的子進程(Android應用進程)會退出來
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
//system_server進程和android應用進程會關閉socket,zygote仍然在runSelectLoop中輪詢監聽socket
zygoteServer.closeServerSocket();
}
// ④ Android應用進程會走到這兒,執行相應的命令
if (caller != null) {
caller.run();
}
}
①: 綁定套接字,用來接收運行Android應用運行請求
frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
void registerServerSocketFromEnv(String socketName) {
if (mServerSocket == null) {
int fileDesc;
//fullSocketName爲“ANDROID_SOCKET_zygote”
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
//獲取ANDROID_SOCKET_zygote的壞境變量(即爲/dev/socket/zygote的文件描述符的值)
//是init進程在啓動zygote進程時保存到環境變量中的
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
//綁定socket,在後面用來接收Android應用啓動請求
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
mServerSocket = new LocalServerSocket(fd);
mCloseSocketFd = true;
} catch (IOException ex) {
......
}
}
}
②: 預加載類和資源,後面從zygote進程fork出的應用進程可以直接共享,加快應用進程啓動速度。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
static void preload(TimingsTraceLog bootTimingsTraceLog) {
......
preloadClasses();
......
preloadResources();
......
nativePreloadAppProcessHALs();
......
preloadOpenGL();
preloadSharedLibraries();
preloadTextResources();
.......
}
preloadClasses
、preloadResources
、nativePreloadAppProcessHALs
預加載類和資源等等,有興趣的同學可以深入瞭解。
③: forkSystemServer
fork出system_server
子進程,並返回可以調用SystemServer中main方法的Runnable r
,並執行對應的run方法,而父進程zygote則繼續往下執行runSelectLoop
,監聽Android應用運行執行請求。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static Runnable forkSystemServer(String abiList, String socketName,ZygoteServer zygoteServer) {
......
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000", //用戶id
"--setgid=1000", //組id
......
"--nice-name=system_server",
......
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
......
//fork出system_server子進程,並且設置對應的參數
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.runtimeFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
//子進程(system_server)
if (pid == 0) {
......
//所以返回的r不爲null,直接執行r.run
return handleSystemServerProcess(parsedArgs);
}
//父進程(zygote),返回的是null,繼續往下執行
return null;
}
ZygoteInit的forkSystemServer
方法會調用Zygote的forkSystemServer
方法,如果是子進程(system_server)就返回handleSystemServerProcess()
,父進程(zygote)就返回null。
frameworks/base/core/java/com/android/internal/os/Zygote.java
public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
......
int pid = nativeForkSystemServer(uid, gid, gids, runtimeFlags,
rlimits, permittedCapabilities, effectiveCapabilities);
......
return pid;
}
調用nativeForkSystemServer
fork出子進程,nativeForkSystemServer
是本地方法,在前面已經通過startReg
方法中的register_com_android_internal_os_Zygote
將nativeForkSystemServer
方法映射到com_android_internal_os_Zygote_nativeForkSystemServer
方法上,有興趣的同學可以深入瞭解一下。
fork出子進程之後,子進程就開始調用handleSystemServerProcess()
方法
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
......
//從環境變量SYSTEMSERVERCLASSPATH獲取到SystemServer類文件相應jar包的路徑
final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
if (systemServerClasspath != null) {
//對相應的jar包做dex優化處理
performSystemServerDexOpt(systemServerClasspath);
......
}
......
ClassLoader cl = null;
if (systemServerClasspath != null) {
//創建類加載器classloader
cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
Thread.currentThread().setContextClassLoader(cl);
}
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}
先從SYSTEMSERVERCLASSPATH
環境中獲取到SystemServer的classpath,然後使用performSystemServerDexOpt
對classpath對應的jar包做dex優化處理。然後創建對應的classloader,後續用來加載SystemServer類,ZygoteInit.zygoteInit()
繼續往下執行:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
......
//將標準輸出流和標準錯誤流重定向到Android log中
RuntimeInit.redirectLogStreams();
......
//本地方法,startReg映射,主要是開啓ProcessState線程池,用來進行binder通信
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
redirectLogStreams
會將標準輸入,錯誤流重定位到Android log中,nativeZygoteInit
JNI函數(startReg映射)會開啓ProcessState線程池,用來進行binder通信。
繼續往下執行RuntimeInit.applicationInit()
:
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
protected static Runnable applicationInit(int targetSdkVersion, String[] argv,ClassLoader classLoader) {
......
// Remaining arguments are passed to the start class's static main
return findStaticMain(args.startClass, args.startArgs, classLoader);
}
繼續往下執行:
沒有翻譯的英文註釋也值得一看哦
/**
* Invokes a static "main(argv[]) method on class "className".
* Converts various failing exceptions into RuntimeExceptions, with
* the assumption that they will then cause the VM instance to exit.
*
* @param className Fully-qualified class name
* @param argv Argument vector for main()
* @param classLoader the classLoader to load {@className} with
*/
protected static Runnable findStaticMain(String className, String[] argv,ClassLoader classLoader) {
Class<?> cl;
......
//獲取到SystemServer的類類型
cl = Class.forName(className, true, classLoader);
......
Method m;
try {
//獲取到main方法的方法id
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
......
} catch (SecurityException ex) {
......
}
//這個就是③中forkSystemServer的返回值r
return new MethodAndArgsCaller(m, argv);
}
findStaicMain
獲取到SystemServer的類類型,並且獲取到SystemServer中的main方法的方法id。然後new MethodAndArgsCaller(m,argv)
就是③中forkSystemServer的返回值r
,讓我們看看r.run
做了一些什麼。
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
static class MethodAndArgsCaller implements Runnable {
/** method to call */
private final Method mMethod;
/** argument array */
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run() {
try {
//通過反射調用mMethod靜態方法
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
......
} catch (InvocationTargetException ex) {
......
}
}
}
由上可知,就是通過反射執行SystemServer類的main方法。衆所周知,system_server進程註冊和運行着AMS、PMS、PKMS等核心系統服務,因爲這不是本文講述的重點,所以有興趣的同學可以繼續深入瞭解一波~
④: zygoteServer.runSelectLoop()
這輪詢會在zygote進程中無限循環,而fork出的子進程(Android應用進程)會退出並繼續往下執行
frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
//開啓zygote進程輪詢監聽。接收新的socket連接(會創建新的ZygoteConnection)
//並且從這些鏈接中中讀取命令,並且執行
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;
}
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) {//如果是新的socket鏈接請求(建立新連接)
//新建ZygoteConnection鏈接
ZygoteConnection newPeer = acceptCommandPeer(abiList);
//添加到鏈接數組中
peers.add(newPeer);
//添加到文件描述符數組中
fds.add(newPeer.getFileDesciptor());
} else {//如果是之前已經建立的socket鏈接(在已有連接上)
try {
//獲取對應的ZygoteConnection
ZygoteConnection connection = peers.get(i);
//會執行ZygoteConnection發送過來的命令
final Runnable command = connection.processOneCommand(this);
if (mIsForkChild) {//子進程走這兒
......
//退出,command就是④中的caller
return command;
} else {//父進程走這兒,上面是while無限循環,zygote進程永遠不會退出
......
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(i);
fds.remove(i);
}
}
} catch (Exception e) {
......
} finally {
mIsForkChild = false;
}
}
}
}
}
上面的流程概括來說,就是會輪詢/dev/socket/zygote的socket,如果有新的鏈接,就新建ZygoteConnection,並將對應的socket fd添加到fds(輪詢數組中),繼續輪詢,如果是新的鏈接,就重複上面的操作,如果是已經建立的鏈接,就執行該鏈接上讀取到的command,也就是connection.processOneCommand()
方法。
Android P之前
processOneCommand
的方法名是runOnce
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
Runnable processOneCommand(ZygoteServer zygoteServer) {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
//讀取命令
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
......
}
......
parsedArgs = new Arguments(args);
......
//fork子進程
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) {
// 子進程中(應用進程中)
zygoteServer.setForkChild();
......
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.startChildZygote);
} else {
//父進程中(zygote)
......
return null;
}
} finally {
......
}
}
從當前鏈接socket中讀取啓動命令。如果讀取成功,zygote將會fork出子進程,並且返回可以調用啓動類的main方法的runnable(也就是④中的caller
)
如果是AMS請求啓動應用進程,啓動類就是
ActivityThread.java
,caller.run()
就會反射調用ActivityThread的main
方法。
zygoteServer.setForkChild()
將mIsForkChild
全局變量設爲true。
我們接下來分析handleChildProc()
方法
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
private Runnable handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,FileDescriptor pipeFd, boolean isZygote) {
//關閉ZygoteConnection中的socket鏈接
closeSocket();
......
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}
......
if (!isZygote) {
return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs,null /* classLoader */);
} else {
......
}
}
從ZygoteInit.zygoteInit()
開始就和③中分析的代碼一模一樣了,這裏就不重複分析了,③中返回的是可以調用SystemServer的main方法的Runnable,而④中返回的是可以調用ActivityThread的main方法的Runnable。
自此,ZygoteInit也已經分析完畢。
總結
上面我們提到Zygote進程是第一個java進程,但整篇分析下來,java進程其實也是運行在c++進程之上的,只不過是java虛擬機屏蔽了這一切。zygote進程的啓動,是從c++世界一步一步過渡到java世界,每個世界做了自己的準備工作。
c++世界(app_main.cpp入口):
- 動態加載虛擬機動態庫,啓動java虛擬機
- 註冊JNI本地函數,減輕虛擬機負擔
- 裝載ZygoteInit到java虛擬機,正式進入java世界
java世界(ZygoteInit.java入口):
- 綁定套接字,用來接收新Android應用程序運行請求
- 預加載Android資源,提高應用進程啓動速度
- 啓動並運行SystemServer(運行AMS、PMS等核心服務)
- 處理新Android應用程序運行請求
zygote進程啓動其實沒有特別難的難點,主要是繁瑣,源碼分析的過程是枯燥無味的,只有靜下心來,纔能有所收穫。
本文忽略了很多細節,主要是介紹大致的流程,如果有錯誤的地方,還請大家批評指出~ 覺得寫的不錯也請點個贊~
參考資料:
《Android框架揭祕》
Android4.4的zygote進程
Linux寫時拷貝技術(copy-on-write)