APK 파일에서 '설치'를 탭하거나 Play 스토어에서 앱을 다운로드하면 뒤에서 복잡한 작업 순서가 시작됩니다. 간단한 진행률 표시줄처럼 보이는 것은 실제로 패키지 구문 분석, 암호화 확인, 권한 관리, 파일 추출 및 코드 최적화와 관련된 수십 단계를 나타냅니다. 이 프로세스를 이해하면 설치가 때때로 실패하는 이유와 이에 대해 수행할 수 있는 작업을 설명하는 데 도움이 됩니다.
이 글에서는 시스템이 APK를 수신하는 순간부터 앱이 실행될 준비가 되는 시점까지 Android 설치 파이프라인의 모든 주요 단계를 살펴보겠습니다.
1단계: 설치 시작
설치 프로세스는 소스에 따라 다르게 시작됩니다.
- 플레이 스토어: Play 스토어 앱은 APK(또는 분할 APK)를 다운로드하고 일부 사용자 확인을 우회하는 특수 권한으로 시스템의 패키지 설치 프로그램을 호출합니다.
- 사이드로딩: APK 파일을 열면 Android는 패키지 설치 프로그램 활동을 시작합니다. Android 8.0 이상에서는 설치 앱에 특정 소스에 대한 '알 수 없는 앱 설치' 권한이 있어야 합니다.
- ADB: adb install 명령은 그래픽 설치 프로그램을 완전히 우회하여 USB를 통해 패키지 관리자 서비스와 직접 통신합니다.
소스에 관계없이 모든 설치는 결국 동일한 시스템 서비스인 에 도달합니다. 이는 Android의 모든 패키지 작업에 대한 중앙 권한입니다. 패키지 관리자 서비스
2단계: 패키지 구문 분석
무엇보다 먼저 시스템은 설치하려는 내용을 이해해야 합니다. PackageManagerService는 패키지파서를 호출하여 APK 파일을 읽고 해당 메타데이터를 추출합니다.
파서는 APK 내에서 AndroidManifest.xml 파일을 읽습니다. 이 바이너리 XML 파일에는 다음과 같은 중요한 정보가 포함되어 있습니다.
- 패키지 이름: 앱의 고유 식별자(예: com.example.myapp)
- 버전 코드 및 이름: 업그레이드인지 새로 설치인지 확인하는 데 사용됩니다.
- 최소 및 대상 SDK 버전: 장치와의 호환성을 결정합니다.
- 선언된 권한: 앱이 요청하는 권한과 앱이 정의하는 맞춤 권한 모두
- 구성요소: 앱이 등록하는 활동, 서비스, 방송 수신기 및 콘텐츠 제공자
- 하드웨어 및 소프트웨어 기능: 카메라, GPS 또는 특정 OpenGL 버전과 같은 요구 사항
매니페스트의 형식이 잘못되었거나 APK 구조가 유효하지 않은 경우 이 단계에서 '구문 분석 오류' 메시지와 함께 설치가 실패합니다. 이는 사이드로드된 APK가 설치되지 않는 가장 일반적인 이유 중 하나입니다.
3단계: 호환성 확인
매니페스트가 구문 분석되면 시스템은 일련의 호환성 검사를 수행합니다.
- SDK 버전: 앱의 minSdkVersion가 기기의 API 레벨보다 높을 경우 설치가 거부됩니다.
- ABI 호환성: APK에 네이티브 라이브러리가 포함되어 있으면 시스템은 해당 라이브러리가 기기의 CPU 아키텍처와 일치하는지 확인합니다. armeabi-v7a 라이브러리만 있는 APK는 x86 전용 기기에 설치되지 않습니다.
- 필수 기능: 앱이 필수 하드웨어 기능(예: android.hardware.telephony을 선언하면 시스템은 장치가 해당 기능을 지원하는지 확인합니다).
- 사용 가능한 저장 공간: 시스템은 추출된 네이티브 라이브러리 및 최적화된 DEX 파일을 위한 공간을 포함하여 앱을 설치할 수 있는 충분한 여유 공간이 있는지 확인합니다.
4단계: 서명 확인
이는 설치 과정에서 가장 중요한 단계 중 하나입니다. Android는 APK의 암호화 서명을 확인하여 무결성과 신뢰성을 보장합니다.
확인 프로세스는 어떤 서명 체계가 있는지에 따라 다릅니다.
V1 서명(JAR 서명)
시스템은 META-INF/ 디렉터리에서 서명 파일(.SF, .RSA 또는 .DSA을 확인합니다). APK의 각 파일은 매니페스트에 나열된 다이제스트를 기준으로 확인됩니다. 모든 파일을 개별적으로 해시해야 하기 때문에 속도가 느립니다.
V2 서명(APK 서명 체계 v2)
Android 7.0에 도입된 이 체계는 전체 APK를 바이너리 blob으로 서명합니다. 서명 블록은 ZIP 중앙 디렉터리와 중앙 디렉터리 끝 레코드 사이에 삽입됩니다. 개별 항목의 압축을 풀 필요 없이 원시 바이트에서 작동하기 때문에 확인이 훨씬 빠릅니다.
V3 서명(키 순환)
Android 9.0부터 사용 가능한 V3는 키 회전 지원을 통해 V2를 확장합니다. 여기에는 이전 서명 키와 새 서명 키를 연결하는 순환 증명 구조가 포함되어 있어 개발자가 업데이트 호환성을 유지하면서 서명 키를 변경할 수 있습니다.
V4 서명(증분)
Android 11에서는 증분 설치를 위해 V4를 도입했습니다. 이는 장치로 스트리밍될 때 개별 블록을 확인할 수 있는 머클 트리 기반 서명을 제공합니다.
어떤 이유로든 서명 확인에 실패하면 설치가 즉시 중단됩니다. APK 검증 도구를 사용하여 설치하기 전에 APK 서명을 확인할 수 있습니다.
서명 일치 업데이트
동일한 패키지 이름을 가진 앱이 이미 설치된 경우 시스템은 추가 확인을 수행합니다. 즉, 새 APK의 서명 인증서가 기존 설치 인증서와 일치해야 합니다. 이렇게 하면 악의적인 당사자가 합법적인 앱을 변조된 버전으로 바꾸는 것을 방지할 수 있습니다. 서명이 일치하지 않으면 "앱이 설치되지 않았습니다. 패키지가 동일한 이름의 기존 패키지와 충돌합니다."라는 오류가 표시됩니다.
5단계: 사용자 확인
사이드로드 설치의 경우 시스템은 다음을 보여주는 설치 확인 대화 상자를 표시합니다.
- 앱 이름 및 아이콘(APK 리소스에서 추출)
- 앱이 요청하는 권한(이전 Android 버전의 경우)
- 신규 설치인지 업데이트인지 여부
- 앱의 소스 또는 잠재적인 위험에 대한 경고
Android 12 이상에서는 런타임 권한이 설치 시점이 아닌 앱에 처음 필요할 때 개별적으로 부여되므로 확인 화면이 더 간단합니다.
6단계: 파일 추출 및 배치
사용자가 확인하면(또는 Play 스토어 설치의 경우 자동으로) 시스템이 파일 추출 및 배치를 시작합니다.
APK 저장소
APK 파일 자체가 /data/app/[package-name]-[random]/base.apk에 복사됩니다. 분할 APK 설치의 경우 split_config.arm64_v8a.apk와 같은 추가 파일이 기본 APK와 함께 배치됩니다. 다운로드 폴더의 원본 APK는 수정되거나 삭제되지 않습니다.
네이티브 라이브러리 추출
APK에 네이티브 라이브러리(lib/ 디렉터리)가 포함된 경우 /data/app/[package-name]-[random]/lib/[abi]/로 추출됩니다. 최신 Android 버전에서는 앱이 APK 내에 압축된 네이티브 라이브러리를 유지하고 android:extractNativeLibs="false"를 사용하여 직접 로드하도록 선택할 수 있으므로 저장 공간이 절약됩니다.
데이터 디렉토리 생성
시스템은 또는 다중 사용자 장치의 경우 /data/user/0/[package-name]/에 앱의 개인 데이터 디렉터리를 생성합니다. 이 디렉터리는 앱에 할당된 고유한 Linux UID가 소유하므로 루트 권한 없이는 다른 앱이 액세스할 수 없습니다. /data/data/[package-name]/
7단계: DEX 최적화
이 단계에서는 Android가 앱의 바이트코드를 기기의 특정 하드웨어에 최적화된 형식으로 변환합니다. 이 프로세스는 Android의 역사에 걸쳐 크게 발전했습니다.
Dalvik 시대(Android 4.4 이하)
원래 Dalvik 가상 머신은 JIT(Just-In-Time) 컴파일을 사용했습니다. 설치 중에 classes.dex 파일은 검증되고 최적화된 바이트코드가 포함된 ODEX 파일로 최적화되었습니다. 이는 상대적으로 빠르지만 대부분의 코드가 여전히 해석되므로 런타임 시 앱 실행 속도가 느려집니다.
AOT가 포함된 ART(Android 5.0~6.0)
Android 런타임(ART)은 Dalvik을 대체하고 AOT(Ahead-Of-Time) 컴파일을 도입했습니다. 설치 중에 전체 DEX 바이트코드가 기본 기계어 코드로 컴파일되었습니다. 이로 인해 앱 실행 속도가 빨라졌지만 설치 시간과 저장 공간 사용량이 크게 늘어났습니다. 일부 앱은 설치하는 데 몇 분이 걸렸습니다.
프로필 기반 컴파일(Android 7.0+)
최신 Android는 하이브리드 접근 방식을 사용합니다. 설치 중에는 중요한 시작 경로만 컴파일됩니다. 사용자가 앱을 실행하면 시스템은 자주 사용되는 코드 경로를 식별하는 실행 프로필을 수집합니다. 유휴 유지 관리 중에(일반적으로 밤새 충전하는 동안) 시스템은 이러한 핫 경로를 네이티브 코드로 컴파일합니다. 이는 설치 속도, 저장소 사용량 및 런타임 성능의 균형을 유지합니다.
컴파일된 코드는 /data/dalvik-cache/에 저장되거나 APK와 함께 .odex, .vdex 및 .art 파일로 저장됩니다. .vdex 파일에는 확인된 DEX 코드가 포함되어 있고, .odex 파일에는 컴파일된 네이티브 코드가 포함되어 있으며, .art 파일에는 더 빠른 시작을 위해 사전 초기화된 힙 이미지가 포함되어 있습니다.
8단계: 권한 등록
PackageManagerService는 앱이 선언한 권한과 구성 요소를 시스템에 등록합니다.
- 예: INTERNET 또는 VIBRATE는 사용자 상호 작용 없이 자동으로 부여됩니다. 설치 시간 권한
- 예: CAMERA 또는 LOCATION는 등록되었지만 부여되지 않았습니다. 앱은 런타임에 이를 요청해야 합니다. 런타임 권한
- 인텐트 필터는 어떤 앱이 어떤 작업(예: URL 열기 또는 콘텐츠 공유)을 처리할 수 있는지 시스템이 알 수 있도록 등록됩니다.
- 콘텐츠 제공자는 해당 기관에 등록되어 있으므로 다른 앱에서 쿼리할 수 있습니다.
9단계: 시스템 통합
마지막 단계는 앱을 Android 시스템에 통합합니다.
- 패키지 데이터베이스 업데이트: 시스템의 패키지 데이터베이스(/data/system/packages.xml는 할당된 UID, 권한 및 구성 요소 선언을 포함하여 새 앱의 정보로 업데이트됩니다).
- 런처 알림: 홈 화면 런처에 새로운 앱이 알려지면 앱 아이콘을 표시할 수 있습니다.
- 방송: 시스템은 PACKAGE_ADDED 브로드캐스트를 전송하여 다른 앱이 새 설치에 반응할 수 있도록 합니다(예: 백업 앱이 백업을 예약할 수 있음).
- SELinux 컨텍스트: 앱의 파일에는 대상 SDK 버전 및 선언된 권한을 기반으로 적절한 SELinux 보안 컨텍스트로 레이블이 지정됩니다.
설치가 실패하는 이유
설치 파이프라인을 이해하면 일반적인 오류를 진단하는 데 도움이 됩니다.
- "파싱 오류": APK가 손상되었거나 불완전하거나 잘못된 매니페스트가 있습니다. 이는 불완전한 다운로드나 부적절하게 변환된 파일에서 자주 발생합니다.
- "앱이 설치되지 않았습니다"(서명 불일치): 다른 키로 서명된 APK로 앱을 업데이트하려고 합니다. 먼저 기존 버전을 제거해야 합니다.
- "저장 공간 부족": APK, 추출된 라이브러리, DEX 최적화 출력을 위한 공간이 부족합니다. 필요한 실제 공간은 일반적으로 APK 크기의 2~3배입니다.
- "패키지가 기존 패키지와 충돌합니다": 동일한 패키지 이름이지만 서명이 다릅니다. Play Store와 사이드로드 버전 간에 전환할 때 일반적입니다.
- 버전 다운그레이드가 차단됨: 기본적으로 Android는 최신 버전 위에 이전 버전을 설치하는 것을 방지합니다. ADB는 이를 adb install -d로 재정의할 수 있습니다.
분할 APK 설치
앱 번들(AAB)에서 분할 APK를 설치하는 경우 프로세스가 약간 다릅니다. 시스템은 세션 기반 설치 API를 사용합니다.
- 새 설치 세션이 생성됩니다.
- 각 분할 APK가 세션에 기록됩니다.
- 세션이 커밋되어 전체 확인 파이프라인이 트리거됩니다.
- 모든 분할에는 일치하는 패키지 이름, 버전 코드 및 서명 인증서가 있어야 합니다.
이는 다중 파일 설치를 처리하기 위해 XAPK 설치 프로그램 및 APKS에서 APK로의 합병와 같은 도구에서 사용되는 메커니즘입니다.
ADB를 통한 설치
adb install를 사용하면 프로세스가 그래픽 설치 프로그램을 우회하지만 동일한 내부 파이프라인을 따릅니다. ADB는 소켓 연결을 통해 패키지 관리자 서비스와 통신합니다. GUI를 통해 사용할 수 없는 추가 플래그를 지원합니다.
- -r: 기존 앱 교체(재설치 허용)
- -d: 버전 다운그레이드 허용
- -g: 모든 런타임 권한을 즉시 부여합니다.
- -t: 테스트 전용 APK 설치 허용
- --install-multiple: 단일 세션에 분할 APK 설치
제거 중 발생하는 상황
완전성을 위해 앱이 제거되면 다음과 같은 일이 발생합니다.
- 앱의 프로세스가 종료되었습니다.
- APK 및 추출된 라이브러리가 /data/app/에서 삭제됩니다.
- 앱의 개인 데이터 디렉터리가 제거됩니다(사용자가 데이터 유지를 선택하지 않은 경우).
- 컴파일된 DEX 캐시 파일이 삭제됩니다.
- 패키지 데이터베이스가 업데이트되었습니다.
- PACKAGE_REMOVED 브로드캐스트가 전송됩니다.
- 런처가 앱 아이콘을 제거합니다.
범위 지정 저장소 적용으로 인해 Android 10 이상에서는 외부 저장소(/Android/data/[package]/ 및 /Android/obb/[package]/의 앱별 파일도 삭제됩니다).
PackageManager를 이해하면 디버깅 시간이 절약되는 이유
Android 설치 프로세스는 보안 검사, 파일 작업 및 시스템 통합이 신중하게 조정된 순서입니다. 각 단계는 변조된 앱으로부터 사용자를 보호하는 것부터 특정 하드웨어의 성능을 최적화하는 것까지 목적을 달성합니다. 설치가 실패하면 오류는 일반적으로 이 파이프라인의 특정 단계를 가리키며, 프로세스를 이해하면 문제를 신속하게 진단하고 해결하는 데 도움이 됩니다.
Play 스토어에서 설치하고, APK를 직접 사이드로딩하고, 동일한 기본 파이프라인을 통해 ADB 모든 퍼널을 사용하여 빌드를 푸시합니다. 이를 통해 기기의 모든 앱이 하드웨어에 맞게 검증되고 올바르게 배치되고 최적화되었는지 확인할 수 있습니다.