Zygote 介绍
在 Android 系统中,DVM(Dalvik 虚拟机)/ART,系统服务进程 system_server 以及应用程序进程都是由 Zygote 进程来创建的(而 Native 程序,也就是 C/C++ 开发的程序则是由 init 进程创建启动的)。Zygote 进程也称孵化器,通过 fork(复制进程) 的形式来创建应用程序进程和 system_server 进程,由于 Zygote 进程在启动时会创建 DVM 或者 ART ,因此通过 fork 而创建的应用程序进程和 system_server 进程可以在内部获取一个 DVM 或者 ART 的实例副本。
Zygote 是一个 C/S模型。Zygote 进程作为服务端,主要负责创建 Java 虚拟机,加载系统资源,启动 system_server 进程以及后续运行过程中启动普通的应用程序进程。其他进程作为客户端向它发送 fork 请求,Zygote 进程接收到这个请求后会 fork 出一个新的进程。
Zygote 通过 Socket 的方式和其他进程进行通信,这里的"其他进程"主要指的是系统服务进程 system_server。
在 Linux 系统中,调用 fork 函数创建子进程的时候,不会复制父进程的内存,而是父子进程共享一个内存空间,只有当子进程或者父进程对内存数据进行修改时才会进行内存复制,从而,父进程和子进程才有各自的内存空间。在此之前,只会以只读的方式共享。
写时拷贝(copy-on-write):等到修改数据的时候才真正的分配内存空间,是一种可以推迟甚至避免拷贝数据的技术。这是对程序性能的优化,这样做的目的是为了避免不必要的拷贝。
Zygote 作为孵化器,可以提前加载一些资源,这样 fork 出的子进程就可以直接使用这些资源,而不用重新加载。比如,system_server 进程就可以直接使用 Zygote 进程中的 JNI 函数、共享库、常用类以及主题资源。
Zygote 启动过程
Zygote 启动文件回顾
在了解Zygote
启动过程之前需要先了解系统启动时init
过程,这里不做介绍,可以参考:XXX, 如果是64位机器,在系统启动时会加载system/core/rootdir/init.zygote64_32.rc
文件
perl
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
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
onrestart restart audioserver //audioserver进程终止了就重启进程
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
task_profiles ProcessCapacityHigh MaxPerformance
critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
class main
priority -20
user root
group root readproc reserved_disk
socket zygote_secondary stream 660 root system
socket usap_pool_secondary stream 660 root system
onrestart restart zygote
task_profiles ProcessCapacityHigh MaxPerformance
Zygote 进程是在 init 进程启动时创建的,起初,Zygote 进程的名称并不是 Zygote,而是 app_process。Zygote 进程启动后,Linux 系统下的 pctrl 系统会调用 app_process,将其名称换成了 Zygote。
上面脚本说明: 1、zygote 要开启的进程名 2、app_process 要执行程序名,位置在/system/bin/路径下 3、main classname 4、如果audioserver、cameraserver、media等进程终止了,就需要进行restart(重启) 5、参数-Xzygote /system/bin --zygote --start-system-server
zygote启动入口
那么zygote启动的入口在哪里?Zygote启动的代码在Framework目录下frameworks/base/cmds/app_process/app_main.cpp
, 下面看一下app_main.cpp
中main
方法:
c
int main(int argc, char* const argv[])
{
....// 省略部分代码
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
....// 省略部分代码
// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
++i; // Skip unused "parent dir" argument.
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
Vector<String8> args;
....// 省略了 args 参数生成过程
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
}
结合上面init.zygote64_32.rc
文件和上面代码发现,在启动zygote的时候,代码中的 zygote
和startSystemServer
变量都会被设置为true
, 导致在后面执行runtime.start("com.android.internal.os.ZygoteInit", args, zygote)
,那么runtime
是什么呢?
AppRuntime
上面发现Zygote
是在AppRuntime
对象中被启动的,这里的AppRuntime
继承AndroidRuntime
并在frameworks/base/cmds/app_process/app_main.cpp
中实现,但是没有重新实现start
函数,那么就需要到AndroidRuntime
中看一下。 AndroidRuntime
在frameworks/base/core/jni/AndroidRuntime.cpp
scss
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
static const String8 startSystemServer("start-system-server");
bool primary_zygote = false;
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)));
}
}
....// 省略部分代码
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
// 启动虚拟机
if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
return;
}
onVmCreated(env);
/*
* Register android functions. 为虚拟机注册 JNI 方法
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
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);
// 从 app_main 的 main 函数得知 className 为 com.android.internel.os.ZygoteInit
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);
}
//将 className 的 "." 替换为 "/"
char* slashClassName = toSlashClassName(className != NULL ? className : "");
// 找到 zygoteInit
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
// 找到 ZygoteInit 的 main 函数
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 {
// 通过 JNI 调用 ZygoteInit 的 main 方法
env->CallStaticVoidMethod(startClass, startMeth, strArray);
....// 省略部分代码
}
}
....// 省略部分代码
}
上面代码主要作用是通过虚拟机jni方式调用zygoteInit
的main
方法启动Zygote
ZygoteInit
ZygoteInit
是个java类,位置在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
,下面看一下main
函数中的关键实现:
ini
public static void main(String[] argv) {
ZygoteServer zygoteServer = null;
....// 省略部分代码
Runnable caller;
try {
....// 省略部分代码
boolean startSystemServer = false;
String zygoteSocketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
// 第一步
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
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]);
}
}
....// 省略部分代码
if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
//第二步
preload(bootTimingsTraceLog); // 预加载类和资源
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
}
....// 省略部分代码
// 第三步
zygoteServer = new ZygoteServer(isPrimaryZygote); // 创建一个 Server 端的 Socket
if (startSystemServer) {
// 第四步
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}
....// 省略部分代码
// 第五步
caller = zygoteServer.runSelectLoop(abiList); // 等待 AMS/ATMS 请求
} 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();
}
}
上面代码说明: 第一步:解析启动参数, 这里面的参数是init.zygote64_32.rc
中, 会发现startSystemServer
被设置为true
, enableLazyPreload
在的Zygote32
启动时设置为了true
第二步:预加载类和资源, 通过init.zygote64_32.rc
文件知道在Zygote64
启动时enableLazyPreload
为false
, 在Zygote32
启动时设置为了true
,所以只有在Zygote64
中会加载类和资源 第三步:创建一个Server 端的 Socket 第四步:启动System_servier 进程 第五步: 等待 AMS/ATMS 请求
ZygoteServer
下面看一下第三步的ZygoteServer
的内部实现 位置:frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
ini
ZygoteServer(boolean isPrimaryZygote) {
mUsapPoolEventFD = Zygote.getUsapPoolEventFD();
if (isPrimaryZygote) {
mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
mUsapPoolSocket =
Zygote.createManagedSocketFromInitSocket(
Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
} else {
mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);
mUsapPoolSocket =
Zygote.createManagedSocketFromInitSocket(
Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
}
mUsapPoolSupported = true;
fetchUsapPoolPolicyProps();
}
通过上面可以看到在Zygote32
和Zygote64
两个中分别创建不同的ZygoteSocket
下面看一下在Zygote
中是如何创建Socket 的 代码位置:frameworks/base/core/java/com/android/internal/os/Zygote.java
java
public static final String PRIMARY_SOCKET_NAME = "zygote";
public static final String SECONDARY_SOCKET_NAME = "zygote_secondary";
private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
int fileDesc;
// 拼接 Socket 名称
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
// 获取Socket 环境变量
String env = System.getenv(fullSocketName);
// 将环境变量转化为文件描述符参数
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
return new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException(
"Error building socket from file descriptor: " + fileDesc, ex);
}
}
上面代码后面可以看到使用获取到的fd
创建了一个LocalServerSocket
,也就是服务端的 Socket,并将这个文件操作符作为参数传进去。在 Zygote 进程将 SystemServer 进程启动后,就会在这个 服务器端的 Socket 上等待 AMS/ATMS 请求 Zygote 进程来创建新的应用程序进程。
下面看一下SystemServer
是如何被启动的,上面代码中调用forkSystemServer
函数创建,看一下具体实现:
scss
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
....// 省略部分代码
/* Hardcoded command line to start the system server */
// 创建启动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,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",
};
ZygoteArguments parsedArgs;
int pid;
try {
ZygoteCommandBuffer commandBuffer = new ZygoteCommandBuffer(args);
try {
parsedArgs = ZygoteArguments.getInstance(commandBuffer);
} catch (EOFException e) {
throw new AssertionError("Unexpected argument error for forking system server", e);
}
commandBuffer.close();
Zygote.applyDebuggerSystemProperty(parsedArgs);
Zygote.applyInvokeWithSystemProperty(parsedArgs);
....// 省略部分代码
/* Request to fork the system server process */
// 创建一个System_server进程
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 */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
}
return null;
}
在创建Server可以看出 system_server
进程的用户 id 和用户组 id 被设置为 1000, 拥有用户组1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011,3012 的权限. 进程名为 system_server
,启动的类名为 com.android.server.SystemServer
,然后调用 Zygote.forkSystemServer
函数创建一个进程
下面看一下 Zygote.forkSystemServer
的实现:
arduino
static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
ZygoteHooks.preFork();
// 调用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;
}
nativeForkSystemServer
是com_android_internal_os_Zygote.cpp
一个jni
调用,简单看一下调用代码: 位置:frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
arduino
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) {
....// 省略部分代码
pid_t pid = zygote::ForkCommon(env, true,
fds_to_close,
fds_to_ignore,
true);
....// 省略部分代码
return pid;
}
在看zygote::ForkCommon
函数实现
c
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) {
....// 省略部分代码
pid_t pid = fork();
....// 省略部分代码
return pid;
}
到这里就可以看到native调用fork()
函数克隆一个进程,这里介绍一下fork()
返回pid的情况 1)在父进程中,fork返回新创建子进程的进程ID; 2)在子进程中,fork返回0; 3)如果出现错误,fork返回一个负值;
所以在上面ZygoteInit
类中forkSystemServer
函数中有这么一段代码:
scss
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
return handleSystemServerProcess(parsedArgs);
}
表示当pid为0时是运行在子进程中,也就是SystemServer进程中, handleSystemServerProcess
函数完成系统服务剩余工作
scss
private static Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) {
....// 省略部分代码
// 获取system server class path
final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
if (systemServerClasspath != null) {
performSystemServerDexOpt(systemServerClasspath);
// 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");
prepareSystemServerProfile(systemServerClasspath);
} catch (Exception e) {
Log.wtf(TAG, "Failed to set up system server profile", e);
}
}
}
if (parsedArgs.mInvokeWith != null) {
....// 省略部分代码
throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
} else {
// 创建类加载器
ClassLoader cl = getOrCreateSystemServerClassLoader();
if (cl != null) {
Thread.currentThread().setContextClassLoader(cl);
}
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mDisabledCompatChanges,
parsedArgs.mRemainingArgs, cl);
}
}
上面代码主要创建ClassLoader
, 看一下ZygoteInit.zygoteInit
函数, 其中环境变量SYSTEMSERVERCLASSPATH,配置如下 SYSTEMSERVERCLASSPATH=/system/framework/services.jar:/system/framework/ethernet-service.jar:/system/framework/com.android.location.provider.jar:/system/framework/service-jobscheduler.jar
scss
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);
}
RuntimeInit.applicationInit
位置:frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
scss
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
return findStaticMain(args.startClass, args.startArgs, classLoader);
}
findStaticMain
函数
php
protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class<?> cl;
try {
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.
*/
return new MethodAndArgsCaller(m, argv);
}
上面代码主要是在ClassLoader
中找到com.android.server.SystemServer
类和main
函数,最后通过MethodAndArgsCaller
执行SystemServer
, 最后看一下MethodAndArgsCaller
的实现
php
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;
}
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
便启动完成了