android6.0原始碼分析之Zygote程序分析
在android6.0原始碼分析之Runtime的初始化一文中,對Zygote程序的初期的Runtime初始化過程進行了分析,在Runtime啟動結束後,會對Zygote程序進行初始化,其它Java程序都需要從Zygote程序來fork,而Zygote的初始化是從ZygoteInit的main函式開始的:
//ZygoteInit.java
public static void main(String argv[]) {
try {
...
//註冊zygote socket
registerZygoteSocket(socketName);
...
//載入資源以及類
preload();
...
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);
//啟動system server程序
if (startSystemServer) {
startSystemServer(abiList, socketName);
}
Log.i(TAG, "Accepting command socket connections" );
//迴圈等待建立程序的socket請求
runSelectLoop(abiList);
//關閉server socket
closeServerSocket();
} catch (MethodAndArgsCaller caller) {//擷取MethodAndArgsCaller異常
//執行新程序的main函式
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception" , ex);
closeServerSocket();
throw ex;
}
}
首先它會對啟動引數進行解析,得到是否需要啟動systemserver,或者得到ABI_LIST_ARG引數和socketName引數等,然後則會呼叫registerZygoteSocket來建立一個LocalServerSocket來與以後需要systemServer建立程序時進行通訊,接著呼叫preload來對VM虛擬機器中的DEX類等資源進行載入,然後會呼叫runSelectLoop來進行迴圈等待,最後會擷取ZygoteInit中丟擲的MethodAndArgsCaller異常,並在異常處理時,呼叫新建程序的main方法實現新程序的啟動。下面將對這四個主要的呼叫分別進行分析。
1、registerZygoteSocket方法分析
//ZygoteInit.java
private static void registerZygoteSocket(String socketName) {
if (sServerSocket == null) {//判斷Zygote socket是否已建立
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);
//建立Zygote socket,它會在runSelectLoop中進行迴圈等待
sServerSocket = new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
由程式碼可知,它建立了一個LocalServerSocket,並且它會在runSelectLoop中阻塞等待socket請求,至於runSelectLoop稍後會進行分析。
2、preload方法分析
//ZygoteInit.java
static void preload() {
Log.d(TAG, "begin preload");
//載入類
preloadClasses();
//載入資源
preloadResources();
//載入OpenGL
preloadOpenGL();
//載入公共庫
preloadSharedLibraries();
//載入文字資源
preloadTextResources();
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
WebViewFactory.prepareWebViewInZygote();
Log.d(TAG, "end preload");
}
由程式碼可知,preload方法主要就是進行類,資源,公共庫以及相關的文字資源的載入,主要分析其中的preloadClasses以及preloadSharedLibraries方法:
//ZygoteInit.java
private static void preloadClasses() {
//獲取虛擬機器執行時
final VMRuntime runtime = VMRuntime.getRuntime();
InputStream is;
try {
//初始化檔案輸入流,路徑為"/system/etc/preloaded-classes"
is = new FileInputStream(PRELOADED_CLASSES);
} catch (FileNotFoundException e) {
return;
}
...
// Alter the target heap utilization. With explicit GCs this
// is not likely to have any effect.
float defaultUtilization = runtime.getTargetHeapUtilization();
runtime.setTargetHeapUtilization(0.8f);
try {
//通過BufferReader來讀取輸入流
BufferedReader br = new BufferedReader(new InputStreamReader(is), 256);
int count = 0;
String line;
//逐行處理
while ((line = br.readLine()) != null) {
// Skip comments and blank lines.
line = line.trim();
if (line.startsWith("#") || line.equals("")) {
continue;
}
try {
...
//載入並顯示地初始化給定的類
Class.forName(line, true, null);
count++;
} catch (ClassNotFoundException e) {
...
}
}
} catch (IOException e) {
Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
} finally {
IoUtils.closeQuietly(is);
// Restore default.
runtime.setTargetHeapUtilization(defaultUtilization);
//將類,域,方法等填充到dex快取中
runtime.preloadDexCaches();
}
}
首先,根據”/system/etc/preloaded-classes”來,逐行解析裡面的類,最後再將預載入的類填充到VM的dex快取中,它會呼叫VMRuntime庫的本地方法preloadDexCaches來填充,此方法的具體實現在VM庫中。
接下來看preloadSharedLibraries方法:
//ZygoteInit.java
private static void preloadSharedLibraries() {
Log.i(TAG, "Preloading shared libraries...");
System.loadLibrary("android");
System.loadLibrary("compiler_rt");
System.loadLibrary("jnigraphics");
}
如程式碼,它主要進行shared庫android,compiler_rt以及jnigraphics的載入。
3、 startSystemServer方法分析
System Server程序是android系統的非常重要的程序,它在Zygote的啟動之後就必須啟動,所以startSystemServer方法也是Zygote初始化中非常重要的呼叫:
//ZygoteInit.java
private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
...
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
//fork一個systemServer程序
pid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids,
parsedArgs.debugFlags,null,parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
//處理子程序
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
//處理system server程序
handleSystemServerProcess(parsedArgs);
}
return true;
}
它首先fork一個systemserver程序,然後再對子程序systemserver進行相關處理,首先來看forkSystemServer方法:
//Zygote.java
public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,int[][] rlimits,
long permittedCapabilities, long effectiveCapabilities) {
VM_HOOKS.preFork();
//呼叫native方法
int pid = nativeForkSystemServer(uid, gid, gids, debugFlags, rlimits, permittedCapabilities,
effectiveCapabilities);
// Enable tracing as soon as we enter the system_server.
if (pid == 0) {
Trace.setTracingEnabled(true);
}
VM_HOOKS.postForkCommon();
return pid;
}
這裡將通過JNI呼叫,進入Native程式碼層,接著分析nativeForkSystemServer方法,它對應的是Native方法是com_android_internal_os_Zygote_nativeForkSystemServer:
//com_android_internal_os_Zygote.cpp
static jint com_android_internal_os_Zygote_nativeForkSystemServer(JNIEnv* env, jclass, uid_t uid,
gid_t gid, jintArray gids,jint debug_flags, jobjectArray rlimits, jlong
permittedCapabilities,jlong effectiveCapabilities) {
//fork 相應程序
pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,debug_flags, rlimits,
permittedCapabilities, effectiveCapabilities,MOUNT_EXTERNAL_DEFAULT, NULL, NULL, true,
NULL,NULL, NULL);
if (pid > 0) {
gSystemServerPid = pid;
int status;
if (waitpid(pid, &status, WNOHANG) == pid) {
//system server程序died,終止執行時,重啟zygote程序
RuntimeAbort(env);
}
}
return pid;
}
它呼叫了ForkAndSpecializeCommon方法來進行程序的建立,最後對建立結果進行了相應的處理,這裡與建立普通程序的區別就是,需要對子程序進行檢查,判斷system server程序是否died,如果died,則會終止runtime,並重啟Zygote程序,接著分析ForkAndSpecializeCommon方法:
//com_android_internal_os_Zygote.cpp
static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
jint debug_flags, jobjectArray javaRlimits,jlong permittedCapabilities, jlong
effectiveCapabilities,jint mount_external,jstring java_se_info, jstring java_se_name,
bool is_system_server, jintArray fdsToClose,jstring instructionSet, jstring dataDir) {
SetSigChldHandler();
//fork一個程序
pid_t pid = fork();
if (pid == 0) {//處理子程序
// The child process.
gMallocLeakZygoteChild = 1;
...
SetGids(env, javaGids);
SetRLimits(env, javaRlimits);
...
rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
...
if (se_info_c_str != NULL) {
//設定執行緒名稱
SetThreadName(se_name_c_str);
}
...
//此處會post一個forkChild的訊息
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
is_system_server ? NULL : instructionSet);
} else if (pid > 0) {
// the parent process
}
return pid;
}
它首先fork一個子程序,然後對子程序進行處理,最後會post一個forkChild的訊息出去,而在ZygoteInit中會對forksystemserver的子程序進行處理,所以,接著看handleSystemServerProcess方法:
//ZygoteInit.java
private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs)
throws ZygoteInit.MethodAndArgsCaller {
...
if (parsedArgs.invokeWith != null) {
String[] args = parsedArgs.remainingArgs;
if (systemServerClasspath != null) {
String[] amendedArgs = new String[args.length + 2];
amendedArgs[0] = "-cp";
amendedArgs[1] = systemServerClasspath;
System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2,
parsedArgs.remainingArgs.length);
}
WrapperInit.execApplication(parsedArgs.invokeWith,parsedArgs.niceName,
parsedArgs.targetSdkVersion,VMRuntime.getCurrentInstructionSet(), null, args);
} else {
ClassLoader cl = null;
if (systemServerClasspath != null) {
//獲取類載入器
cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
Thread.currentThread().setContextClassLoader(cl);
}
//根據引數來啟動System server程序
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
}
}
由程式碼可知,它主要會呼叫RuntimeInit類的zygoteInit方法來對子程序system server進行啟動的處理:
//RuntimeInit.java
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
...
commonInit();
nativeZygoteInit();
applicationInit(targetSdkVersion, argv, classLoader);
}
其中commonInit主要就是進行一些系統屬性的初始化或者重置,這裡重點分析nativeZygoteInit和applicationInit方法。
3.1 nativeZygoteInit方法分析
nativeZygoteInit是Native方法,通過JNI呼叫,它的實現是com_android_internal_os_RuntimeInit_nativeZygoteInit方法:
//AndroidRuntime.cpp
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();
}
由程式碼可知,這裡會回撥App_main.cpp中的onZygoteInit方法:
//App_main.cpp
virtual void onZygoteInit(){
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}
這裡主要就是在程序裡面啟動執行緒池,該執行緒池,是為System server程序建立的,此執行緒池會為Binder提供支援等,這裡不做分析。
3.2 ApplicationInit方法分析
//RuntimeInit.java
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
nativeSetExitWithoutCleanup(true);
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args;
try {
args = new Arguments(argv);
} catch (IllegalArgumentException ex) {
return;
}
//invoke system server的main方法
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
由程式碼可知,它會根據啟動的引數以及類載入器來呼叫InvokeStaticMain方法:
//RuntimeInit.java
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl;
try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {...}
Method m;
try {
//獲取systemserver的main方法,main方法是用來開始systemserver程序的
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {...}
...
//丟擲MethodAndArgsCaller異常,而此異常在ZygoteInit的main方法中會進行撲捉,異常的處理稍後再分析
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}
由程式碼可知,首先,通過Java的反射機制,藉助傳入的引數以及類載入器,從而獲取systemserver程序的main方法,最後再丟擲一個MethodAndArgsCaller的異常,而此異常在ZygoteInit的main方法的最後會進行擷取,具體的異常處理稍後在第四節最後再分析,因為普通程序的建立也是通過丟擲MethodAndArgsCaller的方法來啟動的,至此startsystemserver方法就分析結束了。
4、runSelectLoop方法分析
//ZygoteInit.java
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
//初始化檔案描述符組合ZygoteConnection連線組
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
while (true) {//迴圈等待ZygoteSocket請求並進行相應的處理
...
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
//這裡阻塞等待建立程序的Zygote socket請求
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
//執行ZygoteConnection連線
boolean done = peers.get(i).runOnce();
if (done) {
//處理結束,則將此連線移除
peers.remove(i);
fds.remove(i);
}
}
}
}
}
此方法將會永無休止的進行執行,因為Zygote作為Java域的第一個程序,所有的程序都是由它進行fork的,在android的生命過程中,會不斷有ZygoteConnection請求,所以,看runSelectLoop方法,它首先是呼叫acceptCommandPeer方法來獲取一個ZygoteConnection連線,然後再呼叫ZygoteConnection的runOnce方法來執行連線處理,首先來看acceptCommandPeer方法:
//ZygoteInit.java
private static ZygoteConnection acceptCommandPeer(String abiList) {
try {
//建立ZygoteConnection連線,注意socket的accept阻塞接收請求
return new ZygoteConnection(sServerSocket.accept(), abiList);
} catch (IOException ex) {
throw new RuntimeException("IOException during accept()", ex);
}
}
由代麼可知,這裡是阻塞的,只有在ZygoteInit的main方法中最初註冊的socket有請求時,才會執行,並會根據得到的socket連線來建立一個ZygoteConnection,所以,來看它的建構函式:
// ZygoteConnection.java
ZygoteConnection(LocalSocket socket, String abiList) throws IOException {
mSocket = socket;
this.abiList = abiList;
//獲取socket輸出流
mSocketOutStream = new DataOutputStream(socket.getOutputStream());
//獲取socket輸入流
mSocketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()), 256);
//設定超時
mSocket.setSoTimeout(CONNECTION_TIMEOUT_MILLIS);
try {
peer = mSocket.getPeerCredentials();
} catch (IOException ex) {
throw ex;
}
}
此建構函式會建立socket的stream通道,至此ZygoteConnection就建立好了,接著看它的runOnce方法,socket請求一次,runOnce會執行一次:
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
...
int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;
try {
parsedArgs = new Arguments(args);
if (parsedArgs.abiListQuery) {
return handleAbiListQuery();
}
...
int [] fdsToClose = { -1, -1 };
FileDescriptor fd = mSocket.getFileDescriptor();
...
fd = ZygoteInit.getServerSocketFileDescriptor();
//fork 程序
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,parsedArgs.appDataDir);
} catch (ErrnoException ex) {
...
}
try {
if (pid == 0) {
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
//對子程序做相應處理
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
return true;
} else {
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
//對父程序做相應處理
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
這裡,就是建立普通程序的通道,它的分析類似於startSystemServer方法,它在最後同樣會進入Java層的子程序的處理handleChildProc方法,最後還是會獲取到建立程序的main方法,並且同樣也是會丟擲一個MethodAndArgsCaller的異常。
不管是建立systemServer程序還是建立普通程序,在處理其子程序時,都會獲取建立子程序的main方法,同時最後會丟擲一個MethodAndArgsCaller異常,為什麼要丟擲異常呢,此異常是在ZygoteInit的main函式中呼叫的,而main函式位於堆疊的最頂層,如果不採用拋異常的方式,而是在invokestaticMain方法中直接執行新建程序的main方法,則會浪費之前函式呼叫說佔用的呼叫堆疊。接下來對MethodAndArgsCaller的run方法進行分析:
//ZygoteInit.java
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
...
}
}
其中,mMethod為構造MethodAndArgsCaller時,傳入的方法,即之前startSystemServer或者runSelectLoop函式中獲得的新建程序的main方法,所以run方法的主要作用就是執行此main方法,即進入新建程序。至此,Zygote程序分析結束,它的主要功能有初始化Runtime、fork system server程序以及通過迴圈等待Zygote socket的請求,來處理普通進行的建立。下面將給出時序圖: