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