Utilize module lib and test api superset module in hiddenapi

Hiddenapi takes a single widest api scope stub dex jar as an input, as
the tool does not support handling duplicate classes passed as inputs.
A problem regarding this is that the test and module lib api surfaces do
not strictly have a subset/superset relationship, unlike other api
surfaces.

This has not become a problem for stubs generated from source
files as the stubs contain all methods in the source files, but became a
problem for stubs genereated from text files as the stubs only contain
the methods that are essential for compilation of the stubs and its
reverse dependencies, and there were cases where the hiddenapi flags are
not properly propagated to the subclasses.

To resolve this problem, a java_api_library module that provides the
union of the test and the module lib api surfaces was introcudes. Since
hiddenapi_modular currently defines the module lib api surface to be a
wider api scope over the test api scope, the new module can be passed as
input to hiddenapi over the module lib non updatable stub module to
resolve the problem.

Test: enable hiddenapi for from-text stub build && ENABLE_HIDDENAPI_FLAGS=true m --build-from-text-stub
Bug: 191644675
Bug: 275570206
Change-Id: I9a230ec5082c52ed866f29b0748814f2cf10279b
This commit is contained in:
Jihoon Kang 2023-10-06 16:54:58 +00:00
parent f00200b6fb
commit 244d42a91b
3 changed files with 67 additions and 4 deletions

View file

@ -316,6 +316,60 @@ func TestBootclasspathFragment_StubLibs(t *testing.T) {
android.AssertPathsRelativeToTopEquals(t, "widest dex stubs jar", expectedWidestPaths, info.TransitiveStubDexJarsByScope.StubDexJarsForWidestAPIScope()) android.AssertPathsRelativeToTopEquals(t, "widest dex stubs jar", expectedWidestPaths, info.TransitiveStubDexJarsByScope.StubDexJarsForWidestAPIScope())
} }
func TestFromTextWidestApiScope(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment,
PrepareForTestWithJavaSdkLibraryFiles,
android.FixtureModifyConfig(func(config android.Config) {
config.SetBuildFromTextStub(true)
}),
FixtureWithLastReleaseApis("mysdklibrary", "android-non-updatable"),
FixtureConfigureApexBootJars("someapex:mysdklibrary"),
).RunTestWithBp(t, `
bootclasspath_fragment {
name: "myfragment",
contents: ["mysdklibrary"],
additional_stubs: [
"android-non-updatable",
],
hidden_api: {
split_packages: ["*"],
},
}
java_sdk_library {
name: "mysdklibrary",
srcs: ["a.java"],
shared_library: false,
public: {enabled: true},
system: {enabled: true},
}
java_sdk_library {
name: "android-non-updatable",
srcs: ["b.java"],
compile_dex: true,
public: {
enabled: true,
},
system: {
enabled: true,
},
test: {
enabled: true,
},
module_lib: {
enabled: true,
},
}
`)
fragment := result.ModuleForTests("myfragment", "android_common")
dependencyStubDexFlag := "--dependency-stub-dex=out/soong/.intermediates/default/java/android-non-updatable.stubs.test_module_lib/android_common/dex/android-non-updatable.stubs.test_module_lib.jar"
stubFlagsCommand := fragment.Output("modular-hiddenapi/stub-flags.csv").RuleParams.Command
android.AssertStringDoesContain(t,
"Stub flags generating command does not include the expected dependency stub dex file",
stubFlagsCommand, dependencyStubDexFlag)
}
func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) { func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) {
result := android.GroupFixturePreparers( result := android.GroupFixturePreparers(
prepareForTestWithBootclasspathFragment, prepareForTestWithBootclasspathFragment,

View file

@ -38,10 +38,14 @@ type HiddenAPIScope struct {
// The option needed to passed to "hiddenapi list". // The option needed to passed to "hiddenapi list".
hiddenAPIListOption string hiddenAPIListOption string
// The name sof the source stub library modules that contain the API provided by the platform, // The names of the source stub library modules that contain the API provided by the platform,
// i.e. by modules that are not in an APEX. // i.e. by modules that are not in an APEX.
nonUpdatableSourceModule string nonUpdatableSourceModule string
// The names of from-text stub library modules that contain the API provided by the platform,
// i.e. by modules that are not in an APEX.
nonUpdatableFromTextModule string
// The names of the prebuilt stub library modules that contain the API provided by the platform, // The names of the prebuilt stub library modules that contain the API provided by the platform,
// i.e. by modules that are not in an APEX. // i.e. by modules that are not in an APEX.
nonUpdatablePrebuiltModule string nonUpdatablePrebuiltModule string
@ -86,6 +90,9 @@ func (l *HiddenAPIScope) scopeSpecificStubModule(ctx android.BaseModuleContext,
if ctx.Config().AlwaysUsePrebuiltSdks() { if ctx.Config().AlwaysUsePrebuiltSdks() {
return l.nonUpdatablePrebuiltModule return l.nonUpdatablePrebuiltModule
} else { } else {
if l.nonUpdatableFromTextModule != "" && ctx.Config().BuildFromTextStub() {
return l.nonUpdatableFromTextModule
}
return l.nonUpdatableSourceModule return l.nonUpdatableSourceModule
} }
} else { } else {
@ -117,8 +124,9 @@ var (
hiddenAPIListOption: "--test-stub-classpath", hiddenAPIListOption: "--test-stub-classpath",
}) })
ModuleLibHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{ ModuleLibHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
name: "module-lib", name: "module-lib",
sdkKind: android.SdkModule, sdkKind: android.SdkModule,
nonUpdatableFromTextModule: "android-non-updatable.stubs.test_module_lib",
}) })
CorePlatformHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{ CorePlatformHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
name: "core-platform", name: "core-platform",
@ -647,7 +655,7 @@ func (s StubDexJarsByModule) addStubDexJar(ctx android.ModuleContext, module and
// public version is provided by the art.module.public.api module. In those cases it is necessary // public version is provided by the art.module.public.api module. In those cases it is necessary
// to treat all those modules as they were the same name, otherwise it will result in multiple // to treat all those modules as they were the same name, otherwise it will result in multiple
// definitions of a single class being passed to hidden API processing which will cause an error. // definitions of a single class being passed to hidden API processing which will cause an error.
if name == scope.nonUpdatablePrebuiltModule || name == scope.nonUpdatableSourceModule { if name == scope.nonUpdatablePrebuiltModule || name == scope.nonUpdatableSourceModule || name == scope.nonUpdatableFromTextModule {
// Treat all *android-non-updatable* modules as if they were part of an android-non-updatable // Treat all *android-non-updatable* modules as if they were part of an android-non-updatable
// java_sdk_library. // java_sdk_library.
// TODO(b/192067200): Remove once android-non-updatable is a java_sdk_library or equivalent. // TODO(b/192067200): Remove once android-non-updatable is a java_sdk_library or equivalent.

View file

@ -491,6 +491,7 @@ func gatherRequiredDepsForTest() string {
"android-non-updatable.stubs.system.from-text": systemDroidstubs, "android-non-updatable.stubs.system.from-text": systemDroidstubs,
"android-non-updatable.stubs.test.from-text": testDroidstubs, "android-non-updatable.stubs.test.from-text": testDroidstubs,
"android-non-updatable.stubs.module_lib.from-text": moduleLibDroidstubs, "android-non-updatable.stubs.module_lib.from-text": moduleLibDroidstubs,
"android-non-updatable.stubs.test_module_lib": moduleLibDroidstubs,
} }
for _, droidstubs := range droidstubsStructs { for _, droidstubs := range droidstubsStructs {