xref: /aosp_15_r20/frameworks/base/ravenwood/api-maintainers.md (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1# Ravenwood for API Maintainers
2
3By default, Android APIs aren’t opted-in to Ravenwood, and they default to throwing when called under the Ravenwood environment.
4
5To opt-in to supporting an API under Ravenwood, you can use the inline annotations documented below to customize your API behavior when running under Ravenwood.  Because these annotations are inline in the relevant platform source code, they serve as valuable reminders to future API maintainers of Ravenwood support expectations.
6
7> **Note:** to ensure that API teams are well-supported during early Ravenwood onboarding, the Ravenwood team is manually maintaining an allow-list of classes that are able to use Ravenwood annotations.  Please reach out to ravenwood@ so we can offer design advice and allow-list your APIs.
8
9These Ravenwood-specific annotations have no bearing on the status of an API being public, `@SystemApi`, `@TestApi`, `@hide`, etc.  Ravenwood annotations are an orthogonal concept that are only consumed by the internal `hoststubgen` tool during a post-processing step that generates the Ravenwood runtime environment.  Teams that own APIs can continue to refactor opted-in `@hide` implementation details, as long as the test-visible behavior continues passing.
10
11As described in our Guiding Principles, when a team opts-in an API, we’re requiring that they bring along “bivalent” tests (such as the relevant CTS) to validate that Ravenwood behaves just like a physical device.  At the moment this means adding the bivalent tests to relevant `TEST_MAPPING` files to ensure they remain consistently passing over time.  These bivalent tests are important because they progressively provide the foundation on which higher-level unit tests place their trust.
12
13## Opt-in to supporting a single method while other methods remained opt-out
14
15```
16@RavenwoodKeepPartialClass
17public class MyManager {
18    @RavenwoodKeep
19    public static String modeToString(int mode) {
20        // This method implementation runs as-is on both devices and Ravenwood
21    }
22
23    public static void doComplex() {
24        // This method implementation runs as-is on devices, but because there
25        // is no method-level annotation, and the class-level default is
26        // “keep partial”, this method is not supported under Ravenwood and
27        // will throw
28    }
29}
30```
31
32## Opt-in an entire class with opt-out of specific methods
33
34```
35@RavenwoodKeepWholeClass
36public class MyStruct {
37    public void doSimple() {
38        // This method implementation runs as-is on both devices and Ravenwood,
39        // implicitly inheriting the class-level annotation
40    }
41
42    @RavenwoodThrow
43    public void doComplex() {
44        // This method implementation runs as-is on devices, but the
45        // method-level annotation overrides the class-level annotation, so
46        // this method is not supported under Ravenwood and will throw
47    }
48}
49```
50
51## Replace a complex method when under Ravenwood
52
53```
54@RavenwoodKeepWholeClass
55public class MyStruct {
56    @RavenwoodReplace
57    public void doComplex() {
58        // This method implementation runs as-is on devices, but the
59        // implementation is replaced/substituted by the
60        // doComplex$ravenwood() method implementation under Ravenwood
61    }
62
63    public void doComplex$ravenwood() {
64        // This method implementation only runs under Ravenwood
65    }
66}
67```
68
69## General strategies for side-stepping tricky dependencies
70
71The “replace” strategy described above is quite powerful, and can be used in creative ways to sidestep tricky underlying dependencies that aren’t ready yet.
72
73For example, consider a constructor or static initializer that relies on unsupported functionality from another team.  By factoring the unsupported logic into a dedicated method, that method can then be replaced under Ravenwood to offer baseline functionality.
74
75## Strategies for JNI
76
77At the moment, JNI isn't yet supported under Ravenwood, but you may still want to support APIs that are partially implemented with JNI.  The current approach is to use the “replace” strategy to offer a pure-Java alternative implementation for any JNI-provided logic.
78
79Since this approach requires potentially complex re-implementation, it should only be considered for core infrastructure that is critical to unblocking widespread testing use-cases.  Other less-common usages of JNI should instead wait for offical JNI support in the Ravenwood environment.
80
81When a pure-Java implementation grows too large or complex to host within the original class, the `@RavenwoodNativeSubstitutionClass` annotation can be used to host it in a separate source file:
82
83```
84@RavenwoodKeepWholeClass
85@RavenwoodNativeSubstitutionClass("com.android.platform.test.ravenwood.nativesubstitution.MyComplexClass_host")
86public class MyComplexClass {
87    private static native void nativeDoThing(long nativePtr);
88...
89
90public class MyComplexClass_host {
91    public static void nativeDoThing(long nativePtr) {
92        // ...
93    }
94```
95