The Package Manager
PackageManagerService is where an APK becomes an app: it parses the manifest, verifies the signature, assigns the UID, records the permissions, and answers every intent-resolution question afterwards.
Ask an Android device a question about an app and you are almost always asking PackageManager. What is installed? What can handle this intent? Does this app hold the camera permission? Which signature signed it? All of those answers come from one service, and almost all of them were computed the first time the package was scanned.
TL;DR#
- is the system's registry of installed software and the authority on what each package may do.
- It scans at boot, parses every
AndroidManifest.xml, verifies signatures and assigns UIDs. - It resolves intents by matching against filters parsed at install time, then filtered by the caller's package visibility.
- It owns the permission grant state, though the permission definitions and policy moved to a separate service in Android 11.
- Its state is the single biggest reason a first boot is slow, and the single biggest reason a corrupted package database produces a device that will not finish booting.
Mental model#
Think of a licensing office in a city.
When a business opens, it files a registration: its name, its address, what it intends to do, who owns it. The office checks the paperwork, records it, and issues an identifier. From then on, every question about that business — is it allowed to serve alcohol, can it operate at night, who is authorised to sign for it — is answered by looking it up in the register, not by visiting the shop.
PackageManager is that office. The APK is the filing. The register is the package database. The identifier is the UID.
Where the analogy breaks#
A licensing office is consulted by humans, occasionally. PackageManager is consulted by every intent resolution, every permission check, and every process start, thousands of times a minute. That is why its in-memory state is so aggressively precomputed and cached: the register has to answer in microseconds, not days.
The big picture#
Text description of this diagram
A timeline of system_server's boot phases. PackageManagerService starts early in the boot sequence, well before the phase at which the activity manager is ready, because almost every other service needs to know what is installed. Its scan is one of the dominant costs of a first boot. The phase constants are 100 for the default display, 200 for the sensor service, 480 for lock settings, 500 for system services, 520 for device-specific services, 550 for the activity manager, 600 for third-party apps, and 1000 for boot completed.
That placement is not arbitrary. PackageManager has to be ready before ActivityManager can launch anything, before the permission service can evaluate a grant, and before any app can be started. It is one of the first framework services up and one of the last to finish its background work.
Deep dive#
The scan#
At boot, PackageManagerService walks the directories that hold packages:
/system/apex/*/priv-appand/system/priv-app— privileged system apps./system/app— ordinary system apps./system_ext/...,/product/...,/vendor/...— the other partitions, each with its own policy./data/app— apps the user installed.
For each APK, it parses the binary AndroidManifest.xml, extracts the package name, version code,
minSdkVersion, targetSdkVersion, components, permissions, shared libraries and split
declarations, and verifies the signature. The results are held in an in-memory structure and
persisted in a database under /data/system/.11
On a first boot this is slow because nothing is cached. On later boots the scan is largely incremental: known packages with unchanged timestamps and signatures are not re-parsed from scratch. That optimisation is why a device that has corrupted its package database takes minutes to boot instead of seconds — it is doing the first-boot path again.
Identity: UID, package name and signature#
Three identifiers are established at install time and never change for the life of the install.
The package name is the logical identity. It is unique per user, and it is what intents, permissions and the Play Store refer to.
The UID is the kernel identity. Android assigns a UID from a per-user range, which is why the same app has a different UID for each user on a multi-user device. The UID is the thing the kernel actually enforces, and it is why the sandbox survives even if the framework is confused.
The signature is the authorship identity. It is checked on every update: an update must be
signed by the same key as the installed version, or it is refused. That single rule is what makes
signature permissions meaningful and what makes app identity stable across updates.
Intent resolution#
When an app calls startActivity with an implicit intent, PackageManager has to answer "who can
handle this". It does so by matching the intent against the filters it parsed at install time:
- Action must match.
- Category must match, with
CATEGORY_DEFAULTimplied forstartActivity. - Data must match the scheme, host, port, path and MIME type, according to the filter's pattern.
- The target must be exported and, for a given caller, visible.
The result is a resolution: a best match for explicit launches, or a list for a chooser.2
That visibility filter is one of the more confusing parts of modern Android, because the failure mode
is silence: resolveActivity returns null and no exception is thrown. The package is installed,
the filter is right, and the answer is still no.
Permissions, and the piece that moved#
PackageManager records which permissions a package declares and which it has been granted. That
state is checked by ActivityManager on every IPC call and by the kernel's group IDs for things
like network access.
Since API 30Android 11, the definitions and much of the policy live in a separate service:
PermissionManagerService, published as "permission". The split separated two jobs that had
grown together: knowing what an app is (package state) and deciding what it may do (permission
policy).
is a third layer on top of both. It records per-operation allow/deny for things that are finer-grained than a permission — "may this app read the clipboard right now", "may it start a foreground service from the background". An app can hold a permission and still be blocked by an app-op, which is why "the permission is granted" is never the end of the story.
Installs#
An install is a conversation, not a file copy:
- The installer (Play Store,
adb install, or a package installer app) streams the APK. - PackageManager verifies the signature and the manifest, checks the version code against the installed one, and checks the requested permissions against policy.
- If the app requests a runtime permission, the grant may be deferred to a prompt.
- The APK is copied into
/data/app/<package>-<random>/base.apk(the random suffix prevents path-guessing attacks). - The package database is updated and the app's UID is assigned or reused.
- The package's components become resolvable.
Why it is a single point of failure#
The package database is one of the few pieces of state that the system cannot rebuild cheaply. If it
is corrupted or lost, PackageManager rescans, which can take minutes and, on some devices, can leave
the system unable to complete boot. That fragility is why the database is written carefully, why
/data/system/packages.xml-era designs were replaced with a more robust store, and why "clear
package cache" is a real recovery step rather than a placebo.
How it evolved#
| API | Version | What changed |
|---|---|---|
| 1 | 1.0 |
|
| 4 | 1.6 Donut |
|
| 5 | 2.0 Eclair |
|
| 8 | 2.2 Froyo |
|
| 9 | 2.3 Gingerbread |
|
| 11 | 3.0 Honeycomb |
|
| 13 | 3.2 Honeycomb |
|
| 14 | 4.0 Ice Cream Sandwich |
|
| 16 | 4.1 Jelly Bean |
|
| 17 | 4.2 Jelly Bean |
|
| 18 | 4.3 Jelly Bean |
|
| 19 | 4.4 KitKat |
|
| 20 | 4.4W KitKat (Wear) |
|
| 21 | 5.0 Lollipop |
|
| 22 | 5.1 Lollipop |
|
| 23 | 6.0 Marshmallow |
|
| 24 | 7.0 Nougat |
|
| 26 | 8.0 Oreo |
|
| 27 | 8.1 Oreo |
|
| 28 | 9 Pie |
|
| 29 | 10 |
|
| 30 | 11 |
|
| 31 | 12 |
|
| 32 | 12L |
|
| 33 | 13 Tiramisu |
|
| 34 | 14 Upside Down Cake |
|
| 35 | 15 Vanilla Ice Cream |
|
| 36 | 16 Baklava |
|
| 37 | 17 Cinnamon Bun |
|
Three changes dominate the history. Runtime permissions (API 23Android 6.0) moved the grant decision from install time to run time, which turned PackageManager from a gate into a bookkeeper. Package visibility (API 30Android 11) made the candidate set a function of the caller, not of the device. Mainline moved pieces of the package and permission stack — MediaProvider, PermissionController — out of the platform entirely, so their behaviour can change without an OS release.
Under the hood#
- PackageManagerService.javathe scan, the install path, and intent resolution
- PermissionManagerService.javapermission definitions and policy, split out in Android 11
- PackageManager.javathe public API: flags, resolution, and the query methods
- PackageParser.javathe manifest parser that turns an APK into a Package object
Curiosity corner#
- The UID range is per user. On a device with a work profile, the same app has two UIDs, one per user, and neither can read the other's data.
- A package name can outlive its app. Uninstall does not free the name permanently; a reinstalled app with the same name and signature gets a fresh UID but the same identity.
- There are packages with no code. A "stub" package with only a manifest and resources is legal and is how some system features ship an API surface without a process.
Try it#
adb shell dumpsys package com.example.app | head -40
adb shell pm path com.example.app
adb shell cmd package resolve-activity --brief -a android.intent.action.VIEW -d https://example.com
Example output
package:com.example.app
userId=10123
versionName=1.4.0
targetSdk=35
pkgFlags=[ HAS_CODE ALLOW_CLEAR_USER_DATA ]The userId is the UID that the kernel uses. The pm path output shows every split belonging to
the package. The resolve-activity call is PackageManager answering the exact question an implicit
intent asks.
Check yourself#
Check yourself
How does system_server's process come into existence at boot?
Sources#
Sources
Every version number, API level, class name and date on this page is traced to one of these. Pages are re-verified against them; last_verified above says when.
- docsAndroid platform architecture (AOSP)source.android.comaccessed 2026-10-27↩
- docsIntents and intent filters | App architecturedeveloper.android.comaccessed 2026-10-27↩
- docsPackage visibility filtering on Androiddeveloper.android.comaccessed 2026-10-27↩
- docsApp manifest overviewdeveloper.android.comaccessed 2026-10-27↩
- docsPermissions on Android | Privacydeveloper.android.comaccessed 2026-10-27↩
- docsApplication sandboxsource.android.comaccessed 2026-10-27↩
- docsAbout Android App Bundlesdeveloper.android.comaccessed 2026-10-27↩