ART机制架构详解

概要

从android5.0版本开始,android应用程序默认的运行环境为ART。ART机制与Dalvik不同,在Dalvik下,应用每次运行时,字节码都需要通过即时编译器转换为机器码,这会拖慢应用的运行效率,而在ART环境下,应用在第一次安装时,字节码就会预先编译成机器码,使其成为真正的本地应用。这个过程叫做预编译(Ahead-Of-Time,AOT)。这样,应用的(首次)启动和执行就会变得更加快速。

ART的启动过程

传统的Dalvik虚拟机其实是一个Java虚拟机,只不过它执行的不是CLASS文件,而是DEX文件。因此,ART运行时最理想的方式也是实现一个Java虚拟机的形式,这样就可以很容易地将Davik虚拟机替换掉。ART运行时就是真的和Dalvik虚拟机一样,实现了一套完全兼容Java虚拟机的接口。

ART、Dalvik和JVM的关系

Dalvik虚拟机和ART虚拟机都实现了如下3个用来抽象Java虚拟机的接口。

  • JNI_GetDefaultJavaVMInitArgs:获取虚拟机的默认初始化参数。

  • JNI_CreateJavaVM:在进程中创建虚拟机实例。

  • JNI_GetCreatedJavaVMs:获取进程中创建的虚拟机实例。

    在android系统中,Dalvik虚拟机实现在libdvm.so文件中,ART虚拟机实现在libart.so文件中。此外,android系统还提供了一个系统属性persist.sys.dalvik.vm.lib,其值等于libdvm.so或libart.so,当等于libdvm.so时,表示当前用的是Dalvik虚拟机,当用的是libart.so时,表示当前用的是ART虚拟机。

Dalvik虚拟机执行的是DEX字节码,ART虚拟机执行的是本地机器码。这意味着Dalvik虚拟机包含有一个解释器,用来执行DEX字节码。当然,android从2.2开始,也包含有JIT(Just-In-Time),用来在运行动态地将执行频率更高的DEX字节码翻译成本地机器码,然后再执行。通过JIT,就可以有效地提高Dalvik虚拟机的执行效率。但是,将DEX字节码翻译成本地机器码是发生在应用程序的运行过程中的,并且应用程序每一重新运行时,都要重新做这个翻译工作。因此,即使采用了JIT,Dalvik虚拟机的总体性能还是不能与执行本地机器码的ART虚拟机相比。

