1. 안드로이드 AOSP 시스템 부팅 프로세스(Boot Process) 분석의 중요성
안드로이드 Open Source Project(AOSP) 및 차량용 안드로이드(Android Automotive OS, AAOS) 시스템 개발 시 부팅 시간(Boot Time) 최적화와 초기화 오류 디버깅은 핵심 과제입니다. 디바이스의 전원 인가(Power-On) 시점부터 애플리케이션 프레임워크(Application Framework)가 활성화되는 전 과정을 정확히 이해해야 시스템 지연 문제나 무한 부팅(Bootloop) 현상을 해결할 수 있습니다.
특히 하드웨어 제어 단계인 Bootloader, 리눅스 커널(Linux Kernel) 로딩, 사용자 공간(User Space)의 최상위 프로세스인 init, 자바 런타임 환경을 생성하는 Zygote, 그리고 핵심 서비스를 담당하는 SystemServer 간의 상호작용 구조를 이해해야 합니다. 본 가이드는 안드로이드 부팅 단계별 아키텍처와 핵심 동작 원리, 관련 소스코드 구조를 상세히 설명합니다.
2. 안드로이드 부팅 프로세스 핵심 요약 (Android Boot Sequence Summary)
- Hardware & Kernel Phase: Power-On Reset(POR) 후 ROM/Bootloader(PBL/SBL/U-Boot)가 리눅스 커널(Linux Kernel)을 RAM에 로드하고, start_kernel() 함수를 통해 CPU/메모리 초기화 후 PID 1번인 init 프로세스를 실행합니다.
- Native & Runtime Phase: init 프로세스는 /system/core/init에서 init.rc 스크립트를 파싱하여 Native Daemon을 실행하고, app_process 명령을 통해 Zygote 프로세스를 생성하여 ART(Android Runtime)를 초기화합니다.
- Framework & System Service Phase: Zygote는 SystemServer 프로세스를 포크(Fork)하여 ActivityManagerService(AMS), PackageManagerService(PMS) 등 핵심 서비스를 실행하고 최종적으로 System UI 및 Launcher 앱을 화면에 출력합니다.
3. 안드로이드 부팅 아키텍처 상세 분석 및 구현 (AOSP Boot Architecture Analysis)
3.1. 하드웨어 전원 인가부터 Bootloader 및 Kernel Initialization 과정
하드웨어에 전원이 공급되면 SoC 내부의 Primary Bootloader(PBL)가 Boot ROM에서 실행됩니다. PBL은 Secondary Bootloader(SBL) 및 UEFI/U-Boot를 SRAM 및 DRAM으로 로드합니다. Bootloader는 하드웨어 검증(Verified Boot / AVB)을 수행한 후 Kernel Image(zImage/Image.gz)와 Device Tree Blob(DTB)을 RAM으로 복사하고 커널 실행 지점으로 점프합니다.
// kernel/init/main.c
asmlinkage __visible void __init __start_kernel(void)
{
// Initialize hardware architectures, memory management, and IRQs
setup_arch(&command_line);
mm_init();
sched_init();
// Create the first user-space process (PID 1)
kernel_thread(kernel_init, NULL, CLONE_FS);
}
static int __ref kernel_init(void *unused)
{
// Execute init process from ramdisk or system partition
if (!run_init_process("/init"))
return 0;
panic("No working init found. Try passing init= option to kernel.");
}
3.2. Native User Space Initialization: init Process 및 init.rc Parsing
kernel_init에 의해 실행된 /init 바이너리는 First-stage init과 Second-stage init 단계를 거칩니다. First-stage init에서는 VFS(Virtual File System) 마운트, devtmpfs 설정, SELinux 로딩을 처리합니다. Second-stage init에서는 init.rc 구문 분석(Parsing)을 시작합니다.
# system/core/rootdir/init.rc
# Define Zygote service triggers
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
3.3. Android Runtime Activation: Zygote Process Forking 및 Preloading
init 프로세스는 app_process 바이너리를 통해 Zygote를 실행합니다. Zygote는 AndroidRuntime.cpp 내의 start() 함수를 호출하여 Dalvik/ART Virtual Machine을 생성하고, 앱 구동 시간 단축을 위해 핵심 자바 클래스 및 리소스를 메모리에 Preload합니다.
// frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
// Start the Java Virtual Machine (ART)
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote, primary_cpu) != 0) {
return;
}
onVmCreated(env);
// Register Android Native Functions (JNI)
if (startReg(env) < 0) {
ALOGE("Register of Android runtime failed\n");
return;
}
// Call ZygoteInit main method in Java layer
jclass startClass = env->FindClass(className);
jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
ZygoteInit.java에서는 Preloading이 완료된 후 SystemServer 프로세스를 생성하기 위한 포크 작업을 진행합니다.
// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
// Preload framework classes and resources
preload(bootTimingsTraceLog);
// Fork SystemServer process if flag is set
if (startSystemServer) {
Runnable runnable = forkSystemServer(abiList, socketName, zygoteServer);
if (runnable != null) {
runnable.run();
return;
}
}
// Run Zygote socket select loop for app creation requests
zygoteServer.runSelectLoop(abiList);
}
3.4. Framework Core Services startup: SystemServer Initialization
SystemServer는 안드로이드 OS의 핵심 관리 서비스를 실행하는 메인 프로세스입니다. SystemServer.java의 main() 메서드가 호출되면, 내부적으로 SystemServiceManager를 생성하고 3가지 단계(Bootstrap Services, Core Services, Other Services)로 구분하여 서비스를 순차적으로 시작합니다.
// frameworks/base/services/java/com/android/server/SystemServer.java
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
// Load native libraries for system services
System.loadLibrary("android_servers");
// Initialize SystemServiceManager
mSystemServiceManager = new SystemServiceManager(mSystemContext);
// Start critical bootstrap services
startBootstrapServices(t);
// Start core system services
startCoreServices(t);
// Start all other application framework services
startOtherServices(t);
}
3.5. 안드로이드 부팅 단계별 역할 및 특징 비교
| 부팅 단계 (Phase) | 주 구성 요소 (Main Components) | 실행 환경 (Execution Space) | 핵심 역할 및 결과물 (Primary Function & Output) |
| Bootloader | ROM, SBL, U-Boot, ABL | Hardware / TrustZone | 하드웨어 초기화, AVB 검증, Kernel & DTB 메모리 로드 |
| Linux Kernel | Kernel Image, Drivers, vmlinux | Kernel Space (Ring 0) | MMU/CPU 초기화, Driver Mount, PID 1 init 프로세스 포크 |
| Init Process | /init, init.rc, SELinux | Native User Space (Ring 3) | VFS Mount, Native Daemons 실행, Zygote 서비스 트리거 |
| Zygote | app_process, ART, JNI | Java / Native Hybrid | Dalvik/ART VM 생성, Common Classes/Resources Preload |
| SystemServer | AMS, PMS, WMS, ServiceManager | Framework User Space | Framework Core Services 구동, Boot Completed Broadcast 전송 |
4. 안드로이드 부팅 디버깅 및 분석을 위한 개발 팁 (AOSP Boot Debugging Tips)
4.1. bootchart 도구를 활용한 부팅 시간 병목 분석
AOSP 빌드 환경에서 bootchart를 활성화하면 부팅 중 발생되는 CPU 및 I/O 병목 구간을 시각화할 수 있습니다.
# Enable bootchart logging in AOSP target
adb shell touch /data/bootchart/start
adb reboot
# Extract bootchart logs after reboot
tar -czf bootchart.tgz -C /data/bootchart .
adb pull bootchart.tgz
# Render bootchart image using system tool
system/core/init/grab-bootchart.py
4.2. logcat 및 dmesg 시간 표준화를 통한 부팅 로그 추적
Kernel 시간과 Android Framework 시간축을 동기화하여 특정 디바이스 드라이버 로딩 또는 서비스 생성 지연 원인을 추적합니다.
# Print kernel boot logs with timestamps
adb shell dmesg -T
# Print system logs with thread time format and boot sequence tags
adb logcat -v threadtime -b main -b system -b kernel Zygote:* SystemServer:* ActivityManager:* *:S
5. 안드로이드 부팅 프로세스 개발 시 흔히 하는 실수 (Common Pitfalls & Fixes)
5.1. SystemServer 내 블로킹(Blocking) 작업 수행으로 인한 Watchdog Crash
SystemServer에서 서비스 초기화 중 synchronous I/O 작업 또는 무한 루프가 발생하면 Watchdog가 이를 감지하여 SystemServer를 종료시키고 reboot(무한 부팅) 현상이 유발됩니다.
// INCORRECT: Blocking main thread in SystemServer service initialization
public void onStart() {
// Direct synchronous network or disk I/O causes Watchdog trigger
performSyncBlockOperation();
}
// CORRECT: Offload heavy operations to a background HandlerThread
public void onStart() {
ServiceThread thread = new ServiceThread("MyCustomService", Process.THREAD_PRIORITY_BACKGROUND, true);
thread.start();
Handler handler = new Handler(thread.getLooper());
handler.post(() -> {
performSyncBlockOperation();
});
}
5.2. init.rc 내 서비스 의존성 및 IPC Socket 초기화 순서 오류
Zygote 및 Native Daemon 실행에 필요한 Unix Domain Socket이나 IPC Interface가 준비되지 않은 상태에서 상위 프로세스가 구동될 경우 binder 통신 실패 오류(Binder transaction failed)가 발생합니다. init.rc 선언 시 on property: 조건절 또는 class_start 지시어를 사용하여 종속성을 보장해야 합니다.
6. 결론 (Conclusion)
안드로이드 부팅 프로세스는 하드웨어 초기화부터 리눅스 커널 로딩, Native 영역의 init 프로세스 실행, 자바 영역의 Zygote 구동 및 SystemServer 프레임워크 서비스 활성화로 이어지는 유기적인 구조를 가집니다. 각 단계의 동작 원리와 소스코드 수준의 호출 흐름을 파악함으로써, 임베디드 및 AOSP 시스템 개발 시 발생하는 부팅 지연 및 시스템 크래시 이슈를 효율적으로 분석하고 최적화할 수 있습니다.