Add android_info module type
This is heavily inspired by the implementation in
https://r.android.com/3081436. `android_info` will generate a .txt file
with board specific information which will subsequently be used to
generate build.prop file for vendor.
The key differences are
1. `android_info` is not a singleton module.
2. Create android_info.prop from android_info.txt. The .prop file will
be passed to --prop-files when generating /vendor/build.prop
3. Board info properties like `TARGET_BOARD_INFO_FILES` will not be
added to android.Config API. (But they will be added to the unstable
`PartitionVarsForSoongMigrationOnlyDoNotUse` in a followup CL)
3. android-info.txt will _not_ be installed via ctx.InstallFile,
atleast for now. This file is created in $PRODUCT_OUT, but not
installed on device.
Test: m nothing --no-skip-soong-tests
Bug: 375500423
Change-Id: Ie79f4f5fe828d7876c12e224f4dff1cc17e1b4d4
diff --git a/android/Android.bp b/android/Android.bp
index cf707bd..a9a3564 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -31,6 +31,7 @@
srcs: [
"aconfig_providers.go",
"all_teams.go",
+ "android_info.go",
"androidmk.go",
"apex.go",
"apex_contributions.go",
@@ -121,6 +122,7 @@
"apex_test.go",
"arch_test.go",
"blueprint_e2e_test.go",
+ "build_prop_test.go",
"config_test.go",
"configured_jars_test.go",
"csuite_config_test.go",
diff --git a/android/android_info.go b/android/android_info.go
new file mode 100644
index 0000000..dd78ee4
--- /dev/null
+++ b/android/android_info.go
@@ -0,0 +1,77 @@
+// Copyright 2024 The Android Open Source Project
+//
+// 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 (
+ "github.com/google/blueprint/proptools"
+)
+
+type androidInfoProperties struct {
+ // Name of output file. Defaults to module name
+ Stem *string
+
+ // Paths of board-info.txt files.
+ Board_info_files []string `android:"path"`
+
+ // Name of bootloader board. If board_info_files is empty, `board={bootloader_board_name}` will
+ // be printed to output. Ignored if board_info_files is not empty.
+ Bootloader_board_name *string
+}
+
+type androidInfoModule struct {
+ ModuleBase
+
+ properties androidInfoProperties
+}
+
+func (p *androidInfoModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ if len(p.properties.Board_info_files) > 0 && p.properties.Bootloader_board_name != nil {
+ ctx.ModuleErrorf("Either Board_info_files or Bootloader_board_name should be set. Please remove one of them\n")
+ return
+ }
+ outName := proptools.StringDefault(p.properties.Stem, ctx.ModuleName()+".txt")
+ androidInfoTxt := PathForModuleOut(ctx, outName).OutputPath
+ androidInfoProp := androidInfoTxt.ReplaceExtension(ctx, "prop")
+
+ rule := NewRuleBuilder(pctx, ctx)
+
+ if boardInfoFiles := PathsForModuleSrc(ctx, p.properties.Board_info_files); len(boardInfoFiles) > 0 {
+ rule.Command().Text("cat").Inputs(boardInfoFiles).
+ Text(" | grep").FlagWithArg("-v ", "'#'").FlagWithOutput("> ", androidInfoTxt)
+ } else if bootloaderBoardName := proptools.String(p.properties.Bootloader_board_name); bootloaderBoardName != "" {
+ rule.Command().Text("echo").Text("'board="+bootloaderBoardName+"'").FlagWithOutput("> ", androidInfoTxt)
+ } else {
+ rule.Command().Text("echo").Text("''").FlagWithOutput("> ", androidInfoTxt)
+ }
+
+ rule.Build(ctx.ModuleName(), "generating android-info.prop")
+
+ // Create android_info.prop
+ rule = NewRuleBuilder(pctx, ctx)
+ rule.Command().Text("cat").Input(androidInfoTxt).
+ Text(" | grep 'require version-' | sed -e 's/require version-/ro.build.expect./g' >").Output(androidInfoProp)
+ rule.Build(ctx.ModuleName()+"prop", "generating android-info.prop")
+
+ ctx.SetOutputFiles(Paths{androidInfoProp}, "")
+}
+
+// android_info module generate a file named android-info.txt that contains various information
+// about the device we're building for. This file is typically packaged up with everything else.
+func AndroidInfoFactory() Module {
+ module := &androidInfoModule{}
+ module.AddProperties(&module.properties)
+ InitAndroidModule(module)
+ return module
+}
diff --git a/android/build_prop.go b/android/build_prop.go
index 7c3c506..5547680 100644
--- a/android/build_prop.go
+++ b/android/build_prop.go
@@ -19,8 +19,12 @@
)
func init() {
- ctx := InitRegistrationContext
+ registerBuildPropComponents(InitRegistrationContext)
+}
+
+func registerBuildPropComponents(ctx RegistrationContext) {
ctx.RegisterModuleType("build_prop", BuildPropFactory)
+ ctx.RegisterModuleType("android_info", AndroidInfoFactory)
}
type buildPropProperties struct {
@@ -38,6 +42,10 @@
// Path to a JSON file containing product configs.
Product_config *string `android:"path"`
+ // Path to android-info.txt file containing board specific info.
+ // This is empty for build.prop of all partitions except vendor.
+ Android_info *string `android:"path"`
+
// Optional subdirectory under which this file is installed into
Relative_install_path *string
}
@@ -66,7 +74,10 @@
} else if partition == "odm" {
return ctx.Config().OdmPropFiles(ctx)
} else if partition == "vendor" {
- // TODO (b/375500423): Add android-info.txt to prop files
+ if p.properties.Android_info != nil {
+ androidInfo := PathForModuleSrc(ctx, proptools.String(p.properties.Android_info))
+ return append(ctx.Config().VendorPropFiles(ctx), androidInfo)
+ }
return ctx.Config().VendorPropFiles(ctx)
}
return nil
@@ -111,13 +122,12 @@
}
func (p *buildPropModule) GenerateAndroidBuildActions(ctx ModuleContext) {
- p.outputFilePath = PathForModuleOut(ctx, "build.prop").OutputPath
- if !ctx.Config().KatiEnabled() {
- WriteFileRule(ctx, p.outputFilePath, "# no build.prop if kati is disabled")
- ctx.SetOutputFiles(Paths{p.outputFilePath}, "")
- return
+ if !p.SocSpecific() && p.properties.Android_info != nil {
+ ctx.ModuleErrorf("Android_info cannot be set if build.prop is not installed in vendor partition")
}
+ p.outputFilePath = PathForModuleOut(ctx, "build.prop").OutputPath
+
partition := p.partition(ctx.DeviceConfig())
if !InList(partition, validPartitions) {
ctx.PropertyErrorf("partition", "unsupported partition %q: only %q are supported", partition, validPartitions)
diff --git a/android/build_prop_test.go b/android/build_prop_test.go
new file mode 100644
index 0000000..e75975a
--- /dev/null
+++ b/android/build_prop_test.go
@@ -0,0 +1,41 @@
+// 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 (
+ "testing"
+)
+
+func TestPropFileInputs(t *testing.T) {
+ bp := `
+build_prop {
+ name: "vendor-build.prop",
+ stem: "build.prop",
+ vendor: true,
+ android_info: ":board-info",
+ //product_config: ":product_config",
+}
+android_info {
+ name: "board-info",
+ stem: "android-info.txt",
+}
+`
+
+ res := GroupFixturePreparers(
+ FixtureRegisterWithContext(registerBuildPropComponents),
+ ).RunTestWithBp(t, bp)
+ buildPropCmd := res.ModuleForTests("vendor-build.prop", "").Rule("vendor-build.prop_.vendor-build.prop").RuleParams.Command
+ AssertStringDoesContain(t, "Could not find android-info in prop files of vendor build.prop", buildPropCmd, "--prop-files=out/soong/.intermediates/board-info/android-info.prop")
+}