## Mainline specific patterns [ML] [Mainline](http://go/what-is-mainline) is a project to allow updating subsystems ("mainline modules") of the Android OS individually, rather than updating the whole system image. Mainline modules have to be "unbundled" from the core platform, which means all the interactions between each module and the rest of the world have to be done via formal (public or system) APIs. There are certain design patterns mainline modules should follow. This section describes them. ### The `[Module]FrameworkInitializer` pattern If a mainline module needs to exposes `@SystemService` classes (e.g. `JobScheduler`), use the following pattern: - Expose a `[YourModule]FrameworkInitializer` class from your module. This class needs to be in `$BOOTCLASSPATH`. Example: [StatsFrameworkInitializer](https://cs.android.com/android/platform/superproject/+/master:packages/modules/StatsD/framework/java/android/os/StatsFrameworkInitializer.java) - Mark it with `@SystemApi(client = MODULE_LIBRARIES)`. - Add a `public static void registerServiceWrappers()` method to it. - Use `SystemServiceRegistry.registerContextAwareService()` to register a service manager class when it needs a reference to a `Context`. - Use `SystemServiceRegistry.registerStaticService()` to register a service manager class when it does not need a reference to a `Context`. - Call the `registerServiceWrappers()` method from [`SystemServiceRegistry`](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/app/SystemServiceRegistry.java)'s static initializer. ### The `[Module]ServiceManager` pattern Normally, in order to register system service binder objects and/or get references to them, one would use [`ServiceManager`](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/os/ServiceManager.java), but mainline modules can't use it because it's hidden. This class is hidden because mainline modules are not supposed to register or refer to system service binder objects exposed by the non-updateable platform or by other modules. Mainline modules can use the following pattern instead to be able to register and get references to binder services that are implemented inside the module. - Create a `[YourModule]ServiceManager` class, following the design of [TelephonyServiceManager](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/os/TelephonyServiceManager.java) - Expose the class as `@SystemApi`. If you only need to access it from `$BOOTCLASSPATH` classes or system server classes, you can use `@SystemApi(client = MODULE_LIBRARIES)`; otherwise `@SystemApi(client = PRIVILEGED_APPS)` would work. - This class would consists of: - A hidden constructor, so only the non-updatable platform code can instantiate it. - ~~A nested class `ServiceRegisterer`~~ TODO(omakoto) b/245801672: It shouldn't be an inner class. Create a sharable class for this. - Public getter methods that return a `ServiceRegisterer` instance for a specific name. If you have one binder object, then you need one getter method. If you have two, then you need two getters. - In [`ActivityThread.initializeMainlineModules()`](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/app/ActivityThread.java), instantiate this class, and pass it to a static method exposed by your module. Normally, you add a static `@SystemApi(client = MODULE_LIBRARIES)` API in your `FrameworkInitializer` class that takes it. This pattern would prevent other mainline modules from accessing these APIs because there's no way for other modules to get an instance of `[YourModule]ServiceManager`, even though the `get()` and `register()` APIs are visible to them. Here is how telephony [^telephonymodule] gets a reference to the telephony service: [code search link](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/telephony/java/android/telephony/TelephonyManager.java). [^telephonymodule]: Telephony is not a mainline module (yet), but this still shows a preferred pattern. If your implements a service binder object in native code, you use [the `AServiceManager` native APIs](https://cs.android.com/android/platform/superproject/+/master:frameworks/native/libs/binder/ndk/include_platform/android/binder_manager.h). These APIs correspond to the `ServiceManager` Java APIs but the native ones are directly exposed to mainline modules. **Do not** use them to register or refer to binder objects that are not owned by your module. If you expose a binder object from native, your `[YourModule]ServiceManager.ServiceRegisterer` does not need a `register()` method. ### Defining permissions in Mainline module Mainline modules containing APKs may define (custom) permissions in their APK `AndroidManifest.xml` in the same way as a regular APK. > NOTE: Despite that the APEX `AndroidManifest.xml` currently also allows > `` tags because it's sharing the parsing code with APKs, that is > unsupported and may be removed in the future. If the defined permission is only used internally within a module, its permission name should be prefixed with the APK package name, e.g.: ```xml ``` If the defined permission is to be provided as part of an updatable platform API to other apps, its permission name should be prefixed with "android.permission." (like any non-updatable platform permission) plus the module package name, to signal it's a platform API from a module while avoiding any naming conflicts, e.g.: ```xml ``` Then the module can expose this permission name as an API constant in its API surface, e.g. [`HealthPermissions.READ_ACTIVE_CALORIES_BURNED`](https://developer.android.com/reference/android/health/connect/HealthPermissions#READ_ACTIVE_CALORIES_BURNED).