summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Spandan Das <spandandas@google.com> 2023-12-20 20:13:34 +0000
committer Spandan Das <spandandas@google.com> 2024-01-02 17:56:14 +0000
commit64c9e0ce6e4aa183b2fae40a18e3e5435c49229d (patch)
treee7a6bed3d974b4e0e0b4b73ee63bfbaa537a5d07
parentad579a8c713215e60ac9f560bd32684f604cda7b (diff)
Use the correct bootjars for hiddneapi when multiple prebuilts exist
hiddenapi processing require boot jars from apexes to determine the full set of methods available at runtime. When building with prebuilts, this comes via java_import/java_sdk_library_import, which acts as a hook for prebuilt_apex/apex_set. If we have multiple apexes in the tree, this hook becomes 1:many. This CL prepares platform_bootclasspath to select the right deapexerd .jar files when mutliple prebuilts exist. Implementation details - Create a dependency edge from platform_bootclasspath to all_apex_contributions (DepsMutator) - For every boot jar, query all_apex_contributions to get the path to dexjar file (GenerateAndroidBuildActions) Some other important details - This CL does not drop the old mechanism to get the dex file (i.e. by creating a dep on java_library). Once all mainline modules have been flagged using apex_contributions, the old mechanism will be dropped - This CL has a functional change when building with source apexes. At ToT, the unecoded hiddenapi dex jar is used for package check and generating the monolithic stub file. After this change, the hiddenapi encoded file will be used for these operations. This should be fine since the package and dex signature do not change across the encoded and unencoded dex file. In fact, we already have a split today. When building with prebuilts, we use the encoded dex file. When building with source, we use the unecoded dex file. Test: Added a unit test Test: Manual testing in internal described below - lunch cf_x86_64_phone-next-userdebug - flagged com.google.android.adservices using apex_contributions - aninja -t commands out/soong/hiddenapi/hiddenapi-stubs-flags.txt # no diff before and after Bug: 308790777 Change-Id: I72c70f0ae1b587679203ea254c9c12a48e7aa782
-rw-r--r--apex/apex_test.go16
-rw-r--r--apex/platform_bootclasspath_test.go6
-rw-r--r--java/dexpreopt_bootjars.go44
-rw-r--r--java/hiddenapi_modular.go19
-rw-r--r--java/platform_bootclasspath.go11
5 files changed, 80 insertions, 16 deletions
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 616421af5..1b9fa19f0 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -11436,6 +11436,20 @@ func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) {
}
}
+ // Check that the boot jars of the selected apex are run through boot_jars_package_check
+ // This validates that the jars on the bootclasspath do not contain packages outside an allowlist
+ checkBootJarsPackageCheck := func(t *testing.T, ctx *android.TestContext, expectedBootJar string) {
+ platformBcp := ctx.ModuleForTests("platform-bootclasspath", "android_common")
+ bootJarsCheckRule := platformBcp.Rule("boot_jars_package_check")
+ android.AssertStringMatches(t, "Could not find the correct boot dex jar in package check rule", bootJarsCheckRule.RuleParams.Command, "build/soong/scripts/check_boot_jars/package_allowed_list.txt.*"+expectedBootJar)
+ }
+
+ // Check that the boot jars used to generate the monolithic hiddenapi flags come from the selected apex
+ checkBootJarsForMonolithicHiddenapi := func(t *testing.T, ctx *android.TestContext, expectedBootJar string) {
+ monolithicHiddenapiFlagsCmd := ctx.ModuleForTests("platform-bootclasspath", "android_common").Output("out/soong/hiddenapi/hiddenapi-stub-flags.txt").RuleParams.Command
+ android.AssertStringMatches(t, "Could not find the correct boot dex jar in monolithic hiddenapi flags generation command", monolithicHiddenapiFlagsCmd, "--boot-dex="+expectedBootJar)
+ }
+
bp := `
// Source APEX.
@@ -11575,5 +11589,7 @@ func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) {
)
ctx := testDexpreoptWithApexes(t, bp, "", preparer, fragment)
checkBootDexJarPath(t, ctx, "framework-foo", tc.expectedBootJar)
+ checkBootJarsPackageCheck(t, ctx, tc.expectedBootJar)
+ checkBootJarsForMonolithicHiddenapi(t, ctx, tc.expectedBootJar)
}
}
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index b741963c8..01b616bb6 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -382,6 +382,9 @@ func TestPlatformBootclasspathDependencies(t *testing.T) {
// Make sure that the myplatform-bootclasspath has the correct dependencies.
CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
+ // source vs prebuilt selection metadata module
+ `platform:all_apex_contributions`,
+
// The following are stubs.
`platform:android_stubs_current`,
`platform:android_system_stubs_current`,
@@ -534,6 +537,9 @@ func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) {
// Make sure that the myplatform-bootclasspath has the correct dependencies.
CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
+ // source vs prebuilt selection metadata module
+ `platform:all_apex_contributions`,
+
// The following are stubs.
"platform:prebuilt_sdk_public_current_android",
"platform:prebuilt_sdk_system_current_android",
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 73609bfb1..82cece346 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -699,28 +699,40 @@ func getModulesForImage(ctx android.ModuleContext, imageConfig *bootImageConfig)
// extractEncodedDexJarsFromModulesOrBootclasspathFragments gets the hidden API encoded dex jars for
// the given modules.
func extractEncodedDexJarsFromModulesOrBootclasspathFragments(ctx android.ModuleContext, apexJarModulePairs []apexJarModulePair) bootDexJarByModule {
- apexNameToBcpInfoMap := getApexNameToBcpInfoMap(ctx)
+ apexNameToApexExportInfoMap := getApexNameToApexExportsInfoMap(ctx)
encodedDexJarsByModuleName := bootDexJarByModule{}
for _, pair := range apexJarModulePairs {
- dexJarPath := getDexJarForApex(ctx, pair, apexNameToBcpInfoMap)
+ dexJarPath := getDexJarForApex(ctx, pair, apexNameToApexExportInfoMap)
encodedDexJarsByModuleName.addPath(pair.jarModule, dexJarPath)
}
return encodedDexJarsByModuleName
}
+type apexNameToApexExportsInfoMap map[string]android.ApexExportsInfo
+
+// javaLibraryPathOnHost returns the path to the java library which is exported by the apex for hiddenapi and dexpreopt and a boolean indicating whether the java library exists
+// For prebuilt apexes, this is created by deapexing the prebuilt apex
+func (m *apexNameToApexExportsInfoMap) javaLibraryDexPathOnHost(ctx android.ModuleContext, apex string, javalib string) (android.Path, bool) {
+ if info, exists := (*m)[apex]; exists {
+ if dex, exists := info.LibraryNameToDexJarPathOnHost[javalib]; exists {
+ return dex, true
+ } else {
+ ctx.ModuleErrorf("Apex %s does not provide a dex boot jar for library %s\n", apex, javalib)
+ }
+ }
+ // An apex entry could not be found. Return false.
+ // TODO: b/308174306 - When all the mainline modules have been flagged, make this a hard error
+ return nil, false
+}
+
// Returns the java libraries exported by the apex for hiddenapi and dexpreopt
// This information can come from two mechanisms
// 1. New: Direct deps to _selected_ apexes. The apexes return a ApexExportsInfo
// 2. Legacy: An edge to java_library or java_import (java_sdk_library) module. For prebuilt apexes, this serves as a hook and is populated by deapexers of prebuilt apxes
// TODO: b/308174306 - Once all mainline modules have been flagged, drop (2)
-func getDexJarForApex(ctx android.ModuleContext, pair apexJarModulePair, apexNameToBcpInfoMap map[string]android.ApexExportsInfo) android.Path {
- if info, exists := apexNameToBcpInfoMap[pair.apex]; exists {
- libraryName := android.RemoveOptionalPrebuiltPrefix(pair.jarModule.Name())
- if dex, exists := info.LibraryNameToDexJarPathOnHost[libraryName]; exists {
- return dex
- } else {
- ctx.ModuleErrorf("Apex %s does not provide a dex boot jar for library %s\n", pair.apex, libraryName)
- }
+func getDexJarForApex(ctx android.ModuleContext, pair apexJarModulePair, apexNameToApexExportsInfoMap apexNameToApexExportsInfoMap) android.Path {
+ if dex, found := apexNameToApexExportsInfoMap.javaLibraryDexPathOnHost(ctx, pair.apex, android.RemoveOptionalPrebuiltPrefix(pair.jarModule.Name())); found {
+ return dex
}
// TODO: b/308174306 - Remove the legacy mechanism
if android.IsConfiguredJarForPlatform(pair.apex) || android.IsModulePrebuilt(pair.jarModule) {
@@ -900,14 +912,14 @@ func getProfilePathForApex(ctx android.ModuleContext, apexName string, apexNameT
return fragment.(commonBootclasspathFragment).getProfilePath()
}
-func getApexNameToBcpInfoMap(ctx android.ModuleContext) map[string]android.ApexExportsInfo {
- apexNameToBcpInfoMap := map[string]android.ApexExportsInfo{}
+func getApexNameToApexExportsInfoMap(ctx android.ModuleContext) apexNameToApexExportsInfoMap {
+ apexNameToApexExportsInfoMap := apexNameToApexExportsInfoMap{}
ctx.VisitDirectDepsWithTag(dexpreoptBootJarDepTag, func(am android.Module) {
if info, exists := android.OtherModuleProvider(ctx, am, android.ApexExportsInfoProvider); exists {
- apexNameToBcpInfoMap[info.ApexName] = info
+ apexNameToApexExportsInfoMap[info.ApexName] = info
}
})
- return apexNameToBcpInfoMap
+ return apexNameToApexExportsInfoMap
}
// Generate boot image build rules for a specific target.
@@ -952,7 +964,7 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p
invocationPath := outputPath.ReplaceExtension(ctx, "invocation")
- apexNameToBcpInfoMap := getApexNameToBcpInfoMap(ctx)
+ apexNameToApexExportsInfoMap := getApexNameToApexExportsInfoMap(ctx)
cmd.Tool(globalSoong.Dex2oat).
Flag("--avoid-storing-invocation").
@@ -966,7 +978,7 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p
}
for _, apex := range image.profileImports {
- importedProfile := getProfilePathForApex(ctx, apex, apexNameToBcpInfoMap)
+ importedProfile := getProfilePathForApex(ctx, apex, apexNameToApexExportsInfoMap)
if importedProfile == nil {
ctx.ModuleErrorf("Boot image config '%[1]s' imports profile from '%[2]s', but '%[2]s' "+
"doesn't provide a profile",
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index bf9975784..c3caa084f 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -19,6 +19,7 @@ import (
"strings"
"android/soong/android"
+ "android/soong/dexpreopt"
"github.com/google/blueprint"
)
@@ -1250,9 +1251,27 @@ func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, suffix s
}
// extractBootDexJarsFromModules extracts the boot dex jars from the supplied modules.
+// This information can come from two mechanisms
+// 1. New: Direct deps to _selected_ apexes. The apexes contain a ApexExportsInfo
+// 2. Legacy: An edge to java_sdk_library(_import) module. For prebuilt apexes, this serves as a hook and is populated by deapexers of prebuilt apxes
+// TODO: b/308174306 - Once all mainline modules have been flagged, drop (2)
func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
bootDexJars := bootDexJarByModule{}
+
+ apexNameToApexExportsInfoMap := getApexNameToApexExportsInfoMap(ctx)
+ // For ART and mainline module jars, query apexNameToApexExportsInfoMap to get the dex file
+ apexJars := dexpreopt.GetGlobalConfig(ctx).ArtApexJars.AppendList(&dexpreopt.GetGlobalConfig(ctx).ApexBootJars)
+ for i := 0; i < apexJars.Len(); i++ {
+ if dex, found := apexNameToApexExportsInfoMap.javaLibraryDexPathOnHost(ctx, apexJars.Apex(i), apexJars.Jar(i)); found {
+ bootDexJars[apexJars.Jar(i)] = dex
+ }
+ }
+
+ // TODO - b/308174306: Drop the legacy mechanism
for _, module := range contents {
+ if _, exists := bootDexJars[android.RemoveOptionalPrebuiltPrefix(module.Name())]; exists {
+ continue
+ }
hiddenAPIModule := hiddenAPIModuleFromModule(ctx, module)
if hiddenAPIModule == nil {
continue
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 88d1ae8c0..4db426e0d 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -106,6 +106,9 @@ func (b *platformBootclasspathModule) OutputFiles(tag string) (android.Paths, er
}
func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+ // Create a dependency on all_apex_contributions to determine the selected mainline module
+ ctx.AddDependency(ctx.Module(), apexContributionsMetadataDepTag, "all_apex_contributions")
+
b.hiddenAPIDepsMutator(ctx)
if !dexpreopt.IsDex2oatNeeded(ctx) {
@@ -130,6 +133,8 @@ func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpM
func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
// Add dependencies on all the ART jars.
global := dexpreopt.GetGlobalConfig(ctx)
+ addDependenciesOntoSelectedBootImageApexes(ctx, "com.android.art")
+ // TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly
addDependenciesOntoBootImageModules(ctx, global.ArtApexJars, platformBootclasspathArtBootJarDepTag)
// Add dependencies on all the non-updatable jars, which are on the platform or in non-updatable
@@ -138,6 +143,12 @@ func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.Botto
// Add dependencies on all the updatable jars, except the ART jars.
apexJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
+ apexes := []string{}
+ for i := 0; i < apexJars.Len(); i++ {
+ apexes = append(apexes, apexJars.Apex(i))
+ }
+ addDependenciesOntoSelectedBootImageApexes(ctx, android.FirstUniqueStrings(apexes)...)
+ // TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly
addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag)
// Add dependencies on all the fragments.