Android开机启动流程分析一(Zygote进程)

Posted by 陈宇瀚 on January 3, 2021

   该解析从system/core/init/init.cpp初始化一系列文件系统,解析system/core/rootdir/init.rc文件启动Zygote进程分析至Zygote进程启动完成。

   当我们驱动层启动完毕时首先会启动init进程,也就是用户进程。在system/core/init/init.cpp中会对init.rc文件进行解析,之后会孵化出一些进程和一些重要服务,最后会创建一个Zygote进程。这个实现过程的源码流程如下:

   以下源码基于rk3399_industry Android7.1.2

init.rc

system/core/init/init.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    ....
    //构造出解析文件用的parser(解析器)对象
    Parser& parser = Parser::GetInstance();
    //为一些类型的关键字,创建特定的parser
    parser.AddSectionParser("service",std::make_unique<ServiceParser>());
    parser.AddSectionParser("on", std::make_unique<ActionParser>());
    parser.AddSectionParser("import", std::make_unique<ImportParser>());
    //开始解析init.rc文件
    //init.rc文件是在init进程启动后执行的启动脚本,文件中记录着init进程需执行的操作。
    //在Android系统中,使用init.rc和init.{ hardware }.rc两个文件。
    //init.rc文件在Android系统运行过程中用于通用的环境设置与进程相关的定义
    //init.{hardware}.rc(例如,高通有init.qcom.rc,MTK有init.mediatek.rc)
    //用于定义Android在不同平台下的特定进程和环境设置等。
    //此处加载的init.rc文件是system/core/rootdir/init.rc,此处记载放在下方解析
    parser.ParseConfig("/init.rc");
    
    ....

system/core/rootdir/init.rc

import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc
....

init.rczygote相关的启动配置文件根据ro.zygote而定,ro.zygote的值可分为zygote32、zygote64、zygote32_64、zygote64_32四种,分别代表

  • init.zygote32.rc:32位的zygote进程,对应的执行程序是app_process
  • init.zygote64.rc:64位的zygote进程,对应的执行程序是app_process64
  • init.zygote32_64.rc:启动两个zygote进程 (zygotezygote_secondary),32位的app_process32 为主、64位的app_process64为辅。
  • init.zygote64_32.rc:启动两个zygote进程 (zygotezygote_secondary),64位的app_process64为主、32位的app_process32为辅。 ro.zygote的属性值定义是在 build/target/product/core_64_bit.mkcore_64_bit.mkdevice/rockchip/rk3399/product.mk内调用(根据芯片平台不同,对应的文件便不同,这里以RK3399为例子),代码如下 device/rockchip/rk3399/product.mk
1
2
3
4
5
PRODUCT_RUNTIMES := runtime_libart_default

$(call inherit-product, device/rockchip/rk3399/device.mk)

$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)

其中$(SRC_TARGET_DIR)为build/target,所以对应的文件路径是 build/target/product/core_64_bit.mk

1
2
3
4
5
6
7
8
9
10
11
ifeq ($(strip $(TARGET_BOARD_PLATFORM_PRODUCT)), box)
  PRODUCT_COPY_FILES += system/core/rootdir/init.zygote64_32.box.rc:root/init.zygote64_32.rc
else
  PRODUCT_COPY_FILES += system/core/rootdir/init.zygote64_32.rc:root/init.zygote64_32.rc
endif

# 设置zygote属性以选择64位的主脚本,32位的从脚本,必须在core_minimal.mk中的脚本之前解析这一行
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.zygote=zygote64_32

TARGET_SUPPORTS_32_BIT_APPS := true
TARGET_SUPPORTS_64_BIT_APPS := true

   由于我的源码系统种使用的是init.zygote64_32.rc文件,所以分析这个文件: system/core/rootdir/init.zygote64_32.rc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#创建一个名为zygote的进程,对应的可执行程序路径为/system/bin/app_process64
