FK安卓-1-开机流程

FK安卓-1-开机流程

概念预览

图片来源于http://blog.jobbole.com/67931/
FK安卓-1-开机流程_第1张图片

具体流程

1.按下电源键,引导芯片代码开始从Rom的某一处地方(固定地址)执行,加载引导程序BootLoader到内存后,把执行权交给BootLoader.引导芯片代码是由OEM厂商编写的加载程序.不属于安卓的一部分
2.BootLoader加载Linux内核到内存
3.内核初始化相关驱动,目录,然后创建第一个用户空间进程init
4.init进程主要做以下几个操作
- 创建Zygote,Zygote进程创建虚拟机实例,随后安卓所有的进程都是从Zygote进程fork出来,所以所有的安卓进程都含有虚拟机实例
- 创建android运行时
- 相关后台服务
5.Zygote进程fork出SystemServer服务进程,创建AMS,WMS,PMS等相关服务

代码分析

先贴上一张时序图.

FK安卓-1-开机流程_第2张图片

下面我以安卓6.0源码为基础来分析各个步骤的代码位置和逻辑.(主要讨论Zygote进程)
1.init进程位于源码根目录system/core/init下.我们从main函数开始分析

//总结.
//第一阶段:创建/dev /pro /sys相关目录,内核日志初始化,selinux初始化
//第二阶段:属性系统初始化,解释init.rc,执行相关程序
int main(int argc, char** argv) {
    ...

    //umask,新建目录权限所用到
    // Clear the umask.
    umask(0);

    //设置默认环境变量
    //#define   _PATH_DEFPATH   "/usr/bin:/bin"
    add_environment("PATH", _PATH_DEFPATH);

    //标记当前是不是第一阶段
    bool is_first_stage = (argc == 1) || (strcmp(argv[1], "--second-stage") != 0);

    //下面这段话的意思是在初始化阶段我们需要对一些系统目录进行创建和设置,然后由init.rc文件来指出其余工作
    // Get the basic filesystem setup we need put together in the initramdisk
    // on / and then we'll let the rc file figure out the rest.
    if (is_first_stage) {
        mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
        mkdir("/dev/pts", 0755);
        mkdir("/dev/socket", 0755);
        mount("devpts", "/dev/pts", "devpts", 0, NULL);
        mount("proc", "/proc", "proc", 0, NULL);
        mount("sysfs", "/sys", "sysfs", 0, NULL);
    }

    // We must have some place other than / to create the device nodes for
    // kmsg and null, otherwise we won't be able to remount / read-only
    // later on. Now that tmpfs is mounted on /dev, we can actually talk
    // to the outside world.
    //把标准输入,输出,错误输出重定义到空设备上
    open_devnull_stdio();
    //内核日志初始化
    klog_init();
    klog_set_level(KLOG_NOTICE_LEVEL);

    NOTICE("init%s started!\n", is_first_stage ? "" : " second stage");

    if (!is_first_stage) {
        ...

        //属性系统的初始化
        property_init();

        ...
    }

    //初始化selinux
    // Set up SELinux, including loading the SELinux policy if we're in the kernel domain.
    selinux_initialize(is_first_stage);

    // If we're in the kernel domain, re-exec init to transition to the init domain now
    // that the SELinux policy has been loaded.
    if (is_first_stage) {
        //重新设置init程序
        if (restorecon("/init") == -1) {
            ERROR("restorecon failed: %s\n", strerror(errno));
            security_failure();
        }
        char* path = argv[0];
        char* args[] = { path, const_cast<char*>("--second-stage"), nullptr };
        //再次执行init程序,携带参数--second-stage,进入第二阶段
        if (execv(path, args) == -1) {
            ...
        }
    }
    ...

    //核心部分,解释init.rc
    init_parse_config_file("/init.rc");

    ...

    while (true) {
        if (!waiting_for_exec) {
            //执行命令
            execute_one_command();
            restart_processes();
        }

        ...
    }

    return 0;
}

2.init.rc
init.rc语法不在这里讨论,我们来关心它究竟做了啥.


//我主要说下这几个重要的进程
//servicemanager,这个不必多说.Android系统重要的服务管理者.添加服务和查询服务都要通过servicemanager来完成
service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart drm

//图形管理
service surfaceflinger /system/bin/surfaceflinger
    class core
    user system
    group graphics drmrpc
    onrestart restart zygote
    writepid /dev/cpuset/system-background/tasks

