1*d57664e9SAndroid Build Coastguard Worker# Ravenwood for API Maintainers 2*d57664e9SAndroid Build Coastguard Worker 3*d57664e9SAndroid Build Coastguard WorkerBy default, Android APIs aren’t opted-in to Ravenwood, and they default to throwing when called under the Ravenwood environment. 4*d57664e9SAndroid Build Coastguard Worker 5*d57664e9SAndroid Build Coastguard WorkerTo 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*d57664e9SAndroid Build Coastguard Worker 7*d57664e9SAndroid Build Coastguard Worker> **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*d57664e9SAndroid Build Coastguard Worker 9*d57664e9SAndroid Build Coastguard WorkerThese 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*d57664e9SAndroid Build Coastguard Worker 11*d57664e9SAndroid Build Coastguard WorkerAs 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*d57664e9SAndroid Build Coastguard Worker 13*d57664e9SAndroid Build Coastguard Worker## Opt-in to supporting a single method while other methods remained opt-out 14*d57664e9SAndroid Build Coastguard Worker 15*d57664e9SAndroid Build Coastguard Worker``` 16*d57664e9SAndroid Build Coastguard Worker@RavenwoodKeepPartialClass 17*d57664e9SAndroid Build Coastguard Workerpublic class MyManager { 18*d57664e9SAndroid Build Coastguard Worker @RavenwoodKeep 19*d57664e9SAndroid Build Coastguard Worker public static String modeToString(int mode) { 20*d57664e9SAndroid Build Coastguard Worker // This method implementation runs as-is on both devices and Ravenwood 21*d57664e9SAndroid Build Coastguard Worker } 22*d57664e9SAndroid Build Coastguard Worker 23*d57664e9SAndroid Build Coastguard Worker public static void doComplex() { 24*d57664e9SAndroid Build Coastguard Worker // This method implementation runs as-is on devices, but because there 25*d57664e9SAndroid Build Coastguard Worker // is no method-level annotation, and the class-level default is 26*d57664e9SAndroid Build Coastguard Worker // “keep partial”, this method is not supported under Ravenwood and 27*d57664e9SAndroid Build Coastguard Worker // will throw 28*d57664e9SAndroid Build Coastguard Worker } 29*d57664e9SAndroid Build Coastguard Worker} 30*d57664e9SAndroid Build Coastguard Worker``` 31*d57664e9SAndroid Build Coastguard Worker 32*d57664e9SAndroid Build Coastguard Worker## Opt-in an entire class with opt-out of specific methods 33*d57664e9SAndroid Build Coastguard Worker 34*d57664e9SAndroid Build Coastguard Worker``` 35*d57664e9SAndroid Build Coastguard Worker@RavenwoodKeepWholeClass 36*d57664e9SAndroid Build Coastguard Workerpublic class MyStruct { 37*d57664e9SAndroid Build Coastguard Worker public void doSimple() { 38*d57664e9SAndroid Build Coastguard Worker // This method implementation runs as-is on both devices and Ravenwood, 39*d57664e9SAndroid Build Coastguard Worker // implicitly inheriting the class-level annotation 40*d57664e9SAndroid Build Coastguard Worker } 41*d57664e9SAndroid Build Coastguard Worker 42*d57664e9SAndroid Build Coastguard Worker @RavenwoodThrow 43*d57664e9SAndroid Build Coastguard Worker public void doComplex() { 44*d57664e9SAndroid Build Coastguard Worker // This method implementation runs as-is on devices, but the 45*d57664e9SAndroid Build Coastguard Worker // method-level annotation overrides the class-level annotation, so 46*d57664e9SAndroid Build Coastguard Worker // this method is not supported under Ravenwood and will throw 47*d57664e9SAndroid Build Coastguard Worker } 48*d57664e9SAndroid Build Coastguard Worker} 49*d57664e9SAndroid Build Coastguard Worker``` 50*d57664e9SAndroid Build Coastguard Worker 51*d57664e9SAndroid Build Coastguard Worker## Replace a complex method when under Ravenwood 52*d57664e9SAndroid Build Coastguard Worker 53*d57664e9SAndroid Build Coastguard Worker``` 54*d57664e9SAndroid Build Coastguard Worker@RavenwoodKeepWholeClass 55*d57664e9SAndroid Build Coastguard Workerpublic class MyStruct { 56*d57664e9SAndroid Build Coastguard Worker @RavenwoodReplace 57*d57664e9SAndroid Build Coastguard Worker public void doComplex() { 58*d57664e9SAndroid Build Coastguard Worker // This method implementation runs as-is on devices, but the 59*d57664e9SAndroid Build Coastguard Worker // implementation is replaced/substituted by the 60*d57664e9SAndroid Build Coastguard Worker // doComplex$ravenwood() method implementation under Ravenwood 61*d57664e9SAndroid Build Coastguard Worker } 62*d57664e9SAndroid Build Coastguard Worker 63*d57664e9SAndroid Build Coastguard Worker public void doComplex$ravenwood() { 64*d57664e9SAndroid Build Coastguard Worker // This method implementation only runs under Ravenwood 65*d57664e9SAndroid Build Coastguard Worker } 66*d57664e9SAndroid Build Coastguard Worker} 67*d57664e9SAndroid Build Coastguard Worker``` 68*d57664e9SAndroid Build Coastguard Worker 69*d57664e9SAndroid Build Coastguard Worker## General strategies for side-stepping tricky dependencies 70*d57664e9SAndroid Build Coastguard Worker 71*d57664e9SAndroid Build Coastguard WorkerThe “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*d57664e9SAndroid Build Coastguard Worker 73*d57664e9SAndroid Build Coastguard WorkerFor 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*d57664e9SAndroid Build Coastguard Worker 75*d57664e9SAndroid Build Coastguard Worker## Strategies for JNI 76*d57664e9SAndroid Build Coastguard Worker 77*d57664e9SAndroid Build Coastguard WorkerAt 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*d57664e9SAndroid Build Coastguard Worker 79*d57664e9SAndroid Build Coastguard WorkerSince 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*d57664e9SAndroid Build Coastguard Worker 81*d57664e9SAndroid Build Coastguard WorkerWhen 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*d57664e9SAndroid Build Coastguard Worker 83*d57664e9SAndroid Build Coastguard Worker``` 84*d57664e9SAndroid Build Coastguard Worker@RavenwoodKeepWholeClass 85*d57664e9SAndroid Build Coastguard Worker@RavenwoodNativeSubstitutionClass("com.android.platform.test.ravenwood.nativesubstitution.MyComplexClass_host") 86*d57664e9SAndroid Build Coastguard Workerpublic class MyComplexClass { 87*d57664e9SAndroid Build Coastguard Worker private static native void nativeDoThing(long nativePtr); 88*d57664e9SAndroid Build Coastguard Worker... 89*d57664e9SAndroid Build Coastguard Worker 90*d57664e9SAndroid Build Coastguard Workerpublic class MyComplexClass_host { 91*d57664e9SAndroid Build Coastguard Worker public static void nativeDoThing(long nativePtr) { 92*d57664e9SAndroid Build Coastguard Worker // ... 93*d57664e9SAndroid Build Coastguard Worker } 94*d57664e9SAndroid Build Coastguard Worker``` 95