From 932cdfeb062032b98e237a005a634446a23acd19 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Thu, 28 May 2020 00:19:53 +0900 Subject: [PATCH] Add default_to_stubs option to java_sdk_library Previously, when a lib that doesn't have sdk_version property set depends on a java_sdk_library, the impl library was used for linking. This might be too permissive because the client lib might be using empty sdk_version because it needed some private APIs from the platform, but not from the java_sdk_library. This actually happend for some of the CTS tests. They don't set sdk_version, but were directly depending on android.test.[base|runner|mock].stubs libraries. If we switch the references to the stub libraries into the corresponding java_sdk_library modules (e.g. aandroid.test.[base|runner|mock]), then we would be allowing private APIs to the CTS tests, which is not good. To solve this problem, default_to_stub property is introduced. It when set to true prevents the impl lib from being used for linking. When a module that doesn't have sdk_version depends on it, the widest API surface that the java_sdk_library provides is linked instead. Bug: 157007292 Test: m Change-Id: Id2acc3cafb71d1e90d4fdc9c0c70a73983355e0f --- java/java_test.go | 27 +++++++++++++++++++++++++++ java/sdk_library.go | 19 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/java/java_test.go b/java/java_test.go index 9266d295d..8ea34d975 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -1465,6 +1465,33 @@ func TestJavaSdkLibrary_FallbackScope(t *testing.T) { `) } +func TestJavaSdkLibrary_DefaultToStubs(t *testing.T) { + ctx, _ := testJava(t, ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + system: { + enabled: true, + }, + default_to_stubs: true, + } + + java_library { + name: "baz", + srcs: ["a.java"], + libs: ["foo"], + // does not have sdk_version set, should fallback to module, + // which will then fallback to system because the module scope + // is not enabled. + } + `) + // The baz library should depend on the system stubs jar. + bazLibrary := ctx.ModuleForTests("baz", "android_common").Rule("javac") + if expected, actual := `^-classpath .*:/[^:]*/turbine-combined/foo\.stubs.system\.jar$`, bazLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { + t.Errorf("expected %q, found %#q", expected, actual) + } +} + var compilerFlagsTestCases = []struct { in string out bool diff --git a/java/sdk_library.go b/java/sdk_library.go index 237be1076..bf0d3d633 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -435,6 +435,14 @@ type sdkLibraryProperties struct { // disabled by default. Module_lib ApiScopeProperties + // Determines if the stubs are preferred over the implementation library + // for linking, even when the client doesn't specify sdk_version. When this + // is set to true, such clients are provided with the widest API surface that + // this lib provides. Note however that this option doesn't affect the clients + // that are in the same APEX as this library. In that case, the clients are + // always linked with the implementation library. Default is false. + Default_to_stubs *bool + // Properties related to api linting. Api_lint struct { // Enable api linting. @@ -1342,6 +1350,13 @@ func (module *SdkLibrary) withinSameApexAs(other android.Module) bool { } func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths { + // If the client doesn't set sdk_version, but if this library prefers stubs over + // the impl library, let's provide the widest API surface possible. To do so, + // force override sdk_version to module_current so that the closest possible API + // surface could be found in selectHeaderJarsForSdkVersion + if module.defaultsToStubs() && !sdkVersion.specified() { + sdkVersion = sdkSpecFrom("module_current") + } // Only provide access to the implementation library if it is actually built. if module.requiresRuntimeImplementationLibrary() { @@ -1505,6 +1520,10 @@ func (module *SdkLibrary) requiresRuntimeImplementationLibrary() bool { return !proptools.Bool(module.sdkLibraryProperties.Api_only) } +func (module *SdkLibrary) defaultsToStubs() bool { + return proptools.Bool(module.sdkLibraryProperties.Default_to_stubs) +} + // Defines how to name the individual component modules the sdk library creates. type sdkLibraryComponentNamingScheme interface { stubsLibraryModuleName(scope *apiScope, baseName string) string