1## Implementing compatibility {#compat}
2
3### Referencing new APIs {#compat-newapi}
4
5Generally, methods on library classes should be available to all devices above
6the library's `minSdkVersion`; however, the behavior of the method may vary
7based on platform API availability.
8
9For example, a method may delegate to a platform API on SDKs where the API is
10available, backport a subset of behavior on earlier SDKs, and no-op on very old
11SDKs.
12
13#### Checking device SDK version {#compat-sdk}
14
15The most common way of delegating to platform or backport implementations is to
16compare the device's `Build.VERSION.SDK_INT` field to a known-good SDK version;
17for example, the SDK in which a method first appeared or in which a critical bug
18was first fixed.
19
20When developing against pre-release SDKs where the `SDK_INT` has not been
21finalized, SDK checks **must** use `BuildCompat.isAtLeastX()` methods and
22**must** use a tip-of-tree `project` dependency to ensure that the
23implementation of `BuildCompat` stays up-to-date when the SDK is finalized.
24
25**Do not** assume that the next SDK release's `SDK_INT` will be N+1. The value
26is not finalized until SDK finalization happens, at which point the `isAtLeast`
27check will be updated. **Never** write your own check for a pre-release SDK.
28
29```java {.good}
30@NonNull
31public static List<Window> getAllWindows() {
32  if (BuildCompat.isAtLeastR()) {
33    return ApiRImpl.getAllWindows();
34  }
35  return Collections.emptyList();
36}
37```
38
39```kotlin {.good}
40dependencies {
41  api(project(":core:core"))
42}
43```
44
45#### Validating class verification
46
47To verify that your library does not raise class verification failures, look for
48`dex2oat` output during install time.
49
50You can generate class verification logs from test APKs. Simply call the
51class/method that should generate a class verification failure in a test.
52
53The test APK will generate class verification logs on install.
54
55```bash
56# Enable ART logging (requires root). Note the 2 pairs of quotes!
57adb root
58adb shell setprop dalvik.vm.dex2oat-flags '"--runtime-arg -verbose:verifier"'
59
60# Restart Android services to pick up the settings
61adb shell stop && adb shell start
62
63# Optional: clear logs which aren't relevant
64adb logcat -c
65
66# Install the app and check for ART logs
67# This line is what triggers log lines, and can be repeated
68adb install -d -r someApk.apk
69
70# it's useful to run this _during_ install in another shell
71adb logcat | grep 'dex2oat'
72...
73... I dex2oat : Soft verification failures in
74```
75
76#### View constructors {#compat-view-constructors}
77
78The four-arg View constructor -- `View(Context, AttributeSet, int, int)` -- was
79added in SDK 21 and allows a developer to pass in an explicit default style
80resource rather than relying on a theme attribute to resolve the default style
81resource. Because this API was added in SDK 21, care must be taken to ensure
82that it is not called through any < SDK 21 code path.
83
84Views *may* implement a four-arg constructor in one of the following ways:
85
861.  Do not implement.
871.  Implement and annotate with `@RequiresApi(21)`. This means the three-arg
88    constructor **must not** call into the four-arg constructor.
89
90#### Device-specific issues {#compat-oem}
91
92Library code may work around device- or manufacturer-specific issues -- issues
93not present in AOSP builds of Android -- *only* if a corresponding CTS test
94and/or CDD policy is added to the next revision of the Android platform. Doing
95so ensures that such issues can be detected and fixed by OEMs.
96
97#### Handling `minSdkVersion` disparity {#compat-minsdk}
98
99Methods that only need to be accessible on newer devices, including
100`to<PlatformClass>()` methods, may be annotated with `@RequiresApi(<sdk>)` to
101indicate they must not be called when running on older SDKs. This annotation is
102enforced at build time by the `NewApi` lint check.
103
104#### Handling `targetSdkVersion` behavior changes {#compat-targetsdk}
105
106To preserve application functionality, device behavior at a given API level may
107change based on an application's `targetSdkVersion`. For example, if an app with
108`targetSdkVersion` set to API level 22 runs on a device with API level 29, all
109required permissions will be granted at installation time and the run-time
110permissions framework will emulate earlier device behavior.
111
112Libraries do not have control over the app's `targetSdkVersion` and -- in rare
113cases -- may need to handle variations in platform behavior. Refer to the
114following pages for version-specific behavior changes:
115
116*   Android 14,
117    [API level 34](https://developer.android.com/about/versions/14/behavior-changes-14)
118*   Android 13,
119    [API level 33](https://developer.android.com/about/versions/13/behavior-changes-13)
120*   Android 12,
121    [API level 31](https://developer.android.com/about/versions/12/behavior-changes-12)
122*   Android 11,
123    [API level 30](https://developer.android.com/about/versions/11/behavior-changes-11)
124*   Android 10,
125    [API level 29](https://developer.android.com/about/versions/10/behavior-changes-10)
126*   Android Pie (9.0),
127    [API level 28](https://developer.android.com/about/versions/pie/android-9.0-changes-28)
128*   Android Oreo (8.0),
129    [API level 26](https://developer.android.com/about/versions/oreo/android-8.0-changes)
130*   Android Nougat(7.0),
131    [API level 24](https://developer.android.com/about/versions/nougat/android-7.0-changes)
132*   Android Lollipop (5.0),
133    [API level 21](https://developer.android.com/about/versions/lollipop/android-5.0-changes)
134*   Android KitKat (4.4),
135    [API level 19](https://developer.android.com/about/versions/kitkat/android-4.4#Behaviors)
136
137#### Working around Lint issues {#compat-lint}
138
139In rare cases, Lint may fail to interpret API usages and yield a `NewApi` error
140and require the use of `@TargetApi` or `@SuppressLint('NewApi')` annotations.
141Both of these annotations are strongly discouraged and may only be used
142temporarily. They **must never** be used in a stable release. Any usage of these
143annotation **must** be associated with an active bug, and the usage must be
144removed when the bug is resolved.
145
146#### Java 8+ APIs and core library desugaring {#compat-desugar}
147
148The DEX compiler (D8) supports
149[API desugaring](https://developer.android.com/studio/write/java8-support-table)
150to enable usage of Java 8+ APIs on a broader range of platform API levels.
151Libraries using AGP 8.2+ can express the toolchain requirements necessary for
152desugaring to work as intended, but these requirements are only enforced for
153**apps** that are also building with AGP 8.2+.
154[While adoption of AGP 8.2+ remains low](https://issuetracker.google.com/172590889#comment12),
155AndroidX libraries **must not** rely on `coreLibraryDesugaring` to access Java
156language APIs on earlier platform API levels. For example, `java.time.*` may
157only be used in code paths targeting API level 26 and above.
158
159### Delegating to API-specific implementations {#delegating-to-api-specific-implementations}
160
161#### Referencing SDK constants {#sdk-constants}
162
163Generally speaking, platform and Mainline SDK constants should not be inlined.
164
165Constants that can be inlined by the compiler (most primitives and `String`s)
166should be referenced directly from the SDK rather than copying and pasting the
167value. This will raise an `InlinedApi` lint warning, which may be suppressed.
168
169```
170public static class ViewCompat {
171  @Suppress("InlinedApi")
172  public static final int SOME_CONSTANT = View.SOME_CONSTANT
173}
174```
175
176In rare cases, some SDK constants are not defined at compile-time and cannot be
177inlined by the compiler. In these cases, you will need to handle them like any
178other API using out-of-lining and version gating.
179
180```
181public static final int RUNTIME_CONSTANT =
182    if (SDK_INT > 34) { Api34Impl.RUNTIME_CONSTANT } else { -1 }
183```
184
185Developers **must not** inline platform or Mainline SDK constants that are not
186part of a finalized public SDK. **Do not** inline values from `@hide` constants
187or public constants in an unfinalized SDK.
188
189#### SDK-dependent reflection {#sdk-reflection}
190
191Note: The
192[BanUncheckedReflection](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:lint-checks/src/main/java/androidx/build/lint/BanUncheckedReflection.kt)
193lint check detects disallowed usages of reflection.
194
195Starting in API level 28, the platform restricts which
196[non-SDK interfaces](https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces)
197can be accessed via reflection by apps and libraries. As a general rule, you
198will **not** be able to use reflection to access hidden APIs on devices with
199`SDK_INT` greater than `Build.VERSION_CODES.P` (28).
200
201In cases where a hidden API is a constant value, **do not** inline the value.
202Hidden APIs cannot be tested by CTS and carry no stability guarantees.
203
204Per go/platform-parity, on earlier devices or in cases where an API is marked
205with `@UnsupportedAppUsage`, reflection on hidden platform APIs is allowed
206**only** when an alternative public platform API exists in a later revision of
207the Android SDK. For example, the following implementation is allowed:
208
209```java
210public AccessibilityDelegate getAccessibilityDelegate(View v) {
211    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
212        // Retrieve the delegate using a public API.
213        return v.getAccessibilityDelegate();
214    } else if (Build.VERSION.SDK_INT >= 11) {
215        // Retrieve the delegate by reflecting on a private field. If the
216        // field does not exist or cannot be accessed, this will no-op.
217        if (sAccessibilityDelegateField == null) {
218            try {
219                sAccessibilityDelegateField = View.class
220                        .getDeclaredField("mAccessibilityDelegate");
221                sAccessibilityDelegateField.setAccessible(true);
222            } catch (Throwable t) {
223                sAccessibilityDelegateCheckFailed = true;
224                return null;
225            }
226        }
227        try {
228            Object o = sAccessibilityDelegateField.get(v);
229            if (o instanceof View.AccessibilityDelegate) {
230                return (View.AccessibilityDelegate) o;
231            }
232            return null;
233        } catch (Throwable t) {
234            sAccessibilityDelegateCheckFailed = true;
235            return null;
236        }
237    } else {
238        // There is no way to retrieve the delegate, even via reflection.
239        return null;
240    }
241```
242
243Calls to public APIs added in pre-release revisions *must* be gated using
244`BuildCompat`:
245
246```java
247if (BuildCompat.isAtLeastQ()) {
248   // call new API added in Q
249} else if (Build.SDK_INT.VERSION >= 23) {
250   // make a best-effort using APIs that we expect to be available
251} else {
252   // no-op or best-effort given no information
253}
254```
255
256#### Shadowing platform classes {#sdk-shadowing}
257
258Generally, libraries should **never** create new classes in the `android.*`
259namespace or re-define any classes that may be present in the boot classpath.
260**Do not** create a library class with the same fully-qualified name as one in
261the platform SDK, a Mainline module, sidecar JAR, or another library. Keep all
262classes within your own package based on your Maven group ID.
263
264The reverse also applies: the platform SDK, Mainline modules, sidecar JARs, and
265other libraries **must not** define classes in the `androidx.*` namespace.
266
267In *extremely limited* cases, the overhead of reflecting on a platform class may
268cause performance issues for apps on a scale that warrants using a compile-only
269stub of the platform class to avoid reflection. Any instances of this **must**
270be approved by Jetpack Working Group before submitting the change.
271
272### Inter-process communication {#ipc}
273
274Protocols and data structures used for IPC must support interoperability between
275different versions of libraries and should be treated similarly to public API.
276
277**Do not** design your own serialization mechanism or wire format for disk
278storage or inter-process communication. Preserving and verifying compatibility
279is difficult and error-prone.
280
281**Do not** expose your serialization mechanism in your API surface. Neither
282Stable AIDL nor Protobuf generate stable language APIs.
283
284Generally, any communication prototcol, handshake, etc. must maintain
285compatibility consistent with SemVer guidelines. Consider how your protocol will
286handle addition and removal of operations or constants, compatibility-breaking
287changes, and other modifications without crashing either the host or client
288process.
289
290We recommend the following IPC mechanisms, in order of preference:
291
292#### Stable AIDL <a name="ipc-stableaidl"></a>
293
294Stable AIDL is used by the Android platform and AndroidX to provide a
295platform-native IPC mechanism with strong inter-process compatibility
296guarantees. It supports a subset of standard AIDL.
297
298Use Stable AIDL if your library:
299
300-   Needs to send and receive Android's `Parcelable` data types
301-   Communicates directly with the Android platform, System UI, or other AOSP
302    components *or* is likely to do so in the future
303
304**Do not** use Stable AIDL to persist data to disk.
305
306##### Using Stable AIDL {#ipc-stableaidl-using}
307
308To add Stable AIDL definitions to your project:
309
3101.  Add the Stable AIDL plugin to `build.gradle`:
311
312    ```
313    plugins {
314      id("androidx.stableaidl")
315    }
316    ```
317
3182.  Enable the AIDL build feature and specify an initial version for your Stable
319    AIDL interfaces in `build.gradle`:
320
321    ```
322    android {
323      buildFeatures {
324        aidl = true
325      }
326      buildTypes.all {
327        stableAidl {
328          version 1
329        }
330      }
331    }
332    ```
333
3343.  Migrate existing AIDL files or create new AIDL files under
335    `<project>/src/main/stableAidl`
336
3374.  Generate an initial set of Stable AIDL API tracking files by running
338
339    ```
340    ./gradlew :path:to:project:updateAidlApi
341    ```
342
343##### Annotating unstable AIDL {#ipc-stableaidl-unstable}
344
345Once an API that relies on an IPC contract ships to production in an app, the
346contract is locked in and must maintain compatibility to prevent crashing either
347end of an inter-process communication channel.
348
349Developers **should** annotate unstable IPC classes with a `@RequiresOptIn`
350annotation explaining that they must not be used in production code. Libraries
351**must not** opt-in to these annotations when such classes are referenced
352internally, and should instead propagate the annotations to public API surfaces.
353
354A single annotation for this purpose may be defined per library or atomic group:
355
356```java
357/**
358 * Parcelables and AIDL-generated classes bearing this annotation are not
359 * guaranteed to be stable and must not be used for inter-process communication
360 * in production.
361 */
362@RequiresOptIn
363public @interface UnstableAidlDefinition {}
364```
365
366Generally speaking, at this point in time no libraries should have unstable
367`Parcelable` classes defined in source code, but for completeness:
368
369```java
370@UnstableAidlDefinition
371public class ResultReceiver implements Parcelable { ... }
372```
373
374AIDL definition files under `src/aidl` should use `@JavaPassthrough` with a
375fully-qualified class name to annotate generated classes:
376
377```java
378@JavaPassthrough(annotation="@androidx.core.util.UnstableAidlDefinition")
379oneway interface IResultReceiver {
380    void send(int resultCode, in Bundle resultData);
381}
382```
383
384For Stable AIDL, the build system enforces per-CL compatibility guarantees. No
385annotations are required for Stable AIDL definition files under
386`src/stableAidl`.
387
388#### Protobuf <a name="ipc-protobuf"></a>
389
390Protobuf is used by many Google applications and services to provide an IPC and
391disk persistence mechanism with strong inter-process compatibility guarantees.
392
393Use Protobuf if your library:
394
395-   Communicates directly with other applications or services already using
396    Protobuf
397-   Your data structure is complex and likely to change over time - Needs to
398    persist data to disk
399
400If your data includes `FileDescriptor`s, `Binder`s, or other platform-defined
401`Parcelable` data structures, consider using Stable AIDL instead. Protobuf
402cannot directly handle these types, and they will need to be stored alongside
403the serialized Protobuf bytes in a `Bundle`.
404
405See [Protobuf](#dependencies-protobuf) for more information on using protocol
406buffers in your library.
407
408WARNING While Protobuf is capable of maintaining inter-process compatibility,
409AndroidX does not currently provide compatibility tracking or enforcement.
410Library owners must perform their own validation.
411
412NOTE We are currently investigating the suitability of Square's
413[`wire` library](https://github.com/square/wire) for handling protocol buffers
414in Android libraries. If adopted, it will replace `proto` library dependencies.
415Libraries that expose their serialization mechanism in their API surface *will
416not be able to migrate*.
417
418#### Bundle <a name="ipc-bundle"></a>
419
420`Bundle` is used by the Android platform and AndroidX as a lightweight IPC
421mechanism. It has the weakest type safety and compatibility guarantees of any
422recommendation, and it has many caveats that make it a poor choice.
423
424In some cases, you may need to use a `Bundle` to wrap another IPC mechanism so
425that it can be passed through Android platform APIs, e.g. a `Bundle` that wraps
426a `byte[]` representing a serialized Protobuf.
427
428Use `Bundle` if your library:
429
430-   Has a very simple data model that is unlikely to change in the future
431-   Needs to send or receive `Binder`s, `FileDescriptor`s, or platform-defined
432    `Parcelable`s
433    ([example](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core/src/main/java/androidx/core/graphics/drawable/IconCompat.java;l=820))
434
435Caveats for `Bundle` include:
436
437-   When running on Android S and below, accessing *any* entry in a `Bundle`
438    will result in the platform attempting to deserialize *every* entry. This
439    has been fixed in Android T and later with "lazy" bundles, but developers
440    should be careful when accessing `Bundle` on earlier platforms. If a single
441    entry cannot be loaded -- for example if a developer added a custom
442    `Parcelable` that doesn't exist in the receiver's classpath -- an exception
443    will be thrown when accessing *any* entry.
444-   On all platforms, library code that receives `Bundle`s data from outside the
445    process **must** read the data defensively. See previous note regarding
446    additional concerns for Android S and below.
447-   On all platforms, library code that sends `Bundle`s outside the process
448    *should* discourage clients from passing custom `Parcelable`s.
449-   `Bundle` provides no versioning and Jetpack provides no affordances for
450    tracking the keys or value types associated with a `Bundle`. Library owners
451    are responsible for providing their own system for guaranteeing wire format
452    compatibility between versions.
453
454#### Versioned Parcelable <a name="ipc-versionedparcelable"></a>
455
456`VersionedParcelable` is a deprecated library that was intended to provide
457compatibility guarantees around the Android platform's `Parcelable` class;
458however, the initial version contained bugs and it was not actively maintained.
459
460Use `VersionedParcelable` if your library:
461
462-   Is already using `VersionedParcelable` and you are aware of its
463    compatibility constraints
464
465**Do not** use `VersionedParcelable` in all other cases.
466
467#### Wire <a name="ipc-wire"></a>
468
469We are currently evaluating Square's [Wire](https://github.com/square/wire) as a
470front-end to Protobuf. If this library meets your team's needs based on your own
471research, feel free to use it.
472
473#### gRPC <a name="ipc-grpc"></a>
474
475Some clients have requested to use Google's [gRPC](https://grpc.io/) library to
476align with other Google products. It's okay to use gRPC for network
477communication or communication with libraries and services outside of AndroidX
478that are already using gRPC.
479
480**Do not** use gRPC to communicate between AndroidX libraries or with the
481Android platform.
482
483#### Parcelable <a name="ipc-parcelable"></a>
484
485**Do not** implement `Parcelable` for any class that may be used for IPC or
486otherwise exposed as public API. By default, `Parcelable` does not provide any
487compatibility guarantees and will result in crashes if fields are added or
488removed between library versions. If you are using Stable AIDL, you *may* use
489AIDL-defined parcelables for IPC but not public API.
490