在init
進程詳解的一章中,我們知道init.rc文件中的zygote啓動腳本命令是
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
init
程序會創建一個名爲service
的結構體,並在 boot
action 執行的時候,調用service_start
方法fork
出一個子進程,並在子進程中執行/system/bin/appress
二進制文件。
zygote
本身是用戶空間的一個Native
的應用程序進程,與驅動、內核等均無關係。它最初的名稱是app_process
,然後直接調用linux
系統調用pctrl
將進程名稱改爲了zygote
。
一、 zygote 分析
下面我們來分析app_progress
進程,它對應的文件爲frameworks\base\cmds\app_process\App_main.cpp
文件,入口函數爲main
int main(int argc, char* const argv[])
{
#ifdef __arm__
/*
* b/7188322 - Temporarily revert to the compat memory layout
* to avoid breaking third party apps.
*
* THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE.
*
* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466
* changes the kernel mapping from bottom up to top-down.
* This breaks some programs which improperly embed
* an out of date copy of Android's linker.
*/
char value[PROPERTY_VALUE_MAX];
property_get("ro.kernel.qemu", value, "");
bool is_qemu = (strcmp(value, "1") == 0);
if ((getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) && !is_qemu) {
int current = personality(0xFFFFFFFF);
if ((current & ADDR_COMPAT_LAYOUT) == 0) {
personality(current | ADDR_COMPAT_LAYOUT);
setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1);
execv("/system/bin/app_process", argv);
return -1;
}
}
unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP");
#endif
// These are global variables in ProcessState.cpp
mArgC = argc;
mArgV = argv;
mArgLen = 0;
for (int i=0; i<argc; i++) {// 拷貝 剩餘的參數到 char* 數組中
mArgLen += strlen(argv[i]) + 1;
}
mArgLen--;
AppRuntime runtime; //創建AppRuntime對象
const char* argv0 = argv[0];
// Process command line arguments
// ignore argv[0]
argc--;
argv++;
// Everything up to '--' or first non '-' arg goes to the vm
/*
將 -Xzygote /system/bin --zygote --start-system-server之前的VM 參數
用JavaVMOption 結構體初始化,添加到 mOptions 集合中
*/
int i = runtime.addVmArguments(argc, argv);
// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
const char* parentDir = NULL;
const char* niceName = NULL;
const char* className = NULL;
//處理剩餘的 "-Xzygote /system/bin --zygote --start-system-server"啓動參數
while (i < argc) {
const char* arg = argv[i++];
if (!parentDir) {
parentDir = arg;
} else if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = "zygote"; // 配置該選項後,表明將app_progress的進程名改爲zygote
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true; //表明啓動 system_server
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName = arg + 12; // 配置該選項後,表明將app_progress的進程名改爲其它名字
} else {
className = arg;
break;
}
}
if (niceName && *niceName) {
setArgv0(argv0, niceName);
set_process_name(niceName);//將app_progress進程名改爲niceName,默認情況下爲zygote
}
runtime.mParentDir = parentDir;
if (zygote) {
//調用runtime的start方法,該方法的第二個參數爲start-system-server
runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer ? "start-system-server" : "");
} else if (className) {
// Remainder of args get passed to startup class main()
runtime.mClassName = className;
runtime.mArgC = argc - i;
runtime.mArgV = argv + i;
runtime.start("com.android.internal.os.RuntimeInit",
application ? "application" : "tool");
} 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
中實現
1.1AppRuntime分析
AppRuntime 類的聲名和實現均在App_main.cpp
中,它是從Android_Runtime
中派生出來的。重載了其中的onStart
方法:
/*
* Start the Android runtime. This involves starting the virtual machine
* and calling the "static void main(String[] args)" method in the class
* named by "className".
*
* Passes the main function two arguments, the class name and the specified
* options string.
*/
void AndroidRuntime::start(const char* className, const char* options)
{
ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
className != NULL ? className : "(unknown)");
/*
* 'startSystemServer == true' means runtime is obsolete and not run from
* init.rc anymore, so we print out the boot start event here.
*/
if (strcmp(options, "start-system-server") == 0) {
/* track our progress through the boot sequence */
const int LOG_BOOT_PROGRESS_START = 3000;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
//設置環境變量"ANDROID_ROOT"的值爲"/system"
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);
}
//const char* kernelHack = getenv("LD_ASSUME_KERNEL");
//ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
//啓動虛擬機,得到當前虛擬機對象JavaVM爲全局靜態變量
if (startVm(&mJavaVM, &env) != 0) {
return;
}
onVmCreated(env);
/*
* Register android functions.//註冊定義好的jni函數
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
/*
* We want to call main() with a String array with arguments in it.
* At present we have two arguments, the class name and an option string.
* Create an array to hold them.
*/
/**
爲了調用"com.android.internal.os.ZygoteInit"類中的main(String[])函數。我們需要先創建
一個String[] 對象數組,用於存放"com.android.internal.os.ZygoteInit",和後面的參數
**/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
jstring optionsStr;
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
//創建一個有兩個String 對象數組,即Java代碼: String strArray[]=new String[2];
strArray = env->NewObjectArray(2, stringClass, NULL);
assert(strArray != NULL);
//設置數組第一個元素爲"com.android.internal.os.ZygoteInit"
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
//設置數組第二個元素爲"start-system-server"
optionsStr = env->NewStringUTF(options);
env->SetObjectArrayElement(strArray, 1, optionsStr);
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
//將"com.android.internal.os.ZygoteInit"換成"com/android/internal/os/ZygoteInit",符合jni調用規範
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
//找到ZygoteInit類的static main 方法jmentod ID
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 {
//調用ZygoteInit類的main靜態方法,Zygote進入了Java世界!
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
ALOGD("Shutting down VM\n");
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");
}
通過上面的分析,我們知道了AndroidRuntime::start主要做的三件事:
1.調用startVm創建虛擬機對象。
2.調用startReg註冊好定義的JNI函數。
3.調用找到”com.android.internal.os.ZygoteInit”類的static main 函數進入Java世界
### 1.調用startVM創建Java虛擬機
在AndroidRuntime::startVm
方法中,初始化了創建虛擬機的參數,然後創建虛擬機。
/*
* Start the Dalvik Virtual Machine.
*
* Various arguments, most determined by system properties, are passed in.
* The "mOptions" vector is updated.
*
* Returns 0 on success.
*/
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
{
int result = -1;
JavaVMInitArgs initArgs;
JavaVMOption opt;
.....
/*
*
這個函數的前部分都是根據系統的屬性配置文件創建JavaVMOption結構體,添加
到mOptions集合中,用來設置虛擬機參數。
*/
/*
設置JNI check選項,指的是在 Native層調用JNI函數時,系統做的一些檢查工作
比如調用NewUTFString時,系統會檢查傳入的字符串是不是符合UTF-8的需求。
*/
property_get("dalvik.vm.checkjni", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
checkJni = true;
} else if (strcmp(propBuf, "false") != 0) {
/* property is neither true nor false; fall back on kernel parameter */
property_get("ro.kernel.android.checkjni", propBuf, "");
if (propBuf[0] == '1') {
checkJni = true;
}
}
...
/*
* The default starting and maximum size of the heap. Larger
* values should be specified in a product property override.
*/
strcpy(heapstartsizeOptsBuf, "-Xms");
property_get("dalvik.vm.heapstartsize", heapstartsizeOptsBuf+4, "4m");
opt.optionString = heapstartsizeOptsBuf;
mOptions.add(opt);
/*
設置虛擬機的heapsize,默認爲16MB。絕大多數廠商都會修改這個值,一般是32MB。
heapsize 不能設置得過小,否則在操作大尺寸的圖片時無法分配所需的內存。
*/
strcpy(heapsizeOptsBuf, "-Xmx");
property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
opt.optionString = heapsizeOptsBuf;
mOptions.add(opt);
/*
* We don't have /tmp on the device, but we often have an SD card. Apps
* shouldn't use this, but some test suites might want to exercise it.
*/
opt.optionString = "-Djava.io.tmpdir=/sdcard";
mOptions.add(opt);
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();
initArgs.nOptions = mOptions.size();
initArgs.ignoreUnrecognized = JNI_FALSE;
/*
* Initialize the VM.
*
* The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
* If this call succeeds, the VM is ready, and we can start issuing
* JNI calls.
*/
/*
創建並初始化虛擬機,JavaVM對象是每個進程只有一個。JNIEnv 是每個線程一個。
*/
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
goto bail;
}
result = 0;
bail:
free(stackTraceFile);
return result;
}
2.註冊JNI函數
Java世界用到的一些類的方法是用native方式實現的需要系統提前註冊,下面查看startReg函數
/*
* Register android native functions with the VM.
*/
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
/*
* This hook causes all future threads created in this process to be
* attached to the JavaVM. (This needs to go away in favor of JNI
* Attach calls.)
*/
/*
*設置 Thread類的線程創建函數爲javaCreateThreadEtc
*/
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
ALOGV("--- registering native functions ---\n");
/*
* Every "register" function calls one or more things that return
* a local reference (e.g. FindClass). Because we haven't really
* started the VM yet, they're all getting stored in the base frame
* and never released. Use Push/Pop to manage the storage.
*/
env->PushLocalFrame(200);
//註冊JNI函數。gREgJNI是一個全局數組,裏面存放了要註冊的Java類對應的註冊函數的函數指針
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
//createJavaThread("fubar", quickTest, (void*) "hello");
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++) {
//調用數組中才mProc元素,該元素是一個函數指針,int (*mProc)(JNIEnv *),指向類對應的註冊函數
if (array[i].mProc(env) < 0) {
#ifndef NDEBUG
ALOGD("----------!!! %s failed to load\n", array[i].mName);
#endif
return -1;
}
}
return 0;
}
gRegJNI全局數組
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_debug_JNITest),
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_android_os_SystemClock),
REG_JNI(register_android_util_EventLog),
...
}
register_android_debug_JNITest對應的註冊函數:
/*
* JNI registration.
*/
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "part1", "(IDLjava/lang/String;[I)I",
(void*) android_debug_JNITest_part1 },
{ "part3", "(Ljava/lang/String;)I",
(void*) android_debug_JNITest_part3 },
};
int register_android_debug_JNITest(JNIEnv* env)
{
return jniRegisterNativeMethods(env, "android/debug/JNITest",
gMethods, NELEM(gMethods));
}
2.Java世界分析
通過前面的分析我們知道,Java世界的入口函數爲com.android.internal.os.ZygoteInit
類的main函數。我們來查看這個main函數:
public static void main(String argv[]) {
try {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();
//1.註冊ZygoteSocket用的Socket
registerZygoteSocket();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
//2.預加載類、資源、OpenGL
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();
//啓動後強制垃圾回收
// Do an initial gc to clean up after startup
gc();
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);
// If requested, start system server directly from Zygote
if (argv.length != 2) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
、
if (argv[1].equals("start-system-server")) {
startSystemServer();//3.啓動system_server進程
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
Log.i(TAG, "Accepting command socket connections");
//調用函數runSelectLoop進入一個無限循環
//4.在前面創建的 socket接口中等待ActivityManagerService請求,以創建新的應用程序進程
runSelectLoop();
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
//5.反射調用執行函數
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
在ZygoteInit類的main函數中,我們知道ZygoteInit類主要做了5件事情:
1.註冊ZygoteSocket用的Socket
2.預加載類、資源、OpenGL
3.啓動system_server進程
4.在前面創建的 socket接口中等待ActivityManagerService請求,以創建新的應用程序進程
5.反射調用執行函數
1.建立IPC通信服務斷-registerZygoteSocket
zygote及系統中其他層序的通信沒有使用Binder,而是採用了基於AF_UNIX類型的Socket。registerZygoteSocket 函數就是使用的該Socket
/**
* Registers a server socket for zygote command connections
*
* @throws RuntimeException when open fails
*/
private static void registerZygoteSocket() {
if (sServerSocket == null) {
int fileDesc;
try {
//從環境變量中獲取Zygote Socket文件描述符,環境變量爲ANDROID_SOCKET_zygote=fd
String env = System.getenv(ANDROID_SOCKET_ENV);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(
ANDROID_SOCKET_ENV + " unset or invalid", ex);
}
try {
//根據文件描述符創建服務端Socket,並監聽
sServerSocket = new LocalServerSocket(
createFileDescriptor(fileDesc));
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
LocalServerSocket 的構造方法
/**
58 * Create a LocalServerSocket from a file descriptor that's already
59 * been created and bound. listen() will be called immediately on it.
60 * Used for cases where file descriptors are passed in via environment
61 * variables
62 *
63 * @param fd bound file descriptor
64 * @throws IOException
65 */
66 public LocalServerSocket(FileDescriptor fd) throws IOException
67 {
68 impl = new LocalSocketImpl(fd);
69 impl.listen(LISTEN_BACKLOG);
70 localAddress = impl.getSockAddress();
71 }
2.預加載類和資源和OpenGL
然後調用preload函數加載一些預加載操作:
static void preload() {
preloadClasses();
preloadResources();
preloadOpenGL();
}
preloadClasses()函數會預加載類:
/**
* Performs Zygote process initialization. Loads and initializes
* commonly used classes.
*
* Most classes only cause a few hundred bytes to be allocated, but
* a few will allocate a dozen Kbytes (in one case, 500+K).
*/
private static void preloadClasses() {
final VMRuntime runtime = VMRuntime.getRuntime();
//預加載類的信息存儲在PRELOADED_CLASSES變量中,它的值爲"preloaded-classes"
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(
PRELOADED_CLASSES);
......
try {
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 {
if (false) {
Log.v(TAG, "Preloading " + line + "...");
}
//通過Java反射來加載類,line中存儲的是預加載的類名
Class.forName(line);
if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
if (false) {
Log.v(TAG,
" GC at " + Debug.getGlobalAllocSize());
}
System.gc();
runtime.runFinalizationSync();
Debug.resetGlobalAllocSize();
}
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) {
Log.e(TAG, "Error preloading " + line + ".", t);
if (t instanceof Error) {
throw (Error) t;
}
if (t instanceof RuntimeException) {
throw (RuntimeException) 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);
// Restore default.
runtime.setTargetHeapUtilization(defaultUtilization);
// Fill in dex caches with classes, fields, and methods brought in by preloading.
runtime.preloadDexCaches();
Debug.stopAllocCounting();
// Bring back root. We'll need it later.
setEffectiveUser(ROOT_UID);
setEffectiveGroup(ROOT_GID);
}
}
}
rameworks\base\preloaded-classes
文件中保存了需要預先加載的類,整個加載過程十分耗時,這是android啓動緩慢的原因之一。
PreloadResource和preloadClass類似,它主要是加載framework-res.apk中的資源。在UI編程中常使用的com.android.R.XXX 資源是系統默認的資源,它們就是由zygote加載的
3.啓動system_server
startSystemServer函數會創建Java世界中系統Service所駐留的進程system_server,該進程是framework的核心。如果給進程結束,Zygote進程也會結束。
/**
* Prepare the arguments and fork for the system server process.
*/
private static boolean startSystemServer()
throws MethodAndArgsCaller, RuntimeException {
long capabilities = posixCapabilitiesAsBits(
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
);
//硬編碼設置system_server進程參數
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
"--capabilities=" + capabilities + "," + capabilities,
"--runtime-init",
"--nice-name=system_server",//system_server進程進程名
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
//將參數轉化成Arguments對象
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
//fork一個子進程,這個進程就是system_server進程
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
//system_server進程的工作
handleSystemServerProcess(parsedArgs);
}
//zygote進程返回true
return true;
}
zygote進行了一次無性繁殖,分裂出system_server.
- 循環接收等待請求-runSelectLoopMode
待zygote
從startSystemServer運回後,將進入第四個關鍵函數:runSelectLoopMode。前面在第一個關鍵點registerZygoteSocket中註冊的一個用於IPC的Socket,它的runSelectLoopMode中將體現出來 :
/**
* Runs the zygote process's select loop. Accepts new connections as
* they happen, and reads commands from connections one spawn-request's
* worth at a time.
*
* @throws MethodAndArgsCaller in a child process when a main() should
* be executed.
*/
private static void runSelectLoop() throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
FileDescriptor[] fdArray = new FileDescriptor[4];
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
int loopCount = GC_LOOP_COUNT;
while (true) {
int index;
/*
* Call gc() before we block in select().
* It's work that has to be done anyway, and it's better
* to avoid making every child do it. It will also
* madvise() any free memory as a side-effect.
*
* Don't call it every time, because walking the entire
* heap is a lot of overhead to free a few hundred bytes.
*/
if (loopCount <= 0) {
gc();
loopCount = GC_LOOP_COUNT;
} else {
loopCount--;
}
try {
fdArray = fds.toArray(fdArray);
/*
selectReadable 內部調用select,使用多路複用I/O模型。
當有客戶端連接或有數據時,則selectReadable就會返回。
當有新的連接時,返回ServerSocket的數組下標0
當有Socket數據可讀取時,返回 ZygoteConnectionSocket的數組下標
*/
index = selectReadable(fdArray);
} catch (IOException ex) {
throw new RuntimeException("Error in select()", ex);
}
if (index < 0) {
throw new RuntimeException("Error in select()");
} else if (index == 0) {
//有一個客戶端連接上。客戶端在Zygote的代表ZygoteConnection,它包裝了LocalSocket對象
ZygoteConnection newPeer = acceptCommandPeer();
//將返回的ZygoteConnection對應添加到集合中。
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done;
//客戶端有數組傳送時,找到對應的ZygoteConnection,調用runOnce()方法進行處理
done = peers.get(index).runOnce();
//處理完成後從集合中移除相應的ZygoteConnection;
if (done) {
peers.remove(index);
fds.remove(index);
}
}
}
}
runSelectLoop比較簡單,就是
1.處理客戶連接和客戶請求。其中客戶在zygote中用ZygoteConnection對象來表示。
2客戶的請求由ZygoteConnection的runOnce來處理。
2.3 關於Zygote的總結
整個Zygote創建Java世界的步驟:
1.調用startVm創建虛擬機對象。
2.調用startReg註冊好定義的JNI函數。
3.調用找到”com.android.internal.os.ZygoteInit”類的static main 函數進入Java世界
4.註冊ZygoteSocket用的Socket
5.預加載類、資源、OpenGL
6.啓動system_server進程
7.在前面創建的 socket接口中等待ActivityManagerService請求,以創建新的應用程序進程
二、SystemServer 分析
2.1 SystemServer的創建
SystemServer的進程名實際上叫做system_server
,這裏我們可將其簡稱爲SS:
/**
* Prepare the arguments and fork for the system server process.
*/
private static boolean startSystemServer()
throws MethodAndArgsCaller, RuntimeException {
long capabilities = posixCapabilitiesAsBits(
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
);
//硬編碼設置system_server進程參數
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
"--capabilities=" + capabilities + "," + capabilities,
"--runtime-init",
"--nice-name=system_server",//system_server進程進程名
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
//將參數轉化成Arguments對象
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
//fork一個子進程,這個進程就是system_server進程
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
//system_server進程的工作
handleSystemServerProcess(parsedArgs);
}
//zygote進程返回true
return true;
}
從上面的代碼我們可以看出,SS是由Zygote通過Zygote.forkSystemServer
函數fork誕生出來,它是一個native函數,實現在dalvik_system_Zygote.c
中,如下
/*
* native public static int nativeForkSystemServer(int uid, int gid,
* int[] gids, int debugFlags, int[][] rlimits,
* long permittedCapabilities, long effectiveCapabilities);
*/
static void Dalvik_dalvik_system_Zygote_forkSystemServer(
const u4* args, JValue* pResult)
{
pid_t pid;
//根據參數,fork子進程
pid = forkAndSpecializeCommon(args, true);
/* The zygote process checks whether the child process has died or not. */
if (pid > 0) {
int status;
ALOGI("System server process %d has been created", pid);
//保存system_server進程的進程ID
gDvm.systemServerPid = pid;
/* There is a slight window that the system server process has crashed
* but it went unnoticed because we haven't published its pid yet. So
* we recheck here just to make sure that all is well.
*/
//退出前檢查剛纔創建的system_server子進程是否退出
if (waitpid(pid, &status, WNOHANG) == pid) {
ALOGE("System server process %d has died. Restarting Zygote!", pid);
//如果system_server子進程退出,則幹掉zygote進程,重啓zygote進程。
kill(getpid(), SIGKILL);
}
}
RETURN_INT(pid);
}
forkAndSpecializeCommon
函數:
/*
* Utility routine to fork zygote and specialize the child process.
*/
static pid_t forkAndSpecializeCommon(const u4* args, bool isSystemServer)
{
pid_t pid;
//設置進程信息
uid_t uid = (uid_t) args[0];
gid_t gid = (gid_t) args[1];
ArrayObject* gids = (ArrayObject *)args[2];
u4 debugFlags = args[3];
ArrayObject *rlimits = (ArrayObject *)args[4];
u4 mountMode = MOUNT_EXTERNAL_NONE;
int64_t permittedCapabilities, effectiveCapabilities;
char *seInfo = NULL;
char *niceName = NULL;
....
//設置信號處理函數
setSignalHandler();
dvmDumpLoaderStats("zygote");
//fork子進程
pid = fork();
if (pid == 0) {
//對子進程進行一些處理工作,如設置進程名,設置各種ID等
int err;
/* The child process */
...
} else if (pid > 0) {
/* the parent process */
free(seInfo);
free(niceName);
}
return pid;
}
查看setSignalHandler
函數,它由Zygote
在fork
子進程前調用
/*
* configure sigchld handler for the zygote process
* This is configured very late, because earlier in the dalvik lifecycle
* we can fork() and exec() for the verifier/optimizer, and we
* want to waitpid() for those rather than have them be harvested immediately.
*
* This ends up being called repeatedly before each fork(), but there's
* no real harm in that.
*/
static void setSignalHandler()
{
int err;
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigchldHandler;
err = sigaction (SIGCHLD, &sa, NULL);
if (err < 0) {
ALOGW("Error setting SIGCHLD handler: %s", strerror(errno));
}
}
/*
* This signal handler is for zygote mode, since the zygote
* must reap its children
*/
static void sigchldHandler(int s)
{
pid_t pid;
int status;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
/* Log process-death status that we care about. In general it is not
safe to call ALOG(...) from a signal handler because of possible
reentrancy. However, we know a priori that the current implementation
of ALOG() is safe to call from a SIGCHLD handler in the zygote process.
If the ALOG() implementation changes its locking strategy or its use
of syscalls within the lazy-init critical section, its use here may
become unsafe. */
/*
* If the just-crashed process is the system_server, bring down zygote
* so that it is restarted by init and system server will be restarted
* from there.
*/
//如果死去的進程是SS,則Zygote把自己也幹掉了,
if (pid == gDvm.systemServerPid) {
ALOG(LOG_INFO, ZYGOTE_LOG_TAG,
"Exit zygote because system server (%d) has terminated",
(int) pid);
kill(getpid(), SIGKILL);
}
}
if (pid < 0) {
ALOG(LOG_WARN, ZYGOTE_LOG_TAG,
"Zygote SIGCHLD error in waitpid: %s",strerror(errno));
}
}
SystemServer與Zygote進程生死與共。
2.2 SystemServer的重要使命
SystemServer
,創建以後它的主要任務什麼?
...
/* For child process */
if (pid == 0) {
//system_server進程的工作
handleSystemServerProcess(parsedArgs);
}
...
然後我們查看 handleSystemServerProcess()
方法:
ZygoteInit.java
/**
* Finish remaining work for the newly forked system server process.
*/
private static void handleSystemServerProcess(
ZygoteConnection.Arguments parsedArgs)
throws ZygoteInit.MethodAndArgsCaller {
//關閉從Zygote那裏繼承下來的Socket.
closeServerSocket();
// set umask to 0077 so new files and directories will default to owner-only permissions.
Libcore.os.umask(S_IRWXG | S_IRWXO);
if (parsedArgs.niceName != null) {
//設置當前Systemserver進程名爲system_server
Process.setArgV0(parsedArgs.niceName);
}
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
null, parsedArgs.remainingArgs);
} else {
/*
* Pass the remaining arguments to SystemServer.
*/
//調用ZygoteInit函數
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
}
/* should never reach here */
}
在上述代碼中,調用函數closeServerSocket
後,
然後調用RuntimeInit.zygoteInit方法進行初始化
RuntimeInit.java
/**
* The main function called when started through the zygote process. This
* could be unified with main(), if the native code in nativeFinishInit()
* were rationalized with Zygote startup.<p>
*
* Current recognized args:
* <ul>
* <li> <code> [--] <start class name> <args>
* </ul>
*
* @param targetSdkVersion target SDK version
* @param argv arg strings
*/
public static final void zygoteInit(int targetSdkVersion, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
redirectLogStreams();
//做常規初始化,設置System進程的時區和鍵盤佈局。
commonInit();
//調用函數nativeZygoteInit啓動一個Binder線程池。
nativeZygoteInit();
applicationInit(targetSdkVersion, argv);
}
applicationInit方法
# RuntimeInit.java
private static void applicationInit(int targetSdkVersion, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
...
// Remaining arguments are passed to the start class's static main
invokeStaticMain(args.startClass, args.startArgs);
}
invokeStaticMain()方法
RuntimeInit.java
/**
* Invokes a static "main(argv[]) method on class "className".
* Converts various failing exceptions into RuntimeExceptions, with
* the assumption that they will then cause the VM instance to exit.
*
* @param className Fully-qualified class name
* @param argv Argument vector for main()
*/
private static void invokeStaticMain(String className, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
//className爲"com.android.server.SystemServer"
Class<?> cl;
try {
cl = Class.forName(className);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
//找到com.android.server.SystemServer類的main函數。
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}
int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}
/*
* This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/
//拋出異常,在ZygoteInit.main()方法中被捕獲,然後調用run方法執行main函數
//這樣做的目的是清除設置進程信息中的堆棧
throw new ZygoteInit.MethodAndArgsCaller( , argv);
}
拋出異常,在ZygoteInit.main()方法中被捕獲,然後調用run方法執行main函數這樣做的目的是清除設置進程信息中
Zygote.java
try {
...
startSystemServer();//3.啓動system_server進程
...
//調用函數runSelectLoop進入一個無限循環
//4.在前面創建的 socket接口中等待ActivityManagerService請求,以創建新的應用程序進程
runSelectLoop();
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
//5.反射調用執行函數
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
2.3 SystemServer的main函數詳解
ZygoteInit分裂產生的SystemServer,主要是爲了調用frameworks\base\services\java\com\android\server\SystemServer.java
類的main函數
#frameworks\base\services\java\com\android\server\SystemServer.java
public static void main(String[] args) {
/*
* In case the runtime switched since last boot (such as when
* the old runtime was removed in an OTA), set the system
* property so that it is in sync. We can't do this in
* libnativehelper's JniInvocation::Init code where we already
* had to fallback to a different runtime because it is
* running as root and we need to be the system user to set
* the property. http://b/11463182
*/
SystemProperties.set("persist.sys.dalvik.vm.lib",
VMRuntime.getRuntime().vmLibrary());
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
// If a device's clock is before 1970 (before 0), a lot of
// APIs crash dealing with negative numbers, notably
// java.io.File#setLastModified, so instead we fake it and
// hope that time from cell towers or NTP fixes it
// shortly.
Slog.w(TAG, "System clock is before 1970; setting to 1970.");
SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
}
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfilerIntegration.start();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
//SystemServer性能分析,每小時統計一次
SamplingProfilerIntegration.writeSnapshot("system_server", null);
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
}
//和Dalvik虛擬機相關的設置。主要是內存使用方面的控制
// Mmmmmm... more memory!
dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
Environment.setUserRequired(true);
//加載動態庫libandroid_server.so庫,調用nativeInit函數進行初始化。
System.loadLibrary("android_servers");
Slog.i(TAG, "Entered the Android system server!");
// Initialize native services.
//初始化native服務,本版本中只是啓動了傳感器服務
nativeInit();
// This used to be its own separate thread, but now it is
// just the loop we run on the main thread.
//ServerThread過去用在獨立才線程中,現在用在主線程中
ServerThread thr = new Serve rThread();
//在initAndLoop方法中創建各種服務
thr.initAndLoop();
}
在main方法中加載android_servers.so庫,啓動native服務
#frameworks\base\services\jni\com_android_server_SystemServer.cpp
static void android_server_SystemServer_nativeInit(JNIEnv* env, jobject clazz) {
char propBuf[PROPERTY_VALUE_MAX];
property_get("system_init.startsensorservice", propBuf, "1");
if (strcmp(propBuf, "1") == 0) {
// Start the sensor service
//啓動傳感器服務
SensorService::instantiate();
}
}
然後創建ServerThread對象,調用initAndLoop方法在主線程中創建各種服務對象
#frameworks\base\services\java\com\android\server\SystemServer.java
public void initAndLoop() {
...
//在當前線程中設置Looper對象,Looper內部有消息隊列
Looper.prepareMainLooper();
//在當前線程中設置Looper對象,Looper內部有消息隊列
Looper.prepareMainLooper();
......
//創建ActivityManagerService對象
context = ActivityManagerService.main(factoryTest);
......
//啓動PackageManagerService服務
pm = PackageManagerService.main(context, installer,
factoryTest != SystemServer.FACTORY_TEST_OFF,
onlyCore);
......
//將ActivityManagerService服務對象添加到ServiceManager對中
ActivityManagerService.setSystemProcess();
......
Looper.loop();
三、應用程序創建進程詳解(zygote的分裂)
在啓動Android應用程序過程中,除了可以獲得虛擬機實例外,還可以獲得一個消息循環和Binder線程池。這樣
在應用程序中運行的組件,可以使用系統的信息處理機制和Binder通信機制實現自己的業務邏輯。
zygote 分裂出嫡長子system_server後,通過runSelectLoopMode等待並處理來自客戶信息,
這個信息由ActivityManagerService發送
3.1 ActivityManagerService發送請求
ActivityManagerService也是由SystemServer創建。當我們通過startActivity來啓動一個新的Activity,而這個Activity
附屬於一個還未啓動的進程,這個進程由ActivityManagerService中的startProcessLocked創建。
# frameworks\base\services\java\com\android\server\am\ActivityManagerService.java
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
if (app.pid > 0 && app.pid != MY_PID) {
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(app.pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
app.setPid(0);
}
if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
"startProcessLocked removing on hold: " + app);
mProcessesOnHold.remove(app);
updateCpuStats();
//獲取創建應用程序進程的用戶ID和用戶組ID
try {
int uid = app.uid;
int[] gids = null;
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
if (!app.isolated) {
int[] permGids = null;
try {
final PackageManager pm = mContext.getPackageManager();
permGids = pm.getPackageGids(app.info.packageName);
//檢查是否有獲取外部存儲的權限,有的話掛載
if (Environment.isExternalStorageEmulated()) {
if (pm.checkPermission(
android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE,
app.info.packageName) == PERMISSION_GRANTED) {
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL;
} else {
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
}
}
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Unable to retrieve gids", e);
}
/*
* Add shared application GID so applications can share some
* resources like shared libraries
*/
//添加共享組應用ID以便共享資源
if (permGids == null) {
gids = new int[1];
} else {
gids = new int[permGids.length + 1];
System.arraycopy(permGids, 0, gids, 1, permGids.length);
}
gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
}
if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
&& mTopComponent != null
&& app.processName.equals(mTopComponent.getPackageName())) {
uid = 0;
}
if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
&& (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
uid = 0;
}
}
int debugFlags = 0;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
// Also turn on CheckJNI for debuggable apps. It's quite
// awkward to turn on otherwise.
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
// Run the app in safe mode if its manifest requests so or the
// system is booted in safe mode.
if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
Zygote.systemInSafeMode == true) {
debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
}
if ("1".equals(SystemProperties.get("debug.checkjni"))) {
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
if ("1".equals(SystemProperties.get("debug.jni.logging"))) {
debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
}
if ("1".equals(SystemProperties.get("debug.assert"))) {
debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
}
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
//調用函數start創建應用程序進程,調用成功後返回的結果中有進程ID,調用失敗後會拋出異常。Process類由android提供,非jdk
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, null);
BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
synchronized (bs) {
if (bs.isOnBattery()) {
bs.getProcessStatsLocked(app.uid, app.processName).incStartsLocked();
}
}
EventLog.writeEvent(EventLogTags.AM_PROC_START,
UserHandle.getUserId(uid), startResult.pid, uid,
app.processName, hostingType,
hostingNameStr != null ? hostingNameStr : "");
if (app.persistent) {
Watchdog.getInstance().processStarted(app.processName, startResult.pid);
}
StringBuilder buf = mStringBuilder;
buf.setLength(0);
buf.append("Start proc ");
buf.append(app.processName);
buf.append(" for ");
buf.append(hostingType);
if (hostingNameStr != null) {
buf.append(" ");
buf.append(hostingNameStr);
}
buf.append(": pid=");
buf.append(startResult.pid);
buf.append(" uid=");
buf.append(uid);
buf.append(" gids={");
if (gids != null) {
for (int gi=0; gi<gids.length; gi++) {
if (gi != 0) buf.append(", ");
buf.append(gids[gi]);
}
}
buf.append("}");
Slog.i(TAG, buf.toString());
app.setPid(startResult.pid);
app.usingWrapper = startResult.usingWrapper;
app.removed = false;
synchronized (mPidsSelfLocked) {
this.mPidsSelfLocked.put(startResult.pid, app);
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, startResult.usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
} catch (RuntimeException e) {
// XXX do better error recovery.
app.setPid(0);
Slog.e(TAG, "Failure starting process " + app.processName, e);
}
}
在該方法中,調用了Android中Process類的start方法,並傳遞了android.app.ActivityThread字符串參數
#frameworks\base\core\java\android\Process.java
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String[] zygoteArgs) {
try {
//調用函數startViaZygote讓Zygote進程創建一個應用程序進程,processClass的值爲"android.app.ActivityThread"
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
在該方法中,調用了startViaZygote
方法,該方法是將要創建的應用程序進程的啓動參數,封裝到名爲argsForZygote
列表中,
並調用zygoteSendArgsAndGetPid
函數請求進程Zygote進程創建應用程序。
#frameworks\base\core\java\android\Process.java
private static ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
//將參數封裝到argsForZygote列表中
ArrayList<String> argsForZygote = new ArrayList<String>();
// --runtime-init, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-init");//這個參數很重要
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {
argsForZygote.add("--enable-jni-logging");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
argsForZygote.add("--enable-safemode");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
argsForZygote.add("--enable-debugger");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
argsForZygote.add("--enable-checkjni");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
argsForZygote.add("--enable-assert");
}
if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) {
argsForZygote.add("--mount-external-multiuser");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL) {
argsForZygote.add("--mount-external-multiuser-all");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
//TODO optionally enable debuger
//argsForZygote.add("--enable-debugger");
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
}
argsForZygote.add(processClass);
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
//請求進程Zygote創建應用程序
return zygoteSendArgsAndGetResult(argsForZygote);
}
}
在zygoteSendArgsAndGetPid
函數中,首先調用函數openZygoteSocketIfNeeded
創建一個連接到Zygote進程的本地對象LocalSocket
,然後將
封裝好的參數通過socket發送到zygote進程中
#frameworks\base\core\java\android\Process.java
private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)
throws ZygoteStartFailedEx {
//調用函數openZygoteSocketIfNeeded創建一個連接到Zygote進程的本地對象LocalSocket.
openZygoteSocketIfNeeded();
try {
/**
* See com.android.internal.os.ZygoteInit.readArgumentList()
* Presently the wire format to the zygote process is:
* a) a count of arguments (argc, in essence)
* b) a number of newline-separated argument strings equal to count
*
* After the zygote process reads these it will write the pid of
* the child or -1 on failure, followed by boolean to
* indicate whether a wrapper process was used.
*/
/**
*將要創建的應用程序進程啓動參數列表寫入到本地對象LocalSocket中
*Zygote進程接收到數據之後會創建一個新的應用程序進程,將創建的進程Pid
*返回給ActivityManagerService
*/
sZygoteWriter.write(Integer.toString(args.size()));
sZygoteWriter.newLine();
int sz = args.size();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
if (arg.indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx(
"embedded newlines not allowed");
}
sZygoteWriter.write(arg);
sZygoteWriter.newLine();
}
sZygoteWriter.flush();
// Should there be a timeout on this?
ProcessStartResult result = new ProcessStartResult();
//將返回進程ID保存在ProcessStartResult中
result.pid = sZygoteInputStream.readInt();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
result.usingWrapper = sZygoteInputStream.readBoolean();
return result;
} catch (IOException ex) {
try {
if (sZygoteSocket != null) {
sZygoteSocket.close();
}
} catch (IOException ex2) {
// we're going to fail anyway
Log.e(LOG_TAG,"I/O exception on routine close", ex2);
}
sZygoteSocket = null;
throw new ZygoteStartFailedEx(ex);
}
}
openZygoteSocketIfNeeded函數創建一個連接到Zygote進程的本地對象LocalSocket
#frameworks\base\core\java\android\Process.java
private static void openZygoteSocketIfNeeded()
throws ZygoteStartFailedEx {
int retryCount;
if (sPreviousZygoteOpenFailed) {
/*
* If we've failed before, expect that we'll fail again and
* don't pause for retries.
*/
retryCount = 0;
} else {
retryCount = 10;
}
/*
* See bug #811181: Sometimes runtime can make it up before zygote.
* Really, we'd like to do something better to avoid this condition,
* but for now just wait a bit...
*/
for (int retry = 0
; (sZygoteSocket == null) && (retry < (retryCount + 1))
; retry++ ) {
if (retry > 0) {
try {
Log.i("Zygote", "Zygote not up yet, sleeping...");
Thread.sleep(ZYGOTE_RETRY_MILLIS);
} catch (InterruptedException ex) {
// should never happen
}
}
try {
//創建一個名爲sZygoteSocket的LocalSocket的對象
sZygoteSocket = new LocalSocket();
//將sZygoteSocket對象名爲zygote的Socket地址進行連接
sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,
LocalSocketAddress.Namespace.RESERVED));
//將sZygoteSocket對象的輸入流保存在sZygoteInputStream中
sZygoteInputStream
= new DataInputStream(sZygoteSocket.getInputStream());
//將sZygoteSocket對象的輸出流保存在sZygoteWriter
sZygoteWriter =
new BufferedWriter(
new OutputStreamWriter(
sZygoteSocket.getOutputStream()),
256);
Log.i("Zygote", "Process: zygote socket opened");
sPreviousZygoteOpenFailed = false;
break;
} catch (IOException ex) {
if (sZygoteSocket != null) {
try {
sZygoteSocket.close();
} catch (IOException ex2) {
Log.e(LOG_TAG,"I/O exception on close after exception",
ex2);
}
}
sZygoteSocket = null;
}
}
if (sZygoteSocket == null) {
sPreviousZygoteOpenFailed = true;
throw new ZygoteStartFailedEx("connect failed");
}
}
3.2 Zygote等待請求創建應用程序進程
在第一節中我們知道,Zygote
在runSelectLoopMode()
方法中循環等待Socket連接
# \frameworks\base\core\java\com\android\internal\os\ZygoteInit.java
private static void runSelectLoop() throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
FileDescriptor[] fdArray = new FileDescriptor[4];
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
int loopCount = GC_LOOP_COUNT;
while (true) {
int index;
/*
* Call gc() before we block in select().
* It's work that has to be done anyway, and it's better
* to avoid making every child do it. It will also
* madvise() any free memory as a side-effect.
*
* Don't call it every time, because walking the entire
* heap is a lot of overhead to free a few hundred bytes.
*/
if (loopCount <= 0) {
gc();
loopCount = GC_LOOP_COUNT;
} else {
loopCount--;
}
try {
fdArray = fds.toArray(fdArray);
/*
selectReadable 內部調用select,使用多路複用I/O模型。
當有客戶端連接或有數據時,則selectReadable就會返回。
當有新的連接時,返回ServerSocket的數組下標0
當有Socket數據可讀取時,返回 ZygoteConnectionSocket的數組下標
*/
index = selectReadable(fdArray);
} catch (IOException ex) {
throw new RuntimeException("Error in select()", ex);
}
if (index < 0) {
throw new RuntimeException("Error in select()");
} else if (index == 0) {
//有一個客戶端連接上。客戶端在Zygote的代表ZygoteConnection,它包裝了LocalSocket對象
ZygoteConnection newPeer = acceptCommandPeer();
//將返回的ZygoteConnection對應添加到集合中。
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done;
//客戶端有數組傳送時,找到對應的ZygoteConnection,調用runOnce()方法進行處理
done = peers.get(index).runOnce();
//處理完成後從集合中移除相應的ZygoteConnection;
if (done) {
peers.remove(index);
fds.remove(index);
}
}
}
}
每當有請求數據發來時,Zygote就會調用ZygoteConnection的runOnce函數
# frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
args = readArgumentList();//獲得啓動要創建應用程序進程的參數
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
Log.w(TAG, "IOException on command socket " + ex.getMessage());
closeSocket();
return true;
}
if (args == null) {
// EOF reached.
closeSocket();
return true;
}
/** the stderr of the most recent request, if avail */
PrintStream newStderr = null;
if (descriptors != null && descriptors.length >= 3) {
newStderr = new PrintStream(
new FileOutputStream(descriptors[2]));
}
int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;
try {
parsedArgs = new Arguments(args);
applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyCapabilitiesSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyDebuggerSystemProperty(parsedArgs);
applyInvokeWithSystemProperty(parsedArgs);
int[][] rlimits = null;
if (parsedArgs.rlimits != null) {
rlimits = parsedArgs.rlimits.toArray(intArray2d);
}
if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) {
FileDescriptor[] pipeFds = Libcore.os.pipe();
childPipeFd = pipeFds[1];
serverPipeFd = pipeFds[0];
ZygoteInit.setCloseOnExec(serverPipeFd, true);
}
//調用函數forkAndSpecialize創建應用程序進程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName);
} catch (IOException ex) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} 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) {
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
//子進程處理,這個子進程是我們要創建的對應Activity子進程
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
// should never get here, the child is expected to either
// throw ZygoteInit.MethodAndArgsCaller or exec().
return true;
} else {
// in parent...pid of < 0 means failure
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
在上述代碼中,通過函數readArgumentList獲得啓動進程的參數,並通過forkAndSpecialize創建這個要啓動應用程序的進程.
readArgumentList方法
# frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java
private String[] readArgumentList()
throws IOException {
/**
* See android.os.Process.zygoteSendArgsAndGetPid()
* Presently the wire format to the zygote process is:
* a) a count of arguments (argc, in essence)
* b) a number of newline-separated argument strings equal to count
*
* After the zygote process reads these it will write the pid of
* the child or -1 on failure.
*/
int argc;
try {
String s = mSocketReader.readLine();
if (s == null) {
// EOF reached.
return null;
}
argc = Integer.parseInt(s);
} catch (NumberFormatException ex) {
Log.e(TAG, "invalid Zygote wire format: non-int at argc");
throw new IOException("invalid wire format");
}
// See bug 1092107: large argc can be used for a DOS attack
if (argc > MAX_ZYGOTE_ARGC) {
throw new IOException("max arg count exceeded");
}
String[] result = new String[argc];
for (int i = 0; i < argc; i++) {
result[i] = mSocketReader.readLine();
if (result[i] == null) {
// We got an unexpected EOF.
throw new IOException("truncated request");
}
}
return result;
}
如果是子進程,會調用handleChildProc
方法來啓動這個子進程:
# frameworks\base\core\java\com\android\internal\os\ZygoteConnection.java
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
//關閉用於接收消息的ClientScoket
closeSocket();
//關閉繼承繼承下來的ServerSocket
ZygoteInit.closeServerSocket();
if (descriptors != null) {
try {
ZygoteInit.reopenStdio(descriptors[0],
descriptors[1], descriptors[2]);
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
newStderr = System.err;
} catch (IOException ex) {
Log.e(TAG, "Error reopening stdio", ex);
}
}
//設置當前進程名
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}
//由於之前設置了runtimeInit函數,因此會進入該分支
if (parsedArgs.runtimeInit) {
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
pipeFd, parsedArgs.remainingArgs);
} else {
//沒有設置invokeWith參數,會進入到下面的分支中
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs);
}
} else {
String className;
try {
className = parsedArgs.remainingArgs[0];
} catch (ArrayIndexOutOfBoundsException ex) {
logAndPrintError(newStderr,
"Missing required class name argument", null);
return;
}
String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];
System.arraycopy(parsedArgs.remainingArgs, 1,
mainArgs, 0, mainArgs.length);
if (parsedArgs.invokeWith != null) {
WrapperInit.execStandalone(parsedArgs.invokeWith,
parsedArgs.classpath, className, mainArgs);
} else {
ClassLoader cloader;
if (parsedArgs.classpath != null) {
cloader = new PathClassLoader(parsedArgs.classpath,
ClassLoader.getSystemClassLoader());
} else {
cloader = ClassLoader.getSystemClassLoader();
}
try {
ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
} catch (RuntimeException ex) {
logAndPrintError(newStderr, "Error starting.", ex);
}
}
}
}
接着會調用RuntimeInit.zygoteInit方法進一步初始化該進程
# frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
public static final void zygoteInit(int targetSdkVersion, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
redirectLogStreams();
//做常規初始化,設置System進程的時區和鍵盤佈局。
commonInit();
//調用函數nativeZygoteInit啓動一個Binder線程池。
nativeZygoteInit();
applicationInit(targetSdkVersion, argv);
}
在applicationInit方法中,會調用 invokeStaticMain方法啓動android.app.ActivityThread類的main函數
# frameworks\base\core\java\com\android\internal\os\RuntimeInit.java
private static void applicationInit(int targetSdkVersion, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks. It is not possible to
// shutdown an Android application gracefully. Among other things, the
// Android runtime shutdown hooks close the Binder driver, which can cause
// leftover running threads to crash before the process actually exits.
nativeSetExitWithoutCleanup(true);
// We want to be fairly aggressive about heap utilization, to avoid
// holding on to a lot of memory that isn't needed.
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args;
try {
args = new Arguments(argv);
} catch (IllegalArgumentException ex) {
Slog.e(TAG, ex.getMessage());
// let the process exit
return;
}
//調用startClass,也就是com.android.server.SystemServer函數
// Remaining arguments are passed to the start class's static main
invokeStaticMain(args.startClass, args.startArgs);
}
通過分析我們知道android.app.ActivityThread類實際上是Android中apk程序所對應的進程,它的main函數也就是
apk程序的main函數。
系統運行的apk程序,其父進程都是zygote進程 。