文章目录
深入理解 AndroidFramework 之 Zygote 启动
Zygote 作为Android 第一个出道的进程被广大网友所熟知,那么该进程是如何被加载,如何运行的呢?在这里我们就尝试将她神秘的面纱一层层揭开。
1. Init 进程
Linux中PID为0的进程是所有其他进程的祖先, 也称作idle进程或swapper进程,在系统初始化时由kernel自身从无到有创建。进程0的数据成员大部分是静态定义的。
在Android系统中 0号进程会孵化出2个核心进程,一个进程号为2的名为kthreadd的进程,另一个则是进程号为1名为init的进程。kthreadd进程由idle通过kernel_thread创建,并始终运行在内核空间, 负责所有内核线程的调度和管理,所有的内核线程都是直接或者间接的以kthreadd为父进程。Init 进程是负责解析并执行 rc 文件。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V2VfFhGP-1603424070132)(res/picture/ps.png)]
2. init.rc 启动zygote 服务
Zygote 进程是init 进程通过解析init.zygote64.rc 启动的(如果是32位系统就会解析init.zygote32.rc),接下来我们就来捋一捋zygote的前世今生。
- 涉及的文件:
- system/core/rootdir/init.zygote64.rc
- frameworks/base/cmds/app_process/Android.bp
- frameworks/base/cmds/app_process/app_main.cpp
- frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
- init.zygote64.rc 文件内容如下:
//system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system \\创建socket
socket usap_pool_primary stream 660 root system \\创建socket
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
服务名称:zygote
服务路径名:/system/bin/app_process64
启动参数: ‘-Xzygote’、’/system/bin’、’–zygote’、’–start-system-server’
关于 rc 脚步具体可以参照 system/core/init/README.md
3. Zygote 进程的入口函数 —— main
3.1 Zygote的可执行库文件
从 zygot 的rc文件中可以看出,它的执行路径是“/system/bin/app_process64”,执行的库文件是“app_process64”, 我们通过查找编译文件找到了该执行库文件的Android.bp或Android.mk 所在。
代码路径 frameworks/base/cmds/app_process/Android.bp
Aosp Q code:
cc_binary {
name: "app_process",
srcs: ["app_main.cpp"],
multilib: {
lib32: {
version_script: ":art_sigchain_version_script32.txt",
suffix: "32",//编译32位库
},
lib64: {
version_script: ":art_sigchain_version_script64.txt",
suffix: "64",//编译64位库
},
},
Aosp P code:
LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both //32和64位库都会编译
LOCAL_MODULE_STEM_32 := app_process32 //编译32位库时命名
LOCAL_MODULE_STEM_64 := app_process64 //编译64位库时命名
3.2 main
main 函数的工作内容可以概括为2步:
- 解析执行命令参数。
- AndroidRuntime 启动进程。
在第二步中会通过jni方式执行 AndroidRuntime.cpp 中的 start 方法的第二个参数(“com.android.internal.os.ZygoteInit”)的main方法。
app_process64可执行库文件的 main 源代码如下:
int main(int argc, char* const argv[])
{
...
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) {
// frameworks/base/core/jni/AndroidRuntime.cpp start()
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);//注意这里是去启动 ZygoteInit的main 函数
} 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.");
}
}
> Note: runtime 的 start方法里会去调用startReg()方法去动态注册Framework里的JNI函数。
4. Zygote 的第二个门户 —— ZygoteInit
根据 main 函数的执行过程,可以将main函数分为两部分:
- zygote 启动的 Mark 阶段。
- systemserver 的创建。
4.1 Zygote的 Mark 阶段
这里总结 Mark 阶段总共六个步骤:
- 通过 ZygoteHooks 的 startZygoteNoThreadCreation 与虚拟机建立连接,标记zygote启动。
- 通过Os.setpgid(0, 0)将Zygote加入自己的进程组,第一个0表示当前进程。
- Zygote Init 之前的准备工作,如激活Ddms RuntimeInit.preForkInit();
- 解析main 函数的参数。
- 通过gcAndFinalize()进行一次gc处理
- Zygote 的 Native 层的初始化——Zygote.initNativeState(isPrimaryZygote)。
在初始化 zygote 的 Native 状态时,首先会去查找环境变量"ANDROID_SOCKET_zygote",并将找到的值通过atoi()转换成int类型的文件描述符,如果该环境变量为空,就会通过initUnsolSocketToSystemServer()函数去创建一个socket。最后就是检测selinux 权限并初始化selinux 上下文。
//文件路径: frameworks/base/core/java/com/android/internal/os/Zygote.java
/**
* Initialize the native state of the Zygote. This inclues
* - Fetching socket FDs from the environment
* - Initializing security properties
* - Unmounting storage as appropriate
* - Loading necessary performance profile information
*
* @param isPrimary True if this is the zygote process, false if it is zygote_secondary
*/
static void initNativeState(boolean isPrimary) {
nativeInitNativeState(isPrimary);
}
//文件路径: frameworks/base/core/jni/com_android_internal_os_Zygote.cpp
/**
* The prefix string for environmental variables storing socket FDs created by
* init.
*/
static constexpr std::string_view ANDROID_SOCKET_PREFIX("ANDROID_SOCKET_");
static void com_android_internal_os_Zygote_nativeInitNativeState(JNIEnv* env, jclass,jboolean is_prima) {
/*
* Obtain file descriptors created by init from the environment.
*/
std::string android_socket_prefix(ANDROID_SOCKET_PREFIX);
std::string env_var_name = android_socket_prefix + (is_primary ? "zygote" : "zygote_secondary");
char* env_var_val = getenv(env_var_name.c_str());
if (env_var_val != nullptr) {
gZygoteSocketFD = atoi(env_var_val);
ALOGV("Zygote:zygoteSocketFD = %d", gZygoteSocketFD);
} else {
ALOGE("Unable to fetch Zygote socket file descriptor");
}
env_var_name = android_socket_prefix + (is_primary ? "usap_pool_primary" : "usap_pool_secondary");
env_var_val = getenv(env_var_name.c_str());
if (env_var_val != nullptr) {
gUsapPoolSocketFD = atoi(env_var_val);
ALOGV("Zygote:usapPoolSocketFD = %d", gUsapPoolSocketFD);
} else {
ALOGE("Unable to fetch USAP pool socket file descriptor");
}
initUnsolSocketToSystemServer();
/*
* Security Initialization
*/
// security_getenforce is not allowed on app process. Initialize and cache
// the value before zygote forks.
gIsSecurityEnforced = security_getenforce();
selinux_android_seapp_context_init();
/*
* Storage Initialization
*/
UnmountStorageOnInit(env);
/*
* Performance Initialization
*/
if (!SetTaskProfiles(0, {})) {
ZygoteFailure(env, "zygote", nullptr, "Zygote SetTaskProfiles failed");
}
}
// Create the socket which is going to be used to send unsolicited message
// to system_server, the socket will be closed post forking a child process.
// It's expected to be called at each zygote's initialization.
static void initUnsolSocketToSystemServer() {
gSystemServerSocketFd = socket(AF_LOCAL, SOCK_DGRAM | SOCK_NONBLOCK, 0);
if (gSystemServerSocketFd >= 0) {
ALOGV("Zygote:systemServerSocketFD = %d", gSystemServerSocketFd);
} else {
ALOGE("Unable to create socket file descriptor to connect to system_server");
}
}
4.2 SystemServer的创建
ZygoteInit 只是systemserve创建的发起者,创建systemserver启动的核心成员ZygoteServer和ZygoteArguments,然后由Zygote.java 的nativeForkSystemServer()去实施fork并返回子进程pid。
- ZygoteServer 初始化
ZygoteServer(boolean isPrimaryZygote) {
mUsapPoolEventFD = Zygote.getUsapPoolEventFD();
if (isPrimaryZygote) {
//根据环境变量 ANDROID_SOCKET_zygote 获取socket文件句柄。
mZygoteSocket = Zygote.createManagedSocketFromInitSocket(
Zygote.PRIMARY_SOCKET_NAME);
//根据环境变量 ANDROID_SOCKET_usap_pool_primary 获取usap_pool_primary句柄
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();
}
/**
* Creates a managed LocalServerSocket object using a file descriptor
* created by an init.rc script. The init scripts that specify the
* sockets name can be found in system/core/rootdir. The socket is bound
* to the file system in the /dev/sockets/ directory, and the file
* descriptor is shared via the ANDROID_SOCKET_<socketName> environment
* variable.
*/
static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);
}
try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
return new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException(
"Error building socket from file descriptor: " + fileDesc, ex);
}
}
- ZygoteArguments 的创建
/* 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,1021,1023,"
+ "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010,3011",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
"com.android.server.SystemServer",
};
- 委托 Zygote 创建进程并返回进程ID
父进程中返回的是子进程ID,子进程中返回pid = 0。
public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
ZygoteHooks.preFork();
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;
}
- 关闭子进程中的 socket 文件句柄。
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
//子进程返回 runable 接口
return handleSystemServerProcess(parsedArgs);
}
//父进程返回空。
return null
- 子进程中的 handleSystemServerProcess
创建Binder线程,创建main 函数的反射runable 接口。
/**
* 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 (parsedArgs.mInvokeWith != null) {
...
} else {
ClassLoader cl = null;
if (systemServerClasspath != null) {
cl = createPathClassLoader(systemServerClasspath, parsedArgs.mTargetSdkVersion);
Thread.currentThread().setContextClassLoader(cl);
}
/*
* Pass the remaining arguments to SystemServer.
*/
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mDisabledCompatChanges,
parsedArgs.mRemainingArgs, cl);
}
/* should never reach here */
}
/**
* 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>
*/
public static final Runnable zygoteInit(int targetSdkVersion, long[] disabledCompatChanges, String[] argv, ClassLoader classLoader) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();
ZygoteInit.nativeZygoteInit();//创建Binder线程池,用于Binder通信
return RuntimeInit.applicationInit(targetSdkVersion, disabledCompatChanges, argv, classLoader);
}
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);
}
/**
* 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.
*/
protected static Runnable findStaticMain(String className, String[] argv,
ClassLoader classLoader) {
Class<?> cl;
try {
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {}
Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {}
int modifiers = m.getModifiers();
/*
* 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);
}
/**
* 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;
}
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {}
}
}
- zygote循环监听socket文件变化
创建出systemserver 子进程后,由于systemserver 子进程返回的是非空runable,父进程zygote返回是null,所以子进程会执行run()方法然后return结束。父进程会执行zygoteServer.runSelectLoop(abiList);
public static void main(String argv[]) {
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;
}
}
Log.i(TAG, "Accepting command socket connections");
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
caller = zygoteServer.runSelectLoop(abiList);
// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run();
}
}
runSelectLoop 会去监听两个socket(init.zygote64.rc中的socket)文件句柄的变化,通过acceptCommandPeer()创建socket的接收端ZygoteConnection,一旦文件句柄发生变化就会由ZygoteConnection的processOneCommand(this)来处理。
在processOneCommand方法中通过Zygote.forkAndSpecialize()去处理子进程的创建,通过handleChildProc -> ZygoteInit.zygoteInit 构建main 函数的反射函数的runable 接口,一路返回到ZygoteInit的man函数,由于父进程得到的返回是null,子进程不为空,才会去执行的runable的run 方法,calss的main函数就会被执行到,例如应用创建时的ActivityThread.main()。
5. 总结
ZygoteInit 做初始化
Zygote 用于native层交流
ZygoteServer 永来管理socket
ZygoteConnection 用来接收socket消息并处理。
用了一张图片来总结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KGMpBEeq-1603424070135)(res/picture/zygote启动.jpg)]
本文来自博客园,作者:寒风凛凛,转载请注明原文链接:https://www.cnblogs.com/dongxiaofat/p/15426395.html