1// Copyright 2024 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package android 16 17import ( 18 "fmt" 19 20 "github.com/google/blueprint/proptools" 21) 22 23func init() { 24 registerBuildPropComponents(InitRegistrationContext) 25} 26 27func registerBuildPropComponents(ctx RegistrationContext) { 28 ctx.RegisterModuleType("build_prop", BuildPropFactory) 29 ctx.RegisterModuleType("android_info", AndroidInfoFactory) 30} 31 32type buildPropProperties struct { 33 // Output file name. Defaults to "build.prop" 34 Stem *string 35 36 // List of prop names to exclude. This affects not only common build properties but also 37 // properties in prop_files. 38 Block_list []string 39 40 // Files to be appended at the end of build.prop. These files are appended after 41 // post_process_props without any further checking. 42 Footer_files []string `android:"path"` 43 44 // Path to a JSON file containing product configs. 45 Product_config *string `android:"path"` 46 47 // Path to android-info.txt file containing board specific info. 48 // This is empty for build.prop of all partitions except vendor. 49 Android_info *string `android:"path"` 50 51 // Optional subdirectory under which this file is installed into 52 Relative_install_path *string 53} 54 55type buildPropModule struct { 56 ModuleBase 57 58 properties buildPropProperties 59 60 outputFilePath Path 61 installPath InstallPath 62} 63 64func (p *buildPropModule) stem() string { 65 return proptools.StringDefault(p.properties.Stem, "build.prop") 66} 67 68func (p *buildPropModule) propFiles(ctx ModuleContext) Paths { 69 partition := p.partition(ctx.DeviceConfig()) 70 if partition == "system" { 71 return ctx.Config().SystemPropFiles(ctx) 72 } else if partition == "system_ext" { 73 return ctx.Config().SystemExtPropFiles(ctx) 74 } else if partition == "product" { 75 return ctx.Config().ProductPropFiles(ctx) 76 } else if partition == "odm" { 77 return ctx.Config().OdmPropFiles(ctx) 78 } else if partition == "vendor" { 79 if p.properties.Android_info != nil { 80 androidInfo := PathForModuleSrc(ctx, proptools.String(p.properties.Android_info)) 81 return append(ctx.Config().VendorPropFiles(ctx), androidInfo) 82 } 83 return ctx.Config().VendorPropFiles(ctx) 84 } 85 return nil 86} 87 88func shouldAddBuildThumbprint(config Config) bool { 89 knownOemProperties := []string{ 90 "ro.product.brand", 91 "ro.product.name", 92 "ro.product.device", 93 } 94 95 for _, knownProp := range knownOemProperties { 96 if InList(knownProp, config.OemProperties()) { 97 return true 98 } 99 } 100 return false 101} 102 103// Can't use PartitionTag() because PartitionTag() returns the partition this module is actually 104// installed (e.g. odm module's partition tag can be either "odm" or "vendor") 105func (p *buildPropModule) partition(config DeviceConfig) string { 106 if p.SocSpecific() { 107 return "vendor" 108 } else if p.DeviceSpecific() { 109 return "odm" 110 } else if p.ProductSpecific() { 111 return "product" 112 } else if p.SystemExtSpecific() { 113 return "system_ext" 114 } else if p.InstallInSystemDlkm() { 115 return "system_dlkm" 116 } else if p.InstallInVendorDlkm() { 117 return "vendor_dlkm" 118 } else if p.InstallInOdmDlkm() { 119 return "odm_dlkm" 120 } else if p.InstallInRamdisk() { 121 // From this hardcoding in make: 122 // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/sysprop.mk;l=311;drc=274435657e4682e5cee3fffd11fb301ab32a828d 123 return "bootimage" 124 } 125 return "system" 126} 127 128func (p *buildPropModule) GenerateAndroidBuildActions(ctx ModuleContext) { 129 if !p.SocSpecific() && p.properties.Android_info != nil { 130 ctx.ModuleErrorf("Android_info cannot be set if build.prop is not installed in vendor partition") 131 } 132 133 outputFilePath := PathForModuleOut(ctx, "build.prop") 134 135 partition := p.partition(ctx.DeviceConfig()) 136 137 rule := NewRuleBuilder(pctx, ctx) 138 139 config := ctx.Config() 140 141 cmd := rule.Command().BuiltTool("gen_build_prop") 142 143 cmd.FlagWithInput("--build-hostname-file=", config.BuildHostnameFile(ctx)) 144 cmd.FlagWithInput("--build-number-file=", config.BuildNumberFile(ctx)) 145 // shouldn't depend on BuildFingerprintFile and BuildThumbprintFile to prevent from rebuilding 146 // on every incremental build. 147 cmd.FlagWithArg("--build-fingerprint-file=", config.BuildFingerprintFile(ctx).String()) 148 // Export build thumbprint only if the product has specified at least one oem fingerprint property 149 // b/17888863 150 if shouldAddBuildThumbprint(config) { 151 // In the previous make implementation, a dependency was not added on the thumbprint file 152 cmd.FlagWithArg("--build-thumbprint-file=", config.BuildThumbprintFile(ctx).String()) 153 } 154 cmd.FlagWithArg("--build-username=", config.Getenv("BUILD_USERNAME")) 155 // shouldn't depend on BUILD_DATETIME_FILE to prevent from rebuilding on every incremental 156 // build. 157 cmd.FlagWithArg("--date-file=", ctx.Config().Getenv("BUILD_DATETIME_FILE")) 158 cmd.FlagWithInput("--platform-preview-sdk-fingerprint-file=", ApiFingerprintPath(ctx)) 159 cmd.FlagWithInput("--product-config=", PathForModuleSrc(ctx, proptools.String(p.properties.Product_config))) 160 cmd.FlagWithArg("--partition=", partition) 161 cmd.FlagForEachInput("--prop-files=", p.propFiles(ctx)) 162 cmd.FlagWithOutput("--out=", outputFilePath) 163 164 postProcessCmd := rule.Command().BuiltTool("post_process_props") 165 if ctx.DeviceConfig().BuildBrokenDupSysprop() { 166 postProcessCmd.Flag("--allow-dup") 167 } 168 postProcessCmd.FlagWithArg("--sdk-version ", config.PlatformSdkVersion().String()) 169 if ctx.Config().EnableUffdGc() == "default" { 170 postProcessCmd.FlagWithInput("--kernel-version-file-for-uffd-gc ", PathForOutput(ctx, "dexpreopt/kernel_version_for_uffd_gc.txt")) 171 } else { 172 // still need to pass an empty string to kernel-version-file-for-uffd-gc 173 postProcessCmd.FlagWithArg("--kernel-version-file-for-uffd-gc ", `""`) 174 } 175 postProcessCmd.Text(outputFilePath.String()) 176 postProcessCmd.Flags(p.properties.Block_list) 177 178 for _, footer := range p.properties.Footer_files { 179 path := PathForModuleSrc(ctx, footer) 180 rule.appendText(outputFilePath, "####################################") 181 rule.appendTextf(outputFilePath, "# Adding footer from %v", footer) 182 rule.appendTextf(outputFilePath, "# with path %v", path) 183 rule.appendText(outputFilePath, "####################################") 184 rule.Command().Text("cat").FlagWithInput("", path).FlagWithArg(">> ", outputFilePath.String()) 185 } 186 187 rule.appendText(outputFilePath, "# end of file") 188 189 rule.Build(ctx.ModuleName(), "generating build.prop") 190 191 p.installPath = PathForModuleInstall(ctx, proptools.String(p.properties.Relative_install_path)) 192 ctx.InstallFile(p.installPath, p.stem(), outputFilePath) 193 194 ctx.SetOutputFiles(Paths{outputFilePath}, "") 195 p.outputFilePath = outputFilePath 196} 197 198func (r *RuleBuilder) appendText(path ModuleOutPath, text string) { 199 r.Command().Text("echo").Text(proptools.NinjaAndShellEscape(text)).FlagWithArg(">> ", path.String()) 200} 201 202func (r *RuleBuilder) appendTextf(path ModuleOutPath, format string, a ...any) { 203 r.appendText(path, fmt.Sprintf(format, a...)) 204} 205 206func (p *buildPropModule) AndroidMkEntries() []AndroidMkEntries { 207 return []AndroidMkEntries{{ 208 Class: "ETC", 209 OutputFile: OptionalPathForPath(p.outputFilePath), 210 ExtraEntries: []AndroidMkExtraEntriesFunc{ 211 func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries) { 212 entries.SetString("LOCAL_MODULE_PATH", p.installPath.String()) 213 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base()) 214 }, 215 }, 216 }} 217} 218 219// build_prop module generates {partition}/build.prop file. At first common build properties are 220// printed based on Soong config variables. And then prop_files are printed as-is. Finally, 221// post_process_props tool is run to check if the result build.prop is valid or not. 222func BuildPropFactory() Module { 223 module := &buildPropModule{} 224 module.AddProperties(&module.properties) 225 InitAndroidArchModule(module, DeviceSupported, MultilibCommon) 226 return module 227} 228