Android Framework分析init进程如何启动Zygote进程

在Android系统中,init进程是整个系统最先启动的进程,它的启动过程是整个系统启动过程的第一步。init进程的主要作用是启动系统服务和应用进程,其中,Zygote进程是Android系统中的一个重要进程,它主要负责预热Java虚拟机和启动应用进程。本文将着重分析init进程如何启动Zygote进程,作者将结合代码注释和示例代码,让读者更好地理解Zygote的启动流程。

init进程的启动过程

init进程是Android系统中启动最早的进程,其主要职责是启动系统服务和应用进程。在init进程的启动过程中,主要包含以下几个关键步骤:

  1. init进程读取init.rc配置文件,执行其中的命令,启动各个系统服务。

  2. 在启动过程中,init进程会读取ro.zygote属性,判断是否需要启动Zygote进程。

  3. 如果需要启动Zygote进程,init进程则会执行如下命令:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
  1. 然后,init进程会启动Zygote进程,并通过Binder机制与Zygote进程建立连接,并通过Impersonation进行用户身份验证。

如上所示,init进程启动Zygote进程的关键步骤主要涉及读取ro.zygote属性、启动命令的执行和与Zygote进程的连接。下面我们将逐一进行讲解。

读取ro.zygote属性

在启动过程中,init进程会通过读取ro.zygote属性的方式来判断是否需要启动Zygote进程。ro.zygote属性是一个系统属性,它的值通常是"/system/bin/app_process32"或"/system/bin/app_process64",用于指定Zygote进程的路径。

在读取ro.zygote属性时,init进程会调用getConfigurationProperty()方法,该方法会读取/system/build.prop和/prop/*.prop等多个属性文件,并将结果缓存在静态变量中,以提升系统启动速度。

/**
 * Returns the property value for a given key or {@code defaultValue} if no such property
 * exists.
 */
static String getConfigurationProperty(String key, String defaultValue) {
    if (key == null) return defaultValue;

    String value = (String) sConfigKeysAndValues.get(key);
    if (value == null) {
        // On Android, system properties are prefixed with "ro.", whereas on ctsdevices, they are not. Since CTS is not expected to pass when running on a commercial device, we
        // handle the "ro." prefix here to make it easier to perform target-independent testing.
        value = SystemProperties.get("ro." + key);
        if (TextUtils.isEmpty(value)) {
            value = SystemProperties.get(key);
        }
        if (!TextUtils.isEmpty(value)) {
            sConfigKeysAndValues.put(key, value);
        }
    }

    return !TextUtils.isEmpty(value) ? value : defaultValue;
}

如上所示,getConfigurationProperty()方法是读取系统属性文件的重要方法之一,它会先从缓存中查找属性值,如果缓存中没有,则会依次读取/system/build.prop和/prop/*.prop等属性文件,并通过SystemProperties.get()方法获取属性值。

如果ro.zygote属性存在并且值不为空,则认为需要启动Zygote进程。

启动命令的执行

如果ro.zygote属性存在并且值不为空,则init进程会执行启动Zygote进程的命令:

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

上述命令的核心是执行/system/bin/app_process命令,并启动Zygote进程。下面,我们来详细解析/system/bin/app_process命令的原理。

app_process命令的原理

app_process命令是Android系统中启动Zygote进程的关键命令,它主要负责预热Java虚拟机和启动应用进程。下面,我们来详细了解app_process命令的原理。

app_process命令是通过/system/bin/app_process.sh脚本来实现的,具体实现过程如下:

  1. 通过构造CLASSPATH和LD_LIBRARY_PATH环境变量,将ZygoteInit所依赖的标准库和应用进程的类所在路径加入到系统路径中。
# 构造CLASSPATH和LD_LIBRARY_PATH
MAGIC_VM_ARGS_FIRST="--runtime-args"
MAGIC_VM_ARGS_SECOND="log:logcat -s ZygoteInit"
if [ "$nice_name" = "zygote" ] ; then
    export LD_LIBRARY_PATH=/system/lib64:/system/lib
    CLASSPATH=$SYSTEMSERVERCLASSPATH
else
    CLASSPATH=$ANDROID_ROOT/$SYSTEMSERVERCLASSPATH:$BOOTCLASSPATH
    export ANDROID_ROOT
fi
export CLASSPATH LD_LIBRARY_PATH
  1. 通过读取/android_root/prop文件中的ro.debuggable属性、/system/lib/libz.so库和/system/bin/debuggerd程序来判断是否需要启用调试模式。

  2. 添加/system/bin/config文件中的-Djava.awt.headless=true参数,并构造启动Zygote进程的命令。

# 添加-Djava.awt.headless=true
args="$args -Djava.awt.headless=true"

# 构造启动Zygote进程的命令
exec $ZYGOTE_BINARY $ARGS_FOR_ZYGOTE 
    $MAGIC_VM_ARGS_FIRST
    $args
    $MAGIC_VM_ARGS_SECOND
    "${debug_flags[@]}"

如上所示,通过构造CLASSPATH和LD_LIBRARY_PATH环境变量、判断是否启用调试模式以及构造启动Zygote进程的命令,app_process命令完成了Java虚拟机的预热和Zygote进程的启动。

与Zygote进程的连接

在启动Zygote进程后,init进程会通过Binder机制和Impersonation进行身份验证,与Zygote进程建立连接,并执行如下命令:

write /sys/android_power/request_state 0

目的是让Zygote进程能够释放设备资源,并准备就绪,等待应用进程的请求。在连接建立完成后,init进程会通过Binder机制向Zygote进程发送启动应用进程的请求。

总结

本文主要针对Android系统启动流程中init进程如何启动Zygote进程这个重要的问题展开了详细的讲解。作者结合实际代码,对相关知识点进行了解析,包括ro.zygote属性的读取、app_process命令的原理、与Zygote进程的连接等方面。在了解了这些内容后,读者应该能够更深入地理解Android系统的启动过程,并在实际开发中做出更加明智的决策。

参考资料:

  1. Android Framework源码:https://cs.android.com/android/platform/superproject/

  2. Android Developers官方文档:https://developer.android.com/docs

你可能感兴趣的:(Android,android,zygote,java)