//媒体服务
service media /system/bin/mediaserver
    class main
    user media
    group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm
    ioprio rt 4

//受精卵进程,建立java虚拟机.后面所有安卓进程都是通过fork这个进程而来的.
service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media
    onrestart restart netd
    writepid /dev/cpuset/foreground/tasks

3.分析下Zygote代码
/system/bin/app_process32程序代码位于源码根目录frameworks/base/cmds/app_process下.我们来分析下主执行文件app_main.cpp

int main(int argc, char* const argv[])
{
    ...

    //初始化AppRuntime为后续做准备
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
    ...

    int i;
    for (i = 0; i < argc; i++) {
        if (argv[i][0] != '-') {
            break;
        }
        if (argv[i][1] == '-' && argv[i][2] == 0) {
            ++i; // Skip --.
            break;
        }
        runtime.addOption(strdup(argv[i]));
    }

    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;

    ++i;  // Skip unused "parent dir" argument.
    while (i < argc) {
        const char* arg = argv[i++];
        //带有--zygote标记为受精卵进程,为后面操作做准备
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            //是否开启system_server进程
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }

    Vector args;
    if (!className.isEmpty()) {
        ...
    } else {
        // We're in zygote mode.
        maybeCreateDalvikCache();

        //添加start-system-server到虚拟机启动参数args
        if (startSystemServer) {
            args.add(String8("start-system-server"));
        }

        //static const char ABI_LIST_PROPERTY[] = "ro.product.cpu.abilist64";
        //询问属性系统,得到abi列表.
        char prop[PROP_VALUE_MAX];
        if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
            LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
                ABI_LIST_PROPERTY);
            return 11;
        }
        //添加abi-list到虚拟机启动参数args
        String8 abiFlag("--abi-list=");
        abiFlag.append(prop);
        args.add(abiFlag);

        // In zygote mode, pass all remaining arguments to the zygote
        // main() method.
        //复制传进来的参数到虚拟机启动参数
        for (; i < argc; ++i) {
            args.add(String8(argv[i]));
        }
    }

    if (!niceName.isEmpty()) {
        runtime.setArgv0(niceName.string());
        set_process_name(niceName.string());
    }

    if (zygote) {
        //通过AppRuntime实例的start方法启动ZygoteInit类.
        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;
    }
}

AppRuntime的start

//AppRuntime继承于AndroidRuntime,本身没有重写start方法,所以调用的是基类AndroidRuntime的start
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
    ...

    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    //创建一个虚拟机实例.
    //mJavaVm指向虚拟机实例
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    //回调,AppRuntime的onVmCreated()
    onVmCreated(env);

    //注册相关方法
    if (startReg(env) < 0) {
        ALOGE("Unable to register all android natives\n");
        return;
    }

    //创建一个java层的参数数组(new String[]),依次复制参数复制到该数组中
    /*
     * We want to call main() with a String array with arguments in it.
     * At present we have two arguments, the class name and an option string.
     * Create an array to hold them.
     */
    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);
    }

    /*
     * Start VM.  This thread becomes the main thread of the VM, and will
     * not return until the VM exits.
     */
    char* slashClassName = toSlashClassName(className);
    //找到ZygoteInit类
    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");
        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
        }
    }
    //只有找不到ZygoteInit类和虚拟机退出才会到这一步了
    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");
}

ZygoteInit.main

