Android Runtime(一)

1.Android 架构


Android Runtime(一)_第1张图片

Android上层是java,framework是java,native是c++,驱动是c 。连接起来的是jni,虚拟机

如借用的图所示,Android Runtime连接了framework和lib,包括两部分:core lib和虚拟机(5.1开始art完全取代dv)


2.Android 进程关系

android启动是从init.c开始的,而且init是android的第一个进程,zygot也是其fork的

USER      PID   PPID  VSIZE  RSS   WCHAN              PC  NAME
root      1     0     17112  1304  SyS_epoll_ 0000000000 S /init
root      2     0     0      0       kthreadd 0000000000 S kthreadd
root      3     2     0      0     smpboot_th 0000000000 S ksoftirqd/0
root      5     2     0      0     worker_thr 0000000000 S kworker/0:0H
root      6     2     0      0     diag_socke 0000000000 S kworker/u16:0

root      512   1     6564   388   SyS_epoll_ 0000000000 S /sbin/healthd
root      513   1     18084  1164  binder_thr 0000000000 S /system/bin/performanceadjustor
nobody    516   1     16860  984   poll_sched 0000000000 S /system/bin/rmt_storage
root      517   2     0      0     worker_thr 0000000000 S kworker/7:1H
rfs       518   1     11260  804   poll_sched 0000000000 S /system/bin/tftp_server

这是坚果的,kthreadd应该就是zygote,坚果给重命名了。bin sbin system/bin是init进程fork出来的,PPID是1,其他都是zygote进程fork出来的,PPID是2。


3.Android 启动

1.init进程作为linux启动过程中的一个重要的进程,它主要负责文件系统的挂载,属性的初始化,各种配置的加载启动以及Action触发,Service的启动,而Zygote作为Java环境下的服务进程,也在Init.rc中进行了配置,而init进程是由main函数进行触发的

/system/core/init/init.c

int main(int argc, char **argv)
837{
...
848    if (!strcmp(basename(argv[0]), "ueventd"))
849        return ueventd_main(argc, argv);//uevent 
850
851    if (!strcmp(basename(argv[0]), "watchdogd"))
852        return watchdogd_main(argc, argv);
853
854    /* clear the umask */
855    umask(0);
856
857        /* Get the basic filesystem setup we need put
858         * together in the initramdisk on / and then we'll
859         * let the rc file figure out the rest.
860         */
861    mkdir("/dev", 0755);    //挂在文件系统
862    mkdir("/proc", 0755);
863    mkdir("/sys", 0755);
864
865    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
866    mkdir("/dev/pts", 0755);
867    mkdir("/dev/socket", 0755);
868    mount("devpts", "/dev/pts", "devpts", 0, NULL);
869    mount("proc", "/proc", "proc", 0, NULL);
870    mount("sysfs", "/sys", "sysfs", 0, NULL);
871
872        /* indicate that booting is in progress to background fw loaders, etc */
873    close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));
874
875        /* We must have some place other than / to create the
876         * device nodes for kmsg and null, otherwise we won't
877         * be able to remount / read-only later on.
878         * Now that tmpfs is mounted on /dev, we can actually
879         * talk to the outside world.
880         */
881    open_devnull_stdio();
882    klog_init();  //klog 初始化
883    property_init();//property 初始化
884
885    get_hardware_name(hardware, &revision);
886
887    process_kernel_cmdline();//执行kernel命令
888
889#ifdef HAVE_SELINUX
890    union selinux_callback cb;
891    cb.func_log = klog_write;
892    selinux_set_callback(SELINUX_CB_LOG, cb);
893
894    cb.func_audit = audit_callback;
895    selinux_set_callback(SELINUX_CB_AUDIT, cb);
896
897    INFO("loading selinux policy\n");
898    if (selinux_enabled) {
899        if (selinux_android_load_policy() < 0) {//加载selinux policy
900            selinux_enabled = 0;
901            INFO("SELinux: Disabled due to failed policy load\n");
902        } else {
903            selinux_init_all_handles();//se 初始化
904        }
905    } else {
906        INFO("SELinux:  Disabled by command line option\n");
907    }
908    /* These directories were necessarily created before initial policy load
909     * and therefore need their security context restored to the proper value.
910     * This must happen before /dev is populated by ueventd.
911     */
912    restorecon("/dev");
913    restorecon("/dev/socket");
914#endif
915
916    is_charger = !strcmp(bootmode, "charger");
917
918    INFO("property init\n");
919    if (!is_charger)
920        property_load_boot_defaults(); //加载prop
921
922    INFO("reading config file\n");
923    init_parse_config_file("/init.rc");//解析init.rc里面有zygote信息,各种service信息
...
1026}

