우리가 구글 플레이 스토어나 개발 디버깅 툴을 통해 APK 설치 파일 버튼을 누르면 단 몇 초 만에 앱이 시스템에 등록되고 아이콘이 생성됩니다. 이 과정에서 안드로이드 OS 내부에서는 해당 앱이 안전한지 서명을 검증하고, 어떤 권한을 요구하는지 명세서를 파싱하며, 단말기 아키텍처에 맞게 바이너리를 최적화하여 샌드박스 폴더에 안착시키는 복잡한 연쇄 공정이 일어납니다.
이 모든 패키지의 탄생과 소멸, 그리고 권한 검증 주권을 총괄하는 핵심 서비스가 바로 PackageManagerService(이하 PMS)입니다. PMS는 안드로이드 system_server 프로세스가 구동될 때 단말기 내부의 모든 파일 시스템을 샅샅이 뒤져 설치된 앱들의 데이터 지도를 뇌리에 각인하는 시스템 핵심 서비스입니다. 플랫폼 리소스를 제어하는 OS 엔지니어는 물론, 런타임 권한 예외나 딥링크 매핑을 정밀 제어해야 하는 앱 개발자 모두에게 PMS 내부 구조 파악은 프레임워크 통달을 위한 필수 관문입니다. 본 포스팅에서는 최신 AOSP(Android Open Source Project) 마스터 소스코드를 바탕으로 PMS의 핵심 컴포넌트와 APK 설치 및 삭제 파이프라인의 실체를 완전히 해부해 보겠습니다.