ART虚拟机在app_process进程中启动,因此,分析ART的启动过程,需要从app_process进程,也就是zygote进程入手。

  • 运行app_process进程

    当android系统启动后会创建一个zygote进程,作为应用程序的进程孵化器,并且在启动zygote进程的过程中会创建一个Dalvik虚拟机。zygote进程是通过复制自己来创建新的应用程序进程的,这意味着zygote进程会将自己的Dalvik虚拟机复制给应用程序进程。上述方式可以大大提高应用程序的启动速度,因为这种方式避免了每一个应用程序进程在启动时都要去创建一个Dalvik。事实上,zygote进程通过自我复制的方式来创建应用程序进程,省去的不仅仅是应用程序创建Dalvik虚拟机的时间,还能省去应用程序加载各种系统库和系统资源的时间,因为它们在zygote进程中已经加载过了,并且也会连同Dalvik虚拟机一起复制到应用程序中去。这也是ART优于Dalvik的原因。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    int main(int argc, char* const argv[]) {
    ...
    if (!niceName.isEmpty()) {
    runtime.setArgv0(niceName.string());
    // 此处调用set_process_name()函数,通过Linux下的pctrl系统调用把名字“app_process”换成 了“zygote”
    set_process_name(niceName.string());
    }
    // zygote为true代表的是zygote进程,也就是谁现在正在启动zygote进程。因为zygote进程是通过自己的资源 复制一份来fork一个新的子进程的,也就是说子进程也会进入这个文件的main函数,所以通过这个zygote变量 就可以来区分
    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.");
    return 10;
    }
    }

    在上述代码中,runtime是AppRuntime的实例,AppRuntime继承自AndroidRuntime。类AndroidRuntime中的函数start()的具体实现如下。

    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
    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");
    for (size_t i = 0; i < options.size(); ++i) {
    if (options[i] == startSystemServer) {
    const int LOG_BOOT_PROGRESS_START = 3000;
    LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
    }
    }
    const char* rootDir = getenv("ANDROID_ROOT");
    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);
    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);
    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);
    }
    char* slashClassName = toSlashClassName(className);
    jclass startClass = env->FindClass(slashClassName);
    if (startClass == NULL) {
    ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
    } else {
    jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
    "([Ljava/lang/String;)V");
    if (startMeth == NULL) {
    ALOGE("JavaVM unable to find main() in '%s'\n", className);
    } else {
    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");
    }

    由此可见,类AndroidRuntime的成员函数start()最主要实现了如下3个功能。

    • 创建一个JniInvocation实例,并且调用其成员函数Init()来初始化JNI环境。

      1
      2
      JniInvocation jni_invocation;
      jni_invocation.Init(NULL);
    • 调用AndroidRuntime类的成员函数startVM()来创建一个虚拟机及其对应的JNI接口,即创建一个JavaVM接口和一个JNIEnv接口。

      1
      2
      3
      4
      5
      JNIEnv* env;
      if (startVm(&mJavaVM, &env, zygote) != 0) {
      return;
      }
      onVmCreated(env);
    • 通过上述JavaVM接口和JNIEnv接口在zygote进程中加载指定的class。

    其中,上述前两个功能是最关键的。因此,接下来继续分析它们所对应的函数的实现。

    JniInvocation函数Init()的具体实现如下。

    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
    bool JniInvocation::Init(const char* library) {
    #ifdef __ANDROID__
    char buffer[PROP_VALUE_MAX];
    #else
    char* buffer = NULL;
    #endif
    library = GetLibrary(library, buffer);
    const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE;
    handle_ = dlopen(library, kDlopenFlags);
    if (handle_ == NULL) {
    if (strcmp(library, kLibraryFallback) == 0) {
    ALOGE("Failed to dlopen %s: %s", library, dlerror());
    return false;
    }
    ALOGW("Falling back from %s to %s after dlopen error: %s",
    library, kLibraryFallback, dlerror());
    library = kLibraryFallback;
    handle_ = dlopen(library, kDlopenFlags);
    if (handle_ == NULL) {
    ALOGE("Failed to dlopen %s: %s", library, dlerror());
    return false;
    }
    }
    if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
    "JNI_GetDefaultJavaVMInitArgs")) {
    return false;
    }
    if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
    "JNI_CreateJavaVM")) {
    return false;
    }
    if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
    "JNI_GetCreatedJavaVMs")) {
    return false;
    }
    return true;
    }

    在上述代码中,函数Init()首先读取系统属性persist.sys.dalvik.vm.lib的值。因为系统属性persist.sys.dalvik.vm.lib的值等于libdvm.so或ligart.so,所以接下来就通过函数dlopen()加载到进程的是libdvm.so或ligart.so。无论加载的是哪一个,都要求导出JNI_GetDefaultJavaVMInitArgs、JNI_CreateJavaVM、JNI_GetCreatedJavaVMs这三个接口,并且分别保存在JniInvocation类的3个成员变量JNIGetDefaultJavaVMInitArgs、JNICreateJavaVM和JNIGetCreatedJavaVMs中。

  • 准备启动

    回到函数AndroidRuntime::start()的第二个功能,其主要是调用startVm()函数来启动虚拟机。AndroidRuntime类的成员函数AndroidRuntime::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
    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
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
    {
    JavaVMInitArgs initArgs;
    char propBuf[PROPERTY_VALUE_MAX];
    char stackTraceFileBuf[sizeof("-Xstacktracefile:")-1 + PROPERTY_VALUE_MAX];
    char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
    char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
    char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
    char heapgrowthlimitOptsBuf[sizeof("-XX:HeapGrowthLimit=")-1 + PROPERTY_VALUE_MAX];
    char heapminfreeOptsBuf[sizeof("-XX:HeapMinFree=")-1 + PROPERTY_VALUE_MAX];
    char heapmaxfreeOptsBuf[sizeof("-XX:HeapMaxFree=")-1 + PROPERTY_VALUE_MAX];
    char usejitOptsBuf[sizeof("-Xusejit:")-1 + PROPERTY_VALUE_MAX];
    char jitmaxsizeOptsBuf[sizeof("-Xjitmaxsize:")-1 + PROPERTY_VALUE_MAX];
    char jitinitialsizeOptsBuf[sizeof("-Xjitinitialsize:")-1 + PROPERTY_VALUE_MAX];
    char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX];
    char useJitProfilesOptsBuf[sizeof("-Xjitsaveprofilinginfo:")-1 + PROPERTY_VALUE_MAX];
    char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX];
    char jittransitionweightOptBuf[sizeof("-Xjittransitionweight:")-1 + PROPERTY_VALUE_MAX];
    char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
    char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
    char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
    char cachePruneBuf[sizeof("-Xzygote-max-boot-retry=")-1 + PROPERTY_VALUE_MAX];
    char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
    char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
    char dex2oatXmsFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
    char dex2oatXmxFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
    char dex2oatCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
    char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
    char dex2oatThreadsBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX];
    char dex2oatThreadsImageBuf[sizeof("-j")-1 + PROPERTY_VALUE_MAX];
    char dex2oat_isa_variant_key[PROPERTY_KEY_MAX];
    char dex2oat_isa_variant[sizeof("--instruction-set-variant=") -1 + PROPERTY_VALUE_MAX];
    char dex2oat_isa_features_key[PROPERTY_KEY_MAX];
    char dex2oat_isa_features[sizeof("--instruction-set-features=") -1 + PROPERTY_VALUE_MAX];
    char dex2oatFlagsBuf[PROPERTY_VALUE_MAX];
    char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX];
    char extraOptsBuf[PROPERTY_VALUE_MAX];
    char voldDecryptBuf[PROPERTY_VALUE_MAX];
    enum {
    kEMDefault,
    kEMIntPortable,
    kEMIntFast,
    kEMJitCompiler,
    } executionMode = kEMDefault;
    char localeOption[sizeof("-Duser.locale=") + PROPERTY_VALUE_MAX];
    char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX];
    char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX];
    char cpuAbiListBuf[sizeof("--cpu-abilist=") + PROPERTY_VALUE_MAX];
    char methodTraceFileBuf[sizeof("-Xmethod-trace-file:") + PROPERTY_VALUE_MAX];
    char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX];
    char fingerprintBuf[sizeof("-Xfingerprint:") + PROPERTY_VALUE_MAX];
    bool checkJni = false;
    property_get("dalvik.vm.checkjni", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
    checkJni = true;
    } else if (strcmp(propBuf, "false") != 0) {
    property_get("ro.kernel.android.checkjni", propBuf, "");
    if (propBuf[0] == '1') {
    checkJni = true;
    }
    }
    ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
    if (checkJni) {
    addOption("-Xcheck:jni");
    }
    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;
    }
    parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");
    strcpy(jniOptsBuf, "-Xjniopts:");
    if (parseRuntimeOption("dalvik.vm.jniopts", jniOptsBuf, "-Xjniopts:")) {
    ALOGI("JNI options: '%s'\n", jniOptsBuf);
    }
    addOption("exit", (void*) runtime_exit); // exit()线程处理
    addOption("vfprintf", (void*) runtime_vfprintf); // fprintf()线程处理
    addOption("sensitiveThread", (void*) runtime_isSensitiveThread); // 注册敏感线程框架
    addOption("-verbose:gc");
    // 默认的启动和堆的最大尺寸
    parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
    parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");
    parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
    parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");
    parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
    parseRuntimeOption("dalvik.vm.heaptargetutilization",
    heaptargetutilizationOptsBuf,
    "-XX:HeapTargetUtilization=");
    // 设置最大JIT代码缓存大小
    parseRuntimeOption("dalvik.vm.usejit", usejitOptsBuf, "-Xusejit:");
    parseRuntimeOption("dalvik.vm.jitmaxsize", jitmaxsizeOptsBuf, "-Xjitmaxsize:");
    parseRuntimeOption("dalvik.vm.jitinitialsize", jitinitialsizeOptsBuf, "-Xjitinitialsize:");
    parseRuntimeOption("dalvik.vm.jitthreshold", jitthresholdOptsBuf, "-Xjitthreshold:");
    property_get("dalvik.vm.usejitprofiles", useJitProfilesOptsBuf, "");
    if (strcmp(useJitProfilesOptsBuf, "true") == 0) {
    addOption("-Xjitsaveprofilinginfo");
    }
    parseRuntimeOption("dalvik.vm.jitprithreadweight",
    jitprithreadweightOptBuf,
    "-Xjitprithreadweight:");
    parseRuntimeOption("dalvik.vm.jittransitionweight",
    jittransitionweightOptBuf,
    "-Xjittransitionweight:");
    property_get("ro.config.low_ram", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
    addOption("-XX:LowMemoryMode");
    }
    parseRuntimeOption("dalvik.vm.gctype", gctypeOptsBuf, "-Xgc:");
    parseRuntimeOption("dalvik.vm.backgroundgctype", backgroundgcOptsBuf, "-XX:BackgroundGC=");
    if (zygote) {
    addOption("-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y");
    }
    parseRuntimeOption("dalvik.vm.lockprof.threshold",
    lockProfThresholdBuf,
    "-Xlockprofthreshold:");
    if (executionMode == kEMIntPortable) {
    addOption("-Xint:portable");
    } else if (executionMode == kEMIntFast) {
    addOption("-Xint:fast");
    } else if (executionMode == kEMJitCompiler) {
    addOption("-Xint:jit");
    }
    property_get("vold.decrypt", voldDecryptBuf, "");
    bool skip_compilation = ((strcmp(voldDecryptBuf, "trigger_restart_min_framework") == 0) ||
    (strcmp(voldDecryptBuf, "1") == 0));
    parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xms", dex2oatXmsImageFlagsBuf,
    "-Xms", "-Ximage-compiler-option");
    parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xmx", dex2oatXmxImageFlagsBuf,
    "-Xmx", "-Ximage-compiler-option");
    if (skip_compilation) {
    addOption("-Ximage-compiler-option");
    addOption("--compiler-filter=verify-none");
    } else {
    parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
    "--compiler-filter=", "-Ximage-compiler-option");
    }
    if (!hasFile("/system/etc/preloaded-classes")) {
    ALOGE("Missing preloaded-classes file, /system/etc/preloaded-classes not found: %s\n",
    strerror(errno));
    return -1;
    }
    addOption("-Ximage-compiler-option");
    addOption("--image-classes=/system/etc/preloaded-classes");
    if (hasFile("/system/etc/compiled-classes")) {
    addOption("-Ximage-compiler-option");
    addOption("--compiled-classes=/system/etc/compiled-classes");
    }
    property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
    parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");
    parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xms", dex2oatXmsFlagsBuf,
    "-Xms", "-Xcompiler-option");
    parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xmx", dex2oatXmxFlagsBuf,
    "-Xmx", "-Xcompiler-option");
    if (skip_compilation) {
    addOption("-Xcompiler-option");
    addOption("--compiler-filter=verify-none");
    addOption("--runtime-arg");
    addOption("-Xnorelocate");
    } else {
    parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,
    "--compiler-filter=", "-Xcompiler-option");
    }
    parseCompilerOption("dalvik.vm.dex2oat-threads", dex2oatThreadsBuf, "-j", "-Xcompiler-option");
    parseCompilerOption("dalvik.vm.image-dex2oat-threads", dex2oatThreadsImageBuf, "-j",
    "-Ximage-compiler-option");
    #if defined(__arm__)
    constexpr const char* instruction_set = "arm";
    #elif defined(__aarch64__)
    constexpr const char* instruction_set = "arm64";
    #elif defined(__mips__) && !defined(__LP64__)
    constexpr const char* instruction_set = "mips";
    #elif defined(__mips__) && defined(__LP64__)
    constexpr const char* instruction_set = "mips64";
    #elif defined(__i386__)
    constexpr const char* instruction_set = "x86";
    #elif defined(__x86_64__)
    constexpr const char* instruction_set = "x86_64";
    #else
    constexpr const char* instruction_set = "unknown";
    #endif
    sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set);
    parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant,
    "--instruction-set-variant=", "-Ximage-compiler-option");
    parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant,
    "--instruction-set-variant=", "-Xcompiler-option");
    sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);
    parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,
    "--instruction-set-features=", "-Ximage-compiler-option");
    parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features,
    "--instruction-set-features=", "-Xcompiler-option");
    property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, "");
    parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option");
    property_get("dalvik.vm.extra-opts", extraOptsBuf, "");
    parseExtraOpts(extraOptsBuf, NULL);
    {
    strcpy(localeOption, "-Duser.locale=");
    const std::string locale = readLocale();
    strncat(localeOption, locale.c_str(), PROPERTY_VALUE_MAX);
    addOption(localeOption);
    }
    property_get("ro.debuggable", propBuf, "0");
    if (strcmp(propBuf, "1") == 0) {
    property_get("dalvik.vm.method-trace", propBuf, "false");
    if (strcmp(propBuf, "true") == 0) {
    addOption("-Xmethod-trace");
    parseRuntimeOption("dalvik.vm.method-trace-file",
    methodTraceFileBuf,
    "-Xmethod-trace-file:");
    parseRuntimeOption("dalvik.vm.method-trace-file-siz",
    methodTraceFileSizeBuf,
    "-Xmethod-trace-file-size:");
    property_get("dalvik.vm.method-trace-stream", propBuf, "false");
    if (strcmp(propBuf, "true") == 0) {
    addOption("-Xmethod-trace-stream");
    }
    }
    }
    property_get("ro.dalvik.vm.native.bridge", propBuf, "");
    if (propBuf[0] == '\0') {
    ALOGW("ro.dalvik.vm.native.bridge is not expected to be empty");
    } else if (strcmp(propBuf, "0") != 0) {
    snprintf(nativeBridgeLibrary, sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX,
    "-XX:NativeBridge=%s", propBuf);
    addOption(nativeBridgeLibrary);
    }
    if defined(LP64)
    const char* cpu_abilist_property_name = "ro.product.cpu.abilist64";
    else
    const char* cpu_abilist_property_name = "ro.product.cpu.abilist32";
    endif
    property_get(cpu_abilist_property_name, propBuf, "");
    if (propBuf[0] == '\0') {
    ALOGE("%s is not expected to be empty", cpu_abilist_property_name);
    return -1;
    }
    snprintf(cpuAbiListBuf, sizeof(cpuAbiListBuf), "--cpu-abilist=%s", propBuf);
    addOption(cpuAbiListBuf);
    parseRuntimeOption("dalvik.vm.zygote.max-boot-retry", cachePruneBuf,
    "-Xzygote-max-boot-retry=");
    property_get("debug.generate-debug-info", propBuf, "");
    if (strcmp(propBuf, "true") == 0) {
    addOption("-Xcompiler-option");
    addOption("--generate-debug-info");
    addOption("-Ximage-compiler-option");
    addOption("--generate-debug-info");
    }
    parseRuntimeOption("ro.build.fingerprint", fingerprintBuf, "-Xfingerprint:");
    initArgs.version = JNI_VERSION_1_4;
    initArgs.options = mOptions.editArray();
    initArgs.nOptions = mOptions.size();
    initArgs.ignoreUnrecognized = JNI_FALSE;
    // 初始化VM
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
    ALOGE("JNI_CreateJavaVM failed\n");
    return -1;
    }
    return 0;

    由上述实现代码可知,函数AndroidRuntime::startVM()最终会调用JNI_CreateJavaVM()函数,其具体实现代码如下。

    1
    2
    3
    extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
    return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
    }
    1
    2
    3
    jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
    return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
    }
    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
    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 (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;
    if (!Runtime::Create(options, ignore_unrecognized)) {
    return JNI_ERR;
    }
    android::InitializeNativeLoader();
    // 获取Runtime当前实例,Runtime使用单例模式实现
    Runtime* runtime = Runtime::Current();
    // 调用start()函数
    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;
    }

    类JniInvocation的静态成员函数GetJniInvocation()返回的便是前面所创建的JniInvocation实例。有了这个实例后,就继续调用其成员函数JNI_CreateJavaVM()来创建一个JavaVM接口及其对应的JNIEnv接口。类JniInvocation的成员变量JNICreateJavaVM指向的就是前面所加载的libdvm.so或libart.so所导出的函数JNI_CreateJavaVM()。

  • 创建运行实例

    在文件 art/runtime/java_vm_ext.cc中,函数JNI_CreateJavaVM()会调用函数Create()创建Runtime的实例。

    1
    2
    3
    4
    5
    bool Runtime::Create(const RuntimeOptions& raw_options, bool ignore_unrecognized) {
    RuntimeArgumentMap runtime_options;
    return ParseOptions(raw_options, ignore_unrecognized, &runtime_options) &&
    Create(std::move(runtime_options));
    }

    Create()函数调用ParseOptions(raw_options, ignore_unrecognized, &runtime_options)函数和Create(std::move(runtime_options)函数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    bool Runtime::ParseOptions(const RuntimeOptions& raw_options,
    bool ignore_unrecognized,
    RuntimeArgumentMap* runtime_options) {
    InitLogging(/* argv */ nullptr); // 初始化Log系统
    bool parsed = ParsedOptions::Parse(raw_options, ignore_unrecognized, runtime_options);
    if (!parsed) {
    LOG(ERROR) << "Failed to parse options";
    return false;
    }
    return true;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    bool Runtime::Create(RuntimeArgumentMap&& runtime_options) {
    if (Runtime::instance_ != nullptr) {
    return false;
    }
    instance_ = new Runtime; // 创建Runtime实例
    // 初始化Runtime
    if (!instance_->Init(std::move(runtime_options))) {
    instance_ = nullptr;
    return false;
    }
    return true;
    }

    函数JNI_CreateJavaVM()获取当前Runtime实例后,会调用start()函数,其具体实现如下。

    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
    bool Runtime::Start() {
    VLOG(startup) << "Runtime::Start entering";
    CHECK(!no_sig_chain_) << "A started runtime should have sig chain enabled";
    #if defined(__linux__) && !defined(__ANDROID__) && defined(__x86_64__)
    if (kIsDebugBuild) {
    CHECK_EQ(prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY), 0);
    }
    #endif
    // 获取当前运行线程
    Thread* self = Thread::Current();
    self->TransitionFromRunnableToSuspended(kNative);
    started_ = true;
    if (jit_options_->UseJitCompilation() || jit_options_->GetSaveProfilingInfo()) {
    std::string error_msg;
    if (!IsZygote()) {
    CreateJit();
    } else if (jit_options_->UseJitCompilation()) {
    if (!jit::Jit::LoadCompilerLibrary(&error_msg)) {
    LOG(WARNING) << "Failed to load JIT compiler with error " << error_msg;
    }
    }
    }
    if (!IsImageDex2OatEnabled() || !GetHeap()->HasBootImageSpace()) {
    ScopedObjectAccess soa(self);
    StackHandleScope<2> hs(soa.Self());
    auto class_class(hs.NewHandle<mirror::Class>(mirror::Class::GetJavaLangClass()));
    auto field_class(hs.NewHandle<mirror::Class>(mirror::Field::StaticClass()));
    class_linker_->EnsureInitialized(soa.Self(), class_class, true, true);
    class_linker_->EnsureInitialized(soa.Self(), field_class, true, true);
    }
    {
    ScopedTrace trace2("InitNativeMethods");
    // 完成Native函数的初始化工作
    InitNativeMethods();
    }
    InitThreadGroups(self);
    Thread::FinishStartup();
    system_class_loader_ = CreateSystemClassLoader(this);
    if (is_zygote_) {
    if (!InitZygote()) {
    return false;
    }
    } else {
    if (is_native_bridge_loaded_) {
    PreInitializeNativeBridge(".");
    }
    NativeBridgeAction action = force_native_bridge_
    ? NativeBridgeAction::kInitialize
    : NativeBridgeAction::kUnload;
    InitNonZygoteOrPostFork(self->GetJniEnv(),
    /* is_system_server */ false,
    action,
    GetInstructionSetString(kRuntimeISA));
    }
    StartDaemonThreads();
    {
    ScopedObjectAccess soa(self);
    self->GetJniEnv()->locals.AssertEmpty();
    }
    VLOG(startup) << "Runtime::Start exiting";
    finished_starting_ = true;
    if (profiler_options_.IsEnabled() && !profile_output_filename_.empty()) {
    int fd = open(profile_output_filename_.c_str(), O_RDWR|O_CREAT|O_EXCL, 0660);
    if (fd >= 0) {
    close(fd);
    } else if (errno != EEXIST) {
    LOG(WARNING) << "Failed to access the profile file. Profiler disabled.";
    }
    }
    if (trace_config_.get() != nullptr && trace_config_->trace_file != "") {
    ScopedThreadStateChange tsc(self, kWaitingForMethodTracingStart);
    Trace::Start(trace_config_->trace_file.c_str(),
    -1,
    static_cast<int>(trace_config_->trace_file_size),
    0,
    trace_config_->trace_output_mode,
    trace_config_->trace_mode,
    0);
    }
    return true;
    }

    接下来看看InitNativeMethods()函数的具体实现。

    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
    void Runtime::InitNativeMethods() {
    VLOG(startup) << "Runtime::InitNativeMethods entering";
    Thread* self = Thread::Current();
    JNIEnv* env = self->GetJniEnv(); // 获取JNI环境
    CHECK_EQ(self->GetState(), kNative);
    JniConstants::init(env);
    RegisterRuntimeNativeMethods(env); // 完成Native函数的注册
    WellKnownClasses::Init(env);
    {
    std::string error_msg;
    if (!java_vm_->LoadNativeLibrary(env, "libjavacore.so", nullptr, nullptr, &error_msg)) {
    LOG(FATAL) << "LoadNativeLibrary failed for \"libjavacore.so\": " << error_msg;
    }
    }
    {
    constexpr const char* kOpenJdkLibrary = kIsDebugBuild
    ? "libopenjdkd.so"
    : "libopenjdk.so";
    std::string error_msg;
    if (!java_vm_->LoadNativeLibrary(env, kOpenJdkLibrary, nullptr, nullptr, &error_msg)) {
    LOG(FATAL) << "LoadNativeLibrary failed for \"" << kOpenJdkLibrary << "\": " << error_msg;
    }
    }
    WellKnownClasses::LateInit(env);
    VLOG(startup) << "Runtime::InitNativeMethods exiting";
    }
  • 注册本地JNI函数

    在文件 art/runtime/runtime.cc中的函数Runtime::InitNativeMethods()中,通过调用RegisterRuntimeNativeMethods(env)来注册Native函数,其具体实现如下。

    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
    void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) {
    register_dalvik_system_DexFile(env);
    register_dalvik_system_VMDebug(env);
    register_dalvik_system_VMRuntime(env);
    register_dalvik_system_VMStack(env);
    register_dalvik_system_ZygoteHooks(env);
    register_java_lang_Class(env);
    register_java_lang_DexCache(env);
    register_java_lang_Object(env);
    register_java_lang_ref_FinalizerReference(env);
    register_java_lang_reflect_AbstractMethod(env);
    register_java_lang_reflect_Array(env);
    register_java_lang_reflect_Constructor(env);
    register_java_lang_reflect_Field(env);
    register_java_lang_reflect_Method(env);
    register_java_lang_reflect_Proxy(env);
    register_java_lang_ref_Reference(env);
    register_java_lang_String(env);
    register_java_lang_StringFactory(env);
    register_java_lang_System(env);
    register_java_lang_Thread(env);
    register_java_lang_Throwable(env);
    register_java_lang_VMClassLoader(env);
    register_java_util_concurrent_atomic_AtomicLong(env);
    register_libcore_util_CharsetUtils(env);
    register_org_apache_harmony_dalvik_ddmc_DdmServer(env);
    register_org_apache_harmony_dalvik_ddmc_DdmVmInternal(env);
    register_sun_misc_Unsafe(env);
    }

    在上述代码中列出了需要注册的函数列表。

  • 启动守护进程

    再次返回到Runtime::Start函数,其中调用InitZygote完成一些文件系统的mount工作。然后通过StartDaemonThreads()代码行调用java.lang.Daemons.start()函数启动守护进程,其具体实现如下。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    void Runtime::StartDaemonThreads() {
    ScopedTrace trace(__FUNCTION__);
    VLOG(startup) << "Runtime::StartDaemonThreads entering";
    Thread* self = Thread::Current();
    CHECK_EQ(self->GetState(), kNative);
    JNIEnv* env = self->GetJniEnv();
    env->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons,
    WellKnownClasses::java_lang_Daemons_start);
    if (env->ExceptionCheck()) {
    env->ExceptionDescribe();
    LOG(FATAL) << "Error starting java.lang.Daemons";
    }
    VLOG(startup) << "Runtime::StartDaemonThreads exiting";
    }

    综上所述,android系统通过将ART运行时抽象成一个Java虚拟机,以及通过系统属性persist.sys.dalvik.vm.lib和一个适配层JniInvocation,就可以无缝地将Dalvik虚拟机替换成ART运行时。这个替换过程设计非常巧妙,因为涉及的代码修改非常少。

    ART启动涉及的类

  • 解析参数

    在函数JNI_CreateJavaVM()中,现调用Create()函数创建Runtime。Runtime是一个单例,创建后会马上调用/art/runtime/runtime.cc中的Init()函数。Init()函数的功能是解析参数,初始化Heap和JavaVMExt结构,实现线程和信号处理,并创建ClassLinker等。函数Init()的具体实现代码如下。

    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
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
    RuntimeArgumentMap runtime_options(std::move(runtime_options_in));
    ScopedTrace trace(__FUNCTION__);
    CHECK_EQ(sysconf(_SC_PAGE_SIZE), kPageSize);
    MemMap::Init();
    using Opt = RuntimeArgumentMap;
    VLOG(startup) << "Runtime::Init -verbose:startup enabled";
    QuasiAtomic::Startup();
    oat_file_manager_ = new OatFileManager;
    Thread::SetSensitiveThreadHook(runtime_options.GetOrDefault(Opt::HookIsSensitiveThread));
    Monitor::Init(runtime_options.GetOrDefault(Opt::LockProfThreshold));
    boot_class_path_string_ = runtime_options.ReleaseOrDefault(Opt::BootClassPath);
    class_path_string_ = runtime_options.ReleaseOrDefault(Opt::ClassPath);
    properties_ = runtime_options.ReleaseOrDefault(Opt::PropertiesList);
    compiler_callbacks_ = runtime_options.GetOrDefault(Opt::CompilerCallbacksPtr);
    patchoat_executable_ = runtime_options.ReleaseOrDefault(Opt::PatchOat);
    must_relocate_ = runtime_options.GetOrDefault(Opt::Relocate);
    is_zygote_ = runtime_options.Exists(Opt::Zygote);
    is_explicit_gc_disabled_ = runtime_options.Exists(Opt::DisableExplicitGC);
    dex2oat_enabled_ = runtime_options.GetOrDefault(Opt::Dex2Oat);
    image_dex2oat_enabled_ = runtime_options.GetOrDefault(Opt::ImageDex2Oat);
    dump_native_stack_on_sig_quit_ = runtime_options.GetOrDefault(Opt::DumpNativeStackOnSigQuit);
    vfprintf_ = runtime_options.GetOrDefault(Opt::HookVfprintf);
    exit_ = runtime_options.GetOrDefault(Opt::HookExit);
    abort_ = runtime_options.GetOrDefault(Opt::HookAbort);
    default_stack_size_ = runtime_options.GetOrDefault(Opt::StackSize);
    stack_trace_file_ = runtime_options.ReleaseOrDefault(Opt::StackTraceFile);
    compiler_executable_ = runtime_options.ReleaseOrDefault(Opt::Compiler);
    compiler_options_ = runtime_options.ReleaseOrDefault(Opt::CompilerOptions);
    image_compiler_options_ = runtime_options.ReleaseOrDefault(Opt::ImageCompilerOptions);
    image_location_ = runtime_options.GetOrDefault(Opt::Image);
    max_spins_before_thin_lock_inflation_ =
    runtime_options.GetOrDefault(Opt::MaxSpinsBeforeThinLockInflation);
    // 初始化Monitor(相当于mutex + conditional variable,可用于多个线程同步)和线程链表
    monitor_list_ = new MonitorList;
    monitor_pool_ = MonitorPool::Create();
    thread_list_ = new ThreadList;
    intern_table_ = new InternTable;
    verify_ = runtime_options.GetOrDefault(Opt::Verify);
    allow_dex_file_fallback_ = !runtime_options.Exists(Opt::NoDexFileFallback);
    no_sig_chain_ = runtime_options.Exists(Opt::NoSigChain);
    force_native_bridge_ = runtime_options.Exists(Opt::ForceNativeBridge);
    Split(runtime_options.GetOrDefault(Opt::CpuAbiList), ',', &cpu_abilist_);
    fingerprint_ = runtime_options.ReleaseOrDefault(Opt::Fingerprint);
    if (runtime_options.GetOrDefault(Opt::Interpret)) {
    GetInstrumentation()->ForceInterpretOnly();
    }
    zygote_max_failed_boots_ = runtime_options.GetOrDefault(Opt::ZygoteMaxFailedBoots);
    experimental_flags_ = runtime_options.GetOrDefault(Opt::Experimental);
    is_low_memory_mode_ = runtime_options.Exists(Opt::LowMemoryMode);
    {
    CompilerFilter::Filter filter;
    std::string filter_str = runtime_options.GetOrDefault(Opt::OatFileManagerCompilerFilter);
    if (!CompilerFilter::ParseCompilerFilter(filter_str.c_str(), &filter)) {
    LOG(ERROR) << "Cannot parse compiler filter " << filter_str;
    return false;
    }
    OatFileManager::SetCompilerFilter(filter);
    }
    XGcOption xgc_option = runtime_options.GetOrDefault(Opt::GcOption);
    // 实现比较重 要的Heap以及GC的初始化工作
    heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize),
    runtime_options.GetOrDefault(Opt::HeapGrowthLimit),
    runtime_options.GetOrDefault(Opt::HeapMinFree),
    runtime_options.GetOrDefault(Opt::HeapMaxFree),
    runtime_options.GetOrDefault(Opt::HeapTargetUtilization),
    runtime_options.GetOrDefault(Opt::ForegroundHeapGrowthMultiplier),
    runtime_options.GetOrDefault(Opt::MemoryMaximumSize),
    runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),
    runtime_options.GetOrDefault(Opt::Image),
    runtime_options.GetOrDefault(Opt::ImageInstructionSet),
    xgc_option.collector_type_,
    runtime_options.GetOrDefault(Opt::BackgroundGc),
    runtime_options.GetOrDefault(Opt::LargeObjectSpace),
    runtime_options.GetOrDefault(Opt::LargeObjectThreshold),
    runtime_options.GetOrDefault(Opt::ParallelGCThreads),
    runtime_options.GetOrDefault(Opt::ConcGCThreads),
    runtime_options.Exists(Opt::LowMemoryMode),
    runtime_options.GetOrDefault(Opt::LongPauseLogThreshold),
    runtime_options.GetOrDefault(Opt::LongGCLogThreshold),
    runtime_options.Exists(Opt::IgnoreMaxFootprint),
    runtime_options.GetOrDefault(Opt::UseTLAB),
    xgc_option.verify_pre_gc_heap_,
    xgc_option.verify_pre_sweeping_heap_,
    xgc_option.verify_post_gc_heap_,
    xgc_option.verify_pre_gc_rosalloc_,
    xgc_option.verify_pre_sweeping_rosalloc_,
    xgc_option.verify_post_gc_rosalloc_,
    xgc_option.gcstress_,
    runtime_options.GetOrDefault(Opt::EnableHSpaceCompactForOOM),
    runtime_options.GetOrDefault(Opt::HSpaceCompactForOOMMinIntervalsMs));
    if (!heap_->HasBootImageSpace() && !allow_dex_file_fallback_) {
    LOG(ERROR) << "Dex file fallback disabled, cannot continue without image.";
    return false;
    }
    dump_gc_performance_on_shutdown_ = runtime_options.Exists(Opt::DumpGCPerformanceOnShutdown);
    if (runtime_options.Exists(Opt::JdwpOptions)) {
    Dbg::ConfigureJdwp(runtime_options.GetOrDefault(Opt::JdwpOptions));
    }
    jit_options_.reset(jit::JitOptions::CreateFromRuntimeArguments(runtime_options));
    if (IsAotCompiler()) {
    jit_options_->SetUseJitCompilation(false);
    jit_options_->SetSaveProfilingInfo(false);
    }
    lambda_box_table_ = MakeUnique<lambda::BoxTable>();
    const bool use_malloc = IsAotCompiler();
    arena_pool_.reset(new ArenaPool(use_malloc, /* low_4gb */ false));
    jit_arena_pool_.reset(
    new ArenaPool(/* use_malloc */ false, /* low_4gb */ false, "CompilerMetadata"));
    if (IsAotCompiler() && Is64BitInstructionSet(kRuntimeISA)) {
    low_4gb_arena_pool_.reset(new ArenaPool(/* use_malloc */ false, /* low_4gb */ true));
    }
    linear_alloc_.reset(CreateLinearAlloc());
    BlockSignals();
    InitPlatformSignalHandlers();
    switch (kRuntimeISA) {
    case kArm:
    case kThumb2:
    case kX86:
    case kArm64:
    case kX86_64:
    case kMips:
    case kMips64:
    implicit_null_checks_ = true;
    implicit_so_checks_ = !(RUNNING_ON_MEMORY_TOOL && kMemoryToolIsValgrind);
    break;
    default:
    break;
    }
    if (!no_sig_chain_) {
    InitializeSignalChain();
    if (implicit_null_checks_ || implicit_so_checks_ || implicit_suspend_checks_) {
    fault_manager.Init();
    if (implicit_suspend_checks_) {
    new SuspensionHandler(&fault_manager);
    }
    if (implicit_so_checks_) {
    new StackOverflowHandler(&fault_manager);
    }
    if (implicit_null_checks_) {
    new NullPointerHandler(&fault_manager);
    }
    if (kEnableJavaStackTraceHandler) {
    new JavaStackTraceHandler(&fault_manager);
    }
    }
    }
    java_vm_ = new JavaVMExt(this, runtime_options);
    Thread::Startup();
    Thread* self = Thread::Attach("main", false, nullptr, false);
    CHECK_EQ(self->GetThreadId(), ThreadList::kMainThreadId);
    CHECK(self != nullptr);
    self->TransitionFromSuspendedToRunnable();
    GetHeap()->EnableObjectValidation();
    CHECK_GE(GetHeap()->GetContinuousSpaces().size(), 1U);
    // ClassLinker的初始化操作
    class_linker_ = new ClassLinker(intern_table_);
    ...
    VLOG(startup) << "Runtime::Init exiting";
    return true;
    }

    在文件 art/runtime/runtime.cc中,通过函数Runtime::ParseOptions()解析参数,将raw_options中的参数传入ParsedOptions::Parse()进一步调用ParsedOptions的Parse()函数来解析,其具体实现在parsed_options.cc中。

    1
    2
    3
    4
    5
    6
    7
    8
    bool ParsedOptions::Parse(const RuntimeOptions& options,
    bool ignore_unrecognized,
    RuntimeArgumentMap* runtime_options) {
    CHECK(runtime_options != nullptr);
    ParsedOptions parser;
    return parser.DoParse(options, ignore_unrecognized, runtime_options);
    }
    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
    bool ParsedOptions::DoParse(const RuntimeOptions& options,
    bool ignore_unrecognized,
    RuntimeArgumentMap* runtime_options) {
    for (size_t i = 0; i < options.size(); ++i) {
    if (true && options[0].first == "-Xzygote") {
    LOG(INFO) << "option[" << i << "]=" << options[i].first;
    }
    }
    auto parser = MakeParser(ignore_unrecognized);
    std::vector<std::string> argv_list;
    if (!ProcessSpecialOptions(options, nullptr, &argv_list)) {
    return false;
    }
    CmdlineResult parse_result = parser->Parse(argv_list);
    if (parse_result.IsError()) {
    if (parse_result.GetStatus() == CmdlineResult::kUsage) {
    UsageMessage(stdout, "%s\n", parse_result.GetMessage().c_str());
    Exit(0);
    } else if (parse_result.GetStatus() == CmdlineResult::kUnknown && !ignore_unrecognized) {
    Usage("%s\n", parse_result.GetMessage().c_str());
    return false;
    } else {
    Usage("%s\n", parse_result.GetMessage().c_str());
    Exit(0);
    }
    UNREACHABLE();
    }
    using M = RuntimeArgumentMap;
    RuntimeArgumentMap args = parser->ReleaseArgumentsMap();
    if (args.Exists(M::Help)) {
    Usage(nullptr);
    return false;
    } else if (args.Exists(M::ShowVersion)) {
    UsageMessage(stdout, "ART version %s\n", Runtime::GetVersion());
    Exit(0);
    } else if (args.Exists(M::BootClassPath)) {
    LOG(INFO) << "setting boot class path to " << *args.Get(M::BootClassPath);
    }
    if (args.GetOrDefault(M::UseJitCompilation) && args.GetOrDefault(M::Interpret)) {
    Usage("-Xusejit:true and -Xint cannot be specified together");
    Exit(0);
    }
    if (getenv("BOOTCLASSPATH") != nullptr) {
    args.SetIfMissing(M::BootClassPath, std::string(getenv("BOOTCLASSPATH")));
    }
    if (getenv("CLASSPATH") != nullptr) {
    args.SetIfMissing(M::ClassPath, std::string(getenv("CLASSPATH")));
    }
    args.SetIfMissing(M::ParallelGCThreads, gc::Heap::kDefaultEnableParallelGC ?
    static_cast<unsigned int>(sysconf(_SC_NPROCESSORS_CONF) - 1u) : 0u);
    {
    LogVerbosity *log_verbosity = args.Get(M::Verbose);
    if (log_verbosity != nullptr) {
    gLogVerbosity = *log_verbosity;
    }
    }
    MaybeOverrideVerbosity();
    Trace::SetDefaultClockSource(args.GetOrDefault(M::ProfileClock));
    if (!ProcessSpecialOptions(options, &args, nullptr)) {
    return false;
    }
    {
    gc::CollectorType background_collector_type_;
    gc::CollectorType collector_type_ = (XGcOption{}).collector_type_; // NOLINT
    bool low_memory_mode_ = args.Exists(M::LowMemoryMode);
    background_collector_type_ = args.GetOrDefault(M::BackgroundGc);
    {
    XGcOption* xgc = args.Get(M::GcOption);
    if (xgc != nullptr && xgc->collector_type_ != gc::kCollectorTypeNone) {
    collector_type_ = xgc->collector_type_;
    }
    }
    if (background_collector_type_ == gc::kCollectorTypeNone) {
    if (collector_type_ != gc::kCollectorTypeGSS) {
    background_collector_type_ = low_memory_mode_ ?
    gc::kCollectorTypeSS : gc::kCollectorTypeHomogeneousSpaceCompact;
    } else {
    background_collector_type_ = collector_type_;
    }
    }
    args.Set(M::BackgroundGc, BackgroundGcOption { background_collector_type_ });
    }
    #if defined(ART_TARGET)
    std::string core_jar("/core.jar");
    std::string core_libart_jar("/core-libart.jar");
    #else
    std::string core_jar("/core-hostdex.jar");
    std::string core_libart_jar("/core-libart-hostdex.jar");
    #endif
    auto boot_class_path_string = args.GetOrDefault(M::BootClassPath);
    size_t core_jar_pos = boot_class_path_string.find(core_jar);
    if (core_jar_pos != std::string::npos) {
    boot_class_path_string.replace(core_jar_pos, core_jar.size(), core_libart_jar);
    args.Set(M::BootClassPath, boot_class_path_string);
    }
    {
    auto&& boot_class_path = args.GetOrDefault(M::BootClassPath);
    auto&& boot_class_path_locations = args.GetOrDefault(M::BootClassPathLocations);
    if (args.Exists(M::BootClassPathLocations)) {
    size_t boot_class_path_count = ParseStringList<':'>::Split(boot_class_path).Size();
    if (boot_class_path_count != boot_class_path_locations.Size()) {
    Usage("The number of boot class path files does not match"
    " the number of boot class path locations given\n"
    " boot class path files (%zu): %s\n"
    " boot class path locations (%zu): %s\n",
    boot_class_path.size(), boot_class_path_string.c_str(),
    boot_class_path_locations.Size(), boot_class_path_locations.Join().c_str());
    return false;
    }
    }
    }
    if (!args.Exists(M::CompilerCallbacksPtr) && !args.Exists(M::Image)) {
    std::string image = GetAndroidRoot();
    image += "/framework/boot.art";
    args.Set(M::Image, image);
    }
    if (args.GetOrDefault(M::HeapGrowthLimit) <= 0u ||
    args.GetOrDefault(M::HeapGrowthLimit) > args.GetOrDefault(M::MemoryMaximumSize)) {
    args.Set(M::HeapGrowthLimit, args.GetOrDefault(M::MemoryMaximumSize));
    }
    if (args.GetOrDefault(M::Experimental) & ExperimentalFlags::kLambdas) {
    LOG(WARNING) << "Experimental lambdas have been enabled. All lambda opcodes have "
    << "an unstable specification and are nearly guaranteed to change over time. "
    << "Do not attempt to write shipping code against these opcodes.";
    }
    *runtime_options = std::move(args);
    return true;
    }

    主要是对环境变量BOOTCLASSPATH和CLASSPATH进行处理。

    执行完Runtime中的函数Create()和Init()后,在JNI_CreateJavaVM()函数中Runtime的Start()函数会被调用。

  • 初始化类、方法和域

    在文件runtime.cc的函数InitNativeMethods()中分别调用函数JniConstants::init(env)和WellKnownClasses::Init(env)。这两个函数通过FindClass()、GetStaticFieldID()和GetStaticMethodID()等函数初始化了系统基本类、方法和域,这些都是最基本的类。然后RegisterRuntimeNativeMethods(env)函数注册了系统类中的Native函数。接着函数InitNativeMethods会载入libjavacore.so库,单独载入是因为该库本身包含了System.loadLibrary()实现,不先载入会导致顺序紊乱。

    再次回到Runtime::Start()函数进行线程初始化,再判断是否为zygote线程。如果是则调用InitZygote()进行初始化操作,否则调用InitNonZygoteOrPostFork()函数。最后Start()函数中调用了StartDaemonThreads()函数,此函数的作用是调用Java类的Daemons的start()方法来启动一些Daemons进程,这个过程实际上和Dalvik启动时完成的最后一项工作相同。

    从startVM()返回后,AndroidRuntime执行startReg()在创建线程时加一个hook()函数,这样每个Thread启动时会先去执行AndroidRuntime::javaThreadShell(),而该函数会初始化Java虚拟机环境,这样新建的线程就可以调用Java层了。

