Android FrameWork之Zygote啟動示例詳解
1、Zygote介紹
Zygote是一個進程,當(dāng)開機引導(dǎo)內(nèi)核啟動之后,首先用戶空間的第一個進程Init進程被啟動,接著Init進程會啟動Zygote進程。
Zygote進程作為一個孵化器,主要用于fork新的進程,比如用于系統(tǒng)服務(wù)的SystemServer進程,我們的APP進程等。
而Zygote在啟動的時候會創(chuàng)建啟動我們的Java虛擬機,而Zygote通過fork出的進程也會擁有父進程一樣的功能,也就擁有我們的Java虛擬機環(huán)境。
所以我們常說的在安卓系統(tǒng)中每個進程擁有一個虛擬機的緣由是這樣來的,當(dāng)然除了非Zygote fork的進程。
2、Zygote的啟動腳本
腳本路徑:system/core/rootdir/init.zygote32.rc
腳本內(nèi)容:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks腳本的第一行大概可以看出,Zygote的進程名為 zygote ,執(zhí)行程序為app_process ,class name為main,我們?nèi)フ业綄?yīng)的app_process 。
路徑:frameworks/base/cmds/app_process
在app_process的路徑下有一個app_main.cpp的文件:
frameworks/base/cmds/app_process/app_main.cpp
由此可以猜到這里可以作為zygote 進程啟動的代碼入口。
3、app_process app_main.cpp源碼分析
frameworks/base/cmds/app_process/app_main.cpp
我們找到app_main.cpp其main函數(shù)
int main(int argc, char* const argv[])
{
....
// 1、創(chuàng)建了AppRuntime 對象
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments
// ignore argv[0]
argc--;
argv++;
// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
++i; // Skip unused "parent dir" argument.
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;
}
}
......
......
if (zygote) {
//2、調(diào)用runtime的start函數(shù)
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.");
}
}main函數(shù)的核心功能主要是創(chuàng)建了AppRuntime runtime對象,并調(diào)用start方法,這里傳入的className參數(shù)是com.android.internal.os.ZygoteInit(全類名)
AppRuntime 繼承了AndroidRuntime,我們看AndroidRuntime中的start函數(shù)。
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
....
....
....
/* start the virtual machine 3、啟動Java虛擬機*/
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
.....
/*
* Register android functions.
*Register android native functions with the VM.
* 4、向虛擬機注冊android本地函數(shù)。
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
.....
.....
.....
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
//5、使用env對象,通過JNI調(diào)用startClass這個類的main函數(shù),
//而startClass這個類就是之前傳起來的
//com.android.internal.os.ZygoteInit
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}以上的流程主要就是:
- 創(chuàng)建AppRuntime對象,調(diào)用其start函數(shù)。
- 在start函數(shù)中首先調(diào)用startVm函數(shù)啟動Java虛擬機
- 啟動Java虛擬機之后調(diào)用startReg函數(shù),注冊JNI
- 通過JNI調(diào)用ZygoteInit類的main函數(shù)
之后就從Native進入了Java是世界
4、ZygoteInit.java源碼分析
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
//1、創(chuàng)建一個ZygoteServer對象
ZygoteServer zygoteServer = new ZygoteServer();
final Runnable caller;
try {
....
....
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = 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]);
}
}
//2、注冊一個本地ServerSocket,名為 "zygote"
zygoteServer.registerServerSocket(socketName);
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
//preload執(zhí)行預(yù)加載,在preload函數(shù)中主要調(diào)用了
//preloadClasses和 preloadResources();加載一些系統(tǒng)資源和系統(tǒng)類,
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}
if (startSystemServer) {
//調(diào)用fork函數(shù),啟創(chuàng)建啟動SystemServer進程
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
//這句很關(guān)鍵如果在父進程zygote,則返回null,如果在system_server進程則不會null,
//所以當(dāng)在zygote進程的之后,該條件不滿足
if (r != null) {
r.run();
return;
}
}
Log.i(TAG, "Accepting command socket connections");
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
//在zygote進程中,調(diào)用runSelectLoop進入無線循環(huán),如果是子進程則返回caller 對象
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
//如果不是在zygote進程則退出循環(huán)進入到這里,關(guān)閉socket server
zygoteServer.closeServerSocket();
}
// We're in the child process and have exited the select loop. Proceed to execute the
// command.
//如果是在子進程中,通過返回的caller 對象,調(diào)用caller 的run函數(shù)。
if (caller != null) {
caller.run();
}
}在ZygoteInit的main函數(shù)中主要做了以下工作:
- 創(chuàng)建并注冊一個名為"zygote"本地SocketServer,也就是此時Zygote進程作為LocalSocket的服務(wù)端
- 在preload函數(shù)中的調(diào)用preloadClasses和preloadResources函數(shù)預(yù)加載系統(tǒng)類和一些系統(tǒng)資源
- 調(diào)用forkSystemServer創(chuàng)建啟動SystemServer進程并返回了一個Runnable r對象,此時就同時擁有了Zygote和SystemServer進程在運行,不通進程它們分別執(zhí)行不同的代碼分支
- 如果是在SystemServer進程則直接執(zhí)行 r.run函數(shù)并return,在Zygote進程則往下走,調(diào)用了zygoteServer中的runSelectLoop函數(shù),進入無限循環(huán),注釋也描述了如果是在其他子進程的話,則該循環(huán)會退出,返回一個Runnable caller對象。并且往下走調(diào)用caller.run函數(shù)。
5、小結(jié)
Zygote進程的啟動主要做了以下一些工作
Native層
- 創(chuàng)建啟動Java虛擬機
- 注冊JNI
- 通過JNI調(diào)用ZygoteInit.java的main函數(shù)
Java層 - 創(chuàng)建并注冊名為"zygote"本地SocketServer,用于進程之間通信,Zygote進程作為服務(wù)端,其實目的就是為了和之后的SystemServer進程通信
- 預(yù)加載一些類和一些資源
- fork子進程SystemServer
- runSelectLoop進入無線循環(huán)
以上就是Android FrameWork之Zygote啟動示例詳解的詳細內(nèi)容,更多關(guān)于Android FrameWork Zygote啟動的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android編程實現(xiàn)從字符串中查找電話號碼的方法
這篇文章主要介紹了Android編程實現(xiàn)從字符串中查找電話號碼的方法,涉及Android針對字符串的匹配與查找相關(guān)技巧,需要的朋友可以參考下2016-03-03
Android判斷手機是否是小米MIUI系統(tǒng)的方法
這篇文章主要介紹了Android判斷手機是否是小米MIUI系統(tǒng)的方法的相關(guān)資料,需要的朋友可以參考下2016-02-02
Android studio 生成帶Kotlin文檔的實現(xiàn)方式
這篇文章主要介紹了Android studio 生成帶Kotlin文檔的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03
Android TabLayout(選項卡布局)簡單用法實例分析
這篇文章主要介紹了Android TabLayout(選項卡布局)簡單用法,結(jié)合實例形式簡單分析了Android選項卡布局的界面布局與功能實現(xiàn)具體相關(guān)技巧,需要的朋友可以參考下2016-01-01

