5、zygote
Zygote进程是Android中所有Java进程的父进程。Zygote进程在Init进程启动过程中被以service服务的形式启动。从android5.0开始,android开始支持64位的编译,zygote本身也就有了32位和64位的区别,所以在这里用ro.zygote属性来控制启动不同版本的zygote进程。init.rc位于/system/core/rootdir下。在这个路径下还包括四个关于zygote的rc文件。分别是Init.zygote32.rc,Init.zygote32_64.rc,Init.zygote64.rc,Init.zygote64_32.rc。由硬件决定调用哪个文件。由于现在新款手机大多只支持64位应用,以init.zygote64.rc为例,其内容如下
// /system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main //伴随着main class的启动而启动
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system //创建socket
socket usap_pool_primary stream 660 root system
onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
# NOTE: If the wakelock name here is changed, then also
# update it in SystemSuspend.cpp
onrestart write /sys/power/wake_lock zygote_kwl
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media //当zygote重启时,则会重启media
onrestart restart media.tuner
onrestart restart netd // 当zygote重启时,则会重启netd网络管理
onrestart restart wificond
task_profiles ProcessCapacityHigh MaxPerformance
critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
在Init.zygote64.rc文件中,定义了两个zygote服务:zygote和zygote_secondary。由关键字service告诉init进程创建一个名为zygote的进程,这个进程的要执行的程是/system/bin/app_process64,给这个进程传递了有五个参数,分别是
- Xzygote
/system/bin
–zygote
–start-system-server
–socket-name=zygote
zygote最初的名字是app_process,他对应的源代码是app_main(),init进程解析init.zygote64.rc配置文件之后,会调用app_process
5.1app_main
// /frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
if (!LOG_NDEBUG) {
String8 argv_String;
for (int i = 0; i < argc; ++i) {
argv_String.append("\"");
argv_String.append(argv[i]);
argv_String.append("\" ");
}
ALOGV("app_process main with argv: %s", argv_String.string());
}
// 创建了android运行时环境
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments
// ignore argv[0]
argc--;
argv++;
// Everything up to '--' or first non '-' arg goes to the vm.
//
// The first argument after the VM args is the "parent dir", which
// is currently unused.
//
// After the parent dir, we expect one or more the following internal
// arguments :
//
// --zygote : Start in zygote mode
// --start-system-server : Start the system server.
// --application : Start in application (stand alone, non zygote) mode.
// --nice-name : The nice name for this process.
//
// For non zygote starts, these arguments will be followed by
// the main class name. All remaining arguments are passed to
// the main method of this class.
//
// For zygote starts, all remaining arguments are passed to the zygote.
// main function.
//
// Note that we must copy argument string values since we will rewrite the
// entire argument block when we apply the nice name to argv0.
//
// As an exception to the above rule, anything in "spaced commands"
// goes to the vm even though it has a space in it.
const char* spaced_commands[] = { "-cp", "-classpath" };
// Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
bool known_command = false;
int i;
for (i = 0; i < argc; i++) {
if (known_command == true) {
runtime.addOption(strdup(argv[i]));
// The static analyzer gets upset that we don't ever free the above
// string. Since the allocation is from main, leaking it doesn't seem
// problematic. NOLINTNEXTLINE
ALOGV("app_process main add known option '%s'", argv[i]);
known_command = false;
continue;
}
for (int j = 0;
j < static_cast<int>(sizeof(spaced_commands) / sizeof(spaced_commands[0]));
++j) {
if (strcmp(argv[i], spaced_commands[j]) == 0) {
known_command = true;
ALOGV("app_process main found known command '%s'", argv[i]);
}
}
if (argv[i][0] != '-') {
break;
}
if (argv[i][1] == '-' && argv[i][2] == 0) {
++i; // Skip --.
break;
}
runtime.addOption(strdup(argv[i]));
// The static analyzer gets upset that we don't ever free the above
// string. Since the allocation is from main, leaking it doesn't seem
// problematic. NOLINTNEXTLINE
ALOGV("app_process main add option '%s'", argv[i]);
}
// 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;
}
}
Vector<String8> args;
if (!className.isEmpty()) {
// We're not in zygote mode, the only argument we need to pass
// to RuntimeInit is the application argument.
//
// The Remainder of args get passed to startup class main(). Make
// copies of them before we overwrite them with the process name.
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);
if (!LOG_NDEBUG) {
String8 restOfArgs;
char* const* argv_new = argv + i;
int argc_new = argc - i;
for (int k = 0; k < argc_new; ++k) {
restOfArgs.append("\"");
restOfArgs.append(argv_new[k]);
restOfArgs.append("\" ");
}
ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
}
} else {
// We're in zygote mode.
maybeCreateDalvikCache();
if (startSystemServer) {
args.add(String8("start-system-server"));
}
char prop[PROP_VALUE_MAX];
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
ABI_LIST_PROPERTY);
return 11;
}
String8 abiFlag("--abi-list=");
abiFlag.append(prop);
args.add(abiFlag);
// In zygote mode, pass all remaining arguments to the zygote
// main() method.
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
if (zygote) {
//执行ZygoteInit.java的start方法
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (!className.isEmpty()) {
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.");
}
}
5.2start()
执行到frameworks/base/core/jni/AndroidRuntime.cpp的start()方法
// /frameworks/base/core/jni/AndroidRuntime.cpp
/*
* 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 Vector<String8>& options, bool zygote)
{
ALOGD(">>>>>> START %s uid %d <<<<<<\n",
className != NULL ? className : "(unknown)", getuid());
static const String8 startSystemServer("start-system-server");
// Whether this is the primary zygote, meaning the zygote which will fork system server.
bool primary_zygote = false;
//根据options参数判断是否是第一次启动zygote
/*
* 'startSystemServer == true' means runtime is obsolete and not run from
* init.rc anymore, so we print out the boot start event here.
*/
for (size_t i = 0; i < options.size(); ++i) {
if (options[i] == startSystemServer) {
primary_zygote = true;
/* 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目录环境变量
const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
if (!hasDir("/system")) {
LOG_FATAL("No root directory specified, and /system does not exist.");
return;
}
setenv("ANDROID_ROOT", rootDir, 1);
}
const char* artRootDir = getenv("ANDROID_ART_ROOT");
if (artRootDir == NULL) {
LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable.");
return;
}
const char* i18nRootDir = getenv("ANDROID_I18N_ROOT");
if (i18nRootDir == NULL) {
LOG_FATAL("No runtime directory specified with ANDROID_I18N_ROOT environment variable.");
return;
}
const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT");
if (tzdataRootDir == NULL) {
LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable.");
return;
}
//const char* kernelHack = getenv("LD_ASSUME_KERNEL");
//ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
/* start the virtual machine */
//启动虚拟机,并执行相应初始化操作的函数。startVm函数会启动一个Java虚拟机,并将其保存在mJavaVM变量中。该函数会返回一个JNIEnv指针,用于后续与Java层进行交互。
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
return;
}
//在虚拟机启动完成后执行一些初始化操作
onVmCreated(env);
/*
* Register android functions.
*/
//注册 Android 相关的本地方法
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.
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
for (size_t i = 0; i < options.size(); ++i) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
assert(optionsStr != NULL);
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}
/*
* 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 {
// 调用ZygoteInit类的main()方法
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");
}
startVm启动Dalvik虚拟机
// /frameworks/base/core/jni/AndroidRuntime.cpp start()方法下面
/*
* Start the Dalvik Virtual Machine.
*
* Various arguments, most determined by system properties, are passed in.
* The "mOptions" vector is updated.
*
* CAUTION: when adding options in here, be careful not to put the
* char buffer inside a nested scope. Adding the buffer to the
* options using mOptions.add() does not copy the buffer, so if the
* buffer goes out of scope the option may be overwritten. It's best
* to put the buffer at the top of the function so that it is more
* unlikely that someone will surround it in a scope at a later time
* and thus introduce a bug.
*
* Returns 0 on success.
*/
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool primary_zygote)
{
JavaVMInitArgs initArgs;
// 省略的代码非常长,主要是为ART虚拟机准备启动参数
...
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.
*/
// 前半部分是在处理虚拟机的启动参数,处理完配置参数后,会调用libart.so提供的一个接口:JNI_CreateJavaVM函数
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
return -1;
}
return 0;
}
// /art/runtime/jni/java_vm_ext.cc
// JNI Invocation interface.
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
ScopedTrace trace(__FUNCTION__);
const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);
if (JavaVMExt::IsBadJniVersion(args->version)) {
LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version;
return JNI_EVERSION;
}
RuntimeOptions options;
for (int i = 0; i < args->nOptions; ++i) {
JavaVMOption* option = &args->options[i];
options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo));
}
bool ignore_unrecognized = args->ignoreUnrecognized;
// 通过Runtime的create方法创建单例的Runtime对象,它就是ART虚拟机的前身
if (!Runtime::Create(options, ignore_unrecognized)) {
return JNI_ERR;
}
// When `ART_CRASH_RUNTIME_DELIBERATELY` is defined (which happens only in the
// case of a test APEX), we crash the runtime here on purpose, to test the
// behavior of rollbacks following a failed ART Mainline Module update.
#ifdef ART_CRASH_RUNTIME_DELIBERATELY
LOG(FATAL) << "Runtime crashing deliberately for testing purposes.";
#endif
// Initialize native loader. This step makes sure we have
// everything set up before we start using JNI.
android::InitializeNativeLoader();
// 获取刚刚创建的runtime对象
Runtime* runtime = Runtime::Current();
// 启动runtime
bool started = runtime->Start();
if (!started) {
delete Thread::Current()->GetJniEnv();
delete runtime->GetJavaVM();
LOG(WARNING) << "CreateJavaVM failed";
return JNI_ERR;
}
*p_env = Thread::Current()->GetJniEnv();
*p_vm = runtime->GetJavaVM();
return JNI_OK;
}
startReg注册JNI方法
// /frameworks/base/core/jni/AndroidRuntime.cpp
static const RegJNIRec gRegJNI[] = {
// 本地实现函数
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_com_android_internal_os_ZygoteInit_nativeZygoteInit),
...
};
/*
* Register android native functions with the VM.
*/
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
ATRACE_NAME("RegisterAndroidNatives");
/*
* 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.)
*/
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);
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
//createJavaThread("fubar", quickTest, (void*) "hello");
return 0;
}
AndroidRuntime.cpp的start方法主要做了以下工作:
- 加载libart.so
- 启动虚拟机
- 加载注册JNI方法
- 启动Zygote
5.3main()
执行ZygoteInit.java的main()方法,首次进入Java世界
// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
/**
* This is the entry point for a Zygote process. It creates the Zygote server, loads resources,
* and handles other tasks related to preparing the process for forking into applications.
*
* This process is started with a nice value of -20 (highest priority). All paths that flow
* into new processes are required to either set the priority to the default value or terminate
* before executing any non-system code. The native side of this occurs in SpecializeCommon,
* while the Java Language priority is changed in ZygoteInit.handleSystemServerProcess,
* ZygoteConnection.handleChildProc, and Zygote.childMain.
*
* @param argv Command line arguments used to specify the Zygote's configuration.
*/
@UnsupportedAppUsage
public static void main(String[] argv) {
ZygoteServer zygoteServer = null;
// Mark zygote start. This ensures that thread creation will throw
// an error.
ZygoteHooks.startZygoteNoThreadCreation();
// Zygote goes into its own process group.
try {
//设置进程组id
Os.setpgid(0, 0);
} catch (ErrnoException ex) {
throw new RuntimeException("Failed to setpgid(0,0)", ex);
}
Runnable caller;
try {
// Store now for StatsLogging later.
final long startTime = SystemClock.elapsedRealtime();
final boolean isRuntimeRestarted = "1".equals(
SystemProperties.get("sys.boot_completed"));
String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
Trace.TRACE_TAG_DALVIK);
bootTimingsTraceLog.traceBegin("ZygoteInit");
//创建子进程之前执行一些预先的初始化操作
RuntimeInit.preForkInit();
boolean startSystemServer = false;
String zygoteSocketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
//通过jni调用时设置,还记得app_main.cpp中传的start-system-server参数吗,在这里终于用到了
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)) {
zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
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);
} 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.");
}
// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
//加载动态库,后续进行jni调用
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
}
// Do an initial gc to clean up after startup
bootTimingsTraceLog.traceBegin("PostZygoteInitGC");
// 主动进行一次资源GC
gcAndFinalize();
bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
bootTimingsTraceLog.traceEnd(); // ZygoteInit
//初始化函数,用于在Zygote进程中初始化本地状态
Zygote.initNativeState(isPrimaryZygote);
ZygoteHooks.stopZygoteNoThreadCreation();
//创建ZygoteServer,ZygoteServer用来监听来自应用程序的请求,并根据请求创建相应的子进程
zygoteServer = new ZygoteServer(isPrimaryZygote);
//zygote进程会fork出system_server进程
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
// zygote进程中,r == null;zygote子进程(如system_server进程)中, r != null
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
//通过反射调用systemserver的main方法
r.run();
return;
}
}
Log.i(TAG, "Accepting command socket connections");
// zygote进程会在select loop死循环;而非zygote进程中之前已return。
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
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();
}
}
// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run();
}
}
preload() 的作用就是提前将需要的资源加载到VM中,比如class、resource等
// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
static void preload(TimingsTraceLog bootTimingsTraceLog) {
Log.d(TAG, "begin preload");
bootTimingsTraceLog.traceBegin("BeginPreload");
beginPreload();
bootTimingsTraceLog.traceEnd(); // BeginPreload
bootTimingsTraceLog.traceBegin("PreloadClasses");
// 加载指定的类到内存并且初始化,使用的Class.forName(class, true, null);方式
preloadClasses();
bootTimingsTraceLog.traceEnd(); // PreloadClasses
bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
cacheNonBootClasspathClassLoaders();
bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
bootTimingsTraceLog.traceBegin("PreloadResources");
// 加载Android通用的资源,比如drawable、color...
preloadResources();
bootTimingsTraceLog.traceEnd(); // PreloadResources
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs");
nativePreloadAppProcessHALs();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver");
maybePreloadGraphicsDriver();
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
// 加载共用的Library
preloadSharedLibraries();
// 加载Text资源,字体等
preloadTextResources();
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
// 为了内存共享,WebViewFactory进行任何初始化都要在Zygote进程中
WebViewFactory.prepareWebViewInZygote();
endPreload();
warmUpJcaProviders();
Log.d(TAG, "end preload");
sPreloadComplete = true;
}
preloadClassess 将framework.jar里的preloaded-classes 定义的所有class load到内存里,preloaded-classes 编译Android后可以在framework/base下找到。而preloadResources 将系统的Resource(不是在用户apk里定义的resource)load到内存。资源preload到Zygoted的进程地址空间,所有fork的子进程将共享这份空间而无需重新load, 这大大减少了应用程序的启动时间,但反过来增加了系统的启动时间。通过对preload 类和资源数目进行调整可以加快系统启动。Preload也是Android启动最耗时的部分之一
// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
/**
* Runs several special GCs to try to clean up a few generations of softly- and final-reachable
* objects, along with any other garbage. This is only useful just before a fork().
*/
private static void gcAndFinalize() {
ZygoteHooks.gcAndFinalize();
}
gc()调用只是通知VM进行垃圾回收,是否回收,什么时候回收全由VM内部算法决定。GC的回收有一个复杂的状态机控制,通过多次调用,可以使得尽可能多的资源得到回收。gc()必须在fork之前完成(接下来的StartSystemServer就会有fork操作),这样将来被复制出来的子进程才能有尽可能少的垃圾内存没有释放
5.4forkSystemServer
// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java 在main上面
/**
* Prepare the arguments and forks for the system server process.
*
* @return A {@code Runnable} that provides an entrypoint into system_server code in the child
* process; {@code null} in the parent.
*/
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
);
/* Containers run without some capabilities, so drop any caps that are not available. */
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 &= Integer.toUnsignedLong(data[0].effective) |
(Integer.toUnsignedLong(data[1].effective) << 32);
/* Hardcoded command line to start the system server */
//systemServer创建时需要的信息,命令行来启动SystemServer
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,3005,3006,3007,3009,3010,3011,3012",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
"com.android.server.SystemServer",
};
// 处理与 zygote spawner 相关的 args 的参数解析
ZygoteArguments parsedArgs;
int pid;
try {
ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
try {
//将args转化成ZygoteArguments对象
parsedArgs = ZygoteArguments.getInstance(commandBuffer);
} catch (EOFException e) {
throw new AssertionError("Unexpected argument error for forking system server", e);
}
commandBuffer.close();
//检查是否设置了调试器相关的系统属性
Zygote.applyDebuggerSystemProperty(parsedArgs);
//检查是否使用了 --invoke-with 参数来运行应用程序。 会设置InvokeWith参数,这个参数在接下来的初始化逻辑中会有调用
Zygote.applyInvokeWithSystemProperty(parsedArgs);
if (Zygote.nativeSupportsMemoryTagging()) {
String mode = SystemProperties.get("arm64.memtag.process.system_server", "");
if (mode.isEmpty()) {
/* 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. */
mode = SystemProperties.get("persist.arm64.memtag.default", "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;
}
/* Request to fork the system server process */
// 请求 fork SystemServer进程
pid = Zygote.forkSystemServer(
parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.mGids,
parsedArgs.mRuntimeFlags,
null,
parsedArgs.mPermittedCapabilities,
parsedArgs.mEffectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
// 如果是第一次创建的话pid==0
if (pid == 0) {
// 这里已经是子进程了
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
// SyetemServer进程是复制了Zygote进程的地址空间,因此也会得到Zygote进程创建的Socket,这个Socket对于SyetemServer进程没有用处,因此,需要关闭该Socket
zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
}
return null;
}
我们把方法前的英文注释翻译一下:为system server进程准备参数和forks。在子进程中返回一个提供进入system server代码入口点的Runnable并且在父进程中返回null。
在这里引申一下,我么经常说fork一个进程。那么,什么是fork?fork是一个分叉函数,一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程。fork函数被调用一次但返回两次,两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。
forkSystemServer方法的主要工作流程是:
(1)获取POSIX(可移植操作系统接口)功能列表的相关位数:posixCapabilitiesAsBits
(2)放弃一些容器运行时不可用的功能:逻辑运算符&和|
(3)硬编码命令行启动system server
(4)发送fork一个system server 子进程的请求:Zygote.forkSystemServer
(5)如果pid是0,说明system server启动成功。关闭socket,并且做一些启动system server剩余的工作:handleSystemServerProcess(parsedArgs)
// /frameworks/base/core/java/com/android/internal/os/Zygote.java
/**
* Special method to start the system server process. In addition to the
* common actions performed in forkAndSpecialize, the pid of the child
* process is recorded such that the death of the child process will cause
* zygote to exit.
*
* @param uid the UNIX uid that the new process should setuid() to after
* fork()ing and and before spawning any threads.
* @param gid the UNIX gid that the new process should setgid() to after
* fork()ing and and before spawning any threads.
* @param gids null-ok; a list of UNIX gids that the new process should
* setgroups() to after fork and before spawning any threads.
* @param runtimeFlags bit flags that enable ART features.
* @param rlimits null-ok an array of rlimit tuples, with the second
* dimension having a length of 3 and representing
* (resource, rlim_cur, rlim_max). These are set via the posix
* setrlimit(2) call.
* @param permittedCapabilities argument for setcap()
* @param effectiveCapabilities argument for setcap()
*
* @return 0 if this is the child, pid of the child
* if this is the parent, or -1 on error.
*/
static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
ZygoteHooks.preFork();
// 通过jni调用native方法,最终fork一个进程
int pid = nativeForkSystemServer(
uid, gid, gids, runtimeFlags, rlimits,
permittedCapabilities, effectiveCapabilities);
// Set the Java Language thread priority to the default value for new apps.
Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
ZygoteHooks.postForkCommon();
return pid;
}
native方法的实现,都是在cpp文件中,现在我们来看一下这个源码:
// /frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
NO_STACK_PROTECTOR
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) {
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);
if (pid == 0) {
// System server prcoess does not need data isolation so no need to
// know pkg_data_info_list.
SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities,
effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
false, nullptr, nullptr, /* is_top_app= */ false,
/* pkg_data_info_list */ nullptr,
/* allowlisted_data_info_list */ nullptr, false, false);
} else if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
gSystemServerPid = 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.
int status;
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()) {
// Assign system_server to the correct memory cgroup.
// Not all devices mount memcg so check if it is mounted first
// to avoid unnecessarily printing errors and denials in the logs.
if (!SetTaskProfiles(pid, std::vector<std::string>{"SystemMemoryProcess"})) {
ALOGE("couldn't add process %d into system memcg group", pid);
}
}
}
return pid;
}
ForkAndSpecializeCommon是一个非常长的方法,我们可以看到代码分为两个逻辑,一个是if(pid ==0),另一个是if(pid>0)。前面我们说到过,fork进程成功后,返回两次,子进程返回0,父进程返回子进程的id。到此system_server进程已完成了创建的所有工作。
- fork函数最终返回了一个pid,在这里会对pid判断,这里伙伴们需要注意,虽然fork只会执行一次,但是在返回值上会有两次返回,这是什么原因呢?
- 因为我们在fork进程的时候,我们会在父进程中执行fork函数,同时会将父进程的信息全部拷贝一份,包括堆栈信息,也就是代码会在子进程中再次执行一次,所以从现象上来看,在forkSystemServer方法执行时,会有两次返回,一次是从父进程返回,一次从子进程中返回,那么如何判断是在哪个进程呢?
- 在ForkCommon函数中给了我们答案,当pid = 0时,因为在子进程中没有创建进程,因此返回0;而在父进程中则是会返回创建的子进程pid;如果返回一个负值,那么说明创建进程失败了。
- 因此,在ZygoteInit调用forkSystemServer之后,会判断其返回值,如果pid = 0,那么就说明创建进程成功了,而且是子进程,那么就会执行handleSystemServerProcess方法,此时运行system_server进程。
// /frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
// Utility routine to fork a process from the zygote.
NO_STACK_PROTECTOR
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();
// Curry a failure function.
auto fail_fn = std::bind(zygote::ZygoteFailure, env,
is_system_server ? "system_server" : "zygote",
nullptr, _1);
// Temporarily block SIGCHLD during forks. The SIGCHLD handler might
// log, which would result in the logging FDs we close being reopened.
// This would cause failures because the FDs are not allowlisted.
//
// Note that the zygote process is single threaded at this point.
BlockSignal(SIGCHLD, fail_fn);
// Close any logging related FDs before we start evaluating the list of
// file descriptors.
__android_log_close();
AStatsSocket_close();
// If this is the first fork for this zygote, create the open FD table,
// verifying that files are of supported type and allowlisted. Otherwise (not
// the first fork), check that the open files have not changed. Newly open
// files are not expected, and will be disallowed in the future. Currently
// they are allowed if they pass the same checks as in the
// FileDescriptorTable::Create() above.
if (gOpenFdTable == nullptr) {
gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn);
} else {
gOpenFdTable->Restat(fds_to_ignore, fail_fn);
}
android_fdsan_error_level fdsan_error_level = android_fdsan_get_error_level();
if (purge) {
// Purge unused native memory in an attempt to reduce the amount of false
// sharing with the child process. By reducing the size of the libc_malloc
// region shared with the child process we reduce the number of pages that
// transition to the private-dirty state when malloc adjusts the meta-data
// on each of the pages it is managing after the fork.
if (mallopt(M_PURGE_ALL, 0) != 1) {
mallopt(M_PURGE, 0);
}
}
pid_t pid = fork();
if (pid == 0) {
if (is_priority_fork) {
setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX);
} else {
setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN);
}
#if defined(__BIONIC__) && !defined(NO_RESET_STACK_PROTECTOR)
// Reset the stack guard for the new process.
android_reset_stack_guards();
#endif
// The child process.
PreApplicationInit();
// Clean up any descriptors which must be closed immediately
DetachDescriptors(env, fds_to_close, fail_fn);
// Invalidate the entries in the USAP table.
ClearUsapTable();
// Re-open all remaining open file descriptors so that they aren't shared
// with the zygote across a fork.
gOpenFdTable->ReopenOrDetach(fail_fn);
// Turn fdsan back on.
android_fdsan_set_error_level(fdsan_error_level);
// Reset the fd to the unsolicited zygote socket
gSystemServerSocketFd = -1;
} else if (pid == -1) {
ALOGE("Failed to fork child process: %s (%d)", strerror(errno), errno);
} else {
ALOGD("Forked child process %d", pid);
}
// We blocked SIGCHLD prior to a fork, we unblock it here.
UnblockSignal(SIGCHLD, fail_fn);
return pid;
}
fork函数
现在我们来看看它是怎么工作的
// /system/bionic/libc/bionic/fork.cpp
/**
* __clone_for_fork 函数用于执行实际的进程克隆操作
*
* @return 若克隆成功,在子进程中返回 0,在父进程中返回子进程的进程 ID;若克隆失败,返回 -1
*/
int __clone_for_fork() {
// 获取当前线程的内部结构指针
pthread_internal_t* self = __get_thread();
// 使用 clone 系统调用 创建新进程
// CLONE_CHILD_SETTID 和 CLONE_CHILD_CLEARTID 用于设置和清除子进程的线程 ID
// SIGCHLD 表示子进程结束时发送 SIGCHLD 信号
// 其他参数为 NULL,表示使用默认设置
int result = clone(nullptr, nullptr, (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID | SIGCHLD),
nullptr, nullptr, nullptr, &(self->tid));
// 如果克隆成功(返回值为 0)
if (result == 0) {
// 在子进程中更新缓存的进程 ID,因为 clone 系统调用不会直接设置它(但内核会更新 self->tid)
self->set_cached_pid(gettid());
}
return result;
}
/**
* fork 函数用于创建一个新的进程
*
* @return 若成功创建子进程,在子进程中返回 0,在父进程中返回子进程的进程 ID;若创建失败,返回 -1
*/
int fork() {
// 执行 fork 前的准备工作
__bionic_atfork_run_prepare();
int result = __clone_for_fork();
// 如果结果为 0,表示当前处于新创建的子进程中
if (result == 0) {
// 禁用 fork 后的文件描述符安全检查(fdsan),避免错误触发
// 对于那些先 fork,然后关闭所有文件描述符并执行 exec 的进程
android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_DISABLED);
// 全局禁用文件跟踪(fdtrack)
android_fdtrack_set_globally_enabled(false);
// 重置栈和线程本地存储(TLS)的虚拟内存区域(VMA)名称,防止使用父进程的 tid
__set_stack_and_tls_vma_name(true);
// 在子进程中执行特定的操作
__bionic_atfork_run_child();
} else { // 如果结果不为 0,表示当前处于父进程中
// 在父进程中执行特定的操作
__bionic_atfork_run_parent();
}
return result;
}
子进程与父进程的区别
- 除了文件锁以外,其他的锁都会被继承
- 各自的进程ID和父进程ID不同
- 子进程的未决告警被清除;
- 子进程的未决信号集设置为空集。
写时拷贝 (copy- on-write)
Linux 的 fork() 使用是通过写时拷贝 (copy- on-write) 实现。写时拷贝是一种可以推迟甚至避免拷贝
数据的技术。内核此时并不复制整个进程的地址空间,而是让父子进程共享同一个地址空间。只用在需要写入的时候才会复制地址空间,从而使各个进行拥有各自的地址空间。也就是说,资源的复制是在需要写入的时候才会进行,在此之前,只有以只读方式共享
孤儿进程、僵尸进程
fork系统调用之后,父子进程将交替执行,执行顺序不定。如果父进程先退出,子进程还没退出那么子进程的父进程将变为init进程(托孤给了init进程)。(注:任何一个进程都必须有父进程)如果子进程先退出,父进程还没退出,那么子进程必须等到父进程捕获到了子进程的退出状态才真正结束,否则这个时候子进程就成为僵进程(僵尸进程:只保留一些退出信息供父进程查询)
多线程进程的Fork调用
在 POSIX 标准中,fork 的行为是这样的:复制整个用户空间的数据(通常使用 copy-on-write 的策略,所以可以实现的速度很快)以及所有系统对象,然后仅复制当前线程到子进程。这里:所有父进程中别的线程,到了子进程中都是突然蒸发掉的
假设这么一个环境,在 fork 之前,有一个子线程 lock 了某个锁,获得了对锁的所有权。fork 以
后,在子进程中,所有的额外线程都人间蒸发了。而锁却被正常复制了,在子进程看来,这个锁没
有主人,所以没有任何人可以对它解锁。当子进程想 lock 这个锁时,不再有任何手段可以解开
了。程序发生死锁
man clone
int clone(int (*fn)(void *), void *child_stack,
int flags, void *arg, ...
/* pid_t *ptid, void *newtls, pid_t *ctid */ );
/*
以下是clone函数的参数说明:
fn:指向子进程要执行的函数的指针。
child_stack:为子进程分配的堆栈地址。
flags:用于设置子进程的属性,如是否与父进程共享地址空间、文件系统、文件描述符、信号处理程序等。
arg:传递给子进程的参数。
通过设置不同的flags标志,可以控制子进程与父进程之间的资源共享情况。例如,设置CLONE_VM标志可以共享地址空间,设置CLONE_FS标志可以共享文件系统信息等。
clone函数的返回值表示创建的子进程的PID(进程标识符)。在子进程中,clone函数返回0;在父进程中,返回子进程的PID。
*/
ZygoteInit.forkSystemServer() 方法fork 出一个新的进程,这个进程就是SystemServer进程。fork出来
的子进程在handleSystemServerProcess 里开始初始化工作,主要工作分为:
- prepareSystemServerProfile()方法中将SYSTEMSERVERCLASSPATH中的AppInfo加载到VM
中。 - 判断fork args中是否有invokWith参数,如果有则进行WrapperInit.execApplication。如果没有则调用
5.5handleSystemServerProcess
// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
/**
* Finish remaining work for the newly forked system server process.
*/
private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
// set umask to 0077 so new files and directories will default to owner-only permissions.
Os.umask(S_IRWXG | S_IRWXO);
if (parsedArgs.mNiceName != null) {
Process.setArgV0(parsedArgs.mNiceName);
}
final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
if (systemServerClasspath != null) {
// Capturing profiles is only supported for debug or eng builds since selinux normally
// prevents it.
if (shouldProfileSystemServer() && (Build.IS_USERDEBUG || Build.IS_ENG)) {
try {
Log.d(TAG, "Preparing system server profile");
final String standaloneSystemServerJars =
Os.getenv("STANDALONE_SYSTEMSERVER_JARS");
final String systemServerPaths = standaloneSystemServerJars != null
? String.join(":", systemServerClasspath, standaloneSystemServerJars)
: systemServerClasspath;
// 将SYSTEMSERVERCLASSPATH中的AppInfo加载到VM中
prepareSystemServerProfile(systemServerPaths);
} catch (Exception e) {
Log.wtf(TAG, "Failed to set up system server profile", e);
}
}
}
if (parsedArgs.mInvokeWith != null) {
String[] args = parsedArgs.mRemainingArgs;
// If we have a non-null system server class path, we'll have to duplicate the
// existing arguments and append the classpath to it. ART will handle the classpath
// correctly when we exec a new process.
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;
}
//判断fork args中是否有invokWith参数,如果有则进行WrapperInit.execApplication
WrapperInit.execApplication(parsedArgs.mInvokeWith,
parsedArgs.mNiceName, parsedArgs.mTargetSdkVersion,
VMRuntime.getCurrentInstructionSet(), null, args);
throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
} else {
ClassLoader cl = getOrCreateSystemServerClassLoader();
if (cl != null) {
Thread.currentThread().setContextClassLoader(cl);
}
/*
* Pass the remaining arguments to SystemServer.
*/
// 调用zygoteInit。com.android.server.SystemServer即解析到的parsedArgs.mRemainingArgs
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mDisabledCompatChanges,
parsedArgs.mRemainingArgs, cl);
}
/* should never reach here */
}
// /frameworks/base/core/java/com/android/internal/os/ZygoteInit.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 disabledCompatChanges set of disabled compat changes for the process (all others
* are enabled)
* @param argv arg strings
*/
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();
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();
return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv,
classLoader);
}
5.6 nativeZygoteInit
在看applicationInit方法之前,首先先看一下ZygoteInit中的nativeZygoteInit,这个方法比较重要,我们跟进看一下。这是一个native方法,我们看下C++的代码
通过JNI的gRegJNI数组,可以看出nativeZygoteInit函数对应的是JNI文件AndroidRuntime.cpp的register_com_android_internal_os_ZygoteInit_nativeZygoteInit函数:
// /frameworks/base/core/jni/AndroidRuntime.cpp
int register_com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env)
{
const JNINativeMethod methods[] = {
{ "nativeZygoteInit", "()V",
(void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
};
return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
methods, NELEM(methods));
}
最终执行的是AndroidRuntime的onZygoteInit函数。
// /frameworks/base/core/jni/AndroidRuntime.cpp
static void com_android_internal_os_ZygoteInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
// 调用AndroidRuntime的纯虚函数onZygoteInit()
gCurRuntime->onZygoteInit();
}
gCurRuntime是指什么?在app_main.cpp 中
// /frameworks/base/core/jni/AndroidRuntime.cpp
// 全局静态AndroidRuntime对象指针,在构造函数里赋值并保证进程单例
static AndroidRuntime* gCurRuntime = NULL;
...
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
mExitWithoutCleanup(false),
mArgBlockStart(argBlockStart),
mArgBlockLength(argBlockLength)
{
init_android_graphics();
// Pre-allocate enough space to hold a fair number of options.
mOptions.setCapacity(20);
assert(gCurRuntime == NULL); // one per process
// gCurRuntime 被设置为AndroidRuntime对象自己
gCurRuntime = this;
}
故:此时启动App_main.cpp中onZygoteInit()函数
每个App在启动前必须先创建一个进程,该进程是由Zygote进程fork出来,进程具有独立的资源空间,用于承载app上运行的各种Activity/Service等组件,进程在创建时候打开Binder驱动,然后才能进行Binder IPC通讯,如startActivity()调用流程AMS先检测目标进程是否启动,若没则创建目标进程。
// /frameworks/base/cmds/app_process/app_main.cpp
virtual void onZygoteInit()
{
// 创建sp智能指针引用的ProcessState对象,在其作用域结束后将自动释放
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
// 创建Binder驱动并启动Binder线程池,用于binder通信
proc->startThreadPool();
}
// /frameworks/native/libs/binder/ProcessState.cpp
sp<ProcessState> ProcessState::self()
{
// 上面已经看过这个函数,注意这里调用的第二次参数是false
return init(kDefaultDriver, false /*requireDefault*/);
}
// /frameworks/native/libs/binder/ProcessState.cpp
// 每个支持 Binder 进程间通信机制的进程内都有一个唯一的processState对象
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
// 防止重复启动线程池
if (!mThreadPoolStarted) {
if (mMaxThreads == 0) {
ALOGW("Extra binder thread started, but 0 threads requested. Do not use "
"*startThreadPool when zero threads are requested.");
}
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}
...
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
//创建binder线程名字 binder-xxx
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
sp<Thread> t = sp<PoolThread>::make(isMain);
t->run(name.string());
pthread_mutex_lock(&mThreadCountLock);
mKernelStartedThreads++;
pthread_mutex_unlock(&mThreadCountLock);
}
}
主要就是创建PoolThread对象并调用其run函数启动一个新线程,而PoolThread 继承Thread并重写了线程入口函数threadLoop
// /frameworks/native/libs/binder/ProcessState.cpp
class PoolThread : public Thread
{
public:
explicit PoolThread(bool isMain)
: mIsMain(isMain)
{
}
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
// /frameworks/native/libs/binder/IPCThreadState.cpp
void IPCThreadState::joinThreadPool(bool isMain)
{
LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mCurrentThreads++;
pthread_mutex_unlock(&mProcess->mThreadCountLock);
// 将协议写入到IPCThreadState的输出缓冲区
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
mIsLooper = true;
status_t result;
do {
processPendingDerefs();
// now get the next command to be processed, waiting if necessary
result = getAndExecuteCommand();
if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
LOG_ALWAYS_FATAL("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
mProcess->mDriverFD, result);
}
// Let this thread exit the thread pool if it is no longer
// needed and it is not the main process thread.
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",
(void*)pthread_self(), getpid(), result);
mOut.writeInt32(BC_EXIT_LOOPER);
mIsLooper = false;
// false代表bwr数据的read_buffer为空
talkWithDriver(false);
pthread_mutex_lock(&mProcess->mThreadCountLock);
LOG_ALWAYS_FATAL_IF(mProcess->mCurrentThreads == 0,
"Threadpool thread count = 0. Thread cannot exist and exit in empty "
"threadpool\n"
"Misconfiguration. Increase threadpool max threads configuration\n");
mProcess->mCurrentThreads--;
pthread_mutex_unlock(&mProcess->mThreadCountLock);
}
若talkWithDriver函数长期没有等到IPC请求或者getAndExecuteCommand函数执行超时,且isMain为false时就跳出循环,并向Binder驱动发送BC_EXIT_LOOPER协议告知Binder驱动,前面创建的这个线程它要退出Binder线程池了。
所以这里就有一个面试题,Binder驱动是什么时候启动的?其实就是在fork进程成功之后,处理进程启动的时候完成的,具体函数就是在ZygoteInit的nativeZygoteInit方法。
5.7applicationInit
// /frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
protected static Runnable applicationInit(int targetSdkVersion, long[] disabledCompatChanges,
String[] argv, ClassLoader classLoader) {
// 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);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
VMRuntime.getRuntime().setDisabledCompatChanges(disabledCompatChanges);
final Arguments args = new Arguments(argv);
// The end of of the RuntimeInit event (see #zygoteInit).
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// Remaining arguments are passed to the start class's static main
// findStaticMain来运行args的startClass的main方法
return findStaticMain(args.startClass, args.startArgs, classLoader);
}
// /frameworks/base/core/java/com/android/internal/os/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()
* @param classLoader the classLoader to load {@className} with
*/
protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class<?> cl;
try {
// 反射获取main方法
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
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.
*/
// 返回一个 Runnable,在 Zygote 的 main() 方法中执行器 run() 方法
// 之前的版本是抛出一个异常,在 main() 方法中捕获,注释误导人
return new MethodAndArgsCaller(m, argv);
}
在return语句上面有一段注释,意思是:这个会在ZygoteInit.main方法被捕获,他通过调用异常的run方法来响应。也就是findStaticMain()方法中抛出的异常MethodAndArgsCaller,从而进入caller.run()方法。下面是MethodAndArgsCaller的源码:
很明显这是一个耗时操作所以使用线程来完成:
// /frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
/**
* Helper class which holds a method and arguments and can call them. This is used as part of
* a trampoline to get rid of the initial process setup stack frames.
*/
static class MethodAndArgsCaller implements Runnable {
/** method to call */
private final Method mMethod;
/** argument array */
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
// MethodAndArgsCaller继承自Runnable并实现了run方法,在ZygoteInit.java中调用forkSystemServer(abiList, zygoteSocketName, zygoteServer)返回Runnable对象后回调他的run方法
// run方法的实现,通过反射调用systemserver的main方法
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException(ex);
}
}
}
通过如上代码,我们可以看出,通过反射的方式,进入SystemServer的main方法。(为什么旧版本要通过抛出异常的方式进入main方法呢?因为从ZygoteInit的main开始fork一个进程出来,经过了层层调用,系统中累积了不少栈帧,为了一个创建一个干干净净的进程,需要清除里面的栈帧,故抛出这个异常。)
Zygote进程主要做了以下工作
- 加载虚拟机,并为JVM注册JNI方法
- 提前加载类PreloadClasses
- 提前加载资源PreLoadResouces
- fork system_server
- 调用runSelectLoop方法,等待进程孵化请求
zygote进程在fork子进程的时候可以共享虚拟机和资源,从而加快进程的启动速度,节省内存。
接下来请阅读:android u开机流程详细分析(下) - system service
标签:fork,process,system,zygote,进程,android,main,详细分析 From: https://blog.csdn.net/qq_45845172/article/details/140783171