# -Xzygote:jvm使用的参数;在AndroidRuntime.cpp类的startVm()函数中调用JNI_CreateJavaVM()时被使用。
# /system/bin:代表虚拟机程序所在目录
# --zygote  指明以ZygoteInit类作为虚拟机执行的入口,如果没有–zygote参数,则需要明确指定需要执行的类名。
# --start-system-server仅在指定–zygote参数时才有效,意思是告知ZygoteInit启动完毕后孵化出第一个进程SystemServe
# --socket-name=zygote:指定zygote所用到的socket名为zygote
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    #  指定zygote服务使用到的名为zygote的socket,类型为stream,读写权限为660,用户为root,用户组为system。
    socket zygote stream 660 root system
    # onrestart 服务重启时执行的命令。
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    # writepid <file…> :fork 时将子进程的 pid 写入给定文件。
    writepid /dev/cpuset/foreground/tasks

#与上面类似,启动一个32位的zygote进程
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary
    class main
    socket zygote_secondary stream 660 root system
    onrestart restart zygote
    writepid /dev/cpuset/foreground/tasks
    
#rc文件结构可以简单为
#service <name> <pathname> [ <argument> ]*
#<option>
#<option>
#service 服务名称 服务对应的命令的路径 命令的参数
#选项
#选项

   init.zygote64_32.rc内部启动了两个 zygote 进程 (一个为64位的进程 zygote 和32位的进程zygote_secondary),对应的执行程序分别是 app_process64 (主模式)和app_process32

app_process的执行

   接下来分析zygote64的可执行程序/system/bin/app_process64文件,app_process64frameworks/base/cmds/app_process文件夹内部文件生成,app_process64的执行入口是目录下的app_main.cpp中的main函数,就从这里开始分析Zygote的启动流程: rameworks/base/cmds/app_process/app_main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#if defined(__LP64__)
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
static const char ZYGOTE_NICE_NAME[] = "zygote64";
#else
static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist32";
static const char ZYGOTE_NICE_NAME[] = "zygote";
#endif

//传入的参数根据上方分析得知有
//{-Xzygote , /system/bin , --zygote , --start-system-server , --socket-name=zygote}
// argc = 5
// argv[] = "-Xzygote /system/bin --zygote --start-system-server --socket-name=zygote";
int main(int argc, char* const argv[])
{
    //下方有AppRuntime和 computeArgBlockSize的代码
    //computeArgBlockSize方法会计算并且返回了传入参数的字节数
    //之后会创建有AppRuntime对象runtime
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    // 进程命令行参数
    // 忽略 argv[0] 即-Xzygote
    argc--;
    argv++;

    // '--'开头或者第一个字符非'-'参数开头的所有内容都将进入vm。
    // 虚拟机参数后的第一个参数是“父目录”,即/system/bin,目前还未使用。
    // 在父目录之后,需要一个或多个内部参数:
    // --zygote : zygote 模式启动
    // --start-system-server : 启动系统服务
    // --application : 开始应用(独立,非Zygote)模式。
    // --nice-name : 进程名
    // 对于非Zygote模式开始,这些参数后面将跟着启动类名。所有剩余的参数都传递给这个类的main方法。
    // 对于zygote模式开始,所有剩余参数都传递给zygote main函数。
    int i;
    for (i = 0; i < argc; i++) {
        if (argv[i][0] != '-') {
            // argv[0] = “/system/bin”,所以直接就结束循环
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            ++i; // Skip --.
            break;
        }
        //这里过滤后 这部分只有'-'开头的参数
        runtime.addOption(strdup(argv[i]));
    }

    // 解析运行时参数。在第一次未被识别的选项时停止。
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;
    // 跳过未使用的“父目录(/system/bin)”参数,所以这里需要解析的参数数组为
    // {--zygote , --start-system-server , --socket-name=zygote}
    ++i;  
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {//是否存在--zygote参数
            //设置zygot参数为true,代表启动zygote模式
            zygote = true;
            niceName = ZYGOTE_NICE_NAME; //将niceName设置为"zygote"或者"zygote64"
        } else if (strcmp(arg, "--start-system-server") == 0) {
            //启动zygot模式存在--start-system-server,将startSystemServer设置为true
            startSystemServer = true; 
        } else if (strcmp(arg, "--application") == 0) {//启动zygote模式不存在--application
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {//启动zygot模式不存在--nice-name
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {//启动zygot模式时不会进入
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }
  // 启动zygote时,上面运行完对应参数如下:
  // zygote = true; niceName = ZYGOTE_NICE_NAME;startSystemServer = true; 
  // application = false; className =null;i=3;
  Vector<String8> args;//该参数接下来要传入AndroidRuntime.start函数
    if (!className.isEmpty()) { //启动zygote时不会进入
        // 假如我们要启动的不是zygote进程,而是application或tool程序
        // 我们需要传递给RuntimeInit的唯一参数是应用程序参数。
        // 其余的参数传递给启动类的main()。在使用进程名覆盖它们之前,对它们进行复制。
        args.add(application ? String8("application") : String8("tool"));
        runtime.setClassNameAndArgs(className, argc - i, argv + i);
    } else {
        //启动zygote时
        maybeCreateDalvikCache();//创建/data/dalvik-cache路径,下方会放源码

        if (startSystemServer) {
            // 设置启动系统服务的参数
            args.add(String8("start-system-server"));
        }

        char prop[PROP_VALUE_MAX];
        // 获取到对应的ABI类型
        // [ro.product.cpu.abilist] : [arm64-v8a, armeabi-v7a, armeabi]
        // [ro.product.cpu.abilist32] : [armeabi-v7a, armeabi]
        // [ro.product.cpu.abilist64] : [arm64-v8a]
        // 根据我们的参数这里获得的是arm64-v8a
        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);

        // 将所有剩余参数添加到args
        // 启动zygote时这里argv就剩下“--socket-name=zygote”参数没加入了,添加进args
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }   
    // 继续启动zygote,此时的args的值为
    //{"start-system-server","--abi-list=ro.product.cpu.abilist64",--socket-name=zygote}

    if (!niceName.isEmpty()) { //启动zygote时不成立
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
    }
    if (zygote) { // 启动zygot时成立,调用
        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.");
        return 10;
    }
}

/************ 下面是内部调用的一些方法的源码,有需要可以看看 ************/
//这里计算并且返回了传入参数的字节数,这样的目的可以确保传入的四个参数是在一个连续的内存中。
static size_t computeArgBlockSize(int argc, char* const argv[]) {
    uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
    uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]);
    end += strlen(argv[argc - 1]) + 1;
    return (end - start);
}

