about init in android by andstudy

45
Init process in Android Created by Andstudy Andstudy Seminar 2009 08 22 김 연찬

Upload: iamhjoo-

Post on 24-Jun-2015

12.690 views

Category:

Documents


4 download

DESCRIPTION

안드로이드 init 프로세스 분석

TRANSCRIPT

Page 1: About Init In Android By Andstudy

Init process in Androidin Android

Created by Andstudy

Andstudy Seminar2009 08 22

김 연찬

Page 2: About Init In Android By Andstudy

Android Study

Android Study members

송형주 전형민 박지훈 황세희

이 백 전유진 김연찬 전승원

강명훈 임기영 박은병 이덕용

박은병 박주애 이덕용 구자관

2009 08 15

윤동렬 김신수 김태연

Study web page Spring note : http://andstudy.springnote.com/Android Pub: http://www.androidpub.com/devstudy_groupb

이 문서는 다음의 CCL (creative commons license) 을 따름니다.

http://creativecommons.org/licenses/by-nc-sa/2.0/kr/저작자표시-비영리-동일조건변경허락 2.0 대한민국

Page 3: About Init In Android By Andstudy

Change LOG

Change history changes editor

2009년 08월 22일 최초작성 김 연찬

2009년 09월 05일 1차 교정 (PDF 배포용으로 수정) 김 연찬

Page 4: About Init In Android By Andstudy

About Init.

Init Process 는 PID 가 1인 프로세스이고 부팅과정에서 커널이 생성하는 첫번째 프로세스이다.

그럼 Init Process는 언제 실행되는가?

start_kernel() -> rest_init() -> kernel_thread() -> kernel_init() -> init_post() 에서 "/init"을 수행

안드로이드 소스트리에서 Init process 코드는 어디에?

/system/core/init/init.c

이 문서에서 다루는 부분의 코드는 /system/core/init/ 에서 찾아 볼수 있다.Init.rc 의 경우는 /system/core/rootdir/init.rc 에 존재한다.

Page 5: About Init In Android By Andstudy

Android Init의 기능

SIGCHLD SIGCHLD Device 초Device 초SIGCHLD

signal

처리

SIGCHLD

signal

처리

RC 파일

내용처리

RC 파일

내용처리

Device 초

기화 &

관리

Device 초

기화 &

관리

Property

설정

Property

설정

Page 6: About Init In Android By Andstudy

xxxxxx

KernalKernalInit post()

InitInitmain

act.sa_handler = sigchld_handler;sigaction(SIGCHLD, &act, 0);act.sa_handler = sigchld_handler;sigaction(SIGCHLD, &act, 0); Sigchild handler()Sigchild handler() Zombi processZombi process

- 자식프로세스 처리를 위한 SIGCHLD SIGNAL handler등록- 자식프로세스 처리를 위한 SIGCHLD SIGNAL handler등록

Make Special purposeDevice node filesMake Special purposeDevice node files

mkdir("/dev", 0755); mkdir("/proc", 0755); mkdir("/sys", 0755);mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755")mkdir("/dev/pts", 0755); mkdir("/dev/socket", 0755);mount("devpts", "/dev/pts", "devpts", 0, NULL);

mkdir("/dev", 0755); mkdir("/proc", 0755); mkdir("/sys", 0755);mount("tmpfs", "/dev", "tmpfs", 0, "mode=0755")mkdir("/dev/pts", 0755); mkdir("/dev/socket", 0755);mount("devpts", "/dev/pts", "devpts", 0, NULL);

/

/dev

Socket pts

/proc /sys

tmpfs

Init Process (1)

xxxxxxmount("devpts", "/dev/pts", "devpts", 0, NULL); mount("proc", "/proc", "proc", 0, NULL); mount("sysfs", "/sys", "sysfs", 0, NULL);

mount("devpts", "/dev/pts", "devpts", 0, NULL); mount("proc", "/proc", "proc", 0, NULL); mount("sysfs", "/sys", "sysfs", 0, NULL);

Socket pts

Make Special purposeDevice node filesMake Special purposeDevice node files

open_devnull_stdio();open_devnull_stdio();Fd[0]

Fd[1]

Fd[2]

Fd[3]

Fd[…]

stdin

stdout

stderr

__null__

Fd[0]

Fd[1]

Fd[2]

Fd[3]

Fd[…]

stdin

stdout

stderr

__null__

Make __kmsg__ device file log massage will be written to “/dev/__kmsg__”&set it as “FD_CLOEXEC”

Make __kmsg__ device file log massage will be written to “/dev/__kmsg__”&set it as “FD_CLOEXEC”

log_init();log_init();

mknode(“/dev/__kmsg__”);Log_fd = open(“/dev/__kmsg__”);Fcntl(log_fd, F_SETFD, FD_CLOEXEC);

mknode(“/dev/__kmsg__”);Log_fd = open(“/dev/__kmsg__”);Fcntl(log_fd, F_SETFD, FD_CLOEXEC);

Fd[0]Fd[1]

Fd[3]Fd[2]

stdinstdout

a.txtstderr

parent

Fd[0]Fd[0]Fd[1]Fd[1]Fd[2]Fd[2]

ChildChild

Fd[3]Fd[3]

Ex) FD_CLOEXEC

Page 7: About Init In Android By Andstudy

qemu_init();qemu_init();Qemu 에서 사용하는 메모리영역 초기화Qemu 에서 사용하는 메모리영역 초기화

Init.rc 파일을 Parsing 하여Service_list 와 Action_list를 구성한다.

Init.rc 파일을 Parsing 하여Service_list 와 Action_list를 구성한다. parse_config_file("/init.rc");parse_config_file("/init.rc");

Init Process (2)

Service_listService_list struct servicestruct service

Action_listAction_list Action_listAction_list Action_listAction_list Action_listAction_list

struct servicestruct service

Listnode slistChar *nameChar *classnameInt nargsStruct Action onrestart

Listnode slistChar *nameChar *classnameInt nargsStruct Action onrestart

Slist“console ““default”0“onrestart”

Slist“console ““default”0“onrestart”

struct servicestruct service

Slist“Servicemanager”“default”0“onrestart”

Slist“Servicemanager”“default”0“onrestart”

Listnode alistChar *nameStruct listnode commandStruct command *curtent

Listnode alistChar *nameStruct listnode commandStruct command *curtent

listnode“init”Listnode command

listnode“init”Listnode command

listnode“boot”Listnode command

listnode“boot”Listnode command

QEMU란?

커널 커맨드 라인(/proc/cmdline )을 읽어서 필요한 내용을전역 변수에 저장한다

커널 커맨드 라인(/proc/cmdline )을 읽어서 필요한 내용을전역 변수에 저장한다

get_hardware_name();snprintf(tmp, sizeof(tmp),"/init.%s.rc",hardware)parse_config_file(tmp);

get_hardware_name();snprintf(tmp, sizeof(tmp),"/init.%s.rc",hardware)parse_config_file(tmp);

커널로 부터 H/W 정보를 얻어와서 “init.H/W_name.rc 파일을 Parsing 하여 Service_list와 Action_list 에 추가한다.

커널로 부터 H/W 정보를 얻어와서 “init.H/W_name.rc 파일을 Parsing 하여 Service_list와 Action_list 에 추가한다.

import_kernel_cmdline(0);import_kernel_cmdline(0);

Action list 에서 “early-init”이라는 name의 노드를Action_queue에 삽입하고, Action_queue에 있는 노드를 실행 시킨다.

Action list 에서 “early-init”이라는 name의 노드를Action_queue에 삽입하고, Action_queue에 있는 노드를 실행 시킨다.

action_for_each_trigger("early-init“,action_add_queue_tail);drain_action_queue();

action_for_each_trigger("early-init“,action_add_queue_tail);drain_action_queue();

Argument is ‘0’ : physical H/WArgument is ‘1’ : QEMU emulatorArgument is ‘0’ : physical H/WArgument is ‘1’ : QEMU emulator

Init.rc 와 init.goldfish.rc 에 “early-init” 의name의 항목이 없다. 따라서 여기서 하는일은 없다.

Init.rc 와 init.goldfish.rc 에 “early-init” 의name의 항목이 없다. 따라서 여기서 하는일은 없다.

default h/w configuration is goldfish.->/system/core/rootdir/etc/init.goldfish.rcdefault h/w configuration is goldfish.->/system/core/rootdir/etc/init.goldfish.rc

Page 8: About Init In Android By Andstudy

property_init();property_init();ashmem_create_region(/dev/ashmem) 을 사용하여 공유메모리 공간을 생성한다.

ashmem_create_region(/dev/ashmem) 을 사용하여 공유메모리 공간을 생성한다.

keychords 확인keychords 확인 debuggable = property_get("ro.debuggable"); if (debuggable && !strcmp(debuggable, "1")) debuggable = property_get("ro.debuggable"); if (debuggable && !strcmp(debuggable, "1"))

/dev 이하에 장치 파일을uevent 파일을 이용하여 생성하고 접근권한을 설정한다.

/dev 이하에 장치 파일을uevent 파일을 이용하여 생성하고 접근권한을 설정한다.

device_fd = device_init();device_fd = device_init();

Init Process (3)

/dev 이하에 장치 파일을 uevent 파일을이용하여 생성하고 접근권한을 설정한다./dev 이하에 장치 파일을 uevent 파일을이용하여 생성하고 접근권한을 설정한다.

Property_area memory map

keychords 확인Consols 확인keychords 확인Consols 확인

if( load_565rle_image(INIT_IMAGE_FILE) ) {fd = open("/dev/tty0", O_WRONLY); if (fd >= 0) {

const char *msg; msg = "\n ANDROID“;write(fd, msg, strlen(msg));close(fd); }

if( load_565rle_image(INIT_IMAGE_FILE) ) {fd = open("/dev/tty0", O_WRONLY); if (fd >= 0) {

const char *msg; msg = "\n ANDROID“;write(fd, msg, strlen(msg));close(fd); }

부팅 이미지 출력부팅 이미지 출력

debuggable = property_get("ro.debuggable"); if (debuggable && !strcmp(debuggable, "1"))

keychord_fd = open_keychord(); fd = open(console_name, O_RDWR); if (fd >= 0)

have_console = 1; close(fd);

debuggable = property_get("ro.debuggable"); if (debuggable && !strcmp(debuggable, "1"))

keychord_fd = open_keychord(); fd = open(console_name, O_RDWR); if (fd >= 0)

have_console = 1; close(fd);

Qemu 설정일 때, property에'ro.kernel'이라는 접두어를 붙여 property를 set 한다.

Qemu 설정일 때, property에'ro.kernel'이라는 접두어를 붙여 property를 set 한다.

if (qemu[0]) import_kernel_cmdline(1);

if (qemu[0]) import_kernel_cmdline(1);

로고 파일이 있으면 로고를 출력하고, 로고 파일이 없거나 로딩에 실패하면 tty0에 “ANDROID” 문자열을 출력한다.

로고 파일이 있으면 로고를 출력하고, 로고 파일이 없거나 로딩에 실패하면 tty0에 “ANDROID” 문자열을 출력한다.

Page 9: About Init In Android By Andstudy

action_for_each_trigger("init“,action_add_queue_tail);drain_action_queue();

action_for_each_trigger("init“,action_add_queue_tail);drain_action_queue();

Action list 에서 “init”이라는name의 노드를 Action_queue에삽입하고, Action_queue에 있는

Action list 에서 “init”이라는name의 노드를 Action_queue에삽입하고, Action_queue에 있는

추가 Property 설정추가 Property 설정

if (!strcmp(bootmode,"factory")) property_set("ro.factorytest", "1");

else if (!strcmp(bootmode,"factory2")) property_set("ro.factorytest", "2");

else property_set("ro.factorytest", "0"); property_set("ro.serialno", serialno[0] ? serialno : ""); property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown"); property_set("ro.baseband", baseband[0] ? baseband : "unknown"); property_set("ro.carrier", carrier[0] ? carrier : "unknown"); property_set("ro.bootloader", bootloader[0] ? bootloader: "unknown"); property_set("ro.hardware", hardware); snprintf(tmp, PROP_VALUE_MAX, "%d", revision); property_set("ro.revision", tmp);

if (!strcmp(bootmode,"factory")) property_set("ro.factorytest", "1");

else if (!strcmp(bootmode,"factory2")) property_set("ro.factorytest", "2");

else property_set("ro.factorytest", "0"); property_set("ro.serialno", serialno[0] ? serialno : ""); property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown"); property_set("ro.baseband", baseband[0] ? baseband : "unknown"); property_set("ro.carrier", carrier[0] ? carrier : "unknown"); property_set("ro.bootloader", bootloader[0] ? bootloader: "unknown"); property_set("ro.hardware", hardware); snprintf(tmp, PROP_VALUE_MAX, "%d", revision); property_set("ro.revision", tmp);

Init Process (4)

Ro.bootmodeRo.bootmode

Bootmode[0]Bootmode[0]

Ro.hardwareRo.hardware

goldfishgoldfish

Ro.revisionRo.revision

xxxxxxxxxxxxxx

namenameserialserial

valuevalue

Struct Property infoStruct Property info

/drain_action_queue();drain_action_queue();삽입하고, Action_queue에 있는

노드를 실행 시킨다.create basic FileSystem structure

삽입하고, Action_queue에 있는노드를 실행 시킨다.create basic FileSystem structure

기타 property 파일 및/data/property 경로에 저장된persistent property들을 시스템property 영역에 로드 한다

기타 property 파일 및/data/property 경로에 저장된persistent property들을 시스템property 영역에 로드 한다

if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) signal_fd = s[0]; signal_recv_fd = s[1]; fcntl(s[0], F_SETFD, FD_CLOEXEC); fcntl(s[0], F_SETFL, O_NONBLOCK); fcntl(s[1], F_SETFD, FD_CLOEXEC); fcntl(s[1], F_SETFL, O_NONBLOCK); }

if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) signal_fd = s[0]; signal_recv_fd = s[1]; fcntl(s[0], F_SETFD, FD_CLOEXEC); fcntl(s[0], F_SETFL, O_NONBLOCK); fcntl(s[1], F_SETFD, FD_CLOEXEC); fcntl(s[1], F_SETFL, O_NONBLOCK); }

시그널 처리를 위한 소켓 생성시그널 처리를 위한 소켓 생성

property_set_fd = start_property_service();property_set_fd = start_property_service();

부팅에 필요한 FD 확인부팅에 필요한 FD 확인if ((device_fd < 0) || (property_set_fd < 0) || (signal_recv_fd < 0)) { ERROR("init startup failure\n"); return 1; }

if ((device_fd < 0) || (property_set_fd < 0) || (signal_recv_fd < 0)) { ERROR("init startup failure\n"); return 1; }

default 로 생성한 이미지의 /data/property 에는 4개의 로케일 셋팅 정보 파일이 있다.persist.sys.country persist.sys.languagepersist.sys.localevar persist.sys.timezone

default 로 생성한 이미지의 /data/property 에는 4개의 로케일 셋팅 정보 파일이 있다.persist.sys.country persist.sys.languagepersist.sys.localevar persist.sys.timezone

/dev /proc /sys /sdcard /system /data /cache

Init이 관리하는 FD

Page 10: About Init In Android By Andstudy

queue_all_property_triggers(); drain_action_queue(); queue_all_property_triggers(); drain_action_queue();

action_list 에 있는 노드중에node.name 이 "property" 인 노드들을 acttion queue 에 추가한다.Action_queue에 있는 노드를 실행 시킨다.

action_list 에 있는 노드중에node.name 이 "property" 인 노드들을 acttion queue 에 추가한다.Action_queue에 있는 노드를 실행 시킨다.

init 프로세스가 poll함수로 감시할 파일디스크립터 설정init 프로세스가 poll함수로 감시할 파일디스크립터 설정

ufds[0].fd = device_fd; ufds[0].events = POLLIN;ufds[1].fd = property_set_fd;

ufds[0].fd = device_fd; ufds[0].events = POLLIN;ufds[1].fd = property_set_fd;

Action list 에서 “early-boot”와“boot”이라는 name의 노드를Action_queue에 삽입하고, Action_queue에 있는 노드를실행 시킨다.

Action list 에서 “early-boot”와“boot”이라는 name의 노드를Action_queue에 삽입하고, Action_queue에 있는 노드를실행 시킨다.

action_for_each_trigger("early-boot", action_add_queue_tail);

action_for_each_trigger("boot", action_add_queue_tail);

drain_action_queue();

action_for_each_trigger("early-boot", action_add_queue_tail);

action_for_each_trigger("boot", action_add_queue_tail);

drain_action_queue();

Init Process (5)

- network init- System Server and daemons 의 Permissions 설정- 각 APP group 메모리 사용 설정

- network init- System Server and daemons 의 Permissions 설정- 각 APP group 메모리 사용 설정

Action_listAction_list Action_listAction_list Action_listAction_list

Listnode alistChar *nameStruct listnode

commandStruct command

*curtent

Listnode alistChar *nameStruct listnode

commandStruct command

*curtent

listnode“property”Listnode

command

listnode“property”Listnode

command

[0] fd=device_fd event = POLLINUfds[ ]

For(;;;)drain_action_queue(); restart_processes();

For(;;;)drain_action_queue(); restart_processes();

무한 루프 문에서 action queue에 실행할 action이 있으면 실행하고 재시작이 필요한 프로세스가 있으면 재시작해준다. ufds 를 감시하고POLLIN 이 발생하면 해당 핸들러를 통해 처리 한다.

무한 루프 문에서 action queue에 실행할 action이 있으면 실행하고 재시작이 필요한 프로세스가 있으면 재시작해준다. ufds 를 감시하고POLLIN 이 발생하면 해당 핸들러를 통해 처리 한다.

ufds[1].fd = property_set_fd; ufds[1].events = POLLIN; ufds[2].fd = signal_recv_fd; ufds[2].events = POLLIN;ufds[3].fd = keychord_fd; ufds[3].events = POLLIN;

ufds[1].fd = property_set_fd; ufds[1].events = POLLIN; ufds[2].fd = signal_recv_fd; ufds[2].events = POLLIN;ufds[3].fd = keychord_fd; ufds[3].events = POLLIN;

해당 fd의 POLLIN 에 따라 4가지 핸들러를 호출한다.해당 fd의 POLLIN 에 따라 4가지 핸들러를 호출한다.

while (!wait_for_one_process(0))handle_device_fd(device_fd);handle_property_set_fd(property_set_fd);handle_keychord(keychord_fd);

while (!wait_for_one_process(0))handle_device_fd(device_fd);handle_property_set_fd(property_set_fd);handle_keychord(keychord_fd);

Init [1] fd=property_set_fd event = POLLIN

[2] fd=signal_recv_fd event = POLLIN

[3] fd=keychord_fd event = POLLIN

Page 11: About Init In Android By Andstudy

Init.c 분석 (1)

• File descriptor, Signal 구조체, Polling 을 위한 구조체 등

• int device_fd = -1; struct sigaction act; struct pollfd ufds[4];Init이 사용할 자료구조 선언

• 자식프로세스 처리를 위한 SIGCHLD SIGNAL handler등록SIGCHLD Handler등록

• /dev, /proc, /sys 디렉토리를 각각 생성

• tmpfs, devpts, proc, sysfs 마운트디렉토리를 생성 및 마운트

• tmpfs, devpts, proc, sysfs 마운트

• stdin, stdout, stderr File descriptor 를 문자 디바이스 파일

/dev/__null__ 의 FD 로 연결한다.open_devnull_stdio();

• /dev/__kmsg__ 디바이스 파일을 생성하고, 파일 디스크립터

를 log_fd에 저장log_init();

• /dev/__kmsg__에 log 내용을 기록INFO("reading config file\n");

Page 12: About Init In Android By Andstudy

SIGCHILD SIGNAL

SIGCHILD Signal- 자식 프로세스가 멈추거나 종료하거나 추적당하는 경우 부모프로세스가 받는 시그널

Init process 는왜 SIGCHILD 시그널을사용할까?- 리눅스에서 자식프로세스 보다 부모 프로세스가 먼저 죽는다면, 자식프로세

스의 부모를 init process로 만들어준다. 그래서 고아 프로세스가 죽을 때 처리해야 하는 일을 init process가 대신하게된다. 따라서 init process는SIGCHILD 해야 하는 일을 init process가 대신하게된다. 따라서 init process는SIGCHILD Signal 를 처리 해야만 한다.- init process 의 자식프로세스 중에 프로세스가 종료하고 재 시작 해야 하는프로세스가 있다면, 재 시작 관련 설정을 해줘야 한다. (ex. Restart 옵션으로 시작된 Service)

SA_NOCLDSTOP flag: 만약 SIGCHLD의 시그널 핸들러일 경우 자식 프로세스의 상태가 stop일 경우는 SIGCHLD 시그널이 발생 안됨.

Page 13: About Init In Android By Andstudy

디렉토리를 생성 및 마운트

/

/dev

[tmpfs]

/pts /socket

/proc

[proc]

/SYS

[sysfs]

[devpts]

File System 설명

Tmpfs tmpfs는 램파일시스템의 일종(주로 성능 향상 목적)

Devpts devpts는 가상 터미널을 위한 파일시스템

Proc Proc fs는 커널메모리에서 돌아가는 일종의 가상 파일시스템

Sysfs sysfs 파일 시스템은 proc, devfs, devpts 파일 시스템을하나로 통합한 파일 시스템 (Linux Kernel 2.6 에서 도입)

Page 14: About Init In Android By Andstudy

open_devnull_stdio()

static const char *name = "/dev/__null__";if (mknod(name, S_IFCHR | 0600, (1 << 8) | 3) == 0) {

fd = open(name, O_RDWR);unlink(name);if (fd >= 0) {dup2(fd, 0); dup2(fd, 1); dup2(fd, 2);if (fd > 2) {

close(fd); } 이후로는 stdio 가 null dev로 설정되어 init process가 어떠한 메시지

주번호 1 부번호 3주번호 1 부번호 3

이후로는 stdio 가 null dev로 설정되어 init process가 어떠한 메시지를 stdio로 보내더라도 null dev로 전달되어 stdio 불가능해진다.

Fd[0]

Fd[1]

Fd[2]

Fd[3]

Fd[…]

stdin

stdout

stderr

__null__

Fd[0]

Fd[1]

Fd[2]

Fd[3]

Fd[…]

stdin

stdout

stderr

__null__

Page 15: About Init In Android By Andstudy

log_init()

void log_init(void)static const char *name = "/dev/__kmsg__";

if (mknod(name, S_IFCHR | 0600, (1 << 8) | 11) == 0) {log_fd = open(name, O_WRONLY);

fcntl(log_fd, F_SETFD, FD_CLOEXEC);unlink(name);

/dev/__kmsg__ 디바이스 파일을 생성하고, 파일 디스크립터를 log_fd에 저장

주번호 1 부번호 11주번호 1 부번호 11

FD_CLOEXEC fd의 close-on-exec 플래그를 arg의 FD_CLOEXEC FD_CLOEXEC fd의 close-on-exec 플래그를 arg의 FD_CLOEXEC 비트에 의해 지정된 값으로 설정한다.

close-on-exec 보통 프로세스에서 exec를 시켜서 새로운 프로세스를 실행시키면새로운 프로세스는 기존의 프로세스의 이미지를 덮어쓰게 된다. 그러면서 기존 프로세스가 열었던 파일 지정자를 그대로 넘겨주게된다. 그러나 기존 프로세스가 열었던 파일 디스크립터의 close-on-exec가 set됐을 경우 해당 파일은 새로운 프로세스로는 상속이되지 않는다.

Init 에서 close-on-exec 의 의미

/dev/__kmsg__는 init이 unlink를 했기 때문에 파일의 데이터는 남아있지만 접근할 이름이 없어졌다. 그리고close-on-exec를 set 함으로써 fork를 통해서도 파일 디스크립터는 상속이 되지 않는다. 따라서 /dev/__kmsg__는Init process 만 접근 가능하다.

Page 16: About Init In Android By Andstudy

close-on-exec flag

close-on-exec = unSET close-on-exec = SET

Parent 가 “a.txt”를 open() 후에 Fork()를이용하여 child를 생성할 때 fd 값의 차이.

Fd[0]

Fd[1]

stdin

stdoutparent

Fd[0]

Fd[1]

stdin

stdoutparent

Fd[1]

Fd[3]

Fd[2]

stdout

a.txt

stderr

Fd[0]Fd[0]

Fd[1]Fd[1]

Fd[3]Fd[3]

Fd[2]Fd[2]

ChildChild

Fd[1]

Fd[3]

Fd[2]

stdout

a.txt

stderr

Fd[0]Fd[0]

Fd[1]Fd[1]

Fd[2]Fd[2]

ChildChild

Fd[3]Fd[3]

Page 17: About Init In Android By Andstudy

Init.c 분석 (2)

• init.rc 파일을 파싱해서 각 action, service 섹션별로 연

결 리스트를 생성한다parse_config_file("/init.rc");

• 안드로이드의 에뮬레이터로 사용되는 QEMU와 관련된

접근 권한 관련 변수 초기화qemu_init();

• 커널 커맨드 라인을 읽어서 필요한 내용을 전역 변수에• 커널 커맨드 라인을 읽어서 필요한 내용을 전역 변수에

저장한다. import_kernel_cmdline(0);

• 커널로부터 CPU정보를 읽어와 hardware와 revision 정

보를저장get_hardware_name();

• hardware에 해당하는 init.rc 파일을 추가적으로 파싱

• snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);parse_config_file(tmp);

Page 18: About Init In Android By Andstudy

parse_config_file("/init.rc“)INIT.RC 내용 (/system/core/rootdir/init.rc)

Init.rc 파일을 Parsing 하여 Service_list 와 Action_list를 구성한다.

RC file ? [runtime configuration files] runtime시에 환경설정을 할 수 있도록 설정내용을 정의한 파일

on init [환경 설정]

- 글로벌 변수 초기화- mount point 생성 /sdcard, /system, /data, /cache-MTD 파티션 마운드 (기본적으로 yaffs2 사용)- create basic filesystem structure

on boot[boot action 정의]

- network init- System Server and daemons 의 Permissions 설정- 각 APP group 메모리 사용 설정

class_start default[서비스 시작]

- service 정의 형식- service <name> <pathname> [ <argument> ]*<option><option>

Service_listService_list struct servicestruct service

Action_listAction_list Action_listAction_list Action_listAction_list Action_listAction_list

struct servicestruct service

Listnode slistChar *nameChar *classnameInt nargsStuct Action onrestart

Listnode slistChar *nameChar *classnameInt nargsStuct Action onrestart

Slist“console ““default”0“onrestart”

Slist“console ““default”0“onrestart”

struct servicestruct service

Slist“Servicemanager”“default”0“onrestart”

Slist“Servicemanager”“default”0“onrestart”

Listnode alistChar *nameStruct listnode commandStruct command *curtent

Listnode alistChar *nameStruct listnode commandStruct command *curtent

listnode“init”Listnode command

listnode“init”Listnode command

listnode“boot”Listnode command

listnode“boot”Listnode command

CMD CMDCMD

CMD CMDCMD

Page 19: About Init In Android By Andstudy

APP group & 메모리 설정

APP group ADJvalue

Define the memory thresholds [4k pages ]

FOREGROUND_APP 0 1536 [6M] 전면에 있는 프로그램

VISIBLE_APP 1 2048 [8M] 화면에 보이지만 실행되지 않는APP

SECONDARY_SERVER 2 4096 [16M] Service Demon

HOME_APP 4 4096 [16M] 시작화면에 등록되는 APPHOME_APP 4 4096 [16M] 시작화면에 등록되는 APP

HIDDEN_APP_MIN 7 5120 [20M] 최소화 시킨 APP

CONTENT_PROVIDER 14 5632 [22M] CONTENT_PROVIDER

EMPTY_APP 15 6144 [24M]

About ADJ Value ?- Define the oom_adj values for the classes of processes that can be killed by the kernel- OOM Killer 가 동작해야 할때 계산되는 score 값에 영향을 미치는 값- 숫자가 높을 수록 OOM killer에 의해 죽을 가능성이 높다. - OOM_killer에 절대 죽지 않는 ADJ value 는 -17 이다. (ex init process)

Page 20: About Init In Android By Andstudy

Service Start [service 정의 형식]service <name> <pathname> [ <argument> ]*<option><option>

[code]service servicemanager /system/bin/servicemanager

user systemcriticalonrestart restart zygoteonrestart restart zygoteonrestart restart media

- servicemanager 는 /system/bin/servicemanager 경로에 존재- critcal 옵션 [ 4분 안에 4번의 오류가 발생 한다면 reboot 하겠다는 안드로이드의 시스템 운영정책]- onrestart 옵션 -> servicemanager 가 재시작되면 zygoto & media 도 재시작해라 라는 의미

-ini.rc 에서 시작하는 서비스 리스트Console adbd vold servicemanager ril-daemon zygote mediabootsound dbus hcid hfag hsag installd flash_recovery

※ Init.rc 에 대한 보다 많은 정보는 /system/core/init/readme.txt 문서 참조

Page 21: About Init In Android By Andstudy

qemu_init()

Func 기능 : qemu_perms 영역을 memset() 을 이용하여 초기화 한다.

What is QEMU & Goldfish?

Google은 app 개발자를 위해 SDK 배포시 emulator 를 포함시켰고, 이emulator 에서 동작하도록 하기위한 가상의 device configuration을goldfish 라 합니다. 그리고 이 emulator 를 QEMU라 합니다.

Applications

APP Framework

Android Run- Time

Libraries

Linux Kernel

Emulator or Hardware

Network

QEMUQEMU

ARM coreSimulatorARM coreSimulator

GoldfishHardware Simulator

GoldfishHardware Simulator

Page 22: About Init In Android By Andstudy

import_kernel_cmdline(0)

커널 커맨드 라인(/proc/cmdline )을 읽어서 필요한 내용을 전역 변수에 저장한다

“0”을 인자로 넘길 경우는 실제 타겟을 위한 몇몇 커맨드 라인의 내용이 init 프로세스의 전역변수에 저장

“1”을 인자로 넘길 경우는 QEMU 에뮬레이터를 위해 모든 커맨드 라인의 내용을 "ro.kernel" 접두어를 붙여서 property 값을 set한다.(unix domain socket 이용)socket 이용)

Page 23: About Init In Android By Andstudy

Init.H/W_name.rc 파싱

커널(proc 파일시스템)로부터 CPU정보를 읽어와 hardware와 revision 정보를 전역변수에 저장하고 이를 이용하여 hardware 관련 rc 파일을 추가적으로 파싱한다. 현재는default로 hardware가 goldfish로 되어 있기 때문에 init.goldfish.rc 파일이 파싱 된다.

" /system/core/rootdir/etc/init.goldfish.rc”

[code]get_hardware_name();snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);parse_config_file(tmp);

Init.rc 파일을 파싱해서 만들어놓은 Service_list 와 Action_list 에 해당 항목이 있다면 추Init.rc 파일을 파싱해서 만들어놓은 Service_list 와 Action_list 에 해당 항목이 있다면 추가한다.

Service_listService_list struct servicestruct service

Action_listAction_list Action_listAction_list Action_listAction_list Action_listAction_list

struct servicestruct service

Listnode slistChar *nameChar *classnameInt nargsSteuct Action onrestart

Listnode slistChar *nameChar *classnameInt nargsSteuct Action onrestart

Slist“console ““default”0“onrestart”

Slist“console ““default”0“onrestart”

struct servicestruct service

Slist“Servicemanager”“default”0“onrestart”

Slist“Servicemanager”“default”0“onrestart”

Listnode alistChar *nameStruct listnode commandStruct command *curtent

Listnode alistChar *nameStruct listnode commandStruct command *curtent

listnode“init”Listnode command

listnode“init”Listnode command

listnode“boot”Listnode command

listnode“boot”Listnode command

Action_listAction_list

listnode“xxx”Listnode command

listnode“xxx”Listnode command

CMD CMDCMD

CMD CMDCMD

CMD

CMD

CMD CMD

Page 24: About Init In Android By Andstudy

Init 분석 (2,3)

• action리스트에서 name이 “early-init”인 노드를 ACTION queue에 추

가한다.action_for_each_trigger("early-in

it“,action_add_queue_tail);

• ACTION queue에 저장된 커맨드를 순차적으로 실행한다.

drain_action_queue();

•uevent 파일들에 'add' 명령을 write해서 디바이스 추가 이벤트를 발생

시키고 이렇게 발생된 이벤트는 uevent 소켓을 통해 수신해서 파싱

• uevent메시지를 수신하기 위해 사용한 소켓을 리턴함.device_fd = device_init();

•system property 영역을 생성하고, default property들을 저장함

property_init();

Page 25: About Init In Android By Andstudy

Action_queue에 실행할 노드 추가 & 실행

action리스트에서 name이 “early-init”인 노드를 ACTION queue에 추가한다.

Action-list에 name=“early-init”인 노드가 없기 때문에 아무 일도 하지 않는다.(init.rc 와 init.goldfish.rc 에 “early-init” 항목이 없다)

init 프로세스에서는 다음과 같은 4개의 boot action을 정의 할수 있다.

early-initinit early-boot,

정의된 action 없음create basic filesystem structure정의된 action 없음

action_for_each_trigger("early-init“,action_add_queue_tail)action_for_each_trigger("early-init“,action_add_queue_tail)

early-boot,Boot

정의된 action 없음System Server and daemons 의 Permissions 설정

early-init, early-boot, 추후 시스템의 확장을 고려해서 설계한 것이라 추측된다.

action queue에 있는 내용(커맨드)를 실행한다.

“early-init”에서 추가한 내용이 없을것 이므로 여기서 실행되는 내용도 없을 것이다.

drain_action_queue()drain_action_queue()

Page 26: About Init In Android By Andstudy

device_init()uevent 메시지용 소켓 오픈 하고 3번의 coldboot() 함수를 호출한다.

[code]Fd = open_uevent_socket(); coldboot(fd, "/sys/class");coldboot(fd, "/sys/block");coldboot(fd, "/sys/devices");

cold boot는 무슨일을 하나?

/dev/ 이하 파일들을 init 프로세스에서 생성하는데, 어떠한 디바이스들이 있는지를/dev/ 이하 파일들을 init 프로세스에서 생성하는데, 어떠한 디바이스들이 있는지를확인하기 위해서 netlink socket (device_fd) 를 생성하고, 디바이스 드라이버와uevent 메세지를 주고 받는다. 과정은 디렉토리 "/sys/class" , "/sys/block", "/sys/devices" 를 각각 검색하여, uevent 파일을 열어서 "add" 를 write 한 후, 응답하는 uevent 메세지를 수신하고, 해당 디바이스의 노드 생성 및 접근 권한을 설정한다.

수신된 uevent구조체의 subsysem과path 필드의 정보를 참조하여 /dev 디렉토리 이하의 장치 관련 서브 디렉토리 및장치 파일을 생성 혹은 삭제하고 접근 권한을 설정한다.

event가 firmware subsystem 관련이고, uevent->acttion 이 'ADD'이면 fork()를통해 새로운 프로세스를 만들고 irmware관련 uevent는 새로운 자식 프로세스에서 처리한다. (process_firmware_event(uevent);)

Page 27: About Init In Android By Andstudy

uevent

- LDM(Linux Device Model)에서는 커널 이벤트를 사용자공간으로전달하기 위한 인터페이스를 제공하고 있다. 이것이 바로 uevent다.- uevent는 커널에서 유저 프로세스에게 디바이스 관련 메시지를 전달하는 netlink socket의 한 종류이다.

netlink socket ?netlink socket은 커널과 유저 영역 사이의 통신(IPC) 방법이다

<커널> <-------( netlink socket ) ------> <유저프로세스>

netlink socket 장점

-netlink의 경우는 커널 모듈로 추가 가능.- 다른 IPC에 반해, netlink는 여러 프로세스 그룹으로 멀티캐스트 전송이 가능- 시스템콜과 ioctl의 경우, 유저 애플리케이션에 의해 시작 가능 , 이에 반해netlink는 커널에 의해서 시작 가능

Page 28: About Init In Android By Andstudy

Unix domain socket

Unix domain socket socket

Unix Domain 소켓은 같이 동일 PC내의프로세스끼리 통신을 하기 위해서 사용

네트워크 프로그래밍에서 네트워크로 연결된 서로 다른 PC간의 통신을 위해 사용

파일명을 가지고 바인딩 ip주소와 포트로 바인딩

sock = socket( PF_FILE, SOCK_DGRAM, 0); sock = socket( PF_INET, SOCK_DGRAM, 0);

Unix domain 사용 예struct sockaddr_un server_addr;struct sockaddr_un server_addr;memset( &server_addr, 0, sizeof( server_addr));server_addr.sun_family = AF_UNIX;strcpy( server_addr.sun_path, "/tmp/test_server.dat");

Page 29: About Init In Android By Andstudy

property_init()

• ashmem_create_region(/dev/ashmem) 을 사용하여 공유 메모리 공간을 생성한다. (anonymous shared memory)

• ashmem_create_region(/dev/ashmem) 을 사용하여 공유 메모리 공간을 생성한다. (anonymous shared memory)

Page 30: About Init In Android By Andstudy

Init 분석 (3,4)•Keychord open 조건을 확인하고 참인 조건이면 open

•keychord_fd = open_keychord();keychords 확인

•console을 open해서 동작 유무를 체크한다.

•정상동작을 한다면 have_console = 1 로 셋팅Consols 확인

•565rle image(로고) 파일을 프레임 버퍼에 로딩한다. •565rle image(로고) 파일을 프레임 버퍼에 로딩한다.

• image 파일이 없으면 텍스트 모드로 프레임 버퍼에 “ANDORID” 출력부팅 이미지 출력

• if (qemu[0]) import_kernel_cmdline(1);

•커널 커맨드 라인의 옵션들을 QEMU에서 참조하게끔 'ro.kernel'이라는 접두어

를 붙여 property를 생성한다.

QEMU설정에 따라 CMDLINE

변경

•각 커널 커맨드에 대한 중요 옵션들을 property로 만든다.

•Factory mode, ro.bootmode, ro.baseband등등추가 Property 설정

Page 31: About Init In Android By Andstudy

open_keychord(), Consols 확인

Keychord 란?

Keychord는 핸드폰에 있는 단축키와 조합키 와 같은 특수키와 조합 키를 지원하기 위한 구조이다.

[code]debuggable = property_get("ro.debuggable"); if (debuggable && !strcmp(debuggable, "1"))

keychord_fd = open_keychord();

debuggable 셋팅값에 따라 keychord를 오픈한다.

Consols 동작 확인

[code]fd = open(console_name, O_RDWR); if (fd >= 0)

have_console = 1; close(fd);

Consols 동작 확인을 하고 have_console 변수를 셋 한다.

Page 32: About Init In Android By Andstudy

부팅 이미지 출력

565rle image(로고) 파일을 프레임 버퍼에 로딩한다.

[code]if( load_565rle_image(INIT_IMAGE_FILE) ) {

fd = open("/dev/tty0", O_WRONLY); if (fd >= 0) {

const char *msg; msg = "\n"

"\n“"\n““ A N D R O I D ";

write(fd, msg, strlen(msg)); close(fd); }

-/initlogo.rle 파일이 있다면 이미지를 로딩하여 LCD에 출력한다.-/initlogo.rle 파일이 없거나, image file 로딩이 실패하면 -1을 리턴하고 tty0 에텍스트(“A N D R O I D”)를 출력한다.- 로고이미지는 565rle format 이다.

Page 33: About Init In Android By Andstudy

QEMU설정에 따라 CMDLINE 변경

Qemu 환경이라면 이에 맞는 셋팅을 해준다.

[code]if (qemu[0])

import_kernel_cmdline(1);

import_kernel_cmdline(1) 인자가 1이면 qemu 관련 환경이고, 내부에서property_set() 을 하게된다. Property 는 'ro.kernel'이라는 접두어를 붙여property를 생성한다

property_init() Property_area 로 사용할 공유메모리 공간을 생성한다

property_get() /property_set()

start_property_service() property_service() 를 시작해야 하는 서비스 내용을 소켓을 이용하여 시스템에 알린다.

property service(handle_property_set_fd())

위에서 써진 소켓 내용을 통해 서비스를 시작한다.

Property 관련 함수

Page 34: About Init In Android By Andstudy

추가 Property 설정

각 커널 커맨드에 대한 중요 옵션들을 property로 만든다.

[code]if (!strcmp(bootmode,"factory"))

property_set("ro.factorytest", "1"); else if (!strcmp(bootmode,"factory2"))

property_set("ro.factorytest", "2"); else property_set("ro.factorytest", "0"); property_set("ro.serialno", serialno[0] ? serialno : ""); property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown");

ro.factorytestro.factorytest

11

Ro.hardwareRo.hardware

goldfishgoldfish

namenameserialserial

valuevalue

Struct Property infoStruct Property info

property_set("ro.bootmode", bootmode[0] ? bootmode : "unknown"); property_set("ro.baseband", baseband[0] ? baseband : "unknown"); property_set("ro.carrier", carrier[0] ? carrier : "unknown"); property_set("ro.bootloader", bootloader[0] ? bootloader : "unknown"); property_set("ro.hardware", hardware); snprintf(tmp, PROP_VALUE_MAX, "%d", revision); property_set("ro.revision", tmp);

Property_area에 property_info 구조체의 형태로Property_area를 채운다.

goldfishgoldfish

Ro.revisionRo.revision

xxxxxxxxxxxxxx

Page 35: About Init In Android By Andstudy

Init 분석 ( 4 )

•전체 action list에서 'init'에 해당하는 action에 관계되는 커맨드 내용을 뽑아내

ACTION queue에 저장action_for_each_trigger("init

“,action_add_queue_tail);

•ACTION queue에 저장된 커맨드를 순차적으로 실행한다.

drain_action_queue();

•기타 property 파일 및 /data/property 디렉토리에 저장된 persistent propertyproperty_set_fd = start_pro •기타 property 파일 및 /data/property 디렉토리에 저장된 persistent property

들을 시스템 property 영역에 로드한다. 그리고 property service를 위한 서버용

unix domain socket을 생성하고, 리턴한다.

property_set_fd = start_pro

perty_service();

•sockpair 시스템 콜을 이용해 서로 연결된 unix domain socket 쌍을 생성한다시그널 처리를 위한 소켓 생

•device_fd , property_set_fd, signal_recv_fd 값이 모두 0 보다 커야 한다.

•그 외의 경우는 ERROR()호출 후 return 1부팅에 필요한 FD 확인

Page 36: About Init In Android By Andstudy

“Init” action 실행

-Action리스트에서 name이 “init”인 노드를 ACTION queue에 추가한다.-추가한 action queue에 있는 노드를 실행시킨다.

[code]action_for_each_trigger("init", action_add_queue_tail); drain_action_queue();

Init.rc. “on init “ 섹션에서 정의한 Action이 시작되는 시점이고, 다음과 같은 내용의 명령어를 수행한다.

- 글로벌 변수 초기화- 글로벌 변수 초기화- mount point 생성 /sdcard, /system, /data, /cashe- MTD 파티션 마운드 (기본적으로 yaffs2 사용)- create basic filesystem structure

/

/dev /proc /sys /sdcard /system /data /cashe

basic filesystem structure basic filesystem structure

Page 37: About Init In Android By Andstudy

start_property_service()

property_set_fd = start_property_service();

- 기타 property 파일 및 /data/property 디렉토리에 저장된 persistent property들을 시스템 property 영역에 로드한다. - property service를 위한 서버용 unix domain socket을 생성하고, 리턴한다.- 이후에 property 를 변경할 경우 여기서 생성한 unix domain socket을 이용한다.

/data/property/file 은 안드로이드의 로케일 설정 파일이 있다.persist.sys.country persist.sys.languagepersist.sys.localevar persist.sys.timezonepersist.sys.localevar persist.sys.timezonestart_property_service() 함수에서 참조하는 property fils list

/system/build.prop/system/default.prop/data/local.prop

Page 38: About Init In Android By Andstudy

시그널 처리를 위한 소켓 생성

서로 연결된 unix domain socket 쌍을 생성한다. S[0], S[1]

[code]if (socketpair(AF_UNIX, SOCK_STREAM, 0, s) == 0) { signal_fd = s[0]; signal_recv_fd = s[1]; fcntl(s[0], F_SETFD, FD_CLOEXEC); fcntl(s[0], F_SETFL, O_NONBLOCK); fcntl(s[1], F_SETFD, FD_CLOEXEC);fcntl(s[1], F_SETFD, FD_CLOEXEC);fcntl(s[1], F_SETFL, O_NONBLOCK); }

- sockpair 시스템 콜은 서로 연결된 unix domain socket 쌍을 생성한다. 생성된소켓 쌍은 서로 직접 연결되어 있어 바인딩이 필요 없으며. 4번째 인자에 저장된다.

S[] 는 init이 SIGCHLD시그널 핸들러에서 발생한 시그널번호를 수신하는 소켓이다.

Page 39: About Init In Android By Andstudy

부팅에 필요한 FD 확인

device_fd, property_set_fd, signal_recv_fd가 정상적이어야만 부팅이 진행된다.

if ((device_fd < 0) || (property_set_fd < 0) || (signal_recv_fd < 0)) {ERROR("init startup failure\n"); return 1; }

ERROR() 함수는 __kmsg__ 에 Level =3 으로 로그를 남기는 함수이다.

Fd[0]stdin

Init이 관리

Init

Fd[0]Fd[1]

Fd[2]Fd[x]

Fd[…]

stdinstdout

stderr

__null__

Fd[x]

Fd[x]

Fd[x]

Fd[x]

/dev/keychord

Uevent Socket

Unix domain Socket

Unix domain Socket

device_fd

Property_set_fd

Signal_recv_fdkeychord_fd

__kmsg__

Init이 관리하는 FD

Page 40: About Init In Android By Andstudy

Init 분석 ( 5 )

• action_for_each_trigger("early-boot", action_add_queue_tail);

• action_for_each_trigger("boot", action_add_queue_tail);

• drain_action_queue();

‘early-boot'와 'boot' action에

관계되는 커맨드 실행

• 아직까지 셋팅 되지 않은 property 를

queue에 추가하고 실행한다.

queue_all_property_triggers();

drain_action_queue(); queue에 추가하고 실행한다.drain_action_queue();

• ufds[0] : uevent 메시지 체크

• ufds[1] : property set관련 Unix Domain 소켓 메시지 체크

• ufds[2] : SIGCHLD 시그널 발생 체크

• ufds[3] : keychord 발생 체크

init 프로세스가 poll함수로 감

시할 파일디스크립터 설정

• ufds에서 정의한 파일 디스크립터들의 입력을 감시한다

• 4개의 FD에서 POLLIN이 뜨면 해당 이벤트 처리를 한다.무한 루프 문

Page 41: About Init In Android By Andstudy

action_for_each_trigger(“boot“,action_add_queue_tail)

Action list에서 name이 'early-boot'와 'boot‘ 인 커맨드 내용을 뽑아내ACTION queue에 추가한 후, 각 커맨드를 실행한다

[code]action_for_each_trigger("early-boot", action_add_queue_tail); action_for_each_trigger("boot", action_add_queue_tail);drain_action_queue();

queue_all_property_triggers(); queue_all_property_triggers(); drain_action_queue();

Init.rc. 내용에서 보았듯이 early-boot의 내용은 없었기 때문에 이부분은 실행되는 것이 없을 것이다. Boot 섹션은 다음과 같은 일을 한다.- network init- System Server and daemons 의 Permissions 설정- 각 APP group 메모리 사용 설정

queue_all_property_triggers() 함수에서 아직까지 셋팅 되지 않은 property 를queue에 추가하고 실행한다.

Page 42: About Init In Android By Andstudy

Ufds[ ] 파일디스크립터 설정init 프로세스가 poll함수(I/O multiplexing)로 감시할 파일 디스크립터 설정

[code]ufds[0].fd = device_fd; ufds[0].events = POLLIN; ufds[1].fd = property_set_fd; ufds[1].events = POLLIN; ufds[2].fd = signal_recv_fd; ufds[2].events = POLLIN; fd_count = 3; ufds[3].fd = keychord_fd; ufds[3].events = POLLIN; fd_count++;

ufds[0] : uevent 메시지 체크ufds[0] : uevent 메시지 체크ufds[1] : property set관련 Unix Domain 소켓 메시지 체크ufds[2] : SIGCHLD 시그널 발생 체크ufds[3] : keychord 발생 체크

Init [1] fd=property_set_fd event = POLLIN

[0] fd=device_fd event = POLLIN

[2] fd=signal_recv_fd event = POLLIN

[3] fd=keychord_fd event = POLLIN

Ufds[ ]

Page 43: About Init In Android By Andstudy

무한 루프 문Loop를 돌면서 action queue 에 처리해야 하는 action이 있다면 실행하고, restart 해야 하는 prosess가 있으면 재시작 해준다.Poll() 함수를 이용하여 ufds에서 정의한 파일 디스크립터들의 입력을 감시한다

[code]for (i = 0; i < fd_count; i++)

ufds[i].revents = 0; drain_action_queue(); restart_processes(); nr = poll(ufds, fd_count, timeout); if (nr <= 0) if (nr <= 0)

continue; if (ufds[2].revents == POLLIN) {

read(signal_recv_fd, tmp, sizeof(tmp)); while (!wait_for_one_process(0)) ; continue; }

if (ufds[0].revents == POLLIN) handle_device_fd(device_fd); if (ufds[1].revents == POLLIN) handle_property_set_fd(property_set_fd); if (ufds[3].revents == POLLIN) handle_keychord(keychord_fd);

Page 44: About Init In Android By Andstudy

drain_action_queue(); restart_processes();

ufds[0]ufds[0] wait_for_one_process(0)wait_for_one_process(0)

nr = poll(ufds);

nr = poll(ufds);

Nr > 0

yes

no

yes

yesno

마름모 안에 텍스트는“ufds[x].revents == POLLIN ?”대신 “dfds[x]”로 표현

ufds[1]ufds[1]

ufds[2]ufds[2]

ufds[3]ufds[3]

handle_device_fd(device_fd)handle_device_fd(device_fd)

handle_property_set_fd(property_set_fd)handle_property_set_fd(property_set_fd)

handle_keychord(keychord_fd); handle_keychord(keychord_fd);

yes

yes

yes

no

no

Page 45: About Init In Android By Andstudy

Ufds[ ] handle actionwait_for_one_process(0)SIGCHID 시그널에 발생 했다는 것은 child process가 종료 했다는 것을 의미한다. 따라서 이 함수에서는 process 종료 시에 parent 가 처리해야 하는 내용이 있다. Wait() 하고, 종료된 process 속성 값에 따라 재 시작 해줘야 하는지 확인하고옵션에 따라 기능을 수행한다.

handle_device_fd(device_fd)Device_fd에 Uevent가 발생한것은 디바이스 드라이버에서 핫 플러그 등의 디바이스 관련한 이벤트가 발생할 경우이다. 따라서 init procrss는 이런 디바이스 메이스 관련한 이벤트가 발생할 경우이다. 따라서 init procrss는 이런 디바이스 메시지를 처리해야한다. 이 루틴은 앞서서 devicd_init()에서 이미 호출된 적이 있다.- uevent는 커널에서 유저 프로세스에게 디바이스 관련 메시지를 전달하는netlink socket의 한 종류이다.

handle_property_set_fd(property_set_fd); Property가 변경되어야 할때, 소켓을 통해 전달된 정보를 바탕으로 권한 체크를하고, 문제가 없다면 property_set()을 한다.

handle_keychord(keychord_fd); Keychord 정보를 읽고 나서, 읽어온 keychord 에 매칭되는 서비스가 있으면 실행한다.