| # Integrating proprietary components |
| |
| [TOC] |
| |
| One of the core principles of Jetpack is "Developed as open-source and |
| compatible with AOSP Android," but what does that mean in practice? This guide |
| provides specific, technical guidance on developing an open-source library and |
| interacting with proprietary or closed-source libraries and services. |
| |
| ## What do we mean by "open-source"? |
| |
| Our definition of open-source includes products that provide publicly-available |
| source code that can be compiled by an end-user to generate a functional version |
| of the product, e.g. an `AAR`, that is equivalent to the one used by the |
| library. |
| |
| ### Exceptions |
| |
| #### Android Open Source Project |
| |
| The only unconditional exception to this definition is the Android Open Source |
| Project itself, which does not release sources publicly until well after its API |
| surface has been finalized. |
| |
| Libraries which are developed against the pre-release Android platform SDK _may_ |
| remain closed-source until the platform SDK's API surface is finalized, at which |
| they **must** move to open-source. |
| |
| #### Closed-source dependencies |
| |
| In specific cases, libraries *may* include closed-source dependencies; however, |
| we **strongly recommend** that closed-source dependencies like Play Services be |
| paired with an open-source alternative provided directly in Jetpack, in the |
| Android SDK, or as part of a Mainline module. |
| |
| See the |
| [Open-source compatibility](/docs/api_guidelines/index.md#dependencies-aosp) |
| section of the API Guidelines for details on integrating closed-source |
| components. |
| |
| ### Examples of products that are _not_ open-source |
| |
| * A bundled `.so` file with no publicly-available source code |
| * A Maven dependency with no publicly-available source code, either in the |
| Maven distribution (ex. source `JAR`) or in a public repository |
| * A library that ships source code to GitHub, but the source does not compile |
| * A library that ships source code to AOSP, but binary compiled from that |
| source is not functionally equivalent to the library used by Jetpack |
| * A closed-source web service |
| * Google Play Services |
| |
| ## Why do we care? |
| |
| ### Compatibility with AOSP ecosystem |
| |
| The Android Open-Source Project enables a diverse ecosystem of devices with a |
| wide array of software environments in which our libraries will operate. Many of |
| those devices are certified to run Play Services, but it's important for our |
| libraries to work on all devices that are certified as Android -- even those |
| with no Google software installed. |
| |
| * Features provided by primary artifacts **must** be able to function on AOSP |
| devices without the presence of proprietary components like Play Services |
| |
| ### Testing and testability |
| |
| Isolating behavior makes it easier to write reliable and targeted tests, but |
| introducing dependencies on proprietary components makes this difficult. In a |
| well-abstracted library, developers should be able to write integration tests |
| against the library's documented API surface without concerning themselves with |
| the implementation details of a backing service. |
| |
| * Features provided by primary artifacts that may be backed by proprietary |
| components **must** be written in way that makes it feasible for a developer |
| to write and delegate to their own backing implementation |
| |
| ### Developer choice |
| |
| Developers should be able to choose between proprietary components; however, |
| libraries are also encouraged to provide a sensible default. |
| |
| * Features provided by primary artifacts that may be backed by proprietary |
| components **must** allow developers to choose a specific backing component |
| and **must not** hard-code proprietary components as the default choice |
| * Libraries _may_ use a ranking or filtering heuristic based on platform APIs |
| such as permissions, presence on the system image, or other properties of |
| applications and packages |
| |
| ### Open protocols |
| |
| Third-party developers should be able to provide their own backing services, |
| which means service discovery mechanisms, communication protocols, and API |
| surfaces used to implement a backing service must be publicly available for |
| implementation. |
| |
| Third-party developers should also be able to validate that their implementation |
| conforms to the expectations of the library. Library developers should already |
| be writing tests to cover their backing service, e.g. that a service |
| implementing a protocol or interface is correct, and in many cases these tests |
| will be suitable for third-party developers to verify their own implementations. |
| |
| While we recommend that developers provide a stub backing implementation in a |
| `-testing` artifact or use one in their own unit tests, we do not require one to |
| be provided; only that it is possible to write one. |
| |
| ## Examples of policy violations |
| |
| * A primary artifact uses `Intent` handling as a service discovery mechanism |
| and hard-codes a reference to `com.google.android` as a ranking heuristic. |
| * **What's wrong?** This conflicts with the developer choice principle. |
| Primary artifacts must remain neutral regarding specific proprietary |
| components. |
| * **How to fix?** This library should use an alternative ranking heuristic |
| that takes advantage of platform APIs such as granted permissions or |
| presence of the component on the system image (see |
| [FLAG_SYSTEM](https://developer.android.com/reference/android/content/pm/ApplicationInfo#FLAG_SYSTEM) |
| and |
| [FLAG_UPDATED_SYSTEM_APP](https://developer.android.com/reference/android/content/pm/ApplicationInfo#FLAG_UPDATED_SYSTEM_APP)). |
| The library will also need to provide an API that allows developers to |
| choose an explicit ranking or default component. |
| * A primary artifact uses reflection to delegate to a specific fully-qualified |
| class name. This class is provided by an optional library that delegates to |
| Play Services. |
| * **What's wrong?** This is another situation where the library is |
| limiting developer choice. Features in primary artifacts which may |
| delegate to proprietary services must allow developers to choose a |
| different delegate. Reflection on a fully-qualified class name does |
| *not* allow multiple delegates to exist on the classpath and is not a |
| suitable service discovery mechanism. |
| * **How to fix?** This library should use a more suitable service |
| discovery mechanism that allows multiple providers to coexist and |
| ensures the developer is able to choose among them. |
| * A primary artifact provides a service discovery mechanism that allows |
| multiple providers and exposes an API that lets the developer specify a |
| preference. Communication with the service is managed through a `Bundle` |
| where they keys, values, and behaviors are documented outside of Jetpack. |
| * **What's wrong?** This conflicts with the open protocols principle. |
| Third-party developers should be able to implement their own backing |
| services, but using a `Bundle` with a privately-documented protocol |
| means that (1) it is not possible to write adqeuate tests in Jetpack and |
| (2) developers outside of Google cannot feasibly write correct backing |
| implementations. |
| * **How to fix?** At a minimum, the developer should fully document the |
| keys, values, and behavior expected by the protocol; however, in this |
| case we would strongly recommend replacing or wrapping `Bundle` with a |
| strongly-typed and documented API surface and robust suite of tests to |
| ensure implementations on either side of the protocol are behaving |
| correctly. |
| * A primary artifact provides an `interface` and an API that allows developers |
| to specify a backing service using classes that implement that interface. |
| The `interface` API surface has several `@hide` methods annotated with |
| `@RestrictTo(LIBRARY_GROUP)`. |
| * **What's wrong?** This is another open protocols issue. Third-party |
| developers should be able to implement their own backing services, but |
| using a partially-private `interface` means that only Jetpack libraries |
| can feasibly provide a backing implementation. |
| * **How to fix?** At a minimum, the developer should make the `interface` |
| fully public and documented so that it can be implemented by a |
| third-party. They should also provide robust tests for the default |
| backing implementation with the expectation that third-party developers |
| will use this to verify their own custom implementations. |