//创建了/data/dalvik-cache目录,并修改该路径的用户、用户组和权限信息
static void maybeCreateDalvikCache() {
#if defined(__aarch64__)
    static const char kInstructionSet[] = "arm64";
#elif defined(__x86_64__)
    static const char kInstructionSet[] = "x86_64";
#elif defined(__arm__)
    static const char kInstructionSet[] = "arm";
#elif defined(__i386__)
    static const char kInstructionSet[] = "x86";
#elif defined (__mips__) && !defined(__LP64__)
    static const char kInstructionSet[] = "mips";
#elif defined (__mips__) && defined(__LP64__)
    static const char kInstructionSet[] = "mips64";
#else
#error "Unknown instruction set"
#endif
    const char* androidRoot = getenv("ANDROID_DATA");//这里的androidRoot为"data
    LOG_ALWAYS_FATAL_IF(androidRoot == NULL, "ANDROID_DATA environment variable unset");

    char dalvikCacheDir[PATH_MAX];
    const int numChars = snprintf(dalvikCacheDir, PATH_MAX,
            "%s/dalvik-cache/%s", androidRoot, kInstructionSet);
    LOG_ALWAYS_FATAL_IF((numChars >= PATH_MAX || numChars < 0),
            "Error constructing dalvik cache : %s", strerror(errno));

    //0711 只有属主有读、写、执行权限;而属组用户和其他用户只有执行权限。 
    int result = mkdir(dalvikCacheDir, 0711); //创建/data/dalvik-cache目录
    LOG_ALWAYS_FATAL_IF((result < 0 && errno != EEXIST),
            "Error creating cache dir %s : %s", dalvikCacheDir, strerror(errno));
    
    //更改/data/dalvik-cache目录的用户与用户组为root用户、root用户组
    result = chown(dalvikCacheDir, AID_ROOT, AID_ROOT);
    LOG_ALWAYS_FATAL_IF((result < 0), "Error changing dalvik-cache ownership : %s", strerror(errno));

    result = chmod(dalvikCacheDir, 0711);//更改/data/dalvik-cache路径的权限
    LOG_ALWAYS_FATAL_IF((result < 0),
            "Error changing dalvik-cache permissions : %s", strerror(errno));
}

   由上面源码分析可得。由于rc内启动zygote时带有参数–zygote,所以最后会执行到runtime.start(“com.android.internal.os.ZygoteInit”, args, true);函数, runtimeAppRuntime类的对象,而AppRuntime类继承自AndroidRuntime,对应源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class AppRuntime : public AndroidRuntime
{
public:
    AppRuntime(char* argBlockStart, const size_t argBlockLength)
        : AndroidRuntime(argBlockStart, argBlockLength)
        , mClass(NULL)
    {
    }
    ....
}
/** frameworks/base/core/jni/AndroidRuntime.cpp **/
//静态全局变量gCurRuntime指向AndroidRuntime对象本身,之后我们若需要获取AndroidRuntime对象,获取gCurRuntime就可以了。
static AndroidRuntime* gCurRuntime = NULL;
//创建AndroidRuntime对象
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
        mExitWithoutCleanup(false),
        mArgBlockStart(argBlockStart),
        mArgBlockLength(argBlockLength)
{   
    SkGraphics::Init();
    // 预先分配足够的空间来容纳相当数量的选项。
    mOptions.setCapacity(20);
    
    assert(gCurRuntime == NULL);        // one per process
    gCurRuntime = this;
}

   在AppRuntime类其内部并没有start方法,实际调用的是AndroidRuntime类的start方法,接下来分析这个函数;

