Android Init<br />ENM System 권홍재<br />
Kernel에서 Android init 시작<br /><ul><li>Android 커널 부팅이 완료된 후 루트파일 시스템의 “/init”을 찾아서 수행한다.
안드로이드init은 루트에 위치하기때문에 반드시 커널 부팅옵션에서 “init=/init”옵션이 주어져야 한다.</li></ul>< kernel/init/main.c ><br />static intnoinlineinit_...
Init 프로세스의 시작과 Signal 처리<br /><ul><li>Android init process가 실행한 자식프로세스들이 종료되는 경우의 처리를 위해 SIGCHLD신호를 초기화한다.</li></ul>< andr...
디렉토리 생성과  mount<br /><ul><li>루트파일시스템에 디렉토리를 생성하고 리눅스 가상파일 시스템을 마운트한다.</li></ul>< android/system/core/init/init.c ><br />mk...
Standard I/O 설정<br /><ul><li>안드로이드log메시지를 한곳에서 보기위해(logcat)Standard I/O를 모두 막는다.</li></ul>< android/system/core/init/init....
Init 프로세스의 로그메시지 설정<br /><ul><li>Init process의 로그메시지는 kmsg를 통해 출력한다.</li></ul>(dmesg유틸을 사용하여 확인가능)<br />< android/system/c...
init.rc파싱<br /><ul><li>Standard I/O설정을 변경하였으므로 그 후부터의 메시지를 출력하기위해kmsg를 이용한다. (dmsg유틸을 사용하여 확인가능)</li></ul>< android/system...
Emulator초기화<br /><ul><li>에뮬레이터 환경을 위한 QEMU장치 초기화</li></ul>< android/system/core/init/init.c ><br />int main(intargc, char ...
QEMU기반의 어플리케이션이다.
커널cmdline에 qumu=1의 값이 있다면 안드로이드 에뮬레이터라고 인식한다.
qemu mode에서는 property영역에 ro.kernel.<name>에 해당하는 값을 설정하고 이를 시스템에서 참조한다.
QEMU
PC를 위한 오픈 소스 에뮬레이터
프로세서를 에뮬레이션하는 이외에 네트워크, 비디오 하드웨어와 같은 필요한 모든 하위 시스템을 흉내낸다.
또한 (255개 CPU까지 지원하는) SMP와 같은 최신 개념, ARM이나 PowerPC와 같은 다른 프로세서 아키텍처도 에뮬레이션한다.</li></li></ul><li>Kernel의 cmdline의 내용을 전역변수에 ...
init.[H/W이름].rc파싱<br /><ul><li>하드웨어 명칭을 얻어와서 init.[H/W이름].rc파일의 내용을 action_list와 service_list 구조체에 각각 담는다.</li></ul>< andr...
.rc파일의 early-init섹션 수행<br /><ul><li>Linked list로 연결된 action_list구조체의 내용을 수행한다.</li></ul>< android/system/core/init/init.c ...
init.rc와 init.[H/W 이름].rc파일에서 early-early-init섹션에 해당하는 부분을 실행큐에 담는다.
Drain_action_queue();
실행큐(action_queue)에 저장된 명령어를 하나씩 수행한다.</li></li></ul><li>정적 디바이스 노드파일 생성(Cold Plug)<br /><ul><li>uevent발생을 위한 Socket생성
정적 디바이스 파일 생성 flow</li></ul>< init.c ><br />device_fd = device_init();<br />main()<br />< devices.c ><br />device_init()<b...
property 공간 초기화<br /><ul><li>property정보를 위한 공유메모리 공간을 생성한다</li></ul>(anonymous shared memory)<br />< android/system/core/i...
keychord open 및 serial 동작확인 <br /><ul><li>keychord입력을 받기위해/dev/keychord를 open한다.
Upcoming SlideShare
Loading in …5
×

Android+init+process

8,101 views

Published on

1 Comment
1 Like
Statistics
Notes
  • androidinitprocess
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
8,101
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
215
Comments
1
Likes
1
Embeds 0
No embeds

No notes for slide

Android+init+process

  1. 1. Android Init<br />ENM System 권홍재<br />
  2. 2. Kernel에서 Android init 시작<br /><ul><li>Android 커널 부팅이 완료된 후 루트파일 시스템의 “/init”을 찾아서 수행한다.
  3. 3. 안드로이드init은 루트에 위치하기때문에 반드시 커널 부팅옵션에서 “init=/init”옵션이 주어져야 한다.</li></ul>< kernel/init/main.c ><br />static intnoinlineinit_post(void)<br />{<br />...<br /> if (execute_command) {<br />run_init_process(execute_command);<br />printk(KERN_WARNING "Failed to execute %s. Attempting "<br /> "defaults...n", execute_command);<br /> } <br />run_init_process("/sbin/init");<br />run_init_process("/etc/init");<br />run_init_process("/bin/init");<br />run_init_process("/bin/sh");<br /> panic("No init found. Try passing init= option to kernel.");<br />}<br />
  4. 4. Init 프로세스의 시작과 Signal 처리<br /><ul><li>Android init process가 실행한 자식프로세스들이 종료되는 경우의 처리를 위해 SIGCHLD신호를 초기화한다.</li></ul>< android/system/core/init/init.c ><br />static void sigchld_handler(int s)<br />{<br /> write(signal_fd, &s, 1);<br />}<br />...<br />int main(intargc, char **argv)<br />{<br />...<br />structsigaction act;<br />act.sa_handler = sigchld_handler;<br />act.sa_flags = SA_NOCLDSTOP;<br />act.sa_mask = 0;<br />act.sa_restorer = NULL;<br />sigaction(SIGCHLD, &act, 0);<br />...<br />}<br />
  5. 5. 디렉토리 생성과 mount<br /><ul><li>루트파일시스템에 디렉토리를 생성하고 리눅스 가상파일 시스템을 마운트한다.</li></ul>< android/system/core/init/init.c ><br />mkdir("/dev", 0755);<br />mkdir("/proc", 0755);<br />mkdir("/sys", 0755);<br /> mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755");<br />mkdir("/dev/pts", 0755);<br />mkdir("/dev/socket", 0755);<br /> mount("devpts", "/dev/pts", "devpts", 0, NULL);<br /> mount("proc", "/proc", "proc", 0, NULL);<br /> mount("sysfs", "/sys", "sysfs", 0, NULL);<br />
  6. 6. Standard I/O 설정<br /><ul><li>안드로이드log메시지를 한곳에서 보기위해(logcat)Standard I/O를 모두 막는다.</li></ul>< android/system/core/init/init.c ><br />int main(intargc, char **argv)<br />{<br />...<br />open_devnull_stdio();<br />...<br />}<br />void open_devnull_stdio(void)<br />{<br />intfd;<br /> static const char *name = "/dev/__null__";<br /> if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {<br />fd = open(name, O_RDWR);<br /> unlink(name);<br /> if (fd >= 0) {<br /> dup2(fd, 0); dup2(fd, 1); dup2(fd, 2);<br /> if (fd > 2) {<br /> close(fd);<br /> }<br /> return;<br /> }<br /> }<br /> exit(1);<br />}<br />fd[0]<br />stdin<br />fd[0]<br />stdin<br />fd[1]<br />stdout<br />fd[1]<br />stdout<br />fd[2]<br />stderr<br />fd[2]<br />stderr<br />fd[3]<br />_null_<br />fd[3]<br />_null_<br />fd[…]<br />fd[…]<br />
  7. 7. Init 프로세스의 로그메시지 설정<br /><ul><li>Init process의 로그메시지는 kmsg를 통해 출력한다.</li></ul>(dmesg유틸을 사용하여 확인가능)<br />< android/system/core/init/init.c ><br />int main(intargc, char **argv)<br />{<br />...<br />log_init();<br />…<br />}<br />< android/system/core/init/util.c ><br />#define ERROR(x...) log_write(3, "<3>init: " x)<br />#define NOTICE(x...) log_write(5, "<5>init: " x)<br />#define INFO(x...) log_write(6, "<6>init: " x)<br />void log_init(void)<br />{<br /> static const char *name = "/dev/__kmsg__";<br /> if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {<br />log_fd = open(name, O_WRONLY);<br />…<br /> }<br />}<br />void log_write(int level, const char *fmt, ...)<br />{<br />…<br /> write(log_fd, buf, strlen(buf));<br />}<br />
  8. 8. init.rc파싱<br /><ul><li>Standard I/O설정을 변경하였으므로 그 후부터의 메시지를 출력하기위해kmsg를 이용한다. (dmsg유틸을 사용하여 확인가능)</li></ul>< android/system/core/init/init.c ><br />int main(intargc, char **argv)<br />{<br />...<br />parse_config_file(“init.rc”);<br />….<br />}<br /><ul><li>Init.rc구조</li></ul>< android/system/core/rootdir/init.rc ><br />on init<br />…<br />on boot<br />…<br />on property:ro.kernel.qemu=1<br />…<br />serviceservicemanager /system/bin/servicemanager<br />servicevold /system/bin/vold<br />servicenetd /system/bin/netd<br />…<br />action_list<br />service_list<br />
  9. 9. Emulator초기화<br /><ul><li>에뮬레이터 환경을 위한 QEMU장치 초기화</li></ul>< android/system/core/init/init.c ><br />int main(intargc, char **argv)<br />{<br />...<br />qemu_init();<br />….<br />}<br /><ul><li>Android Emulator
  10. 10. QEMU기반의 어플리케이션이다.
  11. 11. 커널cmdline에 qumu=1의 값이 있다면 안드로이드 에뮬레이터라고 인식한다.
  12. 12. qemu mode에서는 property영역에 ro.kernel.<name>에 해당하는 값을 설정하고 이를 시스템에서 참조한다.
  13. 13. QEMU
  14. 14. PC를 위한 오픈 소스 에뮬레이터
  15. 15. 프로세서를 에뮬레이션하는 이외에 네트워크, 비디오 하드웨어와 같은 필요한 모든 하위 시스템을 흉내낸다.
  16. 16. 또한 (255개 CPU까지 지원하는) SMP와 같은 최신 개념, ARM이나 PowerPC와 같은 다른 프로세서 아키텍처도 에뮬레이션한다.</li></li></ul><li>Kernel의 cmdline의 내용을 전역변수에 저장<br /><ul><li>사용될 /proc/cmdline(커널 실행옵션)의 옵션들을 전역번수에 저장한다.</li></ul>< android/system/core/init/init.c ><br />int main(intargc, char **argv)<br />{<br />...<br />import_kernel_cmdline(0);<br />….<br />}<br /><ul><li>/proc/cmdline내용</li></ul># cat /proc/cmdline<br />init=/init console=ttySAC1,115200 root=/dev/mtdblock2 rwrootfstype=yaffs2 ip=192.168.0.101:192.168.0.198:192.168.0.1:255.255.255.0::eth0:off ethaddr=00:40:5c:26:0a:5b;<br />
  17. 17. init.[H/W이름].rc파싱<br /><ul><li>하드웨어 명칭을 얻어와서 init.[H/W이름].rc파일의 내용을 action_list와 service_list 구조체에 각각 담는다.</li></ul>< android/system/core/init/init.c ><br />int main(intargc, char **argv)<br />{<br />...<br />get_hardware_name();<br />snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);<br />parse_config_file(tmp);<br />….<br />}<br /><ul><li>/proc/cpuinfo내용</li></ul>(Hardware명을소문자로 치환하여 rc파일을 찾는다.)<br /># cat /proc/cpuinfo<br />…<br />Hardware : ENMC100<br />…<br />
  18. 18. .rc파일의 early-init섹션 수행<br /><ul><li>Linked list로 연결된 action_list구조체의 내용을 수행한다.</li></ul>< android/system/core/init/init.c ><br />int main(intargc, char **argv)<br />{<br />...<br />action_for_each_trigger("early-init", action_add_queue_tail);<br />drain_action_queue(); <br />….<br />}<br /><ul><li>action_for_each_trigger("early-init", action_add_queue_tail);
  19. 19. init.rc와 init.[H/W 이름].rc파일에서 early-early-init섹션에 해당하는 부분을 실행큐에 담는다.
  20. 20. Drain_action_queue();
  21. 21. 실행큐(action_queue)에 저장된 명령어를 하나씩 수행한다.</li></li></ul><li>정적 디바이스 노드파일 생성(Cold Plug)<br /><ul><li>uevent발생을 위한 Socket생성
  22. 22. 정적 디바이스 파일 생성 flow</li></ul>< init.c ><br />device_fd = device_init();<br />main()<br />< devices.c ><br />device_init()<br />coldboot()<br />do_coldboot()<br />devperms구조체를 참조하여 <br />uevent강제발생<br />Hot Plug<br />handle_device_fd()<br />handle_device_event()<br />make_device()<br />
  23. 23. property 공간 초기화<br /><ul><li>property정보를 위한 공유메모리 공간을 생성한다</li></ul>(anonymous shared memory)<br />< android/system/core/init/init.c ><br />int main(intargc, char **argv)<br />{<br />...<br />property_init();<br />….<br />}<br />< android/system/core/init/init.c ><br />void property_init(void){<br />init_property_area();<br />load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);  /default.prop<br />}<br />
  24. 24. keychord open 및 serial 동작확인 <br /><ul><li>keychord입력을 받기위해/dev/keychord를 open한다.
  25. 25. serial 연결을 검사한다.</li></ul>< android/system/core/init/init.c ><br />int main(intargc, char **argv)<br />{<br />…<br />// only listen for keychords if ro.debuggable is true<br /> /* nothing to do if no services require keychords */<br />keychord_fd = open_keychord();<br />// check serial<br /> // e.g. console name  /dev/ttySAC1<br />fd = open(console_name, O_RDWR);<br /> if (fd >= 0)<br />have_console = 1;<br /> close(fd);<br />…<br />}<br /><ul><li>Keychord - 핸드폰에 있는 단축키와 조합키 와 같은 특수키와 조합 키를 지원하기 위한 구조</li></li></ul><li>LCD 부팅로그 출력<br /><ul><li>안드로이드 부팅로그를 LCD화면에 출력한다.</li></ul>< android/system/core/init/init.c ><br />int main(intargc, char **argv)<br />{<br />…<br /> if( load_565rle_image(INIT_IMAGE_FILE) ) {<br />fd = open("/dev/tty0", O_WRONLY);<br /> if (fd >= 0) {<br /> const char *msg;<br />msg = "n“<br /> "n" // console is 40 cols x 30 lines<br /> “ A N D R O I D ";<br /> write(fd, msg, strlen(msg));<br /> close(fd);<br /> }<br />…<br />}<br />
  26. 26. property 설정<br /><ul><li>property영역에 시스템 운용에 필요한 초기값을 설정한다.
  27. 27. import_kernel_cmdline에서 읽어온값 설정</li></ul>< android/system/core/init/init.c ><br />int main(intargc, char **argv)<br />{<br />…<br /> if (qemu[0])<br />import_kernel_cmdline(1); <br /> if (!strcmp(bootmode,"factory"))<br />property_set("ro.factorytest", "1");<br /> else if (!strcmp(bootmode,"factory2"))<br />property_set("ro.factorytest", "2");<br /> else<br />property_set("ro.factorytest", "0");<br />property_set("ro.serialno", serialno[0] ? serialno : "");<br />property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown");<br />property_set("ro.baseband", baseband[0] ? baseband : "unknown");<br />property_set("ro.carrier", carrier[0] ? carrier : "unknown");<br />property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown");<br />property_set("ro.hardware", hardware);<br />snprintf(tmp, PROP_VALUE_MAX, "%d", revision);<br />property_set("ro.revision", tmp);<br />…<br />}<br />
  28. 28. property 서버 시작<br /><ul><li>.property파일에서 내용을 로드하고 property 설정 관련서비스를 위한 socket을 생성한다.</li></ul>< android/system/core/init/init.c ><br />property_set_fd = start_property_service();<br />< android/system/core/init/property_service.c ><br />intstart_property_service(void){<br />intfd;<br />load_properties_from_file(PROP_PATH_SYSTEM_BUILD);  /system/build.prop<br />load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);  /system/default.prop<br />load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);  /data/local.prop<br />load_persistent_properties();  /data/property/persist.xxxx파일의 내용을 로드한다.<br />fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);<br /> if(fd < 0) return -1;<br />fcntl(fd, F_SETFD, FD_CLOEXEC);<br />fcntl(fd, F_SETFL, O_NONBLOCK);<br /> listen(fd, 8);<br /> return fd;<br />}<br />< android/system/core/init/util.c ><br />intcreate_socket(const char *name, int type, mode_t perm, uid_tuid, gid_tgid){<br />fd = socket(PF_UNIX, type, 0);<br />memset(&addr, 0 , sizeof(addr));<br />addr.sun_family = AF_UNIX;<br /> // addr.sun_path /dev/socket/property_service<br />snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s“, name);<br /> bind(fd, (structsockaddr *) &addr, sizeof (addr));<br /> return fd;<br />}<br />
  29. 29. SIGCHLD Signal 통신Socket 생성<br /><ul><li>SIGCHLD Signal발생시 통지하기위한Socket을 생성한다.</li></ul>< android/system/core/init/init.c ><br />static void sigchld_handler(int s)<br />{<br /> write(signal_fd, &s, 1);<br />}<br />…<br />int main(intargc, char **argv)<br />{<br />…<br /> /* create a signalling mechanism for the sigchld handler */<br /> if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) {<br />signal_fd = s[0];  쓰기전용 file descriptor<br />signal_recv_fd = s[1];  읽기전용 file descriptor<br />fcntl(s[0], F_SETFD, FD_CLOEXEC);<br />fcntl(s[0], F_SETFL, O_NONBLOCK);<br />fcntl(s[1], F_SETFD, FD_CLOEXEC);<br />fcntl(s[1], F_SETFL, O_NONBLOCK);<br /> }<br />…<br />}<br />
  30. 30. File Descriptor검사 및 boot섹션 수행<br /><ul><li>앞서 얻어온 file descriptor들이 올바른지 검사한다.
  31. 31. early-boot, boot섹션을 실행큐에 담고 수행한다.</li></ul>< android/system/core/init/init.c ><br />int main(intargc, char **argv)<br />{<br />…<br /> /* make sure we actually have all the pieces we need */<br /> if ((device_fd < 0) ||<br /> (property_set_fd < 0) ||<br /> (signal_recv_fd < 0)) {<br /> ERROR("init startup failuren");<br /> return 1;<br /> }<br /> /* execute all the boot actions to get us started */<br />action_for_each_trigger("early-boot", action_add_queue_tail);<br />action_for_each_trigger("boot", action_add_queue_tail);<br />drain_action_queue();<br />…<br />}<br />
  32. 32. on property에 지정된 service수행<br /><ul><li>property섹션을 실행큐에 담고 수행 해당 명령을 수행한다.
  33. 33. property를 설정했을때init.rc에 지정한 명령의수행을 위해 property_triggers를 enable시킨다.</li></ul>< android/system/core/init/init.c ><br />int main(intargc, char **argv)<br />{<br />…<br /> /* run all property triggers based on current state of the properties */<br />queue_all_property_triggers();<br />drain_action_queue();<br /> /* enable property triggers */ <br />property_triggers_enabled = 1; <br />…<br />}<br /><ul><li>현재 설정되어있는 property값이 init.rc의 값과 같다면 특정 명령을 수행시킨다.</li></ul>< android/system/core/rootdir/init.rc ><br />…<br />on property:persist.service.adb.enable=1<br /> start adbd<br />on property:persist.service.adb.enable=0<br /> stop adbd<br />…<br />
  34. 34. 감시할 이벤트 설정<br /><ul><li>앞서 얻어온 file descriptor들이 올바른지 검사한다.
  35. 35. early-boot, boot섹션을 실행큐에 담고 수행한다.</li></ul>< android/system/core/init/init.c ><br />int main(intargc, char **argv)<br />{<br />…<br />structpollfdufds[4];<br />…<br />ufds[0].fd = device_fd;<br />ufds[0].events = POLLIN;<br />ufds[1].fd = property_set_fd;<br />ufds[1].events = POLLIN;<br />ufds[2].fd = signal_recv_fd;<br />ufds[2].events = POLLIN;<br />fd_count = 3;<br /> if (keychord_fd > 0) {<br />ufds[3].fd = keychord_fd;<br />ufds[3].events = POLLIN;<br />fd_count++;<br /> } else {<br />ufds[3].events = 0;<br />ufds[3].revents = 0;<br /> } <br />…<br />}<br />
  36. 36. bootchart생성기능수행<br /><ul><li>INIT_BOOTCHART=true 환경변수를 설정할경우 수행되는 로직.
  37. 37. 안드로이드boot process 분석을위해 관련 데이터들을 수집한다.</li></ul>< android/system/core/init/init.c ><br />int main(intargc, char **argv)<br />{<br />…<br />i#f BOOTCHART<br />bootchart_count = bootchart_init();<br /> if (bootchart_count < 0) {<br /> ERROR("bootcharting init failuren");<br /> } else if (bootchart_count > 0) {<br /> NOTICE("bootcharting started (period=%d ms)n", bootchart_count*BOOTCHART_POLLING_MS);<br /> } else {<br /> NOTICE("bootcharting ignoredn");<br /> }<br />#endif<br />…<br /> for(;;) {<br />#if BOOTCHART<br /> if (bootchart_count > 0) {<br /> if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)<br /> timeout = BOOTCHART_POLLING_MS;<br /> if (bootchart_step() < 0 || --bootchart_count == 0) {<br />bootchart_finish();<br />bootchart_count = 0;<br /> }<br /> }<br />#endif<br />…<br /> }<br />…<br />}<br />
  38. 38. 이벤트 처리루프 수행<br /><ul><li>무한루프를 돌면서 해당하는 이벤트가 발생시 각각 처리한다.</li></ul>int main(intargc, char **argv)<br />{<br />…<br />for(;;) {<br />int nr, i, timeout = -1;<br /> for (i = 0; i < fd_count; i++)<br />ufds[i].revents = 0;<br />drain_action_queue();<br />restart_processes();<br /> if (process_needs_restart) {<br /> timeout = (process_needs_restart - gettime()) * 1000;<br /> if (timeout < 0)<br /> timeout = 0;<br /> }<br /> nr = poll(ufds, fd_count, timeout);<br /> if (nr <= 0)<br /> continue;<br />< android/system/core/init/init.c ><br /> if (ufds[2].revents == POLLIN) {<br /> /* we got a SIGCHLD - reap and restart as needed */<br /> read(signal_recv_fd, tmp, sizeof(tmp));<br /> while (!wait_for_one_process(0))<br /> ;<br /> continue;<br /> }<br /> if (ufds[0].revents == POLLIN)<br />handle_device_fd(device_fd);<br /> if (ufds[1].revents == POLLIN)<br />handle_property_set_fd(property_set_fd);<br /> if (ufds[3].revents == POLLIN)<br />handle_keychord(keychord_fd);<br /> }<br /> return 0;<br />}<br />
  39. 39. - 수고하셨습니다 -<br />

×