public static void main(String argv[]) {
        try {
            //启用DDMS
            RuntimeInit.enableDdms();
            ...
            //获取相关参数.
            //这里我们知道startSystemServer为true
            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)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            //必须要一个abi属性值
            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }

            //注册一个LocalServerSocket
            //目的是等待AMS请求新建应用程序进程
            registerZygoteSocket(socketName);
            //打印LOG_BOOT_PROGRESS_PRELOAD_START事件日志
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
            //预加载相关资源
            preload();
             //打印LOG_BOOT_PROGRESS_PRELOAD_END事件日志,查看这些值可以知道preloader过程的效率如何
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());

            ...

            if (startSystemServer) {
                //真正启动SystemServer进程
                startSystemServer(abiList, socketName);
            }

            //循环接收
            Log.i(TAG, "Accepting command socket connections");
            runSelectLoop(abiList);

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            //startSystemServer方法抛出异常,在这里实现其run方法
            caller.run();
        } catch (RuntimeException ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

    private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        ArrayList fds = new ArrayList();
        ArrayList peers = new ArrayList();

        fds.add(sServerSocket.getFileDescriptor());
        peers.add(null);

        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) {
                    //没有就阻塞.
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    //有新的请求就调用ZygoteConnection的runOnce方法
                    boolean done = peers.get(i).runOnce();
                    if (done) {
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }

以上就是Zygote进程的启动过程.

理论验证

1.init是用户空间第一个进程
通过ps命令,我们可以看到关键信息.PID为1.

root@generic:/ # ps                                                            
USER      PID   PPID  VSIZE  RSS   WCHAN            PC  NAME
root      1     0     2208   828   sys_epoll_ 0006dc70 S /init

2.Zygote是android系统进程的祖先,后续所有安卓进程fork它过来的
PID->70指向Zygote进程,它是由init进程启动的.
其他Phone,launcher等应用进程都是有Zygote进程启动的,所以它们的父进程ID为70

root@generic:/ # ps                                                            
USER      PID   PPID  VSIZE  RSS   WCHAN            PC  NAME
root      1     0     2208   828   sys_epoll_ 0006dc70 S /init
...
root      70    1     515476 49224 poll_sched b6d0be70 S zygote
...
system    252   70    645036 78728 sys_epoll_ b6d0bca8 S system_server
u0_a2     542   70    535136 38464 sys_epoll_ b6d0bca8 S android.process.acore
u0_a35    729   70    539028 37932 sys_epoll_ b6d0bca8 S com.android.inputmethod.latin
radio     745   70    557744 47736 sys_epoll_ b6d0bca8 S com.android.phone
u0_a49    831   70    527728 24756 sys_epoll_ b6d0bca8 S com.android.smspush
u0_a16    1008  70    570328 59100 sys_epoll_ b6d0bca8 S com.android.systemui
u0_a8     1041  70    571084 54336 sys_epoll_ b6d0bca8 S com.android.launcher
u0_a22    1090  70    535236 31296 sys_epoll_ b6d0bca8 S com.android.calendar
u0_a26    1109  70    532528 31560 sys_epoll_ b6d0bca8 S com.android.deskclock
u0_a1     1123  70    527980 30696 sys_epoll_ b6d0bca8 S com.android.providers.calendar
u0_a32    1152  70    532772 28432 sys_epoll_ b6d0bca8 S com.android.gallery3d
u0_a50    1168  70    542908 41296 sys_epoll_ b6d0bca8 S com.android.messaging
u0_a23    1276  70    532364 27640 sys_epoll_ b6d0bca8 S com.android.camera2
u0_a29    1295  70    542336 34928 sys_epoll_ b6d0bca8 S com.android.email
root      1314  62    3020   1168  sys_rt_sig b6dbdf5c S /system/bin/sh
u0_a10    1330  70    524992 25016 sys_epoll_ b6d0bca8 S com.android.musicfx

3.Zygote创建虚拟机实例,加载android程序运行环境所需要的资源
我们可以通过cat /proc/PID/maps来感受下各个进程的不一样

  • Init进程主要启动其他进程,所以除了程序代码和数据没有其他的了
root@generic:/ # cat /proc/1/maps                                              
00008000-0009f000 r-xp 00000000 00:01 1272       /init
000a0000-000a3000 r--p 00097000 00:01 1272       /init
000a3000-000a5000 rw-p 0009a000 00:01 1272       /init
000a5000-000a9000 rw-p 00000000 00:00 0          [heap]
b6d80000-b6e40000 rw-p 00000000 00:00 0          [anon:libc_malloc]
b6e60000-b6e80000 rw-s 00000000 00:0b 1420       /dev/__properties__
b6e80000-b6f00000 rw-p 00000000 00:00 0          [anon:libc_malloc]
b6f19000-b6f1b000 rw-p 00000000 00:00 0 
b6f1b000-b6f1c000 r--p 00000000 00:00 0 
b6f1c000-b6f1d000 ---p 00000000 00:00 0 
b6f1d000-b6f1f000 rw-p 00000000 00:00 0          [anon:thread signal stack]
bea98000-beab9000 rw-p 00000000 00:00 0          [stack]
ffff0000-ffff1000 r-xp 00000000 00:00 0          [vectors]
  • Zygote进程创建了虚拟机实例,加载Android Resource,加载必要的so库
root@generic:/ # cat /proc/70/maps                                             
12c00000-12e07000 rw-p 00000000 00:04 2405       /dev/ashmem/dalvik-main space (deleted)
12e07000-15c00000 ---p 00207000 00:04 2405       /dev/ashmem/dalvik-main space (deleted)
15c00000-15c01000 rw-p 00000000 00:04 2406       /dev/ashmem/dalvik-main space 1 (deleted)
15c01000-18c00000 ---p 00001000 00:04 2406       /dev/ashmem/dalvik-main space 1 (deleted)
6f2ce000-6fcab000 rw-p 00000000 1f:01 7056       /data/dalvik-cache/arm/system@[email protected]
6fcab000-71b74000 r--p 00000000 1f:01 7057       /data/dalvik-cache/arm/system@[email protected]
71b74000-73299000 r-xp 01ec9000 1f:01 7057       /data/dalvik-cache/arm/system@[email protected]
73299000-7329a000 rw-p 035ee000 1f:01 7057       /data/dalvik-cache/arm/system@[email protected]
7329a000-73376000 rw-p 00000000 00:04 2404       /dev/ashmem/dalvik-zygote space (deleted)
73376000-73377000 rw-p 00000000 00:04 2981       /dev/ashmem/dalvik-non moving space (deleted)
73377000-76e9b000 ---p 00001000 00:04 2981       /dev/ashmem/dalvik-non moving space (deleted)
76e9b000-7729a000 rw-p 03b25000 00:04 2981       /dev/ashmem/dalvik-non moving space (deleted)
...
#加载android framework-res.apk.这样子你就可以使用安卓自带的资源了.所以你@android:string
#@android:drawable可以完美执行
ac64e000-ad062000 r--s 00983000 1f:00 855        /system/framework/framework-res.apk
ad062000-ad100000 r--s 014a8000 1f:00 855        /system/framework/framework-res.apk
ad100000-ad140000 rw-p 00000000 00:00 0          [anon:libc_malloc]
ad14c000-ad151000 rw-p 00000000 00:04 2692       /dev/ashmem/dalvik-large object space allocation (deleted)
...
#加载了libandroid库.对应之前的System.loadLibrary("android");当然还有其他好多库.这里举个例子
ad1cc000-ad1da000 r-xp 00000000 1f:00 964        /system/lib/libandroid.so
ad1da000-ad1dc000 r--p 0000d000 1f:00 964        /system/lib/libandroid.so
ad1dc000-ad1dd000 rw-p 0000f000 1f:00 964        /system/lib/libandroid.so
ad1dd000-ad1fd000 r-xp 00000000 1f:00 1082       /system/lib/libpixelflinger.so
ad1fd000-ad1ff000 r--p 0001f000 1f:00 1082       /system/lib/libpixelflinger.so
ad1ff000-ad200000 rw-p 00021000 1f:00 1082       /system/lib/libpixelflinger.so
ad200000-ad216000 r-xp 00000000 1f:00 917        /system/lib/egl/libGLES_android.so
ad216000-ad217000 ---p 00000000 00:00 0 
ad217000-ad218000 r--p 00016000 1f:00 917        /system/lib/egl/libGLES_android.so
ad218000-ad219000 rw-p 00017000 1f:00 917        /system/lib/egl/libGLES_android.so
...
#初始化了字体.实际上就是把相关字体加载进来.供应用进程使用
b0179000-b017f000 r--p 00000000 1f:00 717        /system/fonts/NotoSansCham-Bold.ttf
b017f000-b0185000 r--p 00000000 1f:00 718        /system/fonts/NotoSansCham-Regular.ttf
b0185000-b0189000 r--p 00000000 1f:00 800        /system/fonts/NotoSansThaana-Bold.ttf
...
#实际上是app_process32程序.这里就是代码段和数据段
b6f9a000-b6f9f000 r-xp 00000000 1f:00 233        /system/bin/app_process32
b6f9f000-b6fa0000 r--p 00004000 1f:00 233        /system/bin/app_process32
b6fa0000-b6fa1000 rw-p 00000000 00:00 0 
be189000-be189000 ---p 00000000 00:00 0 
be189000-be988000 rw-p 00000000 00:00 0          [stack]
ffff0000-ffff1000 r-xp 00000000 00:00 0          [vectors]

你可能感兴趣的:(小刀安卓)