1. Intro.
부팅 시퀀스에 대한 충분한 지식이 있으면 벽돌이 된 안드로이드를 문제 해결하거나, 커스텀 ROM을 플래싱하거나, 루팅하는 등의 작업에 유용합니다. 이 주제에 대해 놀라운 글을 쓴 기기별 포럼이 많으므로, 저는 이에 대해 이야기하지 않겠지만, 안드로이드의 부팅 시퀀스, 안드로이드의 다양한 부팅 모드, 부트로더가 잠금 해제된 폰에서 루팅이 어떻게 작동하는지에 대한 기본 사항을 살펴보겠습니다. 이 주제에 대해 조사하는 동안, 잠긴 부트로더 기기에서 루팅 기술에 대한 몇 가지 흥미로운 글을 우연히 발견했습니다. 가까운 미래에 이에 대해 이야기해 보겠습니다.:)
2. Boot Sequence in Android Summary
<안드로이드 부팅 순서 요약>
1) ROM
CPU에 전원이 인가되면, 지정 번지의 ROM code를 찾아 실행
ROM code는 Bootloader를 RAM에 적재시키는 역할을 수행
2) Bootloader
Ram 초기화, HW 초기화, kernel과 Ramdisk를 RAM으로 올림, kernel 시작 지점으로 Jump해서 kernel을 시작시킴
3) kernel
c code 실행환경 준비, kernel subsystem & device driver 초기화, rootFS mount, init process 구동
4) init Process
환경 변수 설정, 마운트 위치 생성, 여러 파일 시스템을 마운트, 마운트된 파일 시스템의 파일 퍼미션 설정
init에 의해 여러 native 데몬이 실행 (ex : service Manager, Vold, neted, ... )
3. Boot Sequence in Android
<부팅 순서 분석>
안드로이드 시스템은 대략적으로 아래의 순서를 따라 부팅을 시작
- 부트로더
- 리눅스 커널
- init process
- Native daemons
- Zygote (native daemon 중 하나)
- system_server
- java 기반의 응용 프로그램
3.1 부트 로더 (Boot Loader)
부트 로더가 하드웨어 초기화를 마치면 부팅 파티션에서 안드로이드 커널과 initrd를 RAM으로 로드하고 안드로이드 커널로 점프합니다.
3.2 안드로이드 커널 (Android Kernel)
모든 중요한 작업이 성공적으로 실행되면 루트 파일 시스템이 마운트되고 첫 번째 사용자 공간 프로세스가 init됩니다.
3.3 init process
3.4 Native Daemons
3.5 Zygote
Zygote는 Dalvik VM을 시작하고 첫 번째 Java 구성 요소 시스템 서버를 시작합니다.
3.6 System Server
4. 부팅의 시작: primary 및 secondary bootloader
<부팅의 시작 : primary 및 secondary 부트로더>
일반적인 Application Process의 부팅 순서
1) Primary BootLoader(PBL)로부터 부팅을 시작
2) Secondary Bootloder(SBL)를 emmc 메모리로부터 Internal Sram으로 가져와 구동시킴
3) 마지막으로 Application bootloader(LK, u-boot)가 linux kernel을 DRAM으로 가져와 부팅을 마무리
5. Linux Kernel과 Ramdisk
<Linux kernel과 Ramdisk>
Application Bootloader는 리눅스 커널과 Ramdisk Image를 eMMC로부터 읽어들여 DRAM에 적재한다.
이어서 커널의 시작 지점으로 점프하여 커널을 시작한다.
커널은 압축된 형태로 RAM으로 적재되기 때문에, 구동 시점에서는 자신의 압축을 직접 풀면서 실행하게 된다.
5.1 커널 부팅 요약
2) LK bootloader가 kernel의 시작번지로 jump하면, kernel은 자신의 압축을 풀기 시작
3) kernel은 C code를 실행하기 위한 환경을 준비
4) kernel subsystem 초기화
5) 각종 device driver 초기화
6) Ramdisk root FS 마운트
7) init process를 구동
8) Idle 상태에서 대기
실제로 파일 시스템을 마운트하는 과정은 init process에서 하게된다.
즉, 실제 마운트 하는 곳은 kernel단이 아니라 android단 이라는 것이다.
5.2 Ramdisk Partition
bookmark_border
Android 10과 11에서는 1단계 램디스크에 fstab 항목에 의해 지정된 대로 초기 마운트를 실행하는 1단계 init 바이너리와 공급업체 fstab 파일이 포함되어 있습니다. Android 9 이하에서와 마찬가지로 system.img에는 $TARGET_ROOT_OUT의 콘텐츠가 포함되어 있습니다.
- 부팅 램디스크가 있고 A/B 이외의 기기인 경우 1단계 init은 /init에 있는 정적 실행 파일입니다. 이러한 기기는 system.img를 /system으로 마운트한 다음 루트를 전환하는 작업을 실행하여 /system의 마운트를 /로 이동합니다. 마운트가 완료되면 램디스크 콘텐츠는 해제됩니다.
- 램디스크로 복구를 사용하는 기기의 경우 1단계 init은 복구 램디스크 내의 /init에 있습니다. 이러한 기기는 먼저 루트를 /first_stage_ramdisk로 전환하여 환경에서 복구 구성요소를 삭제한 후 부팅 램디스크를 사용하는 기기와 동일하게 진행합니다. 즉, system.img를 /system으로 마운트하여 루트를 전환함으로써 해당 마운트를 /로 이동하고 마운트 후 램디스크 콘텐츠를 해제합니다. androidboot.force_normal_boot=1이 커널 명령줄(또는 Android 12 이상의 bootconfig)에 있으면 기기는 복구 모드로 부팅되지 않고 Android로 정상적으로 부팅됩니다.
1단계 init이 끝나면 selinux_setup 인수로 /system/bin/init을 실행하여 SELinux를 컴파일하고 시스템에 로드합니다. 마지막으로 init은 second_stage 인수로 /system/bin/init을 다시 실행합니다. 이 시점에서 init의 주요 단계가 실행되고 init.rc 스크립트를 사용하여 부팅 프로세스를 계속 진행합니다.
참고:Android 10은 램디스크 콘텐츠를 이전 램디스크가 시스템을 부팅했던 방식과 호환되지 않는 1단계 init 실행 파일로 대체합니다.다음 섹션에서는 Android 10 이전과 이후, A/B 이외의 기기의 파티션 레이아웃 차이를 설명합니다.
5.3 Partition Layout (A/B 이외의 기기)
다음 섹션에서는 Android 10 이전과 이후, A/B 이외의 기기의 파티션 레이아웃 차이를 설명합니다.
boot.img
recovery.img
복구 커널과 복구 ramdisk.img를 포함합니다.
system.img
5.4 Partition Layout (A/B 기기)
다음 섹션에서는 Android 10 이전과 이후, A/B 기기의 파티션 레이아웃 차이를 설명합니다.
boot.img
system.img
$TARGET_SYSTEM_OUT과 $TARGET_ROOT_OUT의 병합된 콘텐츠를 포함합니다.
system.img
-/
- init.rc
- init -> /system/bin/init
- etc -> /system/etc
- system/
- bin/
- etc/
- vendor -> /vendor
- ...
- vendor/ (mount point)
- odm/ (mount point)
...
6. init process와 init.rc
<init process와 init.rc>
init은 kernel이 부팅의 거의 마지막 단계에서 실행시켜 주는 최초의 application process로써, 이후 모든 user space application이 init를 통해 실행되고 관리된다.
6.1 init process 기능 요약
- Native daemon 구동
- service manager, vold, netd, rild, mediaserver, bootanimation, keystore 등 실행
SIGCHID signal 처리
child process가 죽으면 다시 살림
system property 설정
init rc 파일은 복수개의 action과 service로 구성되어있다.
6.2 init process 흐름 분석
2) coldboot: ueventd가 device를 성공적으로 초기화 했는지 검사
3) property service 내부 데이터 구조를 초기화
4) keychord를 위한 핸들러를 셋업
5) 콘솔을 초기화하고, 로그 화면 혹은 문자를 출력
6) ro.serialno, ro.bashband, ro.carrier 같은 초기 속성을 설정
7) init 명령을 실행
8) early-fs 명령을 실행
9) fs 명령 실행
10) post-fs 명령 실행
11) service 명령 실행
12) SIGCHID 시그널을 받을 준비
13) service socket과 SIGCHID 핸들러가 준비되었는지를 확인
14) early-boot 명령 실행
15) boot 명령 실행
16) 모든 triggerd 명령 처리
ueventd는 init process가 실행시켜주는 최초의 native daemon으로, ueventd.rc와 ueventd.{hardware}.rc 파일을 토대로 각종장치 노드(/dev)를 정적으로 생성시켜 줌은 물론이고, 커널에서 동적으로 올라오는 event(kobject_uevent() 함수 호출)를 토대로 각종 장치 노드(/dev)를 동적으로 생성 및 초기화 시켜주는 역할을 담당한다.
'Embedded : : Linux > : : Bootloader' 카테고리의 다른 글
MCU Bootloader (0) | 2024.05.04 |
---|