android开发----1.init进程分析

1940阅读 0评论2017-01-17 wangcong02345
分类:Android平台

android源码版本-->4.4.2
linux源码版本-->3.4
一.总体分析
1.
  1. root@MLTE4:/ # ps
  2. USER PID PPID VSIZE  RSS  WCHAN      PC       NAME
  3. root  1   0    1612  428  ffffffff 0001d82c S /init
  4. root  2   0    0      0   c0048904 00000000 S kthreadd
  5. root  3   2    0      0   c002ee84 00000000 S ksoftirqd/0
  6. root  4   2    0      0   c00438bc 00000000 S kworker/0:0
  7. root  6   2    0      0   c0089278 00000000 S migration/0
  8. root  7   2    0      0   c009dacc 00000000 S watchdog/0





二.init进程的启动




三.init进程分析
3.0 在sytem/core/init/init.c中
  1. int main(int argc, char **argv)
  2. {
  3.     int fd_count = 0;
  4.     struct pollfd ufds[4];
  5.     char *tmpdev;
  6.     char* debuggable;
  7.     char tmp[32];
  8.     int property_set_fd_init = 0;
  9.     int signal_fd_init = 0;
  10.     int keychord_fd_init = 0;
  11.     bool is_charger = false;

  12.     char* args_swapon[2];
  13.     args_swapon[0] = "swapon_all";;
  14.     args_swapon[1] = "/fstab.sun8i";;

  15.     char* args_write[3];
  16.     args_write[0] = "write";
  17.     args_write[1] = "/proc/sys/vm/page-cluster";
  18.     args_write[2] = "0";
  19.     //init与ueventd与watchdogd共享一份代码,通过argv[0]来区分到底是调用的哪一个
  20.     if (!strcmp(basename(argv[0]), "ueventd"))
  21.         return ueventd_main(argc, argv);

  22.     if (!strcmp(basename(argv[0]), "watchdogd"))
  23.         return watchdogd_main(argc, argv);

  24.     /* clear the umask */
  25.     ERROR("init proc start\n");
  26.     umask(0);

  27.     //创建dev proc sys目录并分别挂
  28.     mkdir("/dev", 0755);
  29.     mkdir("/proc", 0755);
  30.     mkdir("/sys", 0755);

  31.     mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
  32.     mkdir("/dev/pts", 0755);
  33.     mkdir("/dev/socket", 0755);
  34.     mount("devpts", "/dev/pts", "devpts", 0, NULL);
  35.     mount("proc", "/proc", "proc", 0, NULL);
  36.     mount("sysfs", "/sys", "sysfs", 0, NULL);

  37.     close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));    //这个不知道谁会用到
  38.     //因为现在/dev/刚刚挂载,/dev/下面没有任何文件
  39.     //创建设备结点/dev/__null__,其实就是/dev/null,将标准输入输出与错误都重定向到/dev/__null__上面
  40.     open_devnull_stdio();
  41.     //创建设备结点/dev/__kmsg__,其实就是/dev/kmsg,临时先借用内核的打印函数来输出调试信息
  42.     klog_init();
  43.     property_init();    //初始化android的属性系统
  44.     //打开/proc/cpuinfo,读取文件中全部数据到buf中,查到buf中的Hardware与revision字段,将其值保存在hardware与revision下
  45.     get_hardware_name(hardware, &revision);   
  46.     //打开/proc/cmdline,读取文件中全部数据到buf中,查到buf中的Hardware与revision字段,将其值保存在hardware与revision下
  47.     process_kernel_cmdline();   

  48. #if ASYNC_INIT_SELINUX
  49.     int err = 0;
  50.     int selinux_tid = 0;
  51.     INFO("Selinux async initialize...\n");
  52.     err = pthread_create(&selinux_tid, NULL, selinux_init_thread, NULL);
  53.     if (err != 0)
  54.     {
  55.         ERROR("create selinux init thread failed: %s\n", strerror(err));
  56.         return -1;
  57.     }
  58. #else
  59.     INFO("Selinux sync initialize...\n");
  60.     union selinux_callback cb;
  61.     cb.func_log = klog_write;
  62.     selinux_set_callback(SELINUX_CB_LOG, cb);

  63.     cb.func_audit = audit_callback;
  64.     selinux_set_callback(SELINUX_CB_AUDIT, cb);

  65.     selinux_initialize();
  66.     /* These directories were necessarily created before initial policy load
  67.      * and therefore need their security context restored to the proper value.
  68.      * This must happen before /dev is populated by ueventd.
  69.      */
  70. #endif
  71.     if (!selinux_is_disabled()) {
  72.         restorecon("/dev");
  73.         restorecon("/dev/socket");
  74.         restorecon("/dev/__properties__");
  75.         restorecon_recursive("/sys");
  76.     }

  77.     is_charger = !strcmp(bootmode, "charger");
  78.     if (!is_charger)
  79.         property_load_boot_defaults();
  80.     //打开/proc/cmdline,读取文件中全部数据到buf中,查到buf中的partitions=,在/dev/block/by-name中创建软连接
  81.     get_kernel_cmdline_partitions();
  82.     //打开/proc/cmdline,读取文件中全部数据到buf中,这儿没啥用处
  83.     get_kernel_cmdline_signature();
  84.     //不仅仅解析init.rc还解析import的其它*.rc文件,这会构造多条list
  85.     init_parse_config_file("/init.rc");
  86.     //把early-init与init中的命令都插入到队尾,因为队列是先进先出,所以early-init是最先执行的命令
  87.     action_for_each_trigger("early-init", action_add_queue_tail);   
  88.     action_for_each_trigger("init", action_add_queue_tail);

  89.     /* skip mounting filesystems in charger mode */
  90.     if (!is_charger) {
  91.         action_for_each_trigger("early-fs", action_add_queue_tail);
  92.         queue_builtin_action(wait_for_coldboot_done_action, "wait_for_coldboot_done");
  93.         queue_builtin_action(console_init_action, "console_init");
  94.         action_for_each_trigger("fs", action_add_queue_tail);
  95.         action_for_each_trigger("post-fs", action_add_queue_tail);
  96.         action_for_each_trigger("post-fs-data", action_add_queue_tail);
  97.         //SWAP TO ZRAM if low mem devices
  98.         if (!(get_dram_size() > 512)) {
  99.             char trigger[] = {"early-fs"};
  100.             ERROR("***************************LOW MEM DEVICE DETECT");
  101.             add_command(trigger, 2, args_swapon);
  102.             char trigger2[] = {"post-fs-data"};
  103.             add_command(trigger2, 3, args_write);
  104.         }
  105.     }
  106.     queue_builtin_action(property_service_init_action, "property_service_init");
  107.     queue_builtin_action(init_set_disp_policy, "init_set_disp_policy");
  108.     queue_builtin_action(signal_init_action, "signal_init");
  109.     queue_builtin_action(check_startup_action, "check_startup");

  110.     if (is_charger) {
  111.         action_for_each_trigger("charger", action_add_queue_tail);
  112.     } else {
  113.         action_for_each_trigger("early-boot", action_add_queue_tail);
  114.         action_for_each_trigger("boot", action_add_queue_tail);
  115.     }


  116.         /* run all property triggers based on current state of the properties */
  117.     queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");


  118. #if BOOTCHART
  119.     queue_builtin_action(bootchart_init_action, "bootchart_init");
  120. #endif

  121.     queue_builtin_action(init_sn, "init_sn");
  122.     for(;;) {
  123.         int nr, i, timeout = -1;

  124.         execute_one_command();
  125.         restart_processes();

  126.         if (!property_set_fd_init && get_property_set_fd() > 0) {
  127.             ufds[fd_count].fd = get_property_set_fd();
  128.             ufds[fd_count].events = POLLIN;
  129.             ufds[fd_count].revents = 0;
  130.             fd_count++;
  131.             property_set_fd_init = 1;
  132.         }
  133.         if (!signal_fd_init && get_signal_fd() > 0) {
  134.             ufds[fd_count].fd = get_signal_fd();
  135.             ufds[fd_count].events = POLLIN;
  136.             ufds[fd_count].revents = 0;
  137.             fd_count++;
  138.             signal_fd_init = 1;
  139.         }
  140.         if (!keychord_fd_init && get_keychord_fd() > 0) {
  141.             ufds[fd_count].fd = get_keychord_fd();
  142.             ufds[fd_count].events = POLLIN;
  143.             ufds[fd_count].revents = 0;
  144.             fd_count++;
  145.             keychord_fd_init = 1;
  146.         }

  147.         if (process_needs_restart) {
  148.             timeout = (process_needs_restart - gettime()) * 1000;
  149.             if (timeout < 0)
  150.                 timeout = 0;
  151.         }

  152.         if (!action_queue_empty() || cur_action)
  153.             timeout = 0;

  154. #if BOOTCHART
  155.         if (bootchart_count > 0) {
  156.             if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)
  157.                 timeout = BOOTCHART_POLLING_MS;
  158.             if (bootchart_step() < 0 || --bootchart_count == 0) {
  159.                 bootchart_finish();
  160.                 bootchart_count = 0;
  161.             }
  162.         }
  163. #endif

  164.         nr = poll(ufds, fd_count, timeout);
  165.         if (nr <= 0)
  166.             continue;

  167.         for (i = 0; i < fd_count; i++) {
  168.             if (ufds[i].revents == POLLIN) {
  169.                 if (ufds[i].fd == get_property_set_fd())
  170.                     handle_property_set_fd();
  171.                 else if (ufds[i].fd == get_keychord_fd())
  172.                     handle_keychord();
  173.                 else if (ufds[i].fd == get_signal_fd())
  174.                     handle_signal();
  175.             }
  176.         }
  177.     }

  178.     return 0;
  179. }

