Android zygote 程序啟動分析
文章目錄
- Android zygote 程序啟動分析
- 前言
- 概述
- zygote 程序啟動
- zygote 程序入口
-
- AppRuntim.start
- AppRuntime.startVm
- AppRuntime.startReg
- ZygoteInit.main
-
- ZygoteInit.registerZygoteSocket
- ZygoteInit.preload
- ZygoteInit.startSystemServer
- ZygoteInit.runSelectLoop
- 整體流程圖
- 參考
前言
zygote 程序是 Android 系統中第一個擁有 Java 運作環境的程序,它由使用者空間 1 号程序 init 程序通過解析 init.rc 檔案建立,從 init 程序 fork 而來。從 zygote(受精卵)這個富含生物意義的名字可以知道,它是一個孵化器。Android 系統中所有運作在 Java 虛拟機中的系統服務以及應用均由 zygote 程序孵化而來。
了解 zygote 程序的啟動過程以及所做的工作,将為了解 Java 層系統服務以及所有應用的程序啟動流程打下基礎。
概述
zygote 通過克隆(fork)的方式建立子程序,fork 出來的子程序将繼承父程序的所有資源,基于這個特性,zygote 程序在啟動過程将建立 Java ART 虛拟機,預加載一個 Java 程序需要的所有系統資源,之後子程序被建立後,就可以直接使用這些資源運作了。
自 Android 5.0 系統開始,zygote 不再是一個程序,而是兩個程序,一個是 32 位 zygote,負責孵化 32 位程序(為了相容使用了 armeabi 和 armeabi-v7a 等 32 位架構的本地動态庫的應用),另一個是 64 位 zygote 程序,負責孵化 64 位應用程序(可加載 arm64-v8a 等 64 位架構本地庫)。
zygote 程序主要做了如下工作:
- 建立虛拟機,加載系統 Java 類以及注冊系統類所依賴的 JNI 方法;
- 預加載應用程式程序所需的 drawable 和 color 資源,準備 WebView 和 OpenGL;
- 建立 socket 服務端,以便接收和處理建立應用程序的請求;
- 啟動 system_server 服務程序,用于承載整個 framework 層運作的系統服務;
- 待命以随即處理到來的任務請求。
參考相關資料,對 Android 6.0.1 系統中 zygote 程序啟動關鍵流程進行分析。
zygote 程序啟動
zygote 程序由 init 解析 init.rc 檔案啟動,首先看一下啟動 zygote 的 rc 檔案内容:
32 位 zygote 啟動内容在 init.zygote32.rc 檔案中,64 位 zygote 啟動内容在 init.zygote64.rc 中:
提示:自 Android 9.0 系統開始,兩個 zygote 啟動配置放在一個檔案中:init.zygote64_32.rc。
# init.zygote32.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
writepid /dev/cpuset/foreground/tasks
# init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
writepid /dev/cpuset/foreground/tasks
兩者的唯一差別隻在于可執行檔案的不同,
/system/bin/app_process
和
/system/bin/app_process64
。
zygote 将在如下情況下重新開機:
- servicemanager 程序死亡(啟動配置中包含
);onrestart restart zygote
- surfaceflinger 程序死亡(啟動配置中包含
);onrestart restart zygote
- Zygote 死亡(啟動配置中為非 oneshot);
- system_server 程序死亡;
zygote 程序入口
zygote 可執行檔案
app_process
的實作代碼在
frameworks/base/cmds/app_process/app_main.cpp
中,入口為
main
函數:
// app_main.cpp
// ...
#if defined(__LP64__)
// 如果為 64 位程序,則程序名為 "zygote64",否則為 "zygote"
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
static const char ZYGOTE_NICE_NAME[] = "zygote64";
#else
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
static const char ZYGOTE_NICE_NAME[] = "zygote";
#endif
int main(int argc, char* const argv[])
{
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
// 舊版核心不識别 PR_SET_NO_NEW_PRIVS,将傳回 EINVAL,避免在舊版核心上死掉
if (errno != EINVAL) {
LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
return 12;
}
}
// argv[0] = "/system/bin/app_process"
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// 跳過 argv[0] 參數
argc--;
argv++;
// 直到遇到 '-' 或第一個非 '-' 的參數為止的所有内容都将提供給虛拟機作為 options。
//
// --zygote: 啟動到 zygote 模式
// --start-system-server:啟動 system server
// --application: 以應用程式模式啟動 (獨立啟動, 非 zygote)
// --nice-name: 給程序起一個好名字
//
// 對于非 zygote 啟動,這些參數後面将是主類名,所有其餘的參數都傳遞給此類的 main 方法;
// 對于 zygote 啟動,所有剩餘的參數都傳遞給 zygote 的 main 方法。
int i;
for (i = 0; i < argc; i++) {
if (argv[i][0] != '-') {
break;
}
if (argv[i][1] == '-' && argv[i][2] == 0) {
++i;
break;
}
runtime.addOption(strdup(argv[i]));
}
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
++i;
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;
}
}
Vector<String8> args;
if (!className.isEmpty()) {
// 沒有處于 zygote 模式
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);
} else {
// className 為空,處于 zygote 模式
// 建立 /data/dalvik-cache/ 目錄
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);
// 擷取支援的 abi 清單
args.add(abiFlag);
// 在 zygote 模式下,将所有剩餘參數傳遞給 zygote 的 main() 方法。
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
if (!niceName.isEmpty()) {
// 設定程序名字
runtime.setArgv0(niceName.string());
set_process_name(niceName.string());
}
if (zygote) {
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.");
return 10;
}
}
AppRuntime.main
函數做了如下工作:
- 建立了
對象,傳入虛拟機所需的選項;AppRuntime
- 解析 init.rc 檔案的
啟動參數;zygote
- 調用
函數,根據啟動 zygote 還是指令行(AppRuntime.start
),進入className
或者ZygoteInit
參數分支。RuntimeInit
提示:
app_process
可使用指令行調用,啟動一個 Java 類,并調用
main
方法,此時有
className
參數,處于非 zygote 模式。
格式:
app_process [可選參數] 指令所在路徑 啟動的類名 [可選參數]
示例:
app_process -Djava.class.path=Hello.dex /data/local/ com.example.Hello
AppRuntim.start
下面進入
AppRuntime
的
start
函數中,以
ZygoteInit
參數分支為路徑進行分析:
// AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
ALOGD(">>>>>> START %s uid %d <<<<<<\n",
className != NULL ? className : "(unknown)", getuid());
static const String8 startSystemServer("start-system-server");
for (size_t i = 0; i < options.size(); ++i) {
if (options[i] == startSystemServer) {
const int LOG_BOOT_PROGRESS_START = 3000;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
}
const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
if (!hasDir("/system")) {
LOG_FATAL("No root directory specified, and /android does not exist.");
return;
}
setenv("ANDROID_ROOT", rootDir, 1);
}
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
// 建立虛拟機
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
// 注冊系統類 JNI 方法
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
// Java: strArray = new String[options.size() + 1];
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
// Java: strArray[0] = "com.android.internal.os.ZygoteInit";
env->SetObjectArrayElement(strArray, 0, classNameStr);
// 将相關參數收集至 options 中,下面會傳遞給 ZygoteInit
// --start-system-server, --abi-list=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);
}
// 轉換為 JNI 格式類名:com/android/internal/os/ZygoteInit
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
} else {
// 調用 ZygoteInit.main();
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
}
free(slashClassName);
ALOGD("Shutting down VM\n");
// 關閉 Java 虛拟機
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");
}
上面的代碼也比較清晰,工作如下:
-
函數建立 ART 虛拟機;startVm
-
函數注冊系統 JNI 方法;startReg
- 收集
參數,調用并傳遞給options
。ZygoteInit.main()
下面針對每個方法具體分析。
AppRuntime.startVm
// AndroidRuntime.cpp
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
JavaVMInitArgs initArgs;
// ...
bool checkJni = false;
property_get("dalvik.vm.checkjni", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
checkJni = true;
} else if (strcmp(propBuf, "false") != 0) {
property_get("ro.kernel.android.checkjni", propBuf, "");
if (propBuf[0] == '1') {
checkJni = true;
}
}
ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
if (checkJni) {
/* 擴充的 JNI 檢查 */
addOption("-Xcheck:jni");
/* 啟用 -Xcheck:jni,它提供了 JNI 函數調用跟蹤 */
//addOption("-verbose:jni");
}
parseRuntimeOption("dalvik.vm.zygote.max-boot-retry", cachePruneBuf,
"-Xzygote-max-boot-retry=");
// ...
property_get("dalvik.vm.execution-mode", propBuf, "");
if (strcmp(propBuf, "int:portable") == 0) {
executionMode = kEMIntPortable;
} else if (strcmp(propBuf, "int:fast") == 0) {
executionMode = kEMIntFast;
} else if (strcmp(propBuf, "int:jit") == 0) {
executionMode = kEMJitCompiler;
}
// ...
// 預設的起始和最大堆大小,通常根據具體廠商硬體進行合适的配置
parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");
parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");
parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
parseRuntimeOption("dalvik.vm.heaptargetutilization", heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization=");
// ...
// 確定有可預加載的類檔案,preloaded-classes 中存放了所有需要被預加載的系統 Java 類
if (!hasFile("/system/etc/preloaded-classes")) {
ALOGE("Missing preloaded-classes file, /system/etc/preloaded-classes not found: %s\n", strerror(errno));
return -1;
}
// ... 省略數百行 addOption 相關語句
// 解析 fingerprint 資訊并提供給運作時,ANR dump 資訊将包含 fingerprint 資訊且能夠解析
parseRuntimeOption("ro.build.fingerprint", fingerprintBuf, "-Xfingerprint:");
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();
initArgs.nOptions = mOptions.size();
initArgs.ignoreUnrecognized = JNI_FALSE;
// 初始化虛拟機。JavaVM* 是基于程序的,而 JNIEnv* 是基于線程的,
// 如果調用成功,表示虛拟機已就緒,可以開始 JNI 調用了。
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
return -1;
}
return 0;
}
上述代碼主要是為虛拟機初始化添加運作選項,最後調用
JNI_CreateJavaVM
建立虛拟機,下面就進入了虛拟機流程了,需要了解虛拟機時再探究其源碼。
下面回到上面
AppRuntime.start
函數,看
startReg
的實作。
AppRuntime.startReg
// AndroidRuntime.cpp
#define NELEM(x) (sizeof(x)/sizeof(*(x)))
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
// 設定 Thread 建立函數,用于支援 Android Native 層線程封裝
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
ALOGV("--- registering native functions ---\n");
env->PushLocalFrame(200);
// 注冊 JNI 方法
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
//createJavaThread("fubar", quickTest, (void*) "hello");
return 0;
}
// AndroidRuntim.cpp
#define REG_JNI(name) { name, #name }
struct RegJNIRec {
int (*mProc)(JNIEnv*);
const char* mName;
};
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
REG_JNI(register_android_content_AssetManager),
REG_JNI(register_android_content_StringBlock),
// ... 省略數百行
REG_JNI(register_android_animation_PropertyValuesHolder),
REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
};
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
for (size_t i = 0; i < count; i++) {
if (array[i].mProc(env) < 0) {
#ifndef NDEBUG
ALOGD("----------!!! %s failed to load\n", array[i].mName);
#endif
return -1;
}
}
return 0;
startReg
函數主要是注冊系統類的 JNI 方法,使用
register_jni_procs
進行循環調用注冊方法,每個
mProc
都指向
gRegJNI
數組裡存放的結構體中的
mProc
函數指針,例如
register_com_android_internal_os_RuntimeInit
,檢視一下實作:
static JNINativeMethod gMethods[] = {
{ "nativeFinishInit", "()V",
(void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
{ "nativeZygoteInit", "()V",
(void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },
{ "nativeSetExitWithoutCleanup", "(Z)V",
(void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
};
int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
{
return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
gMethods, NELEM(gMethods));
}
startReg
之後下面就是通過
env->CallStaticVoidMethod
啟動
Zygoteinit.main
進入 Java 層了。
ZygoteInit.main
// ZygoteInit.java
public static void main(String argv[]) {
try {
RuntimeInit.enableDdms();
SamplingProfilerIntegration.start();
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}
// 注冊 socket 服務端
registerZygoteSocket(socketName);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
// 預加載資源
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
SamplingProfilerIntegration.writeZygoteSnapshot();
// 在啟動後執行初始 gc
gcAndFinalize();
Trace.setTracingEnabled(false);
if (startSystemServer) {
// 啟動 system_server
startSystemServer(abiList, socketName);
}
Log.i(TAG, "Accepting command socket connections");
// 啟動 socket 循環
runSelectLoop(abiList);
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
上述代碼做了如下工作:
- 使用
注冊 socket 服務端,為能夠接收建立子程序的請求提供支援;registerZygoteSocket
- 使用
預加載應用程序所需資源;preload()
- 啟動
服務程序;system_server
- 啟動 socket 循環,等待外部請求,随時響應處理。
下面進入函數具體分析。
ZygoteInit.registerZygoteSocket
// ZygoteInit.java
private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
// ...
private static void registerZygoteSocket(String socketName) {
if (sServerSocket == 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);
// 建立了本地 socket 服務端
sServerSocket = new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
主是要建立了本地服務端 socket 對象,命名為
ANDROID_SOCKET_zygote
。
ZygoteInit.preload
// ZygoteInit.java
static void preload() {
Log.d(TAG, "begin preload");
// 預加載 /system/etc/preloaded-classes 檔案中的系統類
preloadClasses();
// 預加載 drawable 和 color 資源
preloadResources();
// 預加載 OpenGL
preloadOpenGL();
// 預加載共享庫
preloadSharedLibraries();
// 預加載文本資源
preloadTextResources();
// WebView 相關初始化
WebViewFactory.prepareWebViewInZygote();
Log.d(TAG, "end preload");
}
private static void preloadSharedLibraries() {
Log.i(TAG, "Preloading shared libraries...");
System.loadLibrary("android");
System.loadLibrary("compiler_rt");
System.loadLibrary("jnigraphics");
}
private static void preloadOpenGL() {
if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false)) {
EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
}
}
private static void preloadTextResources() {
Hyphenator.init();
}
private static void preloadClasses() {
final VMRuntime runtime = VMRuntime.getRuntime();
InputStream is;
try {
is = new FileInputStream(PRELOADED_CLASSES);
} catch (FileNotFoundException e) {
Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
return;
}
// ...
try {
BufferedReader br = new BufferedReader(new InputStreamReader(is), 256);
int count = 0;
String line;
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.startsWith("#") || line.equals("")) {
continue;
}
try {
// 預加載類
Class.forName(line, true, null);
count++;
} catch (ClassNotFoundException e) {
Log.w(TAG, "Class not found for preloading: " + line);
} catch (UnsatisfiedLinkError e) {
Log.w(TAG, "Problem preloading " + line + ": " + e);
} catch (Throwable t) {
// ...
throw new RuntimeException(t);
}
}
Log.i(TAG, "...preloaded " + count + " classes in "
+ (SystemClock.uptimeMillis()-startTime) + "ms.");
} catch (IOException e) {
Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
} finally {
IoUtils.closeQuietly(is);
runtime.setTargetHeapUtilization(defaultUtilization);
// 使用已加載類填充 DexCaches
runtime.preloadDexCaches();
// ...
}
}
private static void preloadResources() {
final VMRuntime runtime = VMRuntime.getRuntime();
try {
mResources = Resources.getSystem();
mResources.startPreloading();
if (PRELOAD_RESOURCES) {
Log.i(TAG, "Preloading resources...");
long startTime = SystemClock.uptimeMillis();
TypedArray ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_drawables);
int N = preloadDrawables(runtime, ar);
ar.recycle();
Log.i(TAG, "...preloaded " + N + " resources in "
+ (SystemClock.uptimeMillis()-startTime) + "ms.");
startTime = SystemClock.uptimeMillis();
ar = mResources.obtainTypedArray(
com.android.internal.R.array.preloaded_color_state_lists);
N = preloadColorStateLists(runtime, ar);
ar.recycle();
Log.i(TAG, "...preloaded " + N + " resources in "
+ (SystemClock.uptimeMillis()-startTime) + "ms.");
}
mResources.finishPreloading();
} catch (RuntimeException e) {
Log.w(TAG, "Failure preloading resources", e);
}
}
private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
int N = ar.length();
for (int i=0; i<N; i++) {
int id = ar.getResourceId(i, 0);
if (id != 0) {
if (mResources.getColorStateList(id, null) == null) {
throw new IllegalArgumentException(
"Unable to find preloaded color resource #0x"
+ Integer.toHexString(id)
+ " (" + ar.getString(i) + ")");
}
}
}
return N;
}
private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
int N = ar.length();
for (int i=0; i<N; i++) {
int id = ar.getResourceId(i, 0);
if (id != 0) {
if (mResources.getDrawable(id, null) == null) {
throw new IllegalArgumentException(
"Unable to find preloaded drawable resource #0x"
+ Integer.toHexString(id)
+ " (" + ar.getString(i) + ")");
}
}
}
return N;
}
上面幾乎把加載資源的所有代碼都列了出來。
預加載這些資源的目的是為了将資源提前放置在記憶體中,當建立子程序的時候,可以直接使用這些資源,而不必每次都重新加載一遍。
ZygoteInit.startSystemServer
// ZygoteInit.java
private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
long capabilities = posixCapabilitiesAsBits(
OsConstants.CAP_BLOCK_SUSPEND,
OsConstants.CAP_KILL,
OsConstants.CAP_NET_ADMIN,
OsConstants.CAP_NET_BIND_SERVICE,
OsConstants.CAP_NET_BROADCAST,
OsConstants.CAP_NET_RAW,
OsConstants.CAP_SYS_MODULE,
OsConstants.CAP_SYS_NICE,
OsConstants.CAP_SYS_RESOURCE,
OsConstants.CAP_SYS_TIME,
OsConstants.CAP_SYS_TTY_CONFIG
);
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3006,3007",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
// fork 出 system_server 程序并使用相關參數設定程序資訊
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)) {
// 等待另一個架構的 zygote 程序啟動
waitForSecondaryZygote(socketName);
}
// 處理 system_server 剩餘工作
handleSystemServerProcess(parsedArgs);
}
return true;
}
上面的代碼使用
Zygote.forkSystemServer
fork 出了子程序,然後将相關參數設定給子程序,例如其中的
uid=1000
和
gid=1000
,下面就進入
handleSystemServerProcess
方法,開始
system_server
的工作。
ZygoteInit.runSelectLoop
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
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 {
// 監聽 socket 連接配接,阻塞并等待描述符上的可讀事件發生
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) {
// i = 0 表明還未添加收到的 socket 請求對象(sServerSocket.accept())
// 建立連接配接對象:new ZygoteConnection(sServerSocket.accept(), abiList);
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
// 添加到 fds 清單中待處理(下次循環将進行 Os.poll 等待描述符可讀)
fds.add(newPeer.getFileDesciptor());
} else {
// i > 0 表示 socket 請求經過 Os.poll 表示已經可讀,那麼對請求進行處理
boolean done = peers.get(i).runOnce();
if (done) {
// 處理完則移除
peers.remove(i);
fds.remove(i);
}
}
}
}
}
runSelectLoop
進入了無限循環,等待并對服務端 socket 接收到的請求進行處理,使用
runOnce
進行請求處理:
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
// 解析 socket 用戶端發送的指令清單
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
Log.w(TAG, "IOException on command socket " + ex.getMessage());
closeSocket();
return true;
}
if (args == null) {
closeSocket();
return true;
}
// ...
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();
if (fd != null) {
fdsToClose[0] = fd.getInt$();
}
fd = ZygoteInit.getServerSocketFileDescriptor();
if (fd != null) {
fdsToClose[1] = fd.getInt$();
}
fd = null;
// 建立子程序
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) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} catch (IllegalArgumentException ex) {
logAndPrintError(newStderr, "Invalid zygote arguments", ex);
} catch (ZygoteSecurityException ex) {
logAndPrintError(newStderr,
"Zygote security policy prevents request: ", ex);
}
try {
if (pid == 0) {
// 進入子程序
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);
}
}
handleChildProc
處理子程序:
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
closeSocket();
// 關閉複制出來的服務端 socket
ZygoteInit.closeServerSocket();
if (descriptors != null) {
try {
Os.dup2(descriptors[0], STDIN_FILENO);
Os.dup2(descriptors[1], STDOUT_FILENO);
Os.dup2(descriptors[2], STDERR_FILENO);
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
newStderr = System.err;
} catch (ErrnoException ex) {
Log.e(TAG, "Error reopening stdio", ex);
}
}
if (parsedArgs.niceName != null) {
// 設定程序名字
Process.setArgV0(parsedArgs.niceName);
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
} else {
// 會輾轉調用到 ActivityThread.main 進入應用程式主流程
// 内部會抛出一個 ZygoteInit.MethodAndArgsCaller 異常(為了清空調用棧),
// 進而傳回到上面 ZygoteInit 的 main 方法的 catch 語句塊中執行
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
當子程序 fork 出來後,處理子程序,關閉 socket 資源,之後進入應用程式程序主流程。
整體流程圖
使用流程圖表示 zygote 整個工作過程:

參考
- http://gityuan.com/2016/02/13/android-zygote/