Inspired by Nikolay Elenkov’s detailed technical posts on Android Explorations, I decided to dig into the Android source code myself and document the package verification mechanism in Android.
Package verification was introduced in Android 4.2 to allow for apps to be verified or checked before they are installed. If you have tried to install a malicious app on a production Android device, you might have seen the following screen, displayed by the verifier:
Android was built in such a way that it tries to be generic for third-parties to implement stuff. Package verification is a feature that is currently only used and implemented by Google, but it is abstracted in such a way that any manufacturer can implement their own. Documentation and examples on how to do this is almost non-existent, although anyone determined enough can read the Android source code and figure it out for themselves.
The verification mechanism consists of what is called the required verifier which decides whether or not your app can be installed on the device. Later on, a mechanism for “non-required package verifiers” or sufficient verifiers was also added. Sufficient verifiers have to be explicitly requested by the app (that is about to be installed) through its manifest file. These verifiers will be consulted before an application package is allowed to be installed. Android will consult the sufficient verifier(s) only when there is a required verifier. If there is no required verifier in the system, no verification of any kind is performed.
Package Manager Internals
Package verification is handled by the
PackageManagerService. Internally it uses
PackageVerificationState to track the verification state of a particular package install, and
PackageVerificationResponse objects for passing messages to the
PackageHandler (a subclassed
Handler). None of these classes are exposed externally. Instead,
PackageManager exposes the verification API that should be used by package verifiers, in particular
The package installation process is driven by
Messages sent to the
PackageHandler. After the verification request intents are broadcasted, a delayed
Messaage is sent to the
Handler‘s message queue using
sendDelayedMessage. All timeouts are implemented the same way, which is why the
extendVerificationTimeout method requires the response to be specified up front — the message containing the response code is created at the time of invocation and sent using
sendDelayedMessage. Calling the verification APIs will also send messages to the
PackageManagerService broadcasts the
PACKAGE_NEEDS_VERIFICATION intent to package verifiers when a package is about to be installed. Package verifiers respond to this intent by calling
extras that specify install flags, the installer package, and the temporary path to the APK file, which allows you to read (or “scan”) the APK.
PACKAGE_VERIFIED intent is also broadcasted to verifiers after verification for a particular package has completed, provided that they have the
PACKAGE_VERIFICATION_AGENT permission and the appropriate intent filter. No action is required by the verifiers. The purpose of this intent is to allow for monitoring of the installation attempts of packages and the verification result, whether allowed or rejected.
There are 2 global settings that influence package verification behaviour:
PACKAGE_VERIFIER_DEFAULT_RESPONSE (these constants are hidden in Settings.Global). The timeout controls how much time elapses before
PackageManager checks whether the verifier(s) have responded (defaults to 10 seconds). The default response determines what happens when the verifier(s) have not replied after the timeout has elapsed. If the default response is
VERIFICATION_ALLOW, packages will be installed even if the verifier(s) do not respond. Package verifiers can call
extendVerificationTimeout if it realises that a response cannot be provided in time (e.g. when it needs to consult a server and there is currently no network connectivity). This method must be called before the verification timeout has elapsed. These settings can be altered using the
settings tool, through an adb shell, like so:
settings put global verifier_default_response -1
Upon startup, the system finds the required verifier by calling the
getRequiredVerifierLPr method. This only happens once, when the
PackageManagerService is being initialized. If there is more than one package that fulfils the requirements of being a required verifier, an exception is thrown and Android will fail to boot up:
E/System ( 2515): ****************************************** E/System ( 2515): ************ Failure starting core service E/System ( 2515): java.lang.RuntimeException: There can be only one required verifier E/System ( 2515): at com.android.server.pm.PackageManagerService.getRequiredVerifierLPr(PackageManagerService.java:1510) E/System ( 2515): at com.android.server.pm.PackageManagerService.<init>(PackageManagerService.java:1468) ...
The required verifier and sufficient verifiers are distinguished from one another by their uids (user IDs). The uids of the verifiers are checked in the
PackageVerificationState class (note the
mSufficientVerifierUids fields within the class). Verifiers should thus have different uids.
The concept of the required verifier is easy to understand. It is the primary mechanism for package verification. If the system has a required verifier, and the system settings have been enabled (which it is by default), the verifier will be consulted for all packages before they are allowed to be installed. Note that the verification mechanism is only concerned with preventing installations — the verifier can choose to display any additional dialog(s) to prompt the user for input or to convey information about the package (e.g. why the installation was disallowed).
Verifiers are notified of pending installs via the
PACKAGE_NEEDS_VERIFICATION intent. When the verifier receives the intent broadcast, it responds by invoking
verifyPendingInstall. The required verifier must have the
PACKAGE_VERIFICATION_AGENT permission in order to receive the broadcast. As this permission is only granted to
signatureOrSystem apps, this means that only device manufacturers or ROM vendors will be able to provide such a verification app.
The required verifier is provided by Google on most production Android devices (but not on the emulator), so it must be one of the Google-bundled apps. Using
adb shell dumpsys package, we can check which package implements this functionality:
Verifiers: Required: com.android.vending (uid=10014) Activity Resolver Table: Full MIME Types: ... MIME Typed Actions: ... android.intent.action.PACKAGE_NEEDS_VERIFICATION: 42a1dd98 com.android.vending/com.google.android.vending.verifier.PackageVerificationReceiver filter 4290d8a0 android.intent.action.PACKAGE_VERIFIED: 42a1dd98 com.android.vending/com.google.android.vending.verifier.PackageVerificationReceiver filter 4290d8a0
PackageManager includes the verifier information at the start of the dump. Further down, you can see that the
com.android.vending package has also registered for the appropriate verification intents. This package will thus be responsible for the verification of packages on the device. If you reverse-engineer the APK, you will find that it consults the Google Safe Browsing API (probably a subset not published publicly) with the package information.
There can only be one required verifier in the system that fulfills the criteria, otherwise the OS will not boot up.
This provides a means for a package to explicitly request for verification, by specifying a
<package-verifier> element in the manifest, which looks something like this:
<package-verifier android:name="org.mycompany.verifier" android:publicKey="Zm9vYmFy..." />
publicKey attribute ensures that the package being installed will only be verified by a legitimate verifier that has been pre-determined (i.e. signed by the specified public key). The public key of the verifier package is base64-encoded, like the ones found in
/data/system/package.xml. This mechanism assures developers that only verifiers they trust will receive verification requests.
There can be multiple sufficient verifiers requested in the manifest. If sufficient verifiers have been requested, at least one of them must be matched, otherwise the installation fails with “Additional verifiers required, but none installed.” For the installation to proceed, there must be at least a single sufficient verifier that responds
ALLOW to the verification request. An exception to this case is if the default verification response is
VERIFICATION_ALLOW and none of the verifiers respond before the timeout. This internally sets the response to
VERIFICATION_ALLOW_WITHOUT_SUFFICIENT, causing the logic in
isInstallAllowed to return true.
Uses for such verifiers are limited as it requires the developer to explicitly request for verification. However, since Android allows for new permissions to be defined by third-party applications, this mechanism might potentially be used for the verification of the consumers of these non-standard permissions.
Sufficient Verifiers Bug
As far as I can tell, the current implementation of sufficient verifiers does not work as intended. They have in place the mechanisms for finding the verifiers, sending the broadcasts to them, and receiving the replies, but the permissions enforcement code in
PackageManager prevents sufficient verifiers from responding to the broadcasts.
Sufficient verifiers are registered almost the same way as the required verifier — by declaring an appropriate receiver — except that they do not require the
PACKAGE_VERIFICATION_AGENT permission. Commit 7e671 was introduced one year later in Aug 2012, adding checks that require package verifiers to have the
PACKAGE_VERIFICATION_AGENT permission to use the verification APIs exposed through
PackageManager. However, recall that if more than one package has this permission, Android will refuse to boot up due to the check at
Until Google fixes this Catch 22, (the current concept of) sufficient verifiers will not work in released versions of Android.
As Google regularly develops features and releases them into the AOSP tree without documentation, it will be interesting to see what Google is planning to do with the concept of “sufficient verifiers”.
Examples of such on-going work also include App Ops, which is still being actively developed and was accidentally exposed to users in Android 4.3.