diff --git a/android/Android.bp b/android/Android.bp index 841a6af6e..96e8133bf 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -106,6 +106,7 @@ bootstrap_go_package { "updatable_modules.go", "util.go", "variable.go", + "vintf_fragment.go", "visibility.go", ], testSrcs: [ @@ -148,6 +149,7 @@ bootstrap_go_package { "test_suites_test.go", "util_test.go", "variable_test.go", + "vintf_fragment_test.go", "visibility_test.go", ], } diff --git a/android/module.go b/android/module.go index f9fab96a9..e161959ab 100644 --- a/android/module.go +++ b/android/module.go @@ -111,6 +111,7 @@ type Module interface { RequiredModuleNames(ctx ConfigAndErrorContext) []string HostRequiredModuleNames() []string TargetRequiredModuleNames() []string + VintfFragmentModuleNames(ctx ConfigAndErrorContext) []string FilesToInstall() InstallPaths PackagingSpecs() []PackagingSpec @@ -497,6 +498,9 @@ type commonProperties struct { // The team (defined by the owner/vendor) who owns the property. Team *string `android:"path"` + + // vintf_fragment Modules required from this module. + Vintf_fragment_modules proptools.Configurable[[]string] `android:"path"` } type distProperties struct { @@ -1028,6 +1032,7 @@ func (m *ModuleBase) baseDepsMutator(ctx BottomUpMutatorContext) { fullManifest := pv.DeviceArch != nil && pv.DeviceName != nil if fullManifest { addRequiredDeps(ctx) + addVintfFragmentDeps(ctx) } } @@ -1105,6 +1110,16 @@ func addRequiredDeps(ctx BottomUpMutatorContext) { } } +var vintfDepTag = struct { + blueprint.BaseDependencyTag + InstallAlwaysNeededDependencyTag +}{} + +func addVintfFragmentDeps(ctx BottomUpMutatorContext) { + mod := ctx.Module() + ctx.AddDependency(mod, vintfDepTag, mod.VintfFragmentModuleNames(ctx)...) +} + // AddProperties "registers" the provided props // each value in props MUST be a pointer to a struct func (m *ModuleBase) AddProperties(props ...interface{}) { @@ -1597,6 +1612,10 @@ func (m *ModuleBase) TargetRequiredModuleNames() []string { return m.base().commonProperties.Target_required } +func (m *ModuleBase) VintfFragmentModuleNames(ctx ConfigAndErrorContext) []string { + return m.base().commonProperties.Vintf_fragment_modules.GetOrDefault(m.ConfigurableEvaluator(ctx), nil) +} + func (m *ModuleBase) InitRc() Paths { return append(Paths{}, m.initRcPaths...) } diff --git a/android/testing.go b/android/testing.go index dae787b7f..3a6643941 100644 --- a/android/testing.go +++ b/android/testing.go @@ -126,6 +126,10 @@ var PrepareForTestWithMakevars = FixtureRegisterWithContext(func(ctx Registratio ctx.RegisterSingletonType("makevars", makeVarsSingletonFunc) }) +var PrepareForTestVintfFragmentModules = FixtureRegisterWithContext(func(ctx RegistrationContext) { + registerVintfFragmentComponents(ctx) +}) + // Test fixture preparer that will register most java build components. // // Singletons and mutators should only be added here if they are needed for a majority of java @@ -149,6 +153,7 @@ var PrepareForTestWithAndroidBuildComponents = GroupFixturePreparers( PrepareForTestWithPackageModule, PrepareForTestWithPrebuilts, PrepareForTestWithVisibility, + PrepareForTestVintfFragmentModules, ) // Prepares an integration test with all build components from the android package. diff --git a/android/vintf_fragment.go b/android/vintf_fragment.go new file mode 100644 index 000000000..329eac974 --- /dev/null +++ b/android/vintf_fragment.go @@ -0,0 +1,84 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +type vintfFragmentProperties struct { + // Vintf fragment XML file. + Src string `android:"path"` +} + +type vintfFragmentModule struct { + ModuleBase + + properties vintfFragmentProperties + + installDirPath InstallPath + outputFilePath OutputPath +} + +func init() { + registerVintfFragmentComponents(InitRegistrationContext) +} + +func registerVintfFragmentComponents(ctx RegistrationContext) { + ctx.RegisterModuleType("vintf_fragment", vintfLibraryFactory) +} + +// vintf_fragment module processes vintf fragment file and installs under etc/vintf/manifest. +// Vintf fragment files formerly listed in vintf_fragment property would be transformed into +// this module type. +func vintfLibraryFactory() Module { + m := &vintfFragmentModule{} + m.AddProperties( + &m.properties, + ) + InitAndroidArchModule(m, DeviceSupported, MultilibFirst) + + return m +} + +func (m *vintfFragmentModule) GenerateAndroidBuildActions(ctx ModuleContext) { + builder := NewRuleBuilder(pctx, ctx) + srcVintfFragment := PathForModuleSrc(ctx, m.properties.Src) + processedVintfFragment := PathForModuleOut(ctx, srcVintfFragment.Base()) + + // Process vintf fragment source file with assemble_vintf tool + builder.Command(). + Flag("VINTF_IGNORE_TARGET_FCM_VERSION=true"). + BuiltTool("assemble_vintf"). + FlagWithInput("-i ", srcVintfFragment). + FlagWithOutput("-o ", processedVintfFragment) + + builder.Build("assemble_vintf", "Process vintf fragment "+processedVintfFragment.String()) + + m.installDirPath = PathForModuleInstall(ctx, "etc", "vintf", "manifest") + m.outputFilePath = processedVintfFragment.OutputPath + + ctx.InstallFile(m.installDirPath, processedVintfFragment.Base(), processedVintfFragment) +} + +// Make this module visible to AndroidMK so it can be referenced from modules defined from Android.mk files +func (m *vintfFragmentModule) AndroidMkEntries() []AndroidMkEntries { + return []AndroidMkEntries{{ + Class: "ETC", + OutputFile: OptionalPathForPath(m.outputFilePath), + ExtraEntries: []AndroidMkExtraEntriesFunc{ + func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries) { + entries.SetString("LOCAL_MODULE_PATH", m.installDirPath.String()) + entries.SetString("LOCAL_INSTALLED_MODULE_STEM", m.outputFilePath.Base()) + }, + }, + }} +} diff --git a/android/vintf_fragment_test.go b/android/vintf_fragment_test.go new file mode 100644 index 000000000..8be534cf4 --- /dev/null +++ b/android/vintf_fragment_test.go @@ -0,0 +1,36 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "strings" + "testing" +) + +func TestVintfManifestBuildAction(t *testing.T) { + bp := ` + vintf_fragment { + name: "test_vintf_fragment", + src: "test_vintf_file", + } + ` + + testResult := PrepareForTestWithAndroidBuildComponents.RunTestWithBp(t, bp) + + vintfFragmentBuild := testResult.TestContext.ModuleForTests("test_vintf_fragment", "android_arm64_armv8-a").Rule("assemble_vintf") + if !strings.Contains(vintfFragmentBuild.RuleParams.Command, "assemble_vintf") { + t.Errorf("Vintf_manifest build command does not process with assemble_vintf : " + vintfFragmentBuild.RuleParams.Command) + } +} diff --git a/apex/apex.go b/apex/apex.go index fc0500aec..dd1c0b52e 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -2370,6 +2370,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.providePrebuiltInfo(ctx) a.required = a.RequiredModuleNames(ctx) + a.required = append(a.required, a.VintfFragmentModuleNames(ctx)...) a.setOutputFiles(ctx) }