0、引言
Android的底層內核是基于Linux構建而成,是在Native世界,而Android上層的應用是隸屬Java世界,那么在Android系統啟動程序中,系統是如何從Native范訓出Java世界的呢?這便是這篇文章的主角Zygote的主要職責,
本文所選Android系統版本是9.0 Pie,文中所有代碼片段路徑在代碼塊第一行已經標注,文章的目的是記錄自己的學習歷程與心得,不做商用或盈利,凡是學習程序中學習或參考過的大佬博文或著作都會盡力標注,在此感謝各位前輩的不吝分享,本文借鑒如下:
- 《Android系統啟動-zygote篇》—— 袁輝輝
- 《Android系統行程Zygote啟動程序的源代碼分析》—— 羅升陽
- 《[深入理解Android卷一全文-第四章]深入理解zygote》 —— 鄧平凡
- 《Android10.0系統啟動之Zygote行程-[Android取經之路]》—— IngresGe
2、Welcome To Java
在上篇博文《Zygote——Android系統中java世界的受精卵(一、C/C++中的Zygote)》中,我們分析了,C/C++世界Zygote相關的啟動代碼,在結尾處,終于在ZygoteInit.main()函式執行時,進入到了Java世界,所以這邊文章就接著main函式往下看,追蹤Java世界中Zygote相關的內容,main()函式的代碼依舊是分割開來決議 ,
2.1、準備作業
// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
public static void main(String[] argv) {
ZygoteServer zygoteServer = null;
//pie\libcore\dalvik\src\main\java\dalvik\system\ZygoteHooks.java
ZygoteHooks.startZygoteNoThreadCreation(); //呼叫native函式,功能是確保此時沒有其他執行緒啟動
try {
Os.setpgid(0, 0); //設定pid
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
Runnable caller;
try {
final long startTime = SystemClock.elapsedRealtime(); //系統啟動到現在的時間,包含設備深度休眠的時間
final boolean isRuntimeRestarted = "1".equals(
SystemProperties.get("sys.boot_completed")); //該屬性值在設備物理重啟時為空,reboot重啟后為1
String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing"; //設定boot時間列印TAG
//pie\frameworks\base\core\java\android\util\TimingsTraceLog.java
TimingsTraceLog bootTimingsTraceLog = new
TimingsTraceLog(bootTimeTag,Trace.TRACE_TAG_DALVIK); //通過systrace來追蹤
bootTimingsTraceLog.traceBegin("ZygoteInit"); //追蹤開始,每個traceBegin()對應一個traceEnd()
//使能DDMS(Dalvik Debug Monitor Server),注冊所有已知的Java VM的處理塊的監聽器,
//執行緒監聽、記憶體監聽、native堆記憶體監聽、debug模式監聽…
RuntimeInit.preForkInit();
boolean startSystemServer = false;
String zygoteSocketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) { //讀取"start-system-server"引數
startSystemServer = true;
//ro.zygote屬性值為zygote64_32或zygote64_32時,會存在另外一個行程zygote_secondary,
//zygote_secondary -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) { //讀取"--abi-list"引數
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) { //讀取"--socket-name"引數
zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
// PRIMARY_SOCKET_NAME = "zygote"
final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
if (!isRuntimeRestarted) {
if (isPrimaryZygote) {
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START,
startTime); //FrameworkStatsLog.java == statslog-framework-java-gen
//SECONDARY_SOCKET_NAME = "zygote_secondary"
} else if (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) {
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START,
startTime);
}
}
if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}
…………
這一部分主要是為后面的任務做準備作業:
- 禁止啟動其他執行緒;
- 設定pid;
- 決議C/C++層傳進來的引數argv;
- 設定相關日志追蹤;
2.2、preload()
// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
public static void main(String[] argv) {
…………
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,SystemClock.uptimeMillis());
preload(bootTimingsTraceLog); //預加載
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd();
}
}
這里的預加載是指將Java類、資源檔案、影像資源等公共資源在zygote啟動的時候就進行加載,這樣一來,根據fork的copy-on-write機制,其他由zygote fork出來的行程在使用這些資源的時候就不需要再次加載了,而是直接使用,所以這是一種犧牲系統開機時間,來提高系統應用運行時的運行效率的手段,
//pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
static void preload(TimingsTraceLog bootTimingsTraceLog) {
Log.d(TAG, "begin preload");
bootTimingsTraceLog.traceBegin("BeginPreload");
beginPreload(); //ZygoteHooks.onBeginPreload();
bootTimingsTraceLog.traceEnd(); //BeginPreload
bootTimingsTraceLog.traceBegin("PreloadClasses");
preloadClasses(); //預加載一些類
bootTimingsTraceLog.traceEnd(); //PreloadClasses
bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
//加載一些應用程式使用但不能放入引導類路徑的jar包庫,這些庫過去是引導類路徑的一部分,但必須洗掉,
//由于向后兼容性的原因,舊的系統應用程式仍然會使用它們,因此它們被快取在這里以保持性能特征
cacheNonBootClasspathClassLoaders();
bootTimingsTraceLog.traceEnd(); //CacheNonBootClasspathClassLoaders
bootTimingsTraceLog.traceBegin("PreloadResources");
preloadResources(); //加載常用資源,以便它們可以跨行程共享,比如apk開發常用到的color、drawable等資源
bootTimingsTraceLog.traceEnd(); //PreloadResources
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
nativePreloadAppProcessHALs(); //一些被大多數app行程加載的內容,需要通過HAL來添加(native)
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
maybePreloadGraphicsDriver(); //根據屬性ro.zygote.disable_gl_preload來判斷是否禁止預加載影像驅動相關內容(native)
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
preloadSharedLibraries(); //加載幾個共享庫:libandroid.so、libcompiler_rt.so、libjnigraphics.so
preloadTextResources(); //啟動字體快取,設定Typeface
WebViewFactory.prepareWebViewInZygote(); //為了記憶體共享,WebViewFactory執行所有必須在zygote行程中運行的初始化
endPreload();
warmUpJcaProviders(); //注冊AndroidKeyStoreProvider并預熱已經注冊的provider
Log.d(TAG, "end preload");
sPreloadComplete = true;
}
其中的preloadClasses()函式是去加載目標設備目錄樹中,/system/etc/preloaded-classes這個檔案中每行一個全限定名格式的類(#開頭的注釋行和空白行則自動跳過),該檔案是由檔案frameworks\base\tools\preload\WritePreloadedClassFile.java自動生成,其對于哪些類需要預加載有明確的說明:
/*
* pie\frameworks\base\tools\preload\WritePreloadedClassFile.java
* The set of classes to preload. We preload a class if:
* a) it's loaded in the bootclasspath (i.e., is a system class) 1、即系統類
* b) it takes > MIN_LOAD_TIME_MICROS = 1250 us to load, and 2、加載時長超過1250ms的類
* c) it's loaded by more than one process, or it's loaded by anapplication 3、不止一個行程會去加載的類
*/
2.3、gcAndFinalize()
//pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
public static void main(String[] argv) {
…………
bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
// 呼叫ZygoteHooks.gcAndFinalize(),通過runFinalizationSync()可以在沒有HeapWorker執行緒的Zygote中呼叫finalizers,
//以運行幾個特殊的gc來嘗試清理幾代軟可及和最終可及的物件,以及任何其他垃圾,
gcAndFinalize();
bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
bootTimingsTraceLog.traceEnd(); // 對應bootTimingsTraceLog.traceBegin("ZygoteInit")
Zygote.initNativeState(isPrimaryZygote); //初始化zygote的native狀態(native方法)
ZygoteHooks.stopZygoteNoThreadCreation(); //可以啟動其他執行緒了,對應前面的ZygoteHooks.startZygoteNoThreadCreation();
…………
}
gcAndFinalize()方法主要就是在預加載動作之后、后續從zygote fork其他行程的動作之前,進行的一次垃圾回收,這里需要補充看一下上面這個代碼段中的Zygote.initNativeState()方法:
// pie\frameworks\base\core\java\com\android\internal\os\Zygote.java
static void initNativeState(boolean isPrimary) {
nativeInitNativeState(isPrimary);
}
// pie\frameworks\base\core\jni\com_android_internal_os_Zygote.cpp
static void com_android_internal_os_Zygote_nativeInitNativeState(JNIEnv* env, jclass, jboolean is_primary) {
gZygoteSocketFD = android_get_control_socket(is_primary ? "zygote" : "zygote_secondary"); //獲取socket的句柄fd
if (gZygoteSocketFD >= 0) {
ALOGV("Zygote:zygoteSocketFD = %d", gZygoteSocketFD);
} else {
ALOGE("Unable to fetch Zygote socket file descriptor");
}
gUsapPoolSocketFD = android_get_control_socket(is_primary ? "usap_pool_primary" : "usap_pool_secondary");
if (gUsapPoolSocketFD >= 0) {
ALOGV("Zygote:usapPoolSocketFD = %d", gUsapPoolSocketFD);
} else {
ALOGE("Unable to fetch USAP pool socket file descriptor");
}
//創建套接字,該套接字將被用來發送未經請求的訊息到system_server,該套接字將在派生子行程后被關閉
initUnsolSocketToSystemServer();
gIsSecurityEnforced = security_getenforce(); //根據selinux策略,普通apk是禁止security_getenforce的,
selinux_android_seapp_context_init(); //所以在zygote fork之前初始化并快取該策略值
//Zygote行程在fork每個子行程之前首先卸載根存盤空間,因為Zygote行程不使用根存盤空間,所以取消對其下面的掛載名稱空間的共享,
//每個fork的子行程(包括SystemServer)只掛載它們自己的根存盤空間,在MountEmulatedStorage方法中不需要卸載存盤操作,
UnmountStorageOnInit(env);
if (!SetTaskProfiles(0, {})) { //加載必須的performance profile資訊
zygote::ZygoteFailure(env, "zygote", nullptr, "Zygote SetTaskProfiles failed");
}
}
該函式的功能概括來講做了這四件事:
- 從環境變數中獲取socket句柄fd;
- 初始化安全屬性;
- 卸載適當的存盤;
- 加載必要的性能概要資訊;
還有需要說明一下的是代碼里出現的USAP(Unspecialized App Process),是指在android高版本里提出來的一種zygote fork子行程的機制,通過prefork的方式提前創建好一批行程,當有應用啟動時,直接將已經創建好的行程分配給它,從而省去了fork的動作,從而可以提升性能,詳情參考《Android Framework | 一種新型的應用啟動機制:USAP》,
2.4、 forkSystemServer()
前面的三個小節做好準備作業后,下面就要開始做zygote比較重要的的一個任務了,那就是fork出system_server行程:
//pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
public static void main(String[] argv) {
…………
zygoteServer = new ZygoteServer(isPrimaryZygote); //創建zygote的ServerSocket
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
if (r != null) { //{r == null} in the parent process, and {r != null} in the child process
r.run(); //通過反射機制執行SystemServer.java的main()函式
return;
}
}
…………
}
這里先是通過ZygoteServer類的建構式,去創建zygote的LocalServerSocket:
//pie\frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
ZygoteServer(boolean isPrimaryZygote) {
mUsapPoolEventFD = Zygote.getUsapPoolEventFD();
if (isPrimaryZygote) {
mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
mUsapPoolSocket = Zygote.createManagedSocketFromInitSocket(Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
} else {
mZygoteSocket =Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);
mUsapPoolSocket = Zygote.createManagedSocketFromInitSocket(Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
}
mUsapPoolSupported = true;
fetchUsapPoolPolicyProps(); //TODO
}
// pie\frameworks\base\core\java\com\android\internal\os\Zygote.java
static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName; // "ANDROID_SOCKET_zygote"
try {
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
return new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException(
"Error building socket from file descriptor: " + fileDesc, ex);
}
}
可以看出createManagedSocketFromInitSocket()函式首先是根據socket默認前綴 "ANDROID_SOCKET_"和該socket名稱"zygote",拼接成環境變數的key = "ANDROID_SOCKET_zygote" ,然后以該key值從環境變數中獲取目標socket的檔案描述符fd,(這個環境變數的鍵值在init階段決議init.zygote.rc、讀取并啟動zygote這個service下面的socket(socket zygote stream 660 root system),在目標設備創建/dev/socket/zygote 這個檔案時,就已經以"ANDROID_SOCKET_zygote"為鍵,創建該socket的檔案描述符fd為值,存盤到環境變數中了,)這里獲取到目標socket的檔案描述符后,就用其創建了LocalServerSocket,
以上這些準備好了之后,就要做forkSystemServer這個重要的動作了,鑒于該函式挺長,所以依然分割開來決議,
2.4.1、引數準備
// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
long capabilities = posixCapabilitiesAsBits(
OsConstants.CAP_IPC_LOCK,
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_PTRACE,
OsConstants.CAP_SYS_TIME,
OsConstants.CAP_SYS_TTY_CONFIG,
OsConstants.CAP_WAKE_ALARM,
OsConstants.CAP_BLOCK_SUSPEND
);
StructCapUserHeader header = new StructCapUserHeader(OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
StructCapUserData[] data;
try {
data = Os.capget(header);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to capget()", ex);
}
capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);
String[] args = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
+ "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
"com.android.server.SystemServer",
};
…………
}
這里主要做的作業就是為后面fork出system_server行程準備啟動引數,首先是通過posixCapabilitiesAsBits()函式配置一個long型別的(POSIX capability)能力引數(說人話就是配置system_server行程可以擁有的能力或權限,即能做哪些事),然后和其他命令列引數一起組成啟動system_server所需要傳入的字串陣列型別的引數args,
其中的OsConstants類位于pie\libcore\luni\src\main\java\android\system\OsConstants.java中,這個類把CAP_KILL這些靜態常量都設定為0,原始碼注釋:A hack to avoid these constants being inlined by javac......because we want to initialize them at runtime.大概意思就是說,這樣做是不想在靜態編譯(javac)的時候這些常量被行內進去,而是想借用native方法在運行時去初始化,具體操作就是在該Java類的靜態塊里面呼叫了一個native介面,該native介面在運行時才會通過GetStaticFieldID()和SetStaticIntField()函式去給這些靜態常量設定具體的值,該native方法位于pie\libcore\luni\src\main\native\android_system_OsConstants.cpp中,而這些值的具體定義是在<linux/capability.h>中,而這個檔案位于pie\bionic\libc\kernel\uapi\linux\capability.h,這些原檔案中對每個數值定義都有詳細的說明注釋,有興趣可以看看這些注釋,看明白這些數值的的定義范圍,回傳來就看得懂函式posixCapabilitiesAsBits()通過傳入的不定引數,對system_server行程能力(Capabilities)的配置程序了:
/**
*kitkak\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
* Gets the bit array representation of the provided list of POSIX capabilities.
*/
private static long posixCapabilitiesAsBits(int... capabilities) {
long result = 0;
for (int capability : capabilities) {
if ((capability < 0) || (capability > OsConstants.CAP_LAST_CAP)) {
throw new IllegalArgumentException(String.valueOf(capability));
}
result |= (1L << capability);
}
return result;
}
其無非就是通過位操作,將目標long型別整數的二進制形式中,能力(Capabilities)使能所代表的位置為1而已,比如不定引數的第一個常量CAP_KILL的數值為5,則代碼將long型別的1有符號左移五位,其他不同的數值也是類似左移不同的位數,最終通過 |= 操作整合出目標數值,
2.4.2、引數決議與標識置位
// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
…………
ZygoteArguments parsedArgs;
int pid;
try {
//將args存盤到zygote命令緩沖區中,這個ZygoteCommandBuffer是一個用于Zygote命令的本機可訪問的緩沖區,
//設計支持重復fork的應用程式,而不干預記憶體分配,從而保持zygote記憶體盡可能穩定
ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
try { //單例模式決議引數
parsedArgs = ZygoteArguments.getInstance(commandBuffer);
} catch (EOFException e) {
throw new AssertionError("Unexpected argument error for forking system server", e);
}
commandBuffer.close(); //及時釋放本地資源,避免命令重復呼叫
Zygote.applyDebuggerSystemProperty(parsedArgs);
Zygote.applyInvokeWithSystemProperty(parsedArgs); //--invoke-with=?
if (Zygote.nativeSupportsMemoryTagging()) {
/* The system server has ASYNC MTE by default, in order to allow system services to specify
* their own MTE level later, as you can't re-enable MTE once it's disabled. */
String mode = SystemProperties.get("arm64.memtag.process.system_server", "async");
if (mode.equals("async")) {
parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC;
} else if (mode.equals("sync")) {
parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_SYNC;
} else if (!mode.equals("off")) {
// When we have an invalid memory tag level, keep the current level.
parsedArgs.mRuntimeFlags |= Zygote.nativeCurrentTaggingLevel();
Slog.e(TAG, "Unknown memory tag level for the system server: \"" + mode + "\"");
}
} else if (Zygote.nativeSupportsTaggedPointers()) {
//Enable pointer tagging in the system server. Hardware support for this is present in all ARMv8 CPUs
parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI;
}
/* Enable gwp-asan on the system server with a small probability. This is the same
* policy as applied to native processes and system apps. */
parsedArgs.mRuntimeFlags |= Zygote.GWP_ASAN_LEVEL_LOTTERY;
if (shouldProfileSystemServer()) {
parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
}
…………
}
這里主要是先將2.4.1部分準備的引數args存盤到ZygoteCommandBuffer這個命令緩沖區中,然后通過ZygoteArguments.getInstance()介面,獲取單例模式的ZygoteArguments類的實體,之后ZygoteArguments類的建構式呼叫parseArgs()函式對這些zygote命令引數進行決議,最后根據一些配置對引數決議出來的結果物件parsedArgs的mRuntimeFlags成員進行標識位置位,
獲取單例模式的ZygoteArguments的實體時,在建構式中呼叫parseArgs()去決議引數的程序:
//pie\frameworks\base\core\java\com\android\internal\os\ZygoteArguments.java
private ZygoteArguments(ZygoteCommandBuffer args, int argCount)
throws IllegalArgumentException, EOFException {
parseArgs(args, argCount);
}
public static ZygoteArguments getInstance(ZygoteCommandBuffer args)
throws IllegalArgumentException, EOFException {
int argCount = args.getCount();
return argCount == 0 ? null : new ZygoteArguments(args, argCount);
}
2.4.3、真正的fork動作
// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
…………
int pid;
try {
…………
pid = Zygote.forkSystemServer(
parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.mGids,
parsedArgs.mRuntimeFlags,
null,
parsedArgs.mPermittedCapabilities,
parsedArgs.mEffectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
…………
}
這里直接去找Zygote.forkSystemServer()方法:
//pie\frameworks\base\core\java\com\android\internal\os\Zygote.java
static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
ZygoteHooks.preFork(); //停掉守護執行緒,停掉當前行程的所有的執行緒,zygote每次fork前呼叫
int pid = nativeForkSystemServer(
uid, gid, gids, runtimeFlags, rlimits,
permittedCapabilities, effectiveCapabilities);
Thread.currentThread().setPriority(Thread.NORM_PRIORITY); //設定當前執行緒優先級
//每次呼叫preFork()后,都會在子行程上呼叫postForkChild(),
//并且都會在父行程和子行程上呼叫postForkCommon(),
//子行程呼叫postForkCommon()在postForkCommon()之后
ZygoteHooks.postForkCommon();
return pid;
}
這里做了fork前的準備后,主要就是通過jni去呼叫了nativeForkSystemServer()函式:
//pie\frameworks\base\core\jni\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 runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
jlong effective_capabilities) {
//初始化USAP相關的一個vector
std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()), fds_to_ignore(fds_to_close);
fds_to_close.push_back(gUsapPoolSocketFD);
if (gUsapPoolEventFD != -1) {
fds_to_close.push_back(gUsapPoolEventFD);
fds_to_ignore.push_back(gUsapPoolEventFD);
}
if (gSystemServerSocketFd != -1) {
fds_to_close.push_back(gSystemServerSocketFd);
fds_to_ignore.push_back(gSystemServerSocketFd);
}
pid_t pid = zygote::ForkCommon(env, true, fds_to_close, fds_to_ignore, true); //fork動作
if (pid == 0) {
/在子行程中進行一些system_server相關配置,有興趣的話去詳細看看
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
permitted_capabilities, effective_capabilities,
MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true, false,
nullptr, nullptr, false, nullptr, false, false);
} else if (pid > 0) {
ALOGI("System server process %d has been created", pid);
gSystemServerPid = pid;
int status;
//在父行程zygote中使用waitpid()函式以及WNOHANG這個選項,監控子行程的結束情況,
//監控到system_server行程結束時,需要重啟zygote,
//waitpid()函式參考https://www.cnblogs.com/zhaihongliangblogger/p/6367041.html
if (waitpid(pid, &status, WNOHANG) == pid) {
ALOGE("System server process %d has died. Restarting Zygote!", pid);
RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!");
}
if (UsePerAppMemcg()) { //檢測是否掛載了memcg
if (!SetTaskProfiles(pid, std::vector<std::string>{"SystemMemoryProcess"})) {
ALOGE("couldn't add process %d into system memcg group", pid);
}
}
}
return pid;
}
這里重點就是通過ForkCommon()函式fork子行程,然后通過SpecializeCommon()函式對子行程做一些配置,這里主要來看一下ForkCommon()函式的fork程序:
// pie\frameworks\base\jni\com_android_internal_os_Zygote.cpp
pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
const std::vector<int>& fds_to_close,
const std::vector<int>& fds_to_ignore,
bool is_priority_fork,
bool purge) {
SetSignalHandlers(); //為zygote管理子行程配置信號SIGCHLD/SIGHUP
//指定ZygoteFailure函式,其用來向runtime報告致命錯誤
auto fail_fn = std::bind(zygote::ZygoteFailure, env, is_system_server ? "system_server" : "zygote", nullptr, _1);
//在fork期間臨時阻塞SIGCHLD,SIGCHLD處理程式可能會記錄日志,
BlockSignal(SIGCHLD, fail_fn); //這將導致我們關閉的日志fd被重新打開,會導致失敗,因為不允許列出fd
__android_log_close(); //在開始計算檔案描述符串列之前,關閉所有與日志記錄相關的fd
AStatsSocket_close();
if (gOpenFdTable == nullptr) { //如果這是zygote的第一次fork,則創建一個打開的FD表,驗證檔案受支持的型別和允許串列
gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn);
} else { //如果不是,則檢查打開的檔案是否沒有更改,不希望并且未來會禁止打開新的檔案,
gOpenFdTable->Restat(fds_to_ignore, fail_fn); //目前的做法是,如果通過了上面的Create檢測,則允許打開新的檔案
}
android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level();
if (purge) { //清除未使用的本機記憶體,以減少與子行程的錯誤共享,通過減少與子行程共享的libc_malloc區域的大小,
mallopt(M_PURGE, 0); //當malloc在fork之后調整它所管理的每個頁面上的元資料時,可以減少轉換到私有臟狀態的頁面數量
}
pid_t pid = fork(); //核心的fork動作
if (pid == 0) { //子行程
if (is_priority_fork) {
setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
} else {
setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN);
}
PreApplicationInit();
DetachDescriptors(env, fds_to_close, fail_fn); //通過dup3()函式清除那些需要立即關閉的檔案描述符
ClearUsapTable(); //清除USAP行程表
gOpenFdTable->ReopenOrDetach(fail_fn); //重新打開所有剩余的打開的檔案描述符,這樣它們就不會通過fork與zygote共享
android_fdsan_set_error_level(fdsan_error_level);
gSystemServerSocketFd = -1;
} else { //父行程
ALOGD("Forked child process %d", pid);
}
UnblockSignal(SIGCHLD, fail_fn); //fork結束后打開阻塞,對應上面的BlockSignal()
return pid;
}
2.4.4、fork后的掃尾作業
// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
…………
//由于fork()函式完成任務后回傳的位置不確定,如果在子行程中,fork函式回傳0;
//如果在父行程中,fork回傳新創建子行程的行程ID
if (pid == 0) {
if (hasSecondZygote(abiList)) { //通過比較設備ABI串列和受精卵串列來確定這一點,
waitForSecondaryZygote(socketName); //如果這個受精卵支持該設備支持的所有abi,就不會有另一個受精卵
}
zygoteServer.closeServerSocket(); //fork出來的子行程中不會用到zygoteServer這個socket,所以要關掉
return handleSystemServerProcess(parsedArgs); //做一些fork system_server的掃尾作業
}
return null;
}
在上一小節的native fork動作結束回傳后,這里需要通過handleSystemServerProcess()方法來做一些system_server行程的收尾動作:
// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
Os.umask(S_IRWXG | S_IRWXO); //行程權限設定為0077,這樣新檔案和目錄將默認為所有者權限
if (parsedArgs.mNiceName != null) { //引數準備部分的"--nice-name=system_server"
Process.setArgV0(parsedArgs.mNiceName); //行程名設定為system_server
}
//環境變數SYSTEMSERVERCLASSPATH=/system/framework/services.jar:
// /system/framework/ethernet-service.jar:
// /system/framework/wifi-service.jar:…………
final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
if (systemServerClasspath != null) {
if (shouldProfileSystemServer() && (Build.IS_USERDEBUG || Build.IS_ENG)) {
try {
Log.d(TAG, "Preparing system server profile");
prepareSystemServerProfile(systemServerClasspath); //debug或eng模式下準備system_server的profile檔案
} catch (Exception e) {
Log.wtf(TAG, "Failed to set up system server profile", e);
}
}
}
if (parsedArgs.mInvokeWith != null) { //TODO
String[] args = parsedArgs.mRemainingArgs;
if (systemServerClasspath != null) {
String[] amendedArgs = new String[args.length + 2];
amendedArgs[0] = "-cp";
amendedArgs[1] = systemServerClasspath;
System.arraycopy(args, 0, amendedArgs, 2, args.length);
args = amendedArgs;
}
WrapperInit.execApplication(parsedArgs.mInvokeWith, parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
VMRuntime.getCurrentInstructionSet(), null, args);
throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
} else { //一般system_server走這個分支
ClassLoader cl = getOrCreateSystemServerClassLoader(); //為system_server創建類加載器
if (cl != null) {
Thread.currentThread().setContextClassLoader(cl); //為當前執行緒設定背景關系類加載器
}
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion, parsedArgs.mDisabledCompatChanges,
parsedArgs.mRemainingArgs, cl);
}
}
繼續追蹤ZygoteInit.zygoteInit() 方法:
// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
public static Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams(); //將java的system.out和system.err log輸出流重定向到AndroidPrintStream
RuntimeInit.commonInit(); //設定log配置、通過persist.sys.timezone的屬性值設定時區、設定默認的HTTP User-agent格式到http.agent屬性
//通過JNI呼叫AndroidRuntime的成員gCurRuntime(即app_process.cpp中)的onZygoteInit()函式,
ZygoteInit.nativeZygoteInit(); //主要完成創建binder的作業
return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv, classLoader);
}
追蹤RuntimeInit.applicationInit()方法:
// pie\frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges, String[] argv, ClassLoader classLoader) {
…………
//從前面準備的引數中決議出"com.android.server.SystemServer"賦值給args.startClass
final Arguments args = new Arguments(argv);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); //對應上面ZygoteInit的traceBegin()
//有了類的全限定名,通過反射機制找到SystemServer.java的main()方法
return findStaticMain(args.startClass, args.startArgs, classLoader);
}
protected static Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) {
………… //省略通過反射機制尋找main方法的程序
return new MethodAndArgsCaller(m, argv);
}
//將main方法封裝到Runnable實體中回傳,最侄訓傳給2.4節一開始的Runnable r,然后通過r.run()執行該main方法
static class MethodAndArgsCaller implements Runnable {
private final Method mMethod;
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
…………
}
}
}
總結一下2.4.4小節主要做了:
- 對fork出來的新行程的權限設定;
- 行程命名為system_server;
- 創建類加載器加載system_server的java類;
- 通過反射機制找到SystemServer.java的main函式,并封裝到Runnable r;
- 方法return到2.4節一開始,通過r.run()執行該main方法,以啟動SystsmServer;
2.5、runSelectLoop()
zygote除了fork出system_server行程這個任務外,還有一個重要的任務,那就是接收AMS(ActivityManagerService)發來創建java層應用程式的請求,fork出一個個行程,并在新行程中執行該請求中相關應用程式的main方法,上層的一個個應用程式就是這樣通過zygote創建而來,因為應用程式都是由zygote孕育而來,所以就不難理解zygote(受精卵)的名稱的由來了,我們繼續往下看看它是如何完成這一任務的:
// pie\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
public static void main(String[] argv) {
…………
Runnable caller;
try {
…………
Log.i(TAG, "Accepting command socket connections");
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with fatal exception", ex);
throw ex;
} finally {
if (zygoteServer != null) {
zygoteServer.closeServerSocket(); //zygote掛掉的時候關閉ServerSocket
}
}
if (caller != null) {
caller.run();
}
}
runSelectLoop()方法冗長,有太多USAP相關的操作,我們這里省略相關內容,只看核心操作:
// pie\frameworks\base\core\java\com\android\internal\os\ZygoteServer.java
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> socketFDs = new ArrayList<>();
ArrayList<ZygoteConnection> peers = new ArrayList<>();
socketFDs.add(mZygoteSocket.getFileDescriptor()); //先將server socket加入到這個socketFDs串列
peers.add(null);
while (true) { //間隔時間持續輪詢
…………
int[] usapPipeFDs = null;
StructPollfd[] pollFDs;
pollFDs = new StructPollfd[socketFDs.size()]; //每輪回圈,都重新創建需要監聽的pollFDs
int pollIndex = 0;
for (FileDescriptor socketFD : socketFDs) {
pollFDs[pollIndex] = new StructPollfd();
pollFDs[pollIndex].fd = socketFD;
pollFDs[pollIndex].events = (short) POLLIN; //關注poll事件到來
++pollIndex;
}
…………
int pollTimeoutMs;//設定poll輪詢時延間隔
int pollReturnValue;
try {
pollReturnValue = Os.poll(pollFDs, pollTimeoutMs);
…………
if (pollReturnValue == 0) { …………
} else {
while (--pollIndex >= 0) {
if ((pollFDs[pollIndex].revents & POLLIN) == 0) {
continue;
}
if (pollIndex == 0) { //server socket最先加入fds, 因此這里是server socket收到資料
ZygoteConnection newPeer = acceptCommandPeer(abiList); //收到新的建立通信的請求,建立通信連接
peers.add(newPeer); //加入到peers和fds, 即下一次也開始監聽
socketFDs.add(newPeer.getFileDescriptor());
} else if (pollIndex < usapPoolEventFDIndex) { //說明接收到AMS通過socket發送過來創建應用程式的請求
try {
//有socket連接時創建ZygoteConnection物件,并添加到pollFDs
ZygoteConnection connection = peers.get(pollIndex);
boolean multipleForksOK = !isUsapPoolEnabled()
&& ZygoteHooks.isIndefiniteThreadSuspensionSafe();
final Runnable command =
connection.processCommand(this, multipleForksOK); //完成創建子行程的請求
if (mIsForkChild) {
if (command == null) {
throw new IllegalStateException("command == null");
}
return command; //依然是提供Runnable介面,通過反射機制執行目標應用程式的main方法
} else {
if (command != null) {
throw new IllegalStateException("command != null");
}
//處理完后,關閉socket連接,并從peers和socketFDs串列中移除
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(pollIndex);
socketFDs.remove(pollIndex);
}
}
} catch (Exception e) {
…………
}
這里大概意思就是,回圈間隔一段時間輪詢連接socket訊息,看是否有AMS客戶端發過來創建應用程式的請求,有的話則通過pie\frameworks\base\core\java\com\android\internal\os\ZygoteConnection.processCommand()方法創建行程并啟動目標應用程式,我們只需要直到這里是接收AMS創建應用程式的請求,完成目標應用程式創建與啟動的就好,詳細細節我后面學習到AMS之后,單獨寫一篇文章來追蹤AMS與zygote之間通過socket通信,創建應用程式的程序吧,
3、結語
總結來說,zygote在開機程序中,其先是啟動虛擬機、注冊JNI函式、進入java世界,然后fork出system_server行程,之后作為守護行程監聽并處理創建普通應用程式的作業,呼叫流程圖原圖請見:| ProcessOn

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/339187.html
標籤:其他