2.init.rc 起zygote。在手机目录能看到system/bin/app_process,--zygote --start-system-server是参数,在后续是决定是zygote还是非zygote模式的参数

/system/core/rootdir/init.rc

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
444    class main
445    socket zygote stream 660 root system
446    onrestart write /sys/android_power/request_state wake
447    onrestart write /sys/power/state on
448    onrestart restart media
449    onrestart restart netd

3.进入app_main.cpp的main函数

frameworks/base/cmds/app_process/app_main.cpp

 

int main(int argc, char* const argv[])
188{
189    if (!LOG_NDEBUG) {
...
196      ALOGV("app_process main with argv: %s", argv_String.string());//log佐证起了app_process
197    }
198
199    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
200    // Process command line arguments
201    // ignore argv[0]
202    argc--;
203    argv++;
204    //这段注释解释的还是比较清楚,由传入的参数决定是zygote还是非zygote模式
205    // Everything up to '--' or first non '-' arg goes to the vm.
206    //
207    // The first argument after the VM args is the "parent dir", which
208    // is currently unused.
209    //
210    // After the parent dir, we expect one or more the following internal
211    // arguments :
212    //
213    // --zygote : Start in zygote mode
214    // --start-system-server : Start the system server.
215    // --application : Start in application (stand alone, non zygote) mode.
216    // --nice-name : The nice name for this process.
217    //
218    // For non zygote starts, these arguments will be followed by
219    // the main class name. All remaining arguments are passed to
220    // the main method of this class.
221    //
222    // For zygote starts, all remaining arguments are passed to the zygote.
223    // main function.
224    //
225    // Note that we must copy argument string values since we will rewrite the
226    // entire argument block when we apply the nice name to argv0.
227    //
228    // As an exception to the above rule, anything in "spaced commands"
229    // goes to the vm even though it has a space in it.
230    const char* spaced_commands[] = { "-cp", "-classpath" };
231    // Allow "spaced commands" to be succeeded by exactly 1 argument (regardless of -s).
...
272    while (i < argc) {//不同参数的赋值,决定后续调用方向
273        const char* arg = argv[i++];
274        if (strcmp(arg, "--zygote") == 0) {
275            zygote = true;
276            niceName = ZYGOTE_NICE_NAME;
277        } else if (strcmp(arg, "--start-system-server") == 0) {
278            startSystemServer = true;
279        } else if (strcmp(arg, "--application") == 0) {
280            application = true;
281        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
282            niceName.setTo(arg + 12);
283        } else if (strncmp(arg, "--", 2) != 0) {
284            className.setTo(arg);
285            break;
286        } else {
287            --i;
288            break;
289        }
290    }
...
342
343    if (zygote) {
344        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
345    } else if (className) {
346        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
347    } else {
348        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
349        app_usage();
350        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
351    }
352}

传了不同的参数ZygoteInit和RuntimeInit 

4. 进入AndroidRuntime.cpp的start函数

frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const char* options)
807{
...
837    /* start the virtual machine */
838    JNIEnv* env;
839    if (startVm(&mJavaVM, &env) != 0) {//启动虚拟机
840        return;
841    }
842    onVmCreated(env);//释放资源,跟进去看就知道
843
844    /*
845     * Register android functions.
846     */
847    if (startReg(env) < 0) {
848        ALOGE("Unable to register all android natives\n");
849        return;
850    }
851
852    /*
853     * We want to call main() with a String array with arguments in it.
854     * At present we have two arguments, the class name and an option string.
855     * Create an array to hold them.
856     *///注释暴露了目标调用class 的main函数
857    jclass stringClass;
858    jobjectArray strArray;
859    jstring classNameStr;
860    jstring optionsStr;
861
862    stringClass = env->FindClass("java/lang/String");
863    assert(stringClass != NULL);
864    strArray = env->NewObjectArray(2, stringClass, NULL);
865    assert(strArray != NULL);
866    classNameStr = env->NewStringUTF(className);
867    assert(classNameStr != NULL);
868    env->SetObjectArrayElement(strArray, 0, classNameStr);
869    optionsStr = env->NewStringUTF(options);
870    env->SetObjectArrayElement(strArray, 1, optionsStr);
871
872    /*
873     * Start VM.  This thread becomes the main thread of the VM, and will
874     * not return until the VM exits.
875     */
876    char* slashClassName = toSlashClassName(className);
877    jclass startClass = env->FindClass(slashClassName);
878    if (startClass == NULL) {
879        ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
880        /* keep going */
881    } else {
882        jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
883            "([Ljava/lang/String;)V");//获取main函数
884        if (startMeth == NULL) {
885            ALOGE("JavaVM unable to find main() in '%s'\n", className);
886            /* keep going */
887        } else {
888            env->CallStaticVoidMethod(startClass, startMeth, strArray);//调用main函数
889
890#if 0
891            if (env->ExceptionCheck())
892                threadExitUncaughtException(env);
893#endif
894        }
895    }
896    free(slashClassName);
897
898    ALOGD("Shutting down VM\n");
899    if (mJavaVM->DetachCurrentThread() != JNI_OK)
900        ALOGW("Warning: unable to detach main thread\n");
901    if (mJavaVM->DestroyJavaVM() != 0)
902        ALOGW("Warning: VM did not shut down cleanly\n");
903}

这里进入了不同的调用流程,Zygote和非Zygote模式,后面再分析

先看下startVm

 

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
444{
...
484 //获取vm的各种属性
485    property_get("dalvik.vm.execution-mode", propBuf, "");
486    if (strcmp(propBuf, "int:portable") == 0) {
487        executionMode = kEMIntPortable;
488    } else if (strcmp(propBuf, "int:fast") == 0) {
...
768    /*
769     * Initialize the VM.
770     *
771     * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
772     * If this call succeeds, the VM is ready, and we can start issuing
773     * JNI calls.
774     */
775    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
776        ALOGE("JNI_CreateJavaVM failed\n");
777        goto bail;
778    }
779
780    result = 0;
781
782bail:
783    free(stackTraceFile);
784    return result;
785}

进入JNI_CreateJavaVM ,追踪得到是在libart.so里面

继续跟踪下一个startReg

1220/*static*/ int AndroidRuntime::startReg(JNIEnv* env)
1221{
1222    /*
1223     * This hook causes all future threads created in this process to be
1224     * attached to the JavaVM.  (This needs to go away in favor of JNI
1225     * Attach calls.)
1226     */
1227    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
1228
1229    ALOGV("--- registering native functions ---\n");
1230
1231    /*
1232     * Every "register" function calls one or more things that return
1233     * a local reference (e.g. FindClass).  Because we haven't really
1234     * started the VM yet, they're all getting stored in the base frame
1235     * and never released.  Use Push/Pop to manage the storage.
1236     */
1237    env->PushLocalFrame(200);
1238
1239    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
1240        env->PopLocalFrame(NULL);
1241        return -1;
1242    }
1243    env->PopLocalFrame(NULL);
1244
1245    //createJavaThread("fubar", quickTest, (void*) "hello");
1246
1247    return 0;
1248}

进入register_jni_procs,可以看到是各种jni注册

你可能感兴趣的:(Android-app)