Android启动流程


一、Android init进程启动

还是从Linux的启动开始吧。Linux被bootloader加载到了内存之后,开始运行,在初始化完Linux运行环境之后,挂载ramdisk.img根文件系统映像,运行里面的init程序,这也是Linux的第一个用户程序,其pid为1。下面的文章是作者关于init进程启动的描述。

http://blog.csdn.net/mr_raptor/article/details/7666906


1、Android Init.c执行流程

Android中的内核启动后,kernel会启动第一个用户级别的进程:init,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行,并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。init始终是第一个进程。
PS:可以通过:ps aux | grep init命令来查看其Pid为1。
init进程对应的代码在android源码目录中的:system/core/init/init.c中。
789 int main(int argc, char **argv)
790 {
# 创建一些linux根文件系统中的目录
817     mkdir("/dev", 0755);
818     mkdir("/proc", 0755);
819     mkdir("/sys", 0755);
820
821     mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755");
822     mkdir("/dev/pts", 0755);
823     mkdir("/dev/socket", 0755);
824     mount("devpts", "/dev/pts", "devpts", 0, NULL);
825     mount("proc", "/proc", "proc", 0, NULL);
826     mount("sysfs", "/sys", "sysfs", 0, NULL); 
# init的标准输入,标准输出,标准错误文件描述符定向到__null__,意味着没有输入和输出,它的输入和输出全部写入到Log中
834     open_devnull_stdio();

# 初始化log,写入init进程信息

835     log_init();
# 读取并且解析init.rc文件
838     parse_config_file("/init.rc");
# 取得硬件名
844     get_hardware_name();
845     snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
# 读取并且解析硬件相关的init脚本文件
846     parse_config_file(tmp);
# 触发在init脚本文件中名字为early-init的action,并且执行其commands,其实是: on early-init
848     action_for_each_trigger("early-init", action_add_queue_tail);
849     drain_action_queue();
# 初始化动态设备管理,设备文件有变化时反应给内核,后面具体解释
852     device_fd = device_init();
# 加载启动动画,如果动画打开失败,则在屏幕上打印: A N D R O I D字样。
872     if( load_565rle_image(INIT_IMAGE_FILE) ) {
 873     fd = open("/dev/tty0", O_WRONLY);
 874     if (fd >= 0) {
 875         const char *msg;
 876             msg = "\n"
 877         "\n"
 878         "\n"
 879         "\n"
 880         "\n"
 881         "\n"
 882         "\n"  // console is 40 cols x 30 lines
 883         "\n"
 884         "\n"
 885         "\n"
 886         "\n"
 887         "\n"
 888         "\n"
 889         "\n"
 890         //"             A N D R O I D ";
 891         write(fd, msg, strlen(msg));
 892         close(fd);
 893     }
 894     }
 895
# 触发在init脚本文件中名字为init的action,并且执行其commands,其实是:on init
919     action_for_each_trigger("init", action_add_queue_tail);
 920     drain_action_queue();
# 启动系统属性服务: system property service
927     property_set_fd = start_property_service();

# 创建socket用来处理孤儿进程信号
930     if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {
 931         signal_fd = s[0];
 932         signal_recv_fd = s[1];
 933         fcntl(s[0], F_SETFD, FD_CLOEXEC);
 934         fcntl(s[0], F_SETFL, O_NONBLOCK);
 935         fcntl(s[1], F_SETFD, FD_CLOEXEC);
 936         fcntl(s[1], F_SETFL, O_NONBLOCK);
 937     }

# 触发在init脚本文件中名字为early-boot和boot的action,并且执行其commands,其实是:on early-boot和on boot
948     action_for_each_trigger("early-boot", action_add_queue_tail);
 949     action_for_each_trigger("boot", action_add_queue_tail);
 950     drain_action_queue();
# 启动所有属性变化触发命令,其实是: on property:ro.xx.xx=xx
953     queue_all_property_triggers();
 954     drain_action_queue();
# 进入死循环
987     for(;;) {

# 启动所有init脚本中声明的service,
# 如:266 service servicemanager /system/bin/servicemanager
#     user system
#     critical
#     onrestart restart zygote
#     onrestart restart media

994         restart_processes();
# 多路监听设备管理,子进程运行状态,属性服务
1012         nr = poll(ufds, fd_count, timeout);
1013         if (nr <= 0)
1014             continue;
1016         if (ufds[2].revents == POLLIN) {
1017             /* we got a SIGCHLD - reap and restart as needed */
1018             read(signal_recv_fd, tmp, sizeof(tmp));
1019             while (!wait_for_one_process(0))
1020                 ;
1021             continue;
1022         }
1023
1024         if (ufds[0].revents == POLLIN)
1025             handle_device_fd(device_fd);
1026
1027         if (ufds[1].revents == POLLIN)
1028             handle_property_set_fd(property_set_fd);
1029         if (ufds[3].revents == POLLIN)
1030             handle_keychord(keychord_fd);
1031     }
1032
1033     return 0;
1034 }

 