3.1 脚本解析的过程
  1. int init_parse_config_file(const char *fn)  //这里的fn="/init.rc"
  2. {
  3.     char *data;
  4.     data = read_file(fn, 0);   //将"/init.rc"的内容全部读取到以data为首指针的buffer中,函数会调用malloc
  5.     if (!data) return -1;      //并在文件最后添加结束标志\n\0

  6.     parse_config(fn, data);
  7.     DUMP();
  8.     return 0;
  9. }















附录1:
/proc/cpuinfo
  1. root@MLTE4:/ # cat /proc/cpuinfo
  2. Processor    : ARMv7 Processor rev 5 (v7l)
  3. processor    : 0
  4. BogoMIPS    : 4800.00

  5. processor    : 1
  6. BogoMIPS    : 4800.00

  7. processor    : 2
  8. BogoMIPS    : 4800.00

  9. processor    : 3
  10. BogoMIPS    : 4800.00

  11. Features    : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpv4 idiva idivt
  12. CPU implementer    : 0x41
  13. CPU architecture: 7
  14. CPU variant    : 0x0
  15. CPU part    : 0xc07
  16. CPU revision    : 5

  17. Hardware    : sun8i
  18. Revision    : 0000
  19. Serial        : 54005035c4180838058e
/proc/cmdline
  1. root@MLTE4:/ # cat /proc/cmdline
  2. console=ttyS0,115200 root=/dev/block/mmcblk0p7 init=/init loglevel=15 vmalloc=384M partitions=bootloader@mmcblk0p2:env@mmcblk0p5:boot@mmcblk0p6:system@mmcblk0p7:misc@mmcblk0p8:recovery@mmcblk0p9:sysrecovery@mmcblk0p10:private@mmcblk0p11:Reserve0@mmcblk0p12:klog@mmcblk0p13:Reserve1@mmcblk0p14:Reserve2@mmcblk0p15:cache@mmcblk0p16:UDISK@mmcblk0p1 mac_addr= wifi_mac= bt_mac= specialstr= serialno= boot_type=2 disp_para=0 init_disp=20b0404 tv_vdid=0 fb_base=0x46400000 config_size=49152

