Loading apex/platform_bootclasspath_test.go +124 −0 Original line number Diff line number Diff line Loading @@ -795,3 +795,127 @@ func TestNonBootJarInFragment(t *testing.T) { } `) } // 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)) } } apex/prebuilt.go +17 −0 Original line number Diff line number Diff line Loading @@ -835,7 +835,21 @@ func (p *prebuiltCommon) providePrebuiltInfo(ctx android.ModuleContext) { 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() Loading Loading @@ -1059,6 +1073,9 @@ func (a *ApexSet) ApexInfoMutator(mctx android.TopDownMutatorContext) { } 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) { Loading java/bootclasspath_fragment.go +25 −2 Original line number Diff line number Diff line Loading @@ -590,13 +590,36 @@ func (b *BootclasspathFragmentModule) configuredJars(ctx android.ModuleContext) // 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 { 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 { Loading Loading
apex/platform_bootclasspath_test.go +124 −0 Original line number Diff line number Diff line Loading @@ -795,3 +795,127 @@ func TestNonBootJarInFragment(t *testing.T) { } `) } // 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)) } }
apex/prebuilt.go +17 −0 Original line number Diff line number Diff line Loading @@ -835,7 +835,21 @@ func (p *prebuiltCommon) providePrebuiltInfo(ctx android.ModuleContext) { 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() Loading Loading @@ -1059,6 +1073,9 @@ func (a *ApexSet) ApexInfoMutator(mctx android.TopDownMutatorContext) { } 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) { Loading
java/bootclasspath_fragment.go +25 −2 Original line number Diff line number Diff line Loading @@ -590,13 +590,36 @@ func (b *BootclasspathFragmentModule) configuredJars(ctx android.ModuleContext) // 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 { 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 { Loading