우리가 매일 사용하는 스마트폰의 전원 버튼을 길게 누르면, 브랜드 로고가 잠시 나타난 뒤 이내 익숙한 홈 화면(런처)이 우리를 맞이합니다. 사용자 처지에서는 불과 수십 초 남짓한 짧은 순간이지만, 기기 내부에서는 하드웨어를 깨우고 운영체제를 올린 뒤 수많은 시스템 서비스를 가동하는 복잡한 연쇄 반응이 일어납니다.
안드로이드 애플리케이션 프레임워크나 임베디드 단을 깊이 있게 다루는 개발자라면 시스템이 어떤 순서로 초기화되고 메인 가상 머신이 어떻게 자리를 잡는지 이해하는 것이 매우 중요합니다. 시스템의 전체적인 생명주기를 파악할 수 있기 때문이죠. 이번 포스팅에서는 AOSP(Android Open Source Project) 소스 코드와 함께 안드로이드 부팅의 4대 핵심 단계를 완벽히 정리해 보겠습니다.

📌 핵심 요약 3줄
- 안드로이드 부팅은 하드웨어를 초기화하는 부트로더 단계에서 출발하여, 리눅스 커널을 거쳐 최초의 사용자 공간 프로세스인 init을 실행합니다.
- init 프로세스는 init.rc 스크립트를 분석해 안드로이드 자바 세상의 뿌리가 되는 Zygote와 핵심 시스템 서비스를 품은 System Server를 가동합니다.
- System Server의 핵심 서비스들이 준비되면 ActivityManagerService(AMS)가 최종적으로 런처 앱을 화면에 띄우며 부팅 시퀀스가 마무리됩니다.
1. 안드로이드 부팅 단계 한눈에 보기
복잡하게 얽힌 부팅의 전체 흐름을 타임라인 순으로 먼저 정리해 드립니다. 이 흐름을 머릿속에 넣어두고 아래 세부 내용을 읽으시면 훨씬 이해하기 수월합니다.
| 부팅 단계 | 실행 주체 / 프로세스 | 주요 역할 및 수행 작업 | 관련 AOSP 디렉터리 경로 |
| 1단계: 하드웨어 깨우기 | Bootloader | CPU, RAM 초기화 및 부트 이미지(커널)를 램(RAM)에 로드 후 실행 | bootable/bootloader/ |
| 2단계: OS 및 기반 다지기 | Linux Kernel & init | 드라이버 로드, ramdisk 마운트 후 첫 사용자 프로세스인 init 가동 및 init.rc 스크립트 실행 | system/core/init/ |
| 3단계: 자바 세상의 탄생 | Zygote & System Server | ART 가상 머신 최적화(클래스 프리로드), 안드로이드 핵심 서비스(AMS, WMS, PMS) 프로세스 생성 | frameworks/base/cmds/app_process/ |
| 4단계: 사용자 마주하기 | Framework & Launcher | 시스템 서비스 초기화 완료 후 런처(홈 화면) 앱을 가동하여 사용자 입력 대기 | frameworks/base/services/ |
2. 1단계: 부트로더(Bootloader) 실행
기기의 전원이 켜지면 하드웨어 칩셋(SoC)에 내정된 ROM 코드가 가동되면서 가장 먼저 부트로더(Bootloader)가 실행됩니다. 삼성 Exynos, 퀄컴 Snapdragon 등 하드웨어 칩셋 제조사마다 구체적인 코드는 다르지만 본연의 임무는 같습니다.
- 하드웨어 기본 초기화: 시스템 연산을 위해 메인 프로세서(CPU)와 메모리(RAM), 스토리지 장치를 안전하게 깨웁니다.
- 부트 파티션 검색: 저장 장치에서 리눅스 커널이 담긴 부트 이미지를 찾아 메모리로 복사합니다.
- 제어권 이양: 준비가 끝나면 리눅스 커널을 메모리에 올리고 실행시키며 부트로더는 임무를 마칩니다.
3. 2단계: 커널 및 init 프로세스 실행
3.1 리눅스 커널 로딩
부트로더에게 바톤을 이어받은 리눅스 커널은 본격적으로 운영체제로서의 기본 환경을 구축합니다. 메모리 관리 유닛을 활성화하고 오디오, 디스플레이, 네트워크 등의 하드웨어 드라이버를 메모리에 바인딩합니다. 이후 임시 루트 파일 시스템(ramdisk)을 마운트한 뒤, 모든 리눅스 시스템의 조상 격인 첫 번째 사용자 공간 프로세스인 init을 호출합니다.
3.2 init 프로세스의 구동과 환경 설정
안드로이드의 init은 일반 리눅스와 다르게 모바일 환경에 최적화된 형태로 짜여 있습니다. 시스템 구동에 필요한 규칙이 적힌 init.rc 파일(설정 스크립트)을 파싱하여 읽어 들이는 게 가장 큰 역할입니다.
AOSP 소스의 system/core/init/ 내부 설정 파일들을 살펴보면, 자바 세상을 열어줄 Zygote 서비스를 다음과 같이 데몬 형태로 등록하여 실행하는 코드를 볼 수 있습니다.
# init.rc 스크립트 중 Zygote 서비스 등록 예시
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
user root
group root
onrestart restart zygote
이 설정 덕분에 init 프로세스는 시스템에 필요한 기본 데몬(vold, ueventd 등)을 띄운 뒤, 바로 이 zygote 명령어를 호출하게 됩니다.
4. 3단계: Zygote 및 System Server 실행
이 단계부터 본격적인 '안드로이드 골격'이 갖춰지기 시작합니다. C/C++ 기반의 저수준 영역에서 자바/코틀린 기반의 프레임워크 영역으로 넘어가는 연결 고리입니다.
4.1 Zygote (세포 분열의 시작)
Zygote는 이름 뜻 그대로 '접합자(수정란)' 역할을 합니다. 안드로이드에서 새로운 앱 프로세스를 만들 때 처음부터 새로 만드는 게 아니라, 자기 자신을 복제(fork)해서 나누어주는 독특한 방식으로 아키텍처가 설계되어 있습니다. 가상 머신(ART)을 미리 깔끔하게 띄워두고 핵심 자바 클래스들을 메모리에 미리 올려둔(preload) 상태에서 대기하는 것이죠.
AOSP의 com.android.internal.os.ZygoteInit 자바 클래스 코드를 보면 이 메인 루프를 확인할 수 있습니다.
public static void main(String argv[]) {
ZygoteServer zygoteServer = new ZygoteServer();
RuntimeInit.enableDdms();
// 1. 공통으로 사용할 안드로이드 프레임워크 클래스와 리소스를 메모리에 미리 로드 (성능 최적화의 핵심)
preload();
// 2. 부팅 과정의 핵심 파트너인 System Server 프로세스를 복제(fork) 방식으로 실행
if (argv.length > 1 && argv[1].equals("--start-system-server")) {
forkSystemServer(abiList, socketName, zygoteServer);
}
// 3. 이후 새로운 앱을 실행하라는 요청이 올 때까지 소켓을 열고 무한 대기
zygoteServer.run();
}
4.2 System Server (프레임워크의 심장)
Zygote가 가장 먼저 복제(fork)해서 만들어내는 거대한 자바 프로세스가 바로 System Server입니다. 우리가 안드로이드 개발을 할 때 컨텍스트를 통해 호출하는 프레임워크의 핵심 '매니저 서비스'들이 전부 이 프로세스 안에서 생성되고 살아 움직입니다.
com.android.server.SystemServer 코드를 보면 시스템의 심장부 서비스들을 하나씩 깨우는 루프가 작동합니다.
public static void main(String[] args) {
// System Server 객체를 생성하고 내부 런타임 가동
new SystemServer().run();
}
private void run() {
// 1. 핵심 서비스 카테고리별 순차 초기화
startBootstrapServices(); // ActivityManagerService(AMS), PowerManagerService 등
startCoreServices(); // BatteryService, UsageStatsService 등
startOtherServices(); // WindowManagerService(WMS), PackageManagerService(PMS) 등
}
5. 4단계: 애플리케이션 프레임워크 및 런처 실행
System Server 내부에 포진한 수많은 시스템 서비스가 모두 성공적으로 초기화되면, 비로소 사용자와 소통할 수 있는 마지막 단계에 도달합니다.
5.1 런처(Launcher) 앱의 가동
초기화를 마친 ActivityManagerService(AMS)는 시스템 부팅 완료 이벤트를 내부적으로 전송하면서, 기기의 기본 홈 화면으로 등록된 런처(Launcher) 애플리케이션을 찾아 실행하라는 명령을 내립니다.
5.2 일반 애플리케이션 프로세스 생성 메커니즘
런처 앱이 화면에 뜨면 드디어 부팅 시퀀스는 끝이 납니다. 이후 사용자가 홈 화면에서 카카오톡이나 유튜브 같은 일반 앱 아이콘을 터치하면 다음과 같은 매커니즘으로 프로세스가 열립니다.
- AMS의 요청: 런처가 터치 신호를 받아 AMS에 해당 앱을 실행해 달라고 요청합니다.
- Zygote의 Fork: AMS는 소켓 통신을 통해 3단계에서 대기 중이던 Zygote 프로세스에 프로세스 생성을 요청합니다.
- 앱 구동: Zygote는 미리 프레임워크 클래스들을 로드해 둔 가상 머신 상태 그대로 프로세스를 fork()하여 떼어내 줍니다. 덕분에 안드로이드 앱들은 매번 무겁게 가상 머신을 처음부터 만들 필요 없이 아주 빠르게 실행될 수 있습니다.
💡 안드로이드 부팅 시퀀스 관련 실전 팁
- BOOT_COMPLETED 브로드캐스트 리시버 주의 사항: 기기 부팅이 끝난 시점에 앱이 자동으로 백그라운드 작업을 시작하게 하려면 android.intent.action.BOOT_COMPLETED 액션을 수신해야 합니다. 하지만 안드로이드 최신 버전은 배터리 및 보안 강화를 위해 사용자가 부팅 후 최소 한 번 기기 잠금을 해제(Direct Boot)하기 전까지는 일반적인 데이터 영역에 접근하지 못하게 막아둡니다. 부팅 직후 꼭 실행되어야 하는 컴포넌트라면 매니페스트에 android:directBootAware="true" 설정을 반드시 고려해야 합니다.
- 부팅 최적화와 프리로드(Preload) 이해: Zygote가 부팅 시 preload()하는 클래스가 많을수록 개별 앱들의 실행 속도는 빨라지지만, 전체 부팅 시간은 길어지고 기본 시스템의 메모리 점유율이 높아집니다. 맞춤형 안드로이드 하드웨어(Kiosk 단말기, 인포테인먼트 등)를 커스텀 제작하는 임베디드 개발자라면 frameworks/base/config/preloaded-classes 파일을 튜닝하여 타겟 시스템에 최적화된 부팅 속도를 확보할 수 있습니다.
⚠️ 흔히 하는 실수
- Application 클래스의 onCreate()에서 무거운 작업 수행: 사용자가 앱 아이콘을 눌러 Zygote가 프로세스를 fork한 직후, 가장 먼저 실행되는 곳이 커스텀 Application 클래스의 onCreate()입니다. 부팅 시 런처가 뜨는 속도나 앱이 처음 켜지는 속도를 빠르게 하겠다고 이곳에 무거운 초기화 로직(SDK 초기화, DB 로드, 네트워크 통신 등)을 동기(Sync) 방식으로 잔뜩 집어넣으면 앱의 첫 화면 렌더링이 멈추는 불상사가 생깁니다. 무거운 초기화는 반드시 백그라운드 스레드나 Jetpack App Startup 라이브러리를 활용해 비동기로 분산시켜야 합니다.
- Zygote의 static 자원 공유 메커니즘 오해: Zygote는 자원을 미리 메모리에 올려두고 fork()로 프로세스를 복제하므로, 프리로드된 정적(static) 데이터는 모든 앱이 초기 상태를 공유하게 됩니다. 만약 시스템 레이어(AOSP)를 직접 커스텀하는 개발자가 프리로드 단계에서 변경 가능한(Mutable) static 객체를 잘못 설계하면, 한 앱에서 바꾼 글로벌 정적 상태가 기기 안의 다른 앱 프로세스 전체에 나비효과처럼 오동작을 유발하는 치명적인 버그가 생길 수 있습니다.
6. 결론
안드로이드의 부팅 과정은 단순한 소프트웨어 실행을 넘어, 하드웨어 장치를 정교하게 제어하는 리눅스 커널의 기술과 앱 가동 속도를 극대화하기 위해 고안된 Zygote의 아이디어가 결합한 아름다운 협업의 결과물입니다. 전원 버튼을 누른 순간부터 런처 앱이 뜨기까지의 레이어 이동 흐름을 완벽히 이해한다면, 향후 ANR 분석이나 시스템 레벨의 최적화 작업을 진행할 때 훨씬 깊이 있고 직관적인 해결책을 찾아내실 수 있을 것입니다.
오늘 정리해 드린 부팅 시퀀스가 안드로이드 전체 생태계를 이해하는 든든한 디딤돌이 되었기를 바랍니다.
'Android System & AOSP Engineering > AOSP Framework & Custom Services' 카테고리의 다른 글
| 안드로이드 HAL 구조 완벽 정리: AIDL 하드웨어 추상화 계층과 Treble 아키텍처 분석 (0) | 2025.03.19 |
|---|---|
| AOSP 커스텀 안드로이드 빌드 환경 구축 가이드: 환경 설정부터 에뮬레이터 구동까지 (0) | 2025.03.18 |
| AOSP 안드로이드 빌드 시스템 총정리: Android.mk(Make)에서 Android.bp(Soong)로의 진화 (0) | 2025.03.17 |
| 안드로이드 아키텍처 완벽 분석: Linux 커널부터 AOSP 소스 코드까지 계층별 총정리 (0) | 2025.03.15 |
| 안드로이드(Android) 역사와 OS 발전사 총정리: 탄생부터 AOSP 아키텍처까지 (0) | 2025.03.14 |