进入main()函数

完成ART的基本初始化工作后,接下来开始执行主函数,具体步骤如下所示:

  • 先通过FindClass()找到相应的类。
  • 然后通过GetStaticMethodID()找到相应的方法。
  • 最后调用CallStaticVoidMethod()进入Java执行托管代码工作。

这里以Zygote初始化操作为例进行分析,其中,类名为com.android.internal.os.ZygoteInit,方法为main。在AndroidRuntime::start中调用startVM()启动虚拟机,然后调用startReg()注册JNI方法,并调用com.android.internal.os.ZygoteInit类的main()函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
}
free(slashClassName);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
static jclass FindClass(JNIEnv* env, const char* name) {
CHECK_NON_NULL_ARGUMENT(name);
Runtime* runtime = Runtime::Current();
// 得到前面初始化好的系统的ClassLoader
ClassLinker* class_linker = runtime->GetClassLinker();
std::string descriptor(NormalizeJniClassDescriptor(name));
ScopedObjectAccess soa(env);
mirror::Class* c = nullptr;
if (runtime->IsStarted()) {
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(GetClassLoader(soa)));
c = class_linker->FindClass(soa.Self(), descriptor.c_str(), class_loader);
} else {
c = class_linker->FindSystemClass(soa.Self(), descriptor.c_str());
}
return soa.AddLocalReference<jclass>(c);
}
1
2
3
4
5
6
7
8
static jmethodID GetStaticMethodID(JNIEnv* env, jclass java_class, const char* name,
const char* sig) {
CHECK_NON_NULL_ARGUMENT(java_class);
CHECK_NON_NULL_ARGUMENT(name);
CHECK_NON_NULL_ARGUMENT(sig);
ScopedObjectAccess soa(env);
return FindMethodID(soa, java_class, name, sig, true);
}
1
2
3
4
5
static void CallStaticVoidMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(mid);
ScopedObjectAccess soa(env);
InvokeWithJValues(soa, nullptr, mid, args);
}

总结

ART优点
  • 系统性能的显著提升
  • 应用启动更快、运行更快、体验更流畅、触感反馈更及时
  • 更长的电池续航能力
  • 支持更低的硬件
ART缺点
  • 更大的存储空间占用,可能会增加10%~20%
  • 更长的应用安装时间

总的来说ART的功效就是“空间换时间”。