frameworks/base/core/jni/AndroidRuntime.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
 * 启动 Android runtime.这部分涉及到启动虚拟机并在名为“className”的类中调用其
 * “static void main(String[] args)”方法。
 * 向main函数传递两个参数,类名和指定的选项字符串。
 */
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
    //此时的options为{"start-system-server","--abi-list=ro.product.cpu.abilist64",--socket-name=zygote}
    static const String8 startSystemServer("start-system-server");

    ....
    const char* rootDir = getenv("ANDROID_ROOT");//rootDir为"/system"目录
    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);
    }
    
    /* 启动虚拟机 */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    onVmCreated(env);
    /*
     * 注册安卓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);
    // String数组
    strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
    assert(strArray != NULL);
    // 即ZygoteInit类名字符串
    classNameStr = env->NewStringUTF(className);
    assert(classNameStr != NULL);
    // 将类名传入String数组strArray的第0个位置
    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);
    }

    /*
     * 启动虚拟机。该线程成为VM的主线程,并且在VM退出之前不会返回。
     */
    char* slashClassName = toSlashClassName(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");//获取ZygoteInit类的main函数
        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
        }
    }
    //释放slashClassName
    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内可分为如下几步:

  • 设置了rootDir的目录为/system
  • 通过startVm(&mJavaVM, &env, zygote)启动了虚拟机;
  • 调用startReg(env)注册jni函数;
  • 创建字符串数组来保存类和设置选项
  • 将生成的字符串数组传入并调用ZygoteInit.main方法

