Android系統啟動-zygote篇
</header>
- 一、啟動調用棧
- 二、App_main
- 三、AndroidRuntime
- 3.1 虛擬機創建startVm
- 3.2 JNI函數注冊startReg
- 四 ZygoteInit
- 4.1 registerZygoteSocket
- 4.2 preload
- 4.3 startSystemServer
- 4.4 runSelectLoop
- 五、總結
基于Android 6.0的源碼剖析, 分析Android啟動過程的Zygote進程
/frameworks/base/cmds/app_process/App_main.cpp (內含AppRuntime類)
/frameworks/base/core/jni/AndroidRuntime.cpp
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
/frameworks/base/core/java/com/android/internal/os/Zygote.java
/frameworks/base/core/java/android/net/LocalServerSocket.java
一、啟動調用棧
Zygote啟動函數調用類的棧關系:
App_main.main
AndroidRuntime.start
startVm
startReg
ZygoteInit.main
registerZygoteSocket
preload
startSystemServer
runSelectLoop
二、App_main
Zygote是由init進程通過解析init.zygote.rc文件而創建的,zygote所對應的可執行程序app_process,所對應的源文件是App_main.cpp,進程名為zygote。
傳到main()的參數為 -Xzygote /system/bin --zygote --start-system-server
[–>App_main.cpp]
int main(int argc, char* const argv[])
{
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
//忽略第一個參數
argc--;
argv++;
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; //對于64位系統nice_name為zygote64,32位系統為zygote
} 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()) {
// 運行application或tool程序
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);
} else {
//進入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) {
return 11;
}
String8 abiFlag("--abi-list=");
abiFlag.append(prop);
args.add(abiFlag);
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
//設置進程名
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string());
set_process_name(niceName.string());
}
if (zygote) {
// 啟動AppRuntime 【見小節3】
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
//沒有指定類名或zygote,參數錯誤
return 10;
}
}
采用cmd命令,是通過fork進程來執行相應的類:
app_process [可選參數] 命令所在路徑 啟動的類名 [可選參數]
三、AndroidRuntime
AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
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;
}
}
const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
if (!hasDir("/system")) {
return;
}
setenv("ANDROID_ROOT", rootDir, 1);
}
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
// 虛擬機創建【見小節3.1】
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
// JNI方法注冊【見小節3.2】
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
//等價 strArray= new String[options.size() + 1];
stringClass = env->FindClass("java/lang/String");
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
//等價 strArray[0] = "com.android.internal.os.ZygoteInit"
classNameStr = env->NewStringUTF(className);
env->SetObjectArrayElement(strArray, 0, classNameStr);
//等價 strArray[1] = "start-system-server";
// strArray[2] = "--abi-list=xxx";其中xxx為系統響應的cpu架構類型,比如arm64-v8a.
for (size_t i = 0; i < options.size(); ++i) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}
//將"com.android.internal.os.ZygoteInit"轉換為"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()方法【見小節4.0】
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
}
free(slashClassName); //釋放相應對象的內存空間
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");
}
3.1 虛擬機創建startVm
[–>AndroidRuntime.cpp]
創建Java虛擬機方法的主要篇幅是關于虛擬機參數的設置,下面只列舉部分在調試優化過程中常用參數。
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
// JNI檢測功能,用于native層調用jni函數時進行常規檢測,比較弱字符串格式是否符合要求,資源是否正確釋放。該功能一般用于早期系統調試或手機Eng版,對于User版往往不會開啟,引用該功能比較消耗系統CPU資源,降低系統性能。
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;
}
}
if (checkJni) {
addOption("-Xcheck:jni");
}
//虛擬機產生的trace文件,主要用于分析系統問題,路徑默認為/data/anr/traces.txt
parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");
//對于不同的軟硬件環境,這些參數往往需要調整、優化,從而使系統達到最佳性能
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文件內容是由WritePreloadedClassFile.java生成的,在ZygoteInit類中會預加載工作將其中的classes提前加載到內存,以提高系統性能
if (!hasFile("/system/etc/preloaded-classes")) {
return -1;
}
//創建虛擬機
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
return -1;
}
}
3.2 JNI函數注冊startReg
[–>AndroidRuntime.cpp]
int AndroidRuntime::startReg(JNIEnv* env)
{
//設置線程創建方法為javaCreateThreadEtc
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
env->PushLocalFrame(200);
//進程NI方法的注冊
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
return 0;
}
register_jni_procs
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) { 【見下文】
return -1;
}
}
return 0;
}
gRegJNI
gRegJNI是一個數組,有100多個成員
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_android_os_Binder),
...
};
REG_JNI
#define REG_JNI(name) { name }
struct RegJNIRec {
int (*mProc)(JNIEnv*);
};
調用mProc,那么gRegJNI數組的其中之一REG_JNI(register_com_android_internal_os_RuntimeInit),等價于調用下面方法:
int register_com_android_internal_os_RuntimeInit(JNIEnv* env)
{
return jniRegisterNativeMethods(env, "com/android/internal/os/RuntimeInit",
gMethods, NELEM(gMethods));
}
//gMethods:java層方法名與jni層的方法的一一映射關系
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 },
};
四 ZygoteInit
[–>ZygoteInit.java]
public static void main(String argv[]) {
try {
RuntimeInit.enableDdms(); //開啟DDMS功能
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.");
}
registerZygoteSocket(socketName); //為Zygote注冊socket【見小節4.1】
preload(); // 預加載類和資源【見小節4.2】
SamplingProfilerIntegration.writeZygoteSnapshot();
gcAndFinalize(); //GC操作
if (startSystemServer) {
startSystemServer(abiList, socketName);//啟動system_server【見小節4.3】
}
runSelectLoop(abiList); //進入循環模式【見小節4.4】
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run(); //啟動system_server中會講到。
} catch (RuntimeException ex) {
closeServerSocket();
throw ex;
}
}
在異常捕獲后調用的方法caller.run(),會在后續的system_server文章會講到。
4.1 registerZygoteSocket
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); //設置文件描述符
sServerSocket = new LocalServerSocket(fd); //創建Socket的本地服務端
} catch (IOException ex) {
throw new RuntimeException("Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
4.2 preload
執行Zygote進程的初始化
static void preload() {
//預加載位于/system/etc/preloaded-classes文件中的類
preloadClasses();
//預加載資源,包含drawable和color資源
preloadResources();
//預加載OpenGL
preloadOpenGL();
//通過System.loadLibrary()方法,
//預加載"android","compiler_rt","jnigraphics"這3個共享庫
preloadSharedLibraries();
//預加載 文本連接符資源
preloadTextResources();
//僅用于zygote進程,用于內存共享的進程
WebViewFactory.prepareWebViewInZygote();
}
對于類加載,采用反射機制Class.forName()方法來加載。對于資源加載,主要是 com.android.internal.R.array.preloaded_drawables和com.android.internal.R.array.preloaded_color_state_lists,在應用程序中以com.android.internal.R.xxx開頭的資源,便是此時由Zygote加載到內存的。
4.3 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);
}
//進入子進程system_server
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
// 完成system_server進程剩余的工作
handleSystemServerProcess(parsedArgs);
}
return true;
}
準備參數并fork新進程,從上面可以看出system server進程參數信息為uid=1000,gid=1000,進程名為sytem_server,從zygote進程fork新進程后,需要關閉zygote原有的socket。另外,對于有兩個zygote進程情況,需等待第2個zygote創建完成。更多詳情見Android系統啟動-systemServer上篇。
4.4 runSelectLoop
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
//sServerSocket是socket通信中的服務端,即zygote進程
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 {
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
//采用I/O多路復用機制,當客戶端發出連接請求或者數據處理請求時,跳過continue,執行后面的代碼
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
//創建客戶端連接
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
//處理客戶端數據事務
boolean done = peers.get(i).runOnce();
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}
Zygote采用高效的I/O多路復用機制,保證在沒有客戶端連接請求或數據處理時休眠,否則響應客戶端的請求。
五、總結
Zygote啟動過程的調用流程圖:
- 解析init.zygote.rc中的參數,創建AppRuntime并調用AppRuntime.start()方法;
- 調用AndroidRuntime的startVM()方法創建虛擬機,再調用startReg()注冊JNI函數;
- 通過JNI方式調用ZygoteInit.main(),第一次進入Java世界;
- registerZygoteSocket()建立socket通道,zygote作為通信的服務端,用于響應客戶端請求;
- preload()預加載通用類、drawable和color資源、openGL以及共享庫以及WebView,用于提高ap啟動效率;
- zygote完畢大部分工作,接下來再通過startSystemServer(),fork得力幫手system_server進程,也是上層framework的運行載體。
- zygote功成身退,調用runSelectLoop(),隨時待命,當接收到請求創建新進程請求時立即喚醒并執行相應工作。