📌 핵심 요약 3줄
- **PackageManagerService(PMS)**는 안드로이드 시스템 내 APK 패키지의 설치, 삭제, 권한 부여 및 인텐트 필터 해석을 관장하는 전권 사령탑입니다.
- 내부적으로 레거시 PackageParser 구조를 탈피하여 PackageParser2, Settings, PermissionManagerService 등의 최신 아키텍처 컴포넌트를 결합해 런타임 앱 메타데이터를 유지합니다.
- 앱 설치 시 InstallPackageHelper를 통해 물리적 APK 검증 및 파싱을 수행하며, 완료 시점에 전역 브로드캐스트를 유기적으로 가동하여 시스템에 새 앱의 탄생을 알립니다.
1. PMS의 중심을 이루는 6대 핵심 데이터 컴포넌트
PMS가 단말 전역의 패키지 상태와 보안 환경을 유지하기 위해 내부적으로 분할 운영하는 6대 핵심 구성 요소 명세표입니다.
| 구성 요소 명칭 | 최신 AOSP 상주 경로 파이프라인 | 패키지 제어 서브시스템 내부에서의 핵심 역할 |
| PackageManagerService | com.android.server.pm.PackageManagerService | 패키지 관리 서브시스템의 메인 컨트롤러. 부팅 시 시스템 서버에 바인더로 등록되며 전방위 앱 트래픽 중재 |
| Installer | com.android.server.pm.Installer | 네이티브 데몬(installd)과의 소켓 통신 가교. 실제 리눅스 파일 시스템 상에서 디렉터리 생성 및 권한 부여 수행 |
| PackageParser2 | com.android.server.pm.parsing.PackageParser2 | APK 바이너리 정밀 해부기. AndroidManifest.xml 내부의 컴포넌트 정보와 인텐트 필터를 메모리 객체로 파싱 |
| Settings | com.android.server.pm.Settings | 패키지 영구 기억 장치. 앱들의 고유 UID 할당 상태 및 설치 경로 메타데이터 정보를 packages.xml 파일에 저장 및 관리 |
| DexManager | com.android.server.pm.dex.DexManager | 런타임 컴파일 최적화 가이드. 앱 실행 빈도 데이터를 기반으로 ART(Android Runtime) 환경의 ART/OAT 파일 최적화 상태 스캔 |
| PermissionManagerService | com.android.server.pm.permission.PermissionManagerService | 런타임 권한의 절대 심판관. 각 패키지별 권한 선언 여부와 사용자가 허용한 권한 매트릭스를 동적으로 매핑 및 방어 |
2. AOSP 코드로 파헤치는 PMS 부팅 및 5단계 파일 시스템 스캔
PMS는 안드로이드 부팅 초기 단계에서 단말기 내부의 모든 저장소를 강도 높게 동기식 스캔하여 메모리에 패키지 지도를 빌드합니다.
2.1 SystemServer에서의 PMS 동기식 점화 구조
// frameworks/base/services/java/com/android/server/SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
t.traceBegin("StartPackageManagerService");
// [AOSP 마스터 표준] 내부 헬퍼 클래스를 가동하여 의존성 주입 체계 기반으로
// PackageManagerService 정식 싱글톤 인스턴스를 메모리에 빌드합니다.
PackageManagerService m = PackageManagerService.main(context, installer,
domainVerificationService, factoryTest, mOnlyCore);
t.traceEnd();
}
2.2 PMS 부팅 시 내부 파일 시스템 5단계 스캔 시퀀스
PMS 부팅자가 가동되면 내부적으로 시스템 파티션부터 사용자 데이터 영역까지 정해진 우선순위 경로 규칙에 따라 순차적 덤프 스캔을 진행합니다.
| 부팅 스캔 단계 | 타깃 파일 시스템 타깃 경로 | 스캔 대상 및 PMS 내부 바인딩 데이터 성격 |
| 1단계: 시스템 코어 스캔 | /system/framework/, /system/app/ | 단말 구동에 필수적인 안드로이드 OS 코어 라이브러리와 필수 시스템 번들 애플리케이션 적재 |
| 2단계: 제조사 커스텀 스캔 | /vendor/app/, /odm/app/ | 칩셋 제조사(AP) 및 단말 벤더사 고유의 하드웨어 제어용 특화 패키지 스캔 |
| 3단계: 권한 및 특권 앱 스캔 | /system/priv-app/ | 시스템 최상위 권한을 행사할 수 있는 특권(Privileged) 지위를 가진 핵심 앱 서명 확인 |
| 4단계: 서드파티 앱 스캔 | /data/app/ | 사용자가 플레이 스토어나 디버깅으로 직접 설치한 일반 애플리케이션의 APK 공간 스캔 및 매핑 |
| 5단계: 데이터 정합성 크로스체크 | /data/system/packages.xml | 앞선 1~4단계 스캔 결과와 기존에 저장된 설정 파일의 UID/서명 정보를 비교 대조하여 최종 맵 픽스 |
3. APK 패키지 설치 파이프라인 심층 코드 분석
사용자가 새로운 APK를 단말에 투입했을 때, 최신 AOSP 프레임워크 내부의 독립 헬퍼 객체들이 바인더 장벽을 넘어 파일 시스템을 제어하는 실시간 런타임 흐름입니다.
3.1 PackageInstallerService 입구 계층
// frameworks/base/services/core/java/com/android/server/pm/PackageInstallerService.java
@Override
public void installPackage(VersionedPackage versionedPackage, String installerPackageName,
IntentSender statusReceiver, int userId) {
// 앱이 요청한 설치 트래픽 세션의 유효성을 체크한 뒤 PMS 의 컨텍스트 파이프라인으로 이송합니다.
mPm.mInstallPackageHelper.installPackageAsUser(versionedPackage, installerPackageName,
statusReceiver, userId);
}
3.2 InstallPackageHelper의 APK 해부 및 파일 복사 계층
최신 안드로이드 아키텍처에서는 거대했던 내부 스크립트들이 InstallPackageHelper 도메인 객체로 이관되어 보안 검증과 이송을 전담합니다.
// frameworks/base/services/core/java/com/android/server/pm/InstallPackageHelper.java
public void installPackageLI(InstallParams params, InstallArgs args, PackageInstalledInfo res) {
// 1. 최신 PackageParser2 인스턴스를 소환하여 APK 내 매니페스트 XML 의 컴포넌트 스펙을 정밀 파싱합니다.
final PackageParser2 pp = mPm.mInjector.getSearchingPackageParser2();
final ParsedPackage parsedPackage = pp.parsePackage(args.codeFile, pp.PARSE_MUST_BE_APK, ...);
// 2. 해당 APK 의 무결성과 개발자 서명이 위변조되지 않았는지 암호학적 검증을 집행합니다.
SigningDetails signingDetails = ParsedPackageSigningRepository.getSigningDetails(parsedPackage);
// 3. 검증이 통과되면 네이티브 데몬인 installd 와 소켓을 열어 안전한 /data/app/ 격리 디렉터리로 바이너리를 카피합니다.
mPm.mInstaller.createAppData(args.volumeUuid, parsedPackage.getPackageName(), ...);
}
3.3 설치 완료 통보 및 인텐트 브로드캐스트 발송 계층
설치 공정이 에러 없이 완결되면 PMS는 시스템 전체에 런타임 이벤트를 공표하여 런처 앱 등이 새 아이콘을 즉시 갱신할 수 있도록 지원합니다.
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
void sendPackageBroadcast(final String action, final String pkg, final Bundle extras, ...) {
// 인텐트 객체에 ACTION_PACKAGE_ADDED 플래그를 결합합니다.
Intent intent = new Intent(action, Uri.fromParts("package", pkg, null));
if (extras != null) {
intent.putExtras(extras);
}
// AMS 비동기 메시지 채널을 경유하여 시스템 전역의 브로드캐스트 리시버들에게 새 앱의 탄생을 통보합니다.
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
}
4. APK 패키지 삭제 파이프라인 소스코드 분석
더 이상 필요 없어진 앱을 언인스톨할 때 호출되는 영구 삭제 로직으로, RemovePackageHelper 가 중심이 되어 데이터베이스와 물리 디렉터리를 정밀 소거합니다.
// frameworks/base/services/core/java/com/android/server/pm/RemovePackageHelper.java
public void removePackageLI(AndroidPackage pkg, boolean chatty) {
final String packageName = pkg.getPackageName();
// 1. 메모리 상의 실시간 인텐트 필터 맵과 컴포넌트 리스트 리지스트리에서 해당 앱의 정보를 영구 격리 배제합니다.
mPm.mComponentResolver.removeAllComponentsOfPackage(pkg);
// 2. 네이티브 가교를 타격하여 /data/user/ 영역에 적재되어 있던 앱의 내부 캐시 및 샌드박스 내부 데이터 폴더를 완파합니다.
mPm.mInstaller.destroyAppData(pkg.getVolumeUuid(), packageName, ...);
// 3. 영구 파일 시스템 설정 엔진인 Settings 데이터베이스 스토리지 내에서 해당 패키지의 노드를 완전히 지웁니다.
mPm.mSettings.removePackageLPw(packageName);
}
5. 앱 실행을 위한 핵심 정보 조회(getPackageInfo) 인터페이스
일반 애플리케이션 프레임워크 단에서 PMS 바인더 인터페이스를 원격 노킹하여 타깃 앱의 버전 및 신원 명세서를 획득하는 로우 레벨 바인딩 관문입니다.
// frameworks/base/services/core/java/com/android/server/pm/IPackageManagerImpl.java
@Override
public PackageInfo getPackageInfo(String packageName, long flags, int userId) {
// 클라이언트의 바인더 접근 권한 샌드박스를 사전 검증합니다.
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, null);
// 내부 컴퓨터 스냅샷 객체를 소환하여 찰나의 순간에 패키지 정보 오브젝트를 안전하게 리턴합니다.
return mComputer.getPackageInfoInternal(packageName, flags, Process.SYSTEM_UID, userId);
}
💡 안드로이드 프레임워크 최적화를 위한 실전 팁
- sharedUserId 레거시 구조 탈피를 통한 PMS 스캔 오버헤드 및 보안 취약점 방어: 과거 안드로이드 환경에서는 여러 앱을 동일한 리눅스 UID 선상에 묶어 내부 자원을 프리패스로 공유하고자 android:sharedUserId 속성을 남발하곤 했습니다. 하지만 최신 안드로이드 프레임워크 빌드 환경에서 이 속성은 PMS가 부팅 시 UID 연산 맵을 복잡하게 꼬아놓아 시스템 부팅 부하를 폭등시킬 뿐만 아니라 샌드박스 보안 경계를 파괴하는 주범으로 지목되어 Deprecated 되었습니다. 동일 제조사 앱 간 데이터 공유가 필요하다면 sharedUserId를 과감히 제거하고, 현대적인 ContentProvider에 맞춤형 커스텀 시그니처 권한(android:protectionLevel="signature")을 바인딩하여 운영하는 것이 PMS 런타임 맵 메모리를 아끼고 보안 성능을 극대화하는 올바른 설계 방향입니다.
- PackageManager.MATCH_DEFAULT_ONLY 플래그의 명시적 선언을 통한 바인더 쿼리 병목 최적화: 외부 앱의 실행 가능성이나 인텐트 분배 가능 여부를 조회하기 위해 queryIntentActivities() 계층 API를 무심코 플래그 없이 전수 호출하면, PMS는 내부 컴포넌트 리졸버의 방대한 인텐트 필터 트리를 깊은 레벨까지 전수 스캔하느라 바인더 스레드를 장시간 점유하게 됩니다. 특정 암시적 인텐트를 수용할 수 있는 액티브 앱 목록만 빠르게 필터링하고 싶다면 조회 플래그 상수에 반드시 해당 매칭 속성을 비트 연산 합산해 주세요. WMS, AMS 와 연동된 인텐트 분석 필터 처리 속도가 기하급수적으로 단축되어 앱 전환 시 발생하는 미세한 프레임 랙을 예방할 수 있습니다.
⚠️ 흔히 하는 실수
- 부팅 스캔 파이프라인 내부에 동기식 파일 I/O 가공 코드를 강제 주입하여 무한 부팅 벽돌(Bootloop) 유발: 제조사 단말 커스텀이나 특수 목적의 임베디드 안드로이드 OS를 빌드하는 엔지니어들이 특정 패키지가 로드될 때 설정 값을 커스텀 파싱하겠다며, PMS의 초기화 스캔 함수 내부나 Settings.java 로직 한복판에 별도의 파일 입력 스트림이나 네트워크 블로킹 동기화 코드를 직접 심어버리는 치명적인 실수입니다. 안드로이드의 시스템 부팅 초기 시퀀스는 엄격한 타임아웃 감시자인 워치독(Watchdog) 서비스가 상시 밀착 감시하고 있습니다. PMS 스캔 루프가 특정 파일 입출력 병목으로 인해 단 몇 초라도 멈춰 서 버리면 워치독은 시스템 서버 전체가 영구 데드락 상태에 빠진 것으로 판단하여 프레임워크 커널 프로세스를 강제로 킬(Kill)해 버리고 단말을 재부팅 시스템 루프(Bootloop) 무한 궤도에 빠뜨립니다. 대용량 메타데이터 가공은 반드시 부팅 스캔이 완료된 사후 시점에 비동기 워커 스레드로 완전히 격리 배정해야 합니다.
- 런타임 권한 갱신 후 PermissionManagerService 상태 동기화 누락으로 인한 불시의 크래시 방치: 시스템 앱이나 플랫폼 앱 레벨에서 사용자의 특정 권한 상태를 수동으로 강제 조정한 뒤, PMS 계층 및 하부 권한 캐시 컨텍스트에 변경 사실을 동기화(flush 또는 관련 리셋 인터페이스 호출)해 주지 않을 때 터지는 고질적인 프레임워크 예외입니다. 메모리 상의 권한 캐시 맵과 실제 저장된 권한 마스크의 상태 불일치가 발생하면, 앱은 권한이 정상 부여된 것으로 인지하고 기분 좋게 리눅스 하드웨어 드라이버나 시스템 API를 찌르지만, 커널 단에서 보안 예외가 터지면서 SecurityException 과 함께 프로세스가 그 자리에서 불시 크래시(Crash)를 일으킵니다. 권한 매트릭스를 직접 건드릴 때는 반드시 원자적 영구 저장이 완결되었는지 동기화 시퀀스를 이중 체크해야 합니다.
6. 결론
Android 시스템의 철저한 보안 가디언이자 파일 스토리지의 입구 지휘소인 PackageManagerService는 OS 내부의 리눅스 권한 체계와 애플리케이션 프레임워크 레이어의 컴포넌트 메타데이터를 유기적으로 동기화해 내는 가장 방대하고 정밀한 데이터베이스 서비스입니다. 시스템 부팅 단계에서 일어나는 5단계 파일 스캔의 순차적 흐름을 명확히 이해하고, InstallPackageHelper 가 가동하는 최신 AOSP 패키지 파싱 파이프라인의 실체를 완전히 제어할 수 있을 때, 비로소 외부 해킹 위협으로부터 단말을 완벽히 방어해 내고 수백 개의 앱이 깔린 환경에서도 단 1초의 딜레이 없는 초고속 부팅 아키텍처를 구현해 낼 수 있습니다.
'Android System & AOSP Engineering > AOSP Framework & Custom Services' 카테고리의 다른 글
| 안드로이드 바인더 구조 분석: Binder IPC 작동 원리와 1-Copy 메모리 매핑 메커니즘 (0) | 2025.04.12 |
|---|---|
| 안드로이드 PMS 구조 분석: PowerManagerService의 WakeLock 제어와 배터리 도즈 모드 메커니즘 (0) | 2025.04.11 |
| 안드로이드 WMS 구조 분석: WindowManagerService의 윈도우 관리와 AOSP 레이어링 메커니즘 (0) | 2025.04.09 |
| 안드로이드 AMS 구조 분석: ActivityManagerService의 프로세스 생명주기와 AOSP 소스코드 해부 (0) | 2025.04.08 |
| 안드로이드 프레임워크 구조 분석: AMS, WMS, PMS 핵심 시스템 서비스와 AOSP 소스코드 탐구 (0) | 2025.04.07 |