AndroidRuntime.startVm:启动虚拟机

   startVm内部定义了虚拟机的一系列参数,下面简单介绍一些虚拟机的参数,大部分省略掉了,太多了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/*
 * 启动Dalvik虚拟机。
 *
 * 传入的各种参数(大多数由系统属性决定)。还有一些由“mOptions” Vector更新。
 *
 * 成功返回0
 */
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
    ....

    bool checkJni = false;
     //JNI检测功能,用于native层调用jni函数时进行常规检测,比较弱字符串格式是否符合要求,资源是否正确释放。
     //该功能一般用于早期系统调试或手机Eng版,对于User版往往不会开启,引用该功能比较消耗系统CPU资源,降低系统性能。
    property_get("dalvik.vm.checkjni", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
        checkJni = true;
    } else if (strcmp(propBuf, "false") != 0) {
        /* 判断kernel层是否开启 */
        property_get("pa.kernel.android.checkjni", propBuf, "");
        if (propBuf[0] == '1') {
            checkJni = true;
        }
    }
    ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
    if (checkJni) {
        /* 开启JNI检测功能 */
        addOption("-Xcheck:jni");
    }
    //dalvik虚拟机启动模式
    property_get("dalvik.vm.execution-mode", propBuf, "");
    if (strcmp(propBuf, "int:portable") == 0) {
        executionMode = kEMIntPortable;
    } else if (strcmp(propBuf, "int:fast") == 0) {
        executionMode = kEMIntFast;
    } else if (strcmp(propBuf, "int:jit") == 0) {
        executionMode = kEMJitCompiler;
    }
    //虚拟机产生的trace文件,主要用于分析系统问题,路径默认为/data/anr/traces.txt
    parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");
    
    ....

    /*
     * 堆的默认启动和最大大小。根据不同的设备可以做相应的调整
     */
    //dalvik.vm.heapstartsize:应用程序启动后为其分配的初始大小
    parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
    //dalvik.vm.heapsize:单个虚拟机可分配的最大内存
    parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");
    //dalvik.vm.heapgrowthlimit:每个应用程序最大可分配内存
    parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
    //dalvik.vm.heapminfree:堆最小空闲内存
    parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");
    //dalvik.vm.heapmaxfree:堆最大空闲内存
    parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
    //dalvik.vm.heaptargetutilization:堆利用率
    parseRuntimeOption("dalvik.vm.heaptargetutilization",
                       heaptargetutilizationOptsBuf,
                       "-XX:HeapTargetUtilization=");
    //heapminfree、heapmaxfree、heaptargetutilization这三个值的设置则对垃圾回收(GC)的某些性能有影响。

    /*
     * JIT编译器相关配置。JIT:即时编译技术
     */
    ....

    //确保有一个预加载的类文件preloaded-classes(由WritePreloadedClassFile.java生成)。
    //在ZygoteInit类中会预加载工作将其中的classes提前加载到内存,以提高系统性能
    if (!hasFile("/system/etc/preloaded-classes")) {
        ALOGE("Missing preloaded-classes file, /system/etc/preloaded-classes not found: %s\n",
              strerror(errno));
        return -1;
    }
    ....

    //创建虚拟机
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
        ALOGE("JNI_CreateJavaVM failed\n");
        return -1;
    }

    return 0;
}

AndroidRuntime.startReg:注册jni函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/*
 * 向VM注册android jni函数。
 */
/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
{
    ATRACE_NAME("RegisterAndroidNatives");
    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);
    
    //调用register_jni_procs进行jni接口注册,gRegJNI就是通过REG_JNI宏定义的jni函数数组
    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
        env->PopLocalFrame(NULL);
        return -1;
    }
    env->PopLocalFrame(NULL);

    return 0;
}

static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
    for (size_t i = 0; i < count; i++) {
        if (array[i].mProc(env) < 0) {
#ifndef NDEBUG
            ALOGD("----------!!! %s failed to load\n", array[i].mName);
#endif
            return -1;
        }
    }
    return 0;
}
//REG_JNI宏定义
#define REG_JNI(name)      { name }
    struct RegJNIRec {
        int (*mProc)(JNIEnv*);
    };
    
static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_com_android_internal_os_RuntimeInit),
    REG_JNI(register_android_os_SystemClock),
    REG_JNI(register_android_util_EventLog),
    REG_JNI(register_android_util_Log),
    REG_JNI(register_android_util_MemoryIntArray),
    REG_JNI(register_android_util_PathParser),
    REG_JNI(register_android_app_admin_SecurityLog),
    REG_JNI(register_android_content_AssetManager),
    REG_JNI(register_android_content_StringBlock),
    REG_JNI(register_android_content_XmlBlock),
    REG_JNI(register_android_text_AndroidCharacter),
    REG_JNI(register_android_text_StaticLayout),
    REG_JNI(register_android_text_AndroidBidi),
    REG_JNI(register_android_view_InputDevice),
    ....
    }

   到此,虚拟机已经启动,jni函数也已经注册,这里只是简单分析,毕竟完整的分析就有点偏离启动流程了。之后进入ZygoteInit.main类的main函数;

ZygoteInit.main

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  private static final String ABI_LIST_ARG = "--abi-list=";

  private static final String SOCKET_NAME_ARG = "--socket-name=";
  
