Merge "Align boot jar exclusion with apex_contributions" into main
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 2be9c10..9f1e1e1 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -795,3 +795,127 @@
}
`)
}
+
+// Source and prebuilt apex provide different set of boot jars
+func TestNonBootJarMissingInPrebuiltFragment(t *testing.T) {
+ bp := `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: ["apex-fragment"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "foo",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: ["myapex"],
+ permitted_packages: ["foo"],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: ["myapex"],
+ permitted_packages: ["bar"],
+ }
+
+ bootclasspath_fragment {
+ name: "apex-fragment",
+ contents: ["foo", "bar"],
+ apex_available:[ "myapex" ],
+ hidden_api: {
+ split_packages: ["*"],
+ },
+ }
+
+ prebuilt_apex {
+ name: "com.google.android.myapex", // mainline prebuilt selection logic in soong relies on the naming convention com.google.android
+ apex_name: "myapex",
+ source_apex_name: "myapex",
+ src: "myapex.apex",
+ exported_bootclasspath_fragments: ["apex-fragment"],
+ }
+
+ java_import {
+ name: "foo",
+ jars: ["foo.jar"],
+ apex_available: ["myapex"],
+ permitted_packages: ["foo"],
+ }
+
+ prebuilt_bootclasspath_fragment {
+ name: "apex-fragment",
+ contents: ["foo"], // Unlike the source fragment, this is missing bar
+ apex_available:[ "myapex" ],
+ hidden_api: {
+ annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
+ metadata: "my-bootclasspath-fragment/metadata.csv",
+ index: "my-bootclasspath-fragment/index.csv",
+ stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
+ all_flags: "my-bootclasspath-fragment/all-flags.csv",
+ },
+ }
+
+ apex_contributions {
+ name: "my_apex_contributions",
+ api_domain: "myapex",
+ contents: [%v],
+ }
+ `
+ testCases := []struct {
+ desc string
+ configuredBootJars []string
+ apexContributionContents string
+ errorExpected bool
+ }{
+ {
+ desc: "Source apex is selected, and APEX_BOOT_JARS is correctly configured for source apex builds",
+ configuredBootJars: []string{"myapex:foo", "myapex:bar"},
+ },
+ {
+ desc: "Source apex is selected, and APEX_BOOT_JARS is missing bar",
+ configuredBootJars: []string{"myapex:foo"},
+ errorExpected: true,
+ },
+ {
+ desc: "Prebuilt apex is selected, and APEX_BOOT_JARS is correctly configured for prebuilt apex build",
+ configuredBootJars: []string{"myapex:foo"},
+ apexContributionContents: `"prebuilt_com.google.android.myapex"`,
+ },
+ {
+ desc: "Prebuilt apex is selected, and APEX_BOOT_JARS is missing foo",
+ configuredBootJars: []string{"myapex:bar"},
+ apexContributionContents: `"prebuilt_com.google.android.myapex"`,
+ errorExpected: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ fixture := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithMyapex,
+ java.FixtureConfigureApexBootJars(tc.configuredBootJars...),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BuildFlags = map[string]string{
+ "RELEASE_APEX_CONTRIBUTIONS_ART": "my_apex_contributions",
+ }
+ }),
+ )
+ if tc.errorExpected {
+ fixture = fixture.ExtendWithErrorHandler(
+ android.FixtureExpectsAtLeastOneErrorMatchingPattern(`in contents.*must also be declared in PRODUCT_APEX_BOOT_JARS`),
+ )
+ }
+ fixture.RunTestWithBp(t, fmt.Sprintf(bp, tc.apexContributionContents))
+ }
+}
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 72a9e52..b2afa39 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -835,7 +835,21 @@
android.SetProvider(ctx, android.PrebuiltInfoProvider, info)
}
+// Uses an object provided by its deps to validate that the contents of bcpf have been added to the global
+// PRODUCT_APEX_BOOT_JARS
+// This validation will only run on the apex which is active for this product/release_config
+func validateApexClasspathFragments(ctx android.ModuleContext) {
+ ctx.VisitDirectDeps(func(m android.Module) {
+ if info, exists := android.OtherModuleProvider(ctx, m, java.ClasspathFragmentValidationInfoProvider); exists {
+ ctx.ModuleErrorf("%s in contents of %s must also be declared in PRODUCT_APEX_BOOT_JARS", info.UnknownJars, info.ClasspathFragmentModuleName)
+ }
+ })
+}
+
func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Validate contents of classpath fragments
+ validateApexClasspathFragments(ctx)
+
p.apexKeysPath = writeApexKeys(ctx, p)
// TODO(jungjw): Check the key validity.
p.inputApex = android.OptionalPathForModuleSrc(ctx, p.prebuiltCommonProperties.Selected_apex).Path()
@@ -1059,6 +1073,9 @@
}
func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Validate contents of classpath fragments
+ validateApexClasspathFragments(ctx)
+
a.apexKeysPath = writeApexKeys(ctx, a)
a.installFilename = a.InstallFilename()
if !strings.HasSuffix(a.installFilename, imageApexSuffix) && !strings.HasSuffix(a.installFilename, imageCapexSuffix) {
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 82a34ca..4d3d794 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -590,13 +590,36 @@
// So ignore it even if it is not in PRODUCT_APEX_BOOT_JARS.
// TODO(b/202896428): Add better way to handle this.
_, unknown = android.RemoveFromList("android.car-module", unknown)
- if isActiveModule(ctx, ctx.Module()) && len(unknown) > 0 {
- ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_APEX_BOOT_JARS", unknown)
+ if isApexVariant(ctx) && len(unknown) > 0 {
+ if android.IsModulePrebuilt(ctx.Module()) {
+ // prebuilt bcpf. the validation of this will be done at the top-level apex
+ providerClasspathFragmentValidationInfoProvider(ctx, unknown)
+ } else if !disableSourceApexVariant(ctx) {
+ // source bcpf, and prebuilt apex are not selected.
+ ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_APEX_BOOT_JARS", unknown)
+ }
}
}
return jars
}
+var ClasspathFragmentValidationInfoProvider = blueprint.NewProvider[ClasspathFragmentValidationInfo]()
+
+type ClasspathFragmentValidationInfo struct {
+ ClasspathFragmentModuleName string
+ UnknownJars []string
+}
+
+// Set a provider with the list of jars that have not been added to PRODUCT_APEX_BOOT_JARS
+// The validation will be done in the ctx of the top-level _selected_ apex
+func providerClasspathFragmentValidationInfoProvider(ctx android.ModuleContext, unknown []string) {
+ info := ClasspathFragmentValidationInfo{
+ ClasspathFragmentModuleName: ctx.ModuleName(),
+ UnknownJars: unknown,
+ }
+ android.SetProvider(ctx, ClasspathFragmentValidationInfoProvider, info)
+}
+
// generateHiddenAPIBuildActions generates all the hidden API related build rules.
func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) *HiddenAPIOutput {