附录2:对cmdline的处理
  1. static void process_kernel_cmdline(void)
  2. {
  3.     /* don't expose the raw commandline to nonpriv processes */
  4.     chmod("/proc/cmdline", 0440);

  5.     import_kernel_cmdline(0, import_kernel_nv);
  6.     if (qemu[0])
  7.         import_kernel_cmdline(1, import_kernel_nv);
  8.     //会设置 ro.boot.serialno, ro.boot.mode, ro.boot.baseband, 
  9.     // ro.boot.bootloader, ro.boot.console, ro.bootmode, ro.boot.hardware
  10.     // 这几个参数
  11.     export_kernel_boot_props();
  12. }
process_kernel_cmdline-->import_kernel_cmdline
  1. void import_kernel_cmdline(int in_qemu,
  2.                            void (*import_kernel_nv)(char *name, int in_qemu))
  3. {
  4.     char cmdline[1024];
  5.     char *ptr;
  6.     int fd;
  7.     //将文件/proc/cmdline的内容读取到buf中
  8.     fd = open("/proc/cmdline", O_RDONLY);
  9.     if (fd >= 0) {
  10.         int n = read(fd, cmdline, 1023);
  11.         if (n < 0) n = 0;

  12.         /* get rid of trailing newline, it happens */
  13.         if (n > 0 && cmdline[n-1] == '\n') n--;

  14.         cmdline[n] = 0;
  15.         close(fd);
  16.     } else {
  17.         cmdline[0] = 0;
  18.     }
  19.     //查找buf中的空格,以空格为分隔符划分出一个个的字符串,每一个字符串就是一个设置,调用回调函数import_kernel_nv
  20.     ptr = cmdline;
  21.     while (ptr && *ptr) {
  22.         char *x = strchr(ptr, ' ');
  23.         if (x != 0) *x++ = 0;            //查找到空格,将空格替换为\0,字符串结束
  24.         import_kernel_nv(ptr, in_qemu);  //如果是实体机in_qemu=0
  25.         ptr = x;
  26.     }
  27. }