// 此时的argv[]为
// {"ZygoteInit","start-system-server","--abi-list=ro.product.cpu.abilist64",--socket-name=zygote}
 public static void main(String argv[]) {
        ....
        try {
            // DDMS:DalvikDebugMonitorServer,Dalvik调试监控服务器
            RuntimeInit.enableDdms();//开启DDMS监听,监听DDMS消息
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();//启动性能统计

            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    // 获得adb类型,此时为ro.product.cpu.abilist64
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                     // socketName = zygote
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }
            if (abiList == null) {
                // 没有获取到abi
                throw new RuntimeException("No ABI list supplied.");
            }
            // 创建名为zygote的的Server端socket
            registerZygoteSocket(socketName);
            preload();// 预加载类和资源
            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);

            SamplingProfilerIntegration.writeZygoteSnapshot();

            // 初始化gc
            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC");
            gcAndFinalize();
            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);

            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);

            // 关闭trace以防止fork出的进程trace错误
            Trace.setTracingEnabled(false);

            // Zygote进程卸载根存储空间,不太明白,希望大神赐教
            Zygote.nativeUnmountStorageOnInit();

            ....
            
            if (startSystemServer) {
                // 启动系统服务
                startSystemServer(abiList, socketName);
            }

            // 进入循环等待
            // 等待Activity管理服务ActivityManagerService请求Zygote进程创建新的应用程序进程
            runSelectLoop(abiList);
            
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

registerZygoteSocket

   registerZygoteSocket:创建名为zygoteServersocket:用来等待ActivityManagerService请求Zygote进程创建新的应用程序进程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 private static LocalServerSocket sServerSocket;
 private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
 private static void registerZygoteSocket(String socketName) {
        if (sServerSocket == null) {
            int fileDesc;
            final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
            try {   
                //env = ANDROID_SOCKET_zygote
                String env = System.getenv(fullSocketName);
                //将env转成文件描述符
                fileDesc = Integer.parseInt(env);
            } catch (RuntimeException ex) {
                throw new RuntimeException(fullSocketName + " unset or invalid", ex);
            }

            try {   
                //根据fileDesc创建一个Server端socket
                FileDescriptor fd = new FileDescriptor();
                fd.setInt$(fileDesc);
                //保存至ZygoteInit的静态成员变量sServerSocket
                sServerSocket = new LocalServerSocket(fd);
            } catch (IOException ex) {
                throw new RuntimeException(
                        "Error binding to local socket '" + fileDesc + "'", ex);
            }
        }
    }

   创建完成后,会进行一些预加载类和资源,如果有需要会调用startSystemServer启动System进程,然后调用runSelectLoop进行循环等待。

runSelectLoop

   runSelectLoop:进入循环等待,等待Activity管理服务ActivityManagerService(以下简称AMS),请求Zygote进程创建新的应用程序进程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
    /**
     * 运行Zygote进程的循环等待,当新的连接请求发生时生成新的应用程序进程。
     */
    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
        //peers是与Zygote进程的Server Socket(mServerSocket)连接的连接列表
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
        //将mServerSocket的文件描述符放入fds
        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);
        //无限循环等待AMS请求Zygote进程创建新的应用程序进程
        while (true) {
            StructPollfd[] pollFds = new StructPollfd[fds.size()];
            for (int i = 0; i < pollFds.length; ++i) {
                pollFds[i] = new StructPollfd();
                pollFds[i].fd = fds.get(i);
                pollFds[i].events = (short) POLLIN;
            }
            try {
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }
            for (int i = pollFds.length - 1; i >= 0; --i) {
                if ((pollFds[i].revents & POLLIN) == 0) {
                    continue;
                }
                if (i == 0) {
                    //AMS与Zygote进程的mServerSocket建立连接
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    //将这个连接添加到sdocket连接列表peer中
                    peers.add(newPeer);
                    //将该连接的socket文件描述符添加到fds中
                    fds.add(newPeer.getFileDesciptor());
                    //添加完成后就可以接受AMS发送过来的创建应用程序进程请求
                } else {
                     //处理AMS与Zygote发送的请求
                     //peers.get(i)就是之前建立起来的连接(ZygoteConnection)
                     //调用其runOnce()来创建一个新的应用程序进程
                    boolean done = peers.get(i).runOnce();
                    if (done) {
                        //处理完成了这个连接,将对应的连接和描述符删除
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }

   runSelectLoop发生在启动System进程完成之后,根据代码得到Zygote进程会进入一个无限循环,不断等待AMS的连接和请求创建新的应用程序进程。针对如何通过ZygoteConnection.runOnce()来创建一个新的进程过程比较复杂,之后另开一篇文章分析;

整个过程可以用流程图简单概括: image