2、Android init脚本语言

前面简单分析了下init.c里的操作,里面提到了解析Init.rc和硬件脚本下面详细解析下Android init脚本语言的规范。

Android初始化语言包含了四种类型的声明:

    Actions(行为)、Commands(命令)、Services(服务)和Options(选项)

  • 所有这些都是以行为单位的,各种记号由空格来隔开。
  • C语言风格的反斜杠号可用于在记号间插入空格。
  • 双引号也可用于防止字符串被空格分割成多个记号。
  • 行末的反斜杠用于折行,注释行以井号(#)开头(允许以空格开头)。


Actions和Services声明一个新的分组Section。所有的命令或选项都属于最近声明的分组。位于第一个分组之前的命令或选项将会被忽略。
Actions和Services有唯一的名字。如果有重名的情况,第二个申明的将会被作为错误忽略。

Actions(行为)
  Actions其实就是一序列的Commands(命令)。Actions都有一个trigger(触发器),它被用于决定action的执行时间。当一个符合action触发条件的事件发生时,action会被加入到执行队列的末尾,除非它已经在队列里了。
    队列中的每一个action都被依次提取出,而这个action中的每个command(命令)都将被依次执行。
Actions的形式如下:
        on <trigger>
           <command1>
           <command2>
           <command3>
on后面跟着一个触发器,当trigger被触发时,command1,command2,command3,会依次执行,直到下一个Action或下一个Service。
简单来说,Actions就是Android在启动时定义的一个启动脚本,当条件满足时,会执行该脚本,脚本里都是一些命令commands,不同的脚本用on来区分。

Triggers(触发器)
    Triggers(触发器)是一个用于匹配特定事件类型的字符串,用于使Actions发生。
        boot:
            这是init执行后的第一个被触发的Triggers(触发器)。(在 /init.conf (启动配置文件)被装载之后)
        <name>=<value>:
            这种形式的Triggers(触发器)会在属性<name>被设置为指定的<value>时被触发。
        device-added-<path>:
        device-removed-<path>:
            这种形式的Triggers(触发器)会在一个设备节点文件被增删时触发。
        service-exited-<name>:
            这种形式的Triggers(触发器)会在一个特定的服务退出时触发。
触发器通常和on一起来联合使用。
示例:
on init
  export LD_LIBRARY_PATH /system/lib
  insmod modules/fsr.ko
  symlink /system/etc /etc
  mkdir /sdcard 0000 system system
  write /proc/cpu/alignment 4

on boot
  …
on property:ro.kernel.qemu=1
   start adbd
上面声明了三个action:init,boot和一个属性触发器,当init被触发时,会顺序执行后面的命令,直到on boot新的action。Init的触发是由init.c里的函数action_for_each_trigger来决定的。当属性ro.kernel.qemu为1 时,会触发start adbd命令。


Services(服务)
Services(服务)是一个程序,它在初始化时启动,并在退出时可选择让其重启。Services(服务)的形式如下:
        service <name> <pathname> [ <argument> ]*
           <option>
           <option>
           ...
name:服务名
pathname:当前服务对应的程序位置
option:当前服务设置的选项

Options(选项)
    Options(选项)是一个Services(服务)的修正者。他们影响Services(服务)在何时,并以何种方式运行。
     critical:
            说明这是一个对于设备关键的服务。如果他四分钟内退出大于四次,系统将会重启并进入recovery(恢复)模式。

     disabled:
            说明这个服务不会同与他同trigger(触发器)下的服务自动启动。他必须被明确的按名启动。

     setenv <name> <value> (设置环境变量)
            在进程启动时将环境变量<name>设置为<value>。

     socket <name> <type> <perm> [ <user> [ <group> ] ]
            创建一个Uinx域的名为/dev/socket/<name> 的套接字,并传递它的文件描述符给已启动的进程。<type> 必须是 "dgram"或"stream"。User 和 group默认为0。

     user <username>
            在启动这个服务前改变该服务的用户名。此时默认为root。(???有可能的话应该默认为nobody)。当前,如果你的进程要求Linux capabilities(能力),你无法使用这个命令。即使你是root,你也必须在程序中请求capabilities(能力)。然后降到你想要的 uid。

     group <groupname> [ <groupname> ]*
            在启动这个服务前改变该服务的组名。除了(必需的)第一个组名,附加的组名通常被用于设置进程的补充组(通过setgroups())。此时默认为root。(???有可能的话应该默认为nobody)。
   
     oneshot
            服务退出时不重启。

     class <name>
            指定一个服务类。所有同一类的服务可以同时启动和停止。如果不通过class选项指定一个类,则默认为"default"类服务。

     onrestart
            当服务重启,执行一个命令(下详)。

Commands(命令)
    exec <path> [ <argument> ]*
         创建和执行一个程序(<path>)。在程序完全执行前,init将会阻塞。由于它不是内置命令,应尽量避免使用exec,它可能会引起init卡死。(??? 是否需要一个超时设置?)
    export <name> <value>
        在全局环境变量中设在环境变量 <name>为<value>。(这将会被所有在这命令之后运行的进程所继承)
    ifup <interface>
        启动网络接口<interface>
    import <filename>
           解析一个init配置文件,扩展当前配置。
    hostname <name>
           设置主机名。
    chmod <octal-mode> <path>
           更改文件访问权限。
    chown <owner> <group> <path>
           更改文件的所有者和组。
    class_start <serviceclass>
           启动所有指定服务类下的未运行服务。
    class_stop <serviceclass>
        停止指定服务类下的所有已运行的服务。
    domainname <name>
           设置域名。
    insmod <path>
           加载<path>中的模块。
    mkdir <path> [mode] [owner] [group]
           创建一个目录<path>,可以选择性地指定mode、owner以及group。如果没有指定,默认的权限为755,并属于root用户和root组。
    mount <type> <device> <dir> [ <mountoption> ]*
        试图在目录<dir>挂载指定的设备。<device> 可以是以 mtd@name 的形式指定一个mtd块设备。<mountoption>包括 "ro"、"rw"、"remount"、"noatime"、 ...
    setprop <name> <value>
           设置系统属性 <name> 为 <value>值.
    setrlimit <resource> <cur> <max>
        设置<resource>的rlimit(资源限制)。
    start <service>
        启动指定服务(如果此服务还未运行)。
    stop <service>
        停止指定服务(如果此服务在运行中)。
    symlink <target> <path>
        创建一个指向<path>的软连接<target>。
    sysclktz <mins_west_of_gmt>
        设置系统时钟基准(0代表时钟滴答以格林威治平均时(GMT)为准)
    trigger <event>
           触发一个事件。用于将一个action与另一个 action排列。
    write <path> <string> [ <string> ]*
           打开路径为<path>的一个文件,并写入一个或多个字符串。

Properties(属性)
    Init更新一些系统属性以提供对正在发生的事件的监控能力:
        init.action
               此属性值为正在被执行的action的名字,如果没有则为""。
        init.command
               此属性值为正在被执行的command的名字,如果没有则为""。
        init.svc.<name>
               名为<name>的service的状态("stopped"(停止), "running"(运行), "restarting"(重启))

 

3、Android init 示例

  1 on init
  2
  3 sysclktz 0
  4
  5 loglevel 3
  6
  7 # setup the global environment
  8     export PATH /system/busybox/bin:/system/busybox/sbin:/system/busybox/usr/bin:/system/busybox/usr/sbin:/sbin:/system/sbin:/system/bin:/system/xbin
  9     export LD_LIBRARY_PATH /system/lib
 10     export ANDROID_BOOTLOGO 1
 11     export ANDROID_ROOT /system
 12     export ANDROID_ASSETS /system/app
 13     export ANDROID_DATA /data
 14     export EXTERNAL_STORAGE /sdcard

... ...

 23     symlink /system/etc /etc
 24     symlink /sys/kernel/debug /d
 25    
 26 # create mountpoints and mount tmpfs on sqlite_stmt_journals
 27     mkdir /sdcard 0000 system system
 28     mkdir /system
 29     mkdir /data 0771 system system
 30     mkdir /cache 0770 system cache
 31     mkdir /config 0500 root root
 32     mkdir /sqlite_stmt_journals 01777 root root
 33     mount tmpfs tmpfs /sqlite_stmt_journals size=4m
 34
 35 #    mount rootfs rootfs / ro remount
 36
 37     write /proc/sys/kernel/panic_on_oops 1
 38     write /proc/sys/kernel/hung_task_timeout_secs 0
 39     write /proc/cpu/alignment 4
 40     write /proc/sys/kernel/sched_latency_ns 10000000
 41     write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000
 42     write /proc/sys/kernel/sched_compat_yield 1
 43     write /proc/sys/kernel/sched_child_runs_first 0
 44
 45 # Create cgroup mount points for process groups
 46     mkdir /dev/cpuctl

 47     mount cgroup none /dev/cpuctl cpu
 48     chown system system /dev/cpuctl
 49     chown system system /dev/cpuctl/tasks
 50     chmod 0777 /dev/cpuctl/tasks
 51     write /dev/cpuctl/cpu.shares 1024
 52
 53     mkdir /dev/cpuctl/fg_boost
 54     chown system system /dev/cpuctl/fg_boost/tasks
 55     chmod 0777 /dev/cpuctl/fg_boost/tasks
 56     write /dev/cpuctl/fg_boost/cpu.shares 1024
 57
 58     mkdir /dev/cpuctl/bg_non_interactive
 59     chown system system /dev/cpuctl/bg_non_interactive/tasks
 60     chmod 0777 /dev/cpuctl/bg_non_interactive/tasks
 61     # 5.0 %
 62     write /dev/cpuctl/bg_non_interactive/cpu.shares 52
 ... ...

146 on boot
147 # basic network init
148     ifup lo
149     hostname localhost
150     domainname localdomain
151
152 # set RLIMIT_NICE to allow priorities from 19 to -20
153     setrlimit 13 40 40
154
155 # Define the oom_adj values for the classes of processes that can be
156 # killed by the kernel.  These are used in ActivityManagerService.
157     setprop ro.FOREGROUND_APP_ADJ 0
158     setprop ro.VISIBLE_APP_ADJ 1
159     setprop ro.SECONDARY_SERVER_ADJ 2
160     setprop ro.BACKUP_APP_ADJ 2
161     setprop ro.HOME_APP_ADJ 4
162     setprop ro.HIDDEN_APP_MIN_ADJ 7

... ...

233 # Define TCP buffer sizes for various networks
234 #   ReadMin, ReadInitial, ReadMax, WriteMin, WriteInitial, WriteMax,
235     setprop net.tcp.buffersize.default 4096,87380,110208,4096,16384,110208
236     setprop net.tcp.buffersize.wifi    4095,87380,110208,4096,16384,110208
237     setprop net.tcp.buffersize.umts    4094,87380,110208,4096,16384,110208
238     setprop net.tcp.buffersize.edge    4093,26280,35040,4096,16384,35040
239     setprop net.tcp.buffersize.gprs    4092,8760,11680,4096,8760,11680
240     setprop net.dns1 8.8.8.8
241     setprop net.eth0.dns1 8.8.8.8
242
243     class_start default

... ...

247 service console /system/bin/sh
248    console
249

252 service adbd /sbin/adbd
253     disabled'

259 on property:persist.service.adb.enable=1
260     start adbd
261
262 on property:persist.service.adb.enable=0
263     stop adbd

265 service servicemanager /system/bin/servicemanager
266     user system
267     critical
268     onrestart restart zygote
269     onrestart restart media

271 service vold /system/bin/vold
272     socket vold stream 0660 root mount

 

282 service ril-daemon /system/bin/rild
283     socket rild stream 660 root radio
284     socket rild-debug stream 660 radio system
285     user root
286     group radio cache inet misc
287
288 service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
289     socket zygote stream 666
290     onrestart write /sys/android_power/request_state wake
291     onrestart write /sys/power/state on
292     onrestart restart media

293
294 service media /system/bin/mediaserver
295     user media
296     group system audio camera graphics inet net_bt net_bt_admin
297
298 service bootsound /system/bin/playmp3
299     user media
300     group audio
301     oneshot
302
303 service bootanim /system/bin/bootanimation
304     user graphics
305     group graphics

306     disabled
307     oneshot

... ...

由上面的例子可知:该init.rc里定义了4个actions:

    on init

    on boot

    on property:persist.service.adb.enable=1
    on property:persist.service.adb.enable=0
   其中,前两个的触发器是由Init.c里的代码action_for_each_trigger实现触发的,后两个是由属性的值发生改变时触发的。当他们被触发时,会依次执行其后面的值,直到遇到一个新的Action或service。

该init.rc中定义了9个services,这些service属于本地服务,它们都是由c或c++代码写的,以可执行文件的方式存在文件系统里的/system/bin或/sbin目录下。由前面知识可知,如果一个服务没有使用class选项指定其分类,则其默认分类为:default,那么这9个services的分类为default。在on boot action触发时,其最后一个命令是class_start default,也就是将这9个services都依次启动。

init.rc中的9个service里,以zygote和servicemanager最为重要。

1> zygote service

该service主要用于创建Dalvik Java虚拟机,然后启动SystemServer,启动所有的Android服务,最终启动Android系统。

2> servicemanager

该service主要用来打开binder驱动,binder是Android Service通信机制的底层实现,在该service里封装了binder的操作接口。

技巧:

  在调试或理解系统的工作原理的时候,我们经常要去找服务程序对应的源码。

  寻找c或c++程序的源码文件:

  例如:以寻找init程序对应的源码为例。

   find ./ -name Android.mk -exec grep -l init {} \;

  注:通过find命令查找所有的Android.mk, 通过grep从中查找程序字符串,得到其路径,然后去路径下找源码即可,这么做的原因是,c或c++代码都是通过Android.mk来指导编译的。

   寻找java源码文件:

   java源码的特点是和类名一致,所以如果我们知道一个类名,找其java源码就直接加上java后缀即可。

  例如:寻找com.android.internal.os.ZygoteInit类的代码。

   find ./ -name ZygoteInit.java




二、Android本地服务的启动

init进程启动完之后,开始初始化并启动Dalvik虚拟机,在Dalvik虚拟机启动之前做了一些工作,请看下面一篇文章。

http://blog.csdn.net/mr_raptor/article/details/7804984


通过上一节Android init进程启动的分析可知,init进程在启动过程中,解析并处理了init.rc和init.hardware.rc两个初始化脚本文件,在两个初始化脚本文件里,定义了一系列的service section,这些service在boot触发器下,通过class_start default依次启动,其过程总结如下:

    1. init 解析init.rc

    2. init 将init.rc里的service放到队列里面等待触发器的触发

    3. init通过 action_for_each_trigger("boot", action_add_queue_tail);触发boot Action

    4. 依次执行boot下的Commands,包括class_start default命令

    5. 所有的service默认的class为默认值:default,所以,所有init.rc中的service都被启动

zygote服务启动


通过init.rc中对zygote服务的描述可知,其对应的程序为:/system/bin/app_process

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    socket zygote stream 666
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart media

该服务会在on boot时触发,其程序为/system/bin/app_process,服务名为zygote-Xzygote /system/bin --zygote --start-system-server为参数列表。

在创建了zygote 服务后,在目录下建立一个stream socket文件/dev/socket/zygote,权限为666,当zygote服务重启时,重启media服务

通过find ./ -name Android.mk  -exec grep -l app_process {} \; 命令,查找到,它在./frameworks/base/cmds/app_process/目录中被编译,其主要入口文件为:

./frameworks/base/cmds/app_process/app_main.cpp

找到该程序的main入口函数,

118 int main(int argc, const char* const argv[])
119 {
120     // These are global variables in ProcessState.cpp
121     mArgC = argc;
122     mArgV = argv;
123
124     mArgLen = 0;
125     for (int i=0; i<argc; i++) {
126         mArgLen += strlen(argv[i]) + 1;
127     }
128     mArgLen--;
129
130     AppRuntime runtime;
131     const char *arg;
132     const char *argv0;
133
134     argv0 = argv[0];
135
136     // Process command line arguments
137     // ignore argv[0]
138     argc--;
139     argv++;

141     // Everything up to '--' or first non '-' arg goes to the vm
142     // 在zygote服务的参数列表中,以‘--和非‘-’开头的参数,是dalvik的参数:/system/bin--zygote --start-system-server,交给Vm来处理

143     int i = runtime.addVmArguments(argc, argv);
144
145     // 找到zygote的目录:/system/bin
146     if (i < argc) {
147         runtime.mParentDir = argv[i++];
148     }
149
150     // 如果接下来的参数是:--zygote --start-system-server的话,设置argv0=“zygote”,startSystemServer= true,启动java VM
151     if (i < argc) {
152         arg = argv[i++];
153         if (0 == strcmp("--zygote", arg)) {
154             bool startSystemServer = (i < argc) ?
155                     strcmp(argv[i], "--start-system-server") == 0 : false;
156             setArgv0(argv0, "zygote");
157             set_process_name("zygote");
158             runtime.start("com.android.internal.os.ZygoteInit",
159                 startSystemServer);
160         } else {
161             set_process_name(argv0);
162
163             runtime.mClassName = arg;
164
165             // Remainder of args get passed to startup class main()
166             runtime.mArgC = argc-i;

167             runtime.mArgV = argv+i;
168
169             LOGV("App process is starting with pid=%d, class=%s.\n",
170                  getpid(), runtime.getClassName());
171             runtime.start();
172         }
173     } else {
174         LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
175         fprintf(stderr, "Error: no class name or --zygote supplied.\n");
176         app_usage();
177         return 10;
178     }
179
180 }

 根据service zygote的参数,启动VM:

runtime.start("com.android.internal.os.ZygoteInit", startSystemServer);

runtime是AppRuntime的对象,AppRuntime是AndroidRuntime的子类:

runtime.start方法在AndroidRuntime里实现:

 859 void AndroidRuntime::start(const char* className, const bool startSystemServer)
 860 {
 861     LOGD("\n>>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<\n");  // logcat里最显眼的字样
 862
 863     char* slashClassName = NULL;
 864     char* cp;
 865     JNIEnv* env;
 866
 867     blockSigpipe();
 868
 869     /*
 870      * 'startSystemServer == true' means runtime is obslete and not run from
 871      * init.rc anymore, so we print out the boot start event here.
 872      */
 873     if (startSystemServer) {
 874         /* track our progress through the boot sequence */
 875         const int LOG_BOOT_PROGRESS_START = 3000;
 876         LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
 877                        ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
 878     }

 880     const char* rootDir = getenv("ANDROID_ROOT");  // 取得Android的根目录:/system
 881     if (rootDir == NULL) {
 882         rootDir = "/system";
 883         if (!hasDir("/system")) {
 884             LOG_FATAL("No root directory specified, and /android does not exist.");
 885             goto bail;
 886         }
 887         setenv("ANDROID_ROOT", rootDir, 1);
 888     }
 889
 890     //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
 891     //LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
 892
 893     /* start the virtual machine */

// 启动Dalvik虚拟机,在AndroidRuntime::startVm方法中,设备了大量VM的参数,最后调用JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs),通过JNI启动虚拟机
 894     if (startVm(&mJavaVM, &env) != 0)     

 895         goto bail;
 896
 897     /*
 898      * Register android functions.
 899      */
 900     if (startReg(env) < 0) {      // 注册系统使用的JNI函数
 901         LOGE("Unable to register all android natives\n");
 902         goto bail;
 903     }

 910     jclass stringClass;
 911     jobjectArray strArray;
 912     jstring classNameStr;
 913     jstring startSystemServerStr;
 914
 915     stringClass = env->FindClass("java/lang/String");          // 从Dalvik虚拟机里,查找到String类,
 916     assert(stringClass != NULL);
 917     strArray = env->NewObjectArray(2, stringClass, NULL);  // 创建一个String数组,有两个元素(strArray =  new String[2])
 918     assert(strArray != NULL);
 919     classNameStr = env->NewStringUTF(className);       // 创建一个Java String对象,初始值为:className,其实是start第一个参数:com.android.internal.os.ZygoteInit
 920     assert(classNameStr != NULL);
 921     env->SetObjectArrayElement(strArray, 0, classNameStr);   // 设置strArray 第一个元素的值为:classNameStr (strArray[0] =classNameStr)
 922     startSystemServerStr = env->NewStringUTF(startSystemServer ?
 923                                                  "true" : "false");   // 创建一个Java String对象,初始值为:startSystemServer ,其实是start第二个参数:true
 924     env->SetObjectArrayElement(strArray, 1, startSystemServerStr); // 设置strArray 第二个元素的值为:strArray[1] =startSystemServerStr

 925
 926     /*
 927      * Start VM.  This thread becomes the main thread of the VM, and will
 928      * not return until the VM exits.
 929      */

          // 根据上面的解释可知:准备启动Java VM,并且创建VM的主线程,只要VM不退出,这个主线程一直运行。
 930     jclass startClass;
 931     jmethodID startMeth;

 933     slashClassName = strdup(className);
 934     for (cp = slashClassName; *cp != '\0'; cp++)    // 将com.android.internal.os.ZygoteInit中的包分隔符‘.’换成‘/’即:com/android/internal/os/ZygoteInit
 
935         if (*cp == '.')
 936             *cp = '/';
 937
 938     startClass = env->FindClass(slashClassName);   // 从VM中查找ZygoteInit类,难道它要在VM里加载这个类。。。。
 939     if (startClass == NULL) {
 940         LOGE("JavaVM unable to locate class '%s'\n", slashClassName);
 941         /* keep going */
 942     } else {
 943         startMeth = env->GetStaticMethodID(startClass, "main",
 944             "([Ljava/lang/String;)V");   // 查找到com/android/internal/os/ZygoteInit类中的main方法ID,接合Java文件命名规则,你能更深刻的理解,为什么主类名要和文件名一致,并且main方法为static方法。
 945         if (startMeth == NULL) {
 946             LOGE("JavaVM unable to find main() in '%s'\n", className);
 947             /* keep going */
 948         } else {
 949             env->CallStaticVoidMethod(startClass, startMeth, strArray);  // 调用ZygoteInit类里的main方法,这不是运行ZygoteInit这个JAVA程序吗!!
 950
 951 #if 0
 952             if (env->ExceptionCheck())
 953                 threadExitUncaughtException(env);
 954 #endif
 955         }
 956     }

 957
 958     LOGD("Shutting down VM\n");
 959     if (mJavaVM->DetachCurrentThread() != JNI_OK)
 960         LOGW("Warning: unable to detach main thread\n");
 961     if (mJavaVM->DestroyJavaVM() != 0)
 962         LOGW("Warning: VM did not shut down cleanly\n");
 963
 964 bail:
 965     free(slashClassName);
 966 }
 967
由上面的分析可知,
AndroidRuntime::start方法实现了下面功能:

  1> 通过startVm来启动虚拟机,并且注册了一些系统JNI函数,由于这个时候VM里还没有程序,只是个空的VM执行环境

  2> 通过AndroidRuntime::start的参数,在JNI代码里构建第一个Java程序ZygoteInit,将其作为VM的主线程,同时给其传递两个JNI构建的参数:

       "com/android/internal/os/ZygoteInit"和"true"

总结:

Android系统的启动是由init进程加载并启动了里面的/system/bin/ app_process程序作为zygote服务,然后在zygote服务里执行runtime.start启动Dalvik虚拟机,加载了ZygoteInit类作为Dalvik虚拟机的第一个主线程。至此,Android的Java运行环境就准备完毕了。






三、Android启动总结:

init进程在执行过程中可以分为以下几个阶段:

Ø 启动准备:创建文件系统的基本目录、打开标准输入、标准输出、标准错误,初始化log日志功能等

Ø 解析init.rc和init.hardware.rc文件:将rc文件逐行解析成Action或Service。解析出来的Action和Service分别存放在action_list和service_list链表里,每个Action都对应一个或多个Commands,每个依附于Action的Commands也由一个链表维护。

Ø 将early-initAction添加到action_queue队列里,等待执行

Ø 将init Action添加到action_queue队列里,等待执行

Ø 添加其它条件的Action到action_queue队列里

Ø 进入死循环

o 从action_queue队列里依次取出每个Action,执行其维护的Commands链表里的命令

o 重新启动service_list中标记为SVC_RESTARTING服务

o 监听系统属性状态变化事件、子进程信号、Keychord组合按键事件

注:在代码里没有明显运行service_list里服务的代码,每个服务都有一个class属性,该属性决定了服务的分类,在init.rc文件的on boot Action最后有两个命令:

[plain] view plaincopy
                1. on boot
                2. …
                3. ...
                4. class_start core
                5. class_start main

class_start命令是指运行某一类的服务,先启动了class为core的服务,然后再启动了class为main的服务。

init.rc中class为core的服务有:

Service名对应程序及参数
ueventd/sbin/ueventd
console/system/bin/sh
adbd/sbin/adbd
servicemanager/system/bin/servicemanager
vold/system/bin/vold

class为main的服务有:

Service名对应程序及参数
netd/system/bin/netd
debuggerd/system/bin/debuggerd
ril-daemon/system/bin/rild
surfaceflinger/system/bin/surfaceflinger
zygote/system/bin/app_process -Xzygote /system/bin --zygote--start-system-server
drm/system/bin/drmserver
media/system/bin/mediaserver
bootanim/system/bin/bootanimation
dbus/system/bin/dbus-daemon --system --nofork
bluetoothd/system/bin/bluetoothd -n
installd/system/bin/installd
flash_recovery/system/etc/install-recovery.sh
racoon/system/bin/racoon
mtpd/system/bin/mtpd
keystore/system/bin/keystore /data/misc/keystore
dumpstate/system/bin/dumpstate -s
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值