如果是实体机for_emulator=0,
  1. static void import_kernel_nv(char *name, int for_emulator)
  2. {
  3.     char *value = strchr(name, '=');
  4.     int name_len = strlen(name);

  5.     if (value == 0) return;
  6.     *value++ = 0;
  7.     if (name_len == 0) return;

  8.     if (for_emulator) {       //for_emulator=0
  9.         /* in the emulator, export any kernel option with the
  10.          * ro.kernel. prefix */
  11.         char buff[PROP_NAME_MAX];
  12.         int len = snprintf( buff, sizeof(buff), "ro.kernel.%s", name );

  13.         if (len < (int)sizeof(buff))
  14.             property_set( buff, value );
  15.         return;
  16.     }

  17.     if (!strcmp(name,"qemu")) {                              //检查cmdline中是否有qemu字段,这儿没有
  18.         strlcpy(qemu, value, sizeof(qemu));
  19.     } else if (!strncmp(name, "androidboot.", 12) && name_len > 12) {  //检查cmdline中是否有androidboot.字段,这儿没有
  20.         const char *boot_prop_name = name + 12;
  21.         char prop[PROP_NAME_MAX];
  22.         int cnt;

  23.         cnt = snprintf(prop, sizeof(prop), "ro.boot.%s", boot_prop_name);
  24.         if (cnt < PROP_NAME_MAX)
  25.             property_set(prop, value);
  26.     }
  27. }





上一篇:linux驱动17---arm获取内存的大小
下一篇:android开发----3.property分析