Granting signature and signatureOrSystem permissions of OEM application

Volodymyr Kozhemiakin
Make Android
Published in
7 min readJun 4, 2023

This blog describes how to sign and install an OEM application that uses system APIs from Gradle build.

Photo by David von Diemar on Unsplash

An OEM application refers to a specific app that is pre-installed on an Android device by the manufacturer. Some apps can be categorized as system apps, using the APIs that require system-level permissions. These permissions and APIs allow your app to interact closely with the Android operating system and access advanced functionalities. System-level permissions grant your app privileged access to perform specific actions or access sensitive resources. Examples include permission to modify system settings, access protected storage, manage network connections, control hardware features, and more.

Usually vendors use Android.bp AOSP build configuration file and Soong build system to build OEM application. It allows vendors to have their applications pre-installed on an Android device.

Android.bp file provides a declarative way to define modules, their properties, dependencies, and other build-related information. Here are some common fields that can be specified in an Android.bp file:

android_app_import {
name: "Launcher",
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
platform_apis: false,
certificate: "shared",
privileged: false,
static_libs: [
"androidx.appcompat:appcompat",
],
...
}

android_app_import— defines the type of module.

name: "Launcher" — specifies the unique name of the module. It is used to identify the module within the build system.

srcs:["src/**/*.java"] — include all Java source files in the specified directories when building the module, also can be Kotlin files.

resource_dirs:["res"] — specifying the resource directories for a particular module.

platform_apis: false— means that the module does not requires access to the specific resources and functionality provided by the Android platform, which prevents the use of platform-specific functions and APIs.

certificate: "shared" — indicates that the module will be signed with a shared certificate. A shared certificate is a generic certificate used for modules that are not part of the core Android platform. It is typically used for third-party or user-installed applications and libraries.

privileged: false— indicates that the module does not require special privileges or access to system-level resources. It will be treated as a regular app or component within the Android system.

static_libs: — specify the static libraries that a module depends on during the Android build process, these are dependencies as in the gradle.build file.

While developing OEM applications, let’s take as an example Launcher app, we are facing use of certain system-related APIs that require signature or signatureOrSystem permissions. In case of a Launcher, it might need to implement Widgets that using AppWidgetManager#bindAppWidgetIdIfAllowed(int appWidgetId, ComponentName provider) method. This method requires permission with "signature|privileged" protection level:

<!-- Allows an application to tell the AppWidget service which application 
can access AppWidget's data. The normal user flow is that a user
picks an AppWidget to go into a particular host, thereby giving that
host application access to the private data from the AppWidget app.
An application that has this permission should honor that contract.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.BIND_APPWIDGET"
android:protectionLevel="signature|privileged" />

Description of all permissions we could find in the AOSP AndroidManifest.xml, it varies from Android version.

The "signature|privileged" is protection level of this permission is a permission that the system grants only to applications that are in a dedicated folder on the Android system image or that are signed with the same certificate as the application that declared the permission.

Thus, we have 2 options to grant that permission:

  1. App should be signed with the same certificate as the application that declared the permission.
  2. Install APK to a dedicated folder on the Android system image.

From Android.bp file of Launcher we can easily grant android.permission.BIND_APPWIDGET permission and use system-related API by setting the following properties:

  • certificate: "platform" — signed with the platform certificate and grants signature permissions. It is used for system-level components, such as the Android framework, system apps, and core system libraries.

or

  • privileged: true — indicates that the APK will be installed in the /system/priv-app/ partition on an Android device and grants signatureOrSystem permissions. This partition is specifically designated for privileged system applications that have elevated access and permissions.
  • required: ["privapp_permissions.xml"]— indicates that the module requires the "privapp_permissions.xml" file to define its privileged app permissions. File is typically located in the "/etc/permissions" Android system partition and contains "signature|privileged" permissions.

I would like to share a method for granting signature and signatureOrSystem permissions to an OEM application that uses system-related APIs using Gradle build.

Building APK by Gradle allows installing and running APK from Android Studio, viewing layout design changes in the XML Android Studio as if they were 3rd party apps. Also, installing built APK by Gradle to a privileged partition /system/priv-app/ can be useful when we do not have access to entire AOSP build, but still need to install, run and test APK on system.

Let’s consider the first option “App should be signed with the same certificate as the application that declared the permission”, example of signing APKs from Android Studio. This method allows to grant signature or signatureOrSystem permissions. In general, it is necessary to generate signature keystore through platform.x509.pem certificate and platform.pk8 private key that we can take from AOSP and sign the APK. Here is a step-by-step guide we can follow:

a. Install the Java Development Kit (JDK) if you haven’t already done so.

b. Open a terminal or command prompt and navigate to the directory where the platform.x509.pem and platform.pk8 files are located. I prefer to put all files in the same folder just for convenience.

c. Convert the platform.pk8 file to a DER format by running the following command:

openssl pkcs8 -inform DER -nocrypt -in platform.pk8 -out platform.key

d. Generate a PKCS12 file by combining an X.509 certificate and a private key, assigning a name to the certificate, and specifying a password:

openssl pkcs12 -export -in platform.x509.pem -inkey platform.key -name platform -out platform.pem -password pass:password

e. Import a PKCS12 keystore file named platform.pem into a new keystore file named platform.keystore with a specified password:

keytool -importkeystore -destkeystore platform.keystore -deststorepass password -srckeystore platform.pem -srcstoretype PKCS12 -srcstorepass password

f. Create directory /keystore in the root of project and put generated platform.keystore file in it.

g. In module build.gradle file add debug or/and release signing configs:

android {
def keystore_path = project.rootProject.getProjectDir().toString() + "\\keystore\\platform.keystore"

signingConfigs {
debug {
storeFile file(keystore_path)
keyAlias 'platform'
storePassword 'password'
keyPassword 'password'
}
}

buildTypes {
debug {
signingConfig signingConfigs.debug
}
}
}

h. Build and run the project: Android Studio → Build → Rebuild project and Run. That’s all, your OEM app granted signature or signatureOrSystem permissions.

Let’s consider the second option “To put app to a dedicated folder on the android system image”. Apps installed in /system/priv-app/ as privileged applications will only grant permissions with protection level signatureOrSystem to privileged apps [1]. In general, we need to build APK by Gradle (without platform key as 3rd party apps) then push APK to the privileged partition and add required permissions to the privapp_permissions.xml file.

Here is an instruction how to install system APK manually on device with firmware build type userdebug:

First of all, grant root access and remount the system partition on Android device, allowing read and write access to system files. In short make /system partition writable:

adb root
adb remount
adb shell "su 0 mount -o rw,remount /system" # adb shell "su 0 mount -o rw,remount /"

Create directory and push APK to /system/priv-app/ partition:

adb shell mkdir /system/priv-app/Launcher
adb push Launcher.apk /system/priv-app/Launcher

Change permissions of APK file on Android device. It grants read and write for the owner, and read-only for the group and others:

adb shell chmod 644 /system/priv-app/Launcher/Launcher.apk

Also important to add required permissions to the privapp_permissions.xml file in the Android system. First of all, pull file:

adb pull /etc/permissions/privapp-permissions-platform.xml .

Edit privapp_permissions.xml file, it will be look like:

<?xml version="1.0" encoding="utf-8"?>
<permissions>
...
<privapp-permissions package="com.example.launcher">
<permission name="android.permission.BIND_APPWIDGET"/>
</privapp-permissions>
</permissions>

Make sure package name the same as in APK com.example.launcher. After adding permission android.permission.BIND_APPWIDGETpush file to the same path:

adb push privapp-permissions-platform.xml /etc/permissions/

Reboot device and that is all, your APK grants signatureOrSystem permission:

adb reboot

JFYI: After finishing OEM app development with this method, we can still integrate this APK into the AOSP build and make this APK pre-installed. There are two ways to add APK to AOSP build system: add the complete project or compiled APK see as example.

Thus, we could temporarily use this sign and install method to develop, install, run and test an OEM application that uses system-related APIs.

Pros: real-time viewing layout design changes made, fast installing and uninstalling APK, allows to grant signature or signatureOrSystem permissions.

Cons: can be lack of libraries (Car library) in Gradle dependencies, so it might need to add compiled library from AOSP to the Android project. Also, some API can be hidden, so in this case stubs can be created in the project or use reflection.

Caution: access to system permissions and APIs requires additional security and privacy responsibilities. Make sure your application complies with best practices for handling sensitive data, securing communications channels, and respecting user privacy.

Literature

  1. Android Security Internals: An In-Depth Guide to Android’s Security Architecture Book by Nikolay Elenkov 2014.

OEM — Original Equipment Manufacturer

APK — Android Package Kit

AOSP — Android Open Source Project

.keystore — is a specific file format utilized in Java for storing cryptographic keys, including private keys and certificates.

--

--

Volodymyr Kozhemiakin
Make Android

Android Engineer | Mobile | Automotive | Enterprise | AOSP | Applications, Android Framework, System Services, HAL, Kernel | C/C++ | Java | Kotlin