정보공간_1

[Android System 분석] 02. init 프로세스 ,안드로이드 udev 본문

IT 놀이터/IT Storehouse

[Android System 분석] 02. init 프로세스 ,안드로이드 udev

알 수 없는 사용자 2011. 12. 2. 01:54

안녕하세요. 저는 강남멤버십 21-1기 채경훈, 그리고 21-2기 김현규입니다.
저희는  강남멤버십에서 Menux라는 SIG 활동을 진행하고 있으며, 안드로이드의 모든것 이라는 책을 통하여 안드로이드 시스템 분석이라는 주제로 스터디를 진행하고 있습니다. 이번에 저희가 스터디 한 내용은 안드로이드 init 프로세스와 안드로이드 디바이스 관리하는 데몬인 udev 에 대해서 공부하였는데요. 스터디 한 내용을 바탕으로 init 프로세스와 안드로이드 디바이스 관리 데몬인 udev에 대해 알아보도록 하겠습니다.

----------------------------------------------------------------
안드로이드 init 프로세스

1.     Init 이란?

Init은 모든 유닉스 시스템에서 가장 먼저 실행되는 프로세스이면서 또한 부팅 시 커널이 수행하는 맨 마지막 과정입니다. Init은 시스템 시동에 필요한 여러 가지 작업을 수행함으로써 부팅 과정을 계속 이어나갑니다(파일시스템을 검사하고 마운트하기, 데몬 시동시키기 등의 다양한 작업을 합니다).

시스템이 셧다운될 때 남아있는 프로세스를 모두 종료시키고 모든 파일시스템의 마운트를 해제하는 것도 init이라고 할 수 있습니다. 그 밖에 시스템 종료 시 수행하도록 정해준 기타 작업도 init이 처리합니다.

2.     안드로이드 init의 중요한 기능

A.     커널 부팅 후 /init이 실행됩니다

B.      필요한 디렉터리를 만들고 부팅에 필요한 init.rx, init.%hardware%.rc파일을 로딩합니다.

C.      /dev 디렉터리에 기본적인 디바이스 노드 구성을 합니다.

D.     Init.rc init.%hardware%.rc를 분석한 내용에 따라 각 부분에서 지정한 일을 합니다. 부트부분에서는 주로 각종 서비스를 동작시키는 일을 합니다.

3.     rc 문법

커널에 의해 init 프로세스가 실행되면 여러가지 일을 하게 되는데, 이렇게 실행되면서 하는 일은 여러 시스템마다 다를 수 있기 때문에 안드로이드의 경우에는 환경 설정을 할 수 있도록 특별한 문법을 가지는 rc 파일을 만들어 두었습니다. Init 프로세스 소스를 분석하기 전에 이 rc 파일의 문법을 이해하면 한결 보기가 편할 것 입니다.

rc 파일의 문법은 크게 action, service, commands로 구분할 수 있습니다.

4.     안드로이드 부팅 과정 그림

    

5.     안드로이드 주요 부팅 순서
A.     Bootloader kernel을 로드합니다.

B.      android/kernel/arch/arm/kernel/head-common.S 에서 start_kernel 함수 호출 합니다.

C.      android/kernel/init/main.c 에 있는 start_kernel() 호출 합니다.

D.     함수 끝의 rest_init() 함수 호출 합니다.


E.      rest_init()함수에서 kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND) 로 가고 다시 kernel_init() 함수를 호출합니다.


F.      init 프로세스를 위한 제반 작업을 준비합니다.


G.     함수 가장 마지막 부분에서 init_post 함수를 호출한다.

 

H.     Init_post 함수의 run_init_process(ramdisk_execute_command)를 통해서 init 프로세스가 실행되게 됩니다. 위치는 android/system/core/init/init.c가 됩니다.


I.       init.c는 하나의 프로세스이기 때문에 시작점인 main()함수를 포함합니다. main함수에서는 변수 초기화 후 필요한 디렉터리를 생성하고 마운트 합니다.


J.       다음에는 open_devnull_stdio 함수를 호출합니다. 이 함수는 아래에 나와있습니다. Stdio null 디바이스로 연결하는 부분입니다.


K.      Parse_config_file(“/init.rc”); 함수 호출을 통해 init.rc파일을 parsing 하여 service_list action_list를 구성합니다.

L.   device_fd = device_init() 을 통해 /dev 이하에 장치 파일을 uevent 파일을이용하여 생성하고 접근권한을 설정합니다.

M.    시그널 처리를 위한 소켓을 생성합니다.


N.     Action list 에서 “early-boot”“boot”라는 name의 노드를 action_queue에 삽입하고, action_queue에 있는 노드를 실행 시킵니다.


O.     Action_list에 있는 노드중에 node.name “property” 인 노드들을 action queue에 추가한후에, Action_queue에 있는 노드를 실행 시킵니다..


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

Q.     해당 fd POLLIN에 따라 4가지 핸들러를 호출합니다.


안드로이드 udev,ueventd
 

1.     시스템 리소스 추상화 이란?

시스템 리소스 추상화는 시스템 리소스를 파일로 표현 및 제공하는 것을 의미합니다. 실제로 리눅스 시스템의 /proc, /dev , /sys 와 같은 디렉터리는 시스템이 사용하고 있는 디바이스나 각종 리소스를 추상화 하여 파일로 제공해주는 디렉터리라 할 수 있습니다.

일 예로 /proc cpuinfo 는 프로세스스를 추상화 하며 /dev sda,had는 하드디스크를 추상화 한다고 볼 수 있습니다.

즉 이러한 추상화된 파일은 어플리케이션을 위한 인터페이스 도구라 할 수 있습니다. 그 이유는 사용자 공간/ 커널공간이 가상주소를 기반으로 분리되어 있기 때문에 커널 리소스를 사용하기 위해서 유저 레벨 프로세스는 시스템 콜을 통하여 작업을 요청하는 것입니다. 이때 시스템 콜을 하기 위해 인자로 넘겨주는 것이 이러한 장치 파일을 나타내는 파일 디스크립터라 할 수 있습니다.

2.     udev의 탄생 배경

udev는 유닉스의 디바이스 드라이버 관련 디바이스 노드 파일을 생성하는 유저 영역에서 수행되는 데몬입니다. udev /dev 아래 디바이스 파일노드를 만드는데 기존의 방법으로는 해결하기 힘든 문제가 생겼기 때문입니다. 예를 들어 /dev에는 18000개의 디바이스 노드 파일이 있는데 이는 이후 생성될 가능성이 있는 모든 디바이스에 대한 모든 노드 파일을 시스템 설치시 생성했기 때문입니다.

3.     udev란 무엇인가

실제로 있는 디바이스에 대해 파일 노드 생성을 사용자 공간에서 자동화 하여 처리 하도록 구성되 어 있으며 , 장치파일 삭제 및 생성을 동적으로 처리 할수있도록 구성되어 있습니다. Udev의 동작과정은 다음과 같습니다.

1.     안드로이드 부팅시 ueventd 이 동작하게 됩니다.

2.     실제 디바이스다 detect 되면 udev 데몬이 sysfs에 등록하고 해당 디바이스는 사용자 공간에서 /sys에 등록됩니다.

3.     Udeve 데몬으로 netlinkk socket을 이용하여 새로운 디바이스가 생성되었다는 메시지메 전송합니다.

4.     Udev 데몬은 /sys의 디바이스 내용을 이용하여 /dev에 디바이스 노드를 생성합니다.


[/dev 에 장치파일이 만들어지는 순서]

4.     uevent 와 디바이스

Firmware는 제조사에서 배포되는 특정 하드웨어가 동작되도록 하는 code 이미지입니다. Firmware을 사용하는 가장 광범위한 방법은 헤더 파일에 static 하게 링크하는것입니다. 하지만 firmware는 업그레이드 되고 재배포 될 수 있습니다. 이경우 드라이버의 firmware는 단 한번의 사용일 지라도 static 하게 링크되어 메모리에 항상 상주하게 됩니다. 따라서 이러한 문제를 해결하기 위해 request_firmware() hotplug 간의 인터페이스가 생기게 되었습니다. 디바이스 드라이버와 Hotplug간의 절차는 아래와 같습니다.

1.     드라이버 초기화시 request_firmware 함수를 호출합니다.

if(request_firmware(&fw_entry,$FIRMWARE,device)==0)

    copy_fw_to_device(fw_entry->data,fw_entry->size);

release(fw_entry)

request_firmware /sys/class/firmware/xxx/loading,/sys/class/firmware/xxx/data 에 파일을 생성하여 사용자 공간으로 hotplug가 호출되게 됩니다.

2.     사용자 공간에서 hotplug

사용자 공간에서 /sys/class/firmware/xxx/loading,/sys/class/firmware/xxx/data 파일이 나타나며 $DEVPATH,$FIRMWARE가 환경변수로 전달됩니다. 이때 /sys/$DEVPATH/loading 1을 기록하여 복사가 시작됨을 알리며 firmware 파일 $HOTPLUG_FW_DIR/$FIRMWARE sysfs/$DEVPATH/data 로 복사합니다. 이후 /sys/$DEVPATH/loading 0을 기록해서 복사가 완료 됨을 알립니다.

3.     커널에서의 작업

Request_firmware 함수가 리턴되면 fw_entry->data,fw_entry->size firmware의 크기 정보가 저장되며 이를 드라이버에서 특정하드웨어에 맞는 작업을 수행합니다.

사용자의 공간으로 전달되는 환경변수는 다음과같습니다.

SUBSYSTEM=module

DEVPATH=/modyle/firmware_sample_driver

LD_LIBRARY_PATH=:/user/app/lib

PATH=/sbin:/bin:/usr/sbin:/usr/bin:/user/app/bin

ACTION=add

PWD=/

SHLVL=1

HOME=/

SEQNUM=933

_=/usr/bin/env

 


 ---------------------------------------------------------------
지금까지 안드로이드 init 프로세스와 안드로이드 디바이스 관리에 대해서 다루어 보았는데요, 다음에는 안드로이드의 Input device와 센서 시스템에 대해서 다루어 보도록 하겠습니다.