1// Copyright (C) 2024 The Android Open Source Project 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 filesystem 16 17import ( 18 "cmp" 19 "fmt" 20 "path/filepath" 21 "slices" 22 "sort" 23 "strings" 24 "sync/atomic" 25 26 "android/soong/android" 27 "android/soong/java" 28 29 "github.com/google/blueprint" 30 "github.com/google/blueprint/proptools" 31) 32 33var proguardDictToProto = pctx.AndroidStaticRule("proguard_dict_to_proto", blueprint.RuleParams{ 34 Command: `${symbols_map} -r8 $in -location $location -write_if_changed $out`, 35 Restat: true, 36 CommandDeps: []string{"${symbols_map}"}, 37}, "location") 38 39type PartitionNameProperties struct { 40 // Name of the super partition filesystem module 41 Super_partition_name *string 42 // Name of the boot partition filesystem module 43 Boot_partition_name *string 44 // Name of the vendor boot partition filesystem module 45 Vendor_boot_partition_name *string 46 // Name of the init boot partition filesystem module 47 Init_boot_partition_name *string 48 // Name of the system partition filesystem module 49 System_partition_name *string 50 // Name of the system_ext partition filesystem module 51 System_ext_partition_name *string 52 // Name of the product partition filesystem module 53 Product_partition_name *string 54 // Name of the vendor partition filesystem module 55 Vendor_partition_name *string 56 // Name of the odm partition filesystem module 57 Odm_partition_name *string 58 // Name of the recovery partition filesystem module 59 Recovery_partition_name *string 60 // The vbmeta partition and its "chained" partitions 61 Vbmeta_partitions []string 62 // Name of the userdata partition filesystem module 63 Userdata_partition_name *string 64 // Name of the system_dlkm partition filesystem module 65 System_dlkm_partition_name *string 66 // Name of the vendor_dlkm partition filesystem module 67 Vendor_dlkm_partition_name *string 68 // Name of the odm_dlkm partition filesystem module 69 Odm_dlkm_partition_name *string 70} 71 72type DeviceProperties struct { 73 // Path to the prebuilt bootloader that would be copied to PRODUCT_OUT 74 Bootloader *string `android:"path"` 75 // Path to android-info.txt file containing board specific info. 76 Android_info *string `android:"path"` 77 // If this is the "main" android_device target for the build, i.e. the one that gets built 78 // when running a plain `m` command. Currently, this is the autogenerated android_device module 79 // in soong-only builds, but in the future when we check in android_device modules, the main 80 // one will be determined based on the lunch product. TODO: Figure out how to make this 81 // blueprint:"mutated" and still set it from filesystem_creator 82 Main_device *bool 83 84 Ab_ota_updater *bool 85 Ab_ota_partitions []string 86 Ab_ota_keys []string 87 Ab_ota_postinstall_config []string 88 89 Ramdisk_node_list *string `android:"path"` 90 Releasetools_extension *string `android:"path"` 91 FastbootInfo *string `android:"path"` 92 93 Partial_ota_update_partitions []string 94 Flash_block_size *string 95 Bootloader_in_update_package *bool 96 97 // The kernel version in the build. Will be verified against the actual kernel. 98 // If not provided, will attempt to extract it from the loose kernel or the kernel inside 99 // the boot image. The version is later used to decide whether or not to enable uffd_gc 100 // when dexpreopting apps. So setting this doesn't really do anything except enforce that the 101 // actual kernel version is as specified here. 102 Kernel_version *string 103} 104 105type androidDevice struct { 106 android.ModuleBase 107 108 partitionProps PartitionNameProperties 109 110 deviceProps DeviceProperties 111 112 allImagesZip android.Path 113 114 proguardDictZip android.Path 115 proguardDictMapping android.Path 116 proguardUsageZip android.Path 117 kernelConfig android.Path 118 kernelVersion android.Path 119 miscInfo android.Path 120 rootDirForFsConfig string 121 rootDirForFsConfigTimestamp android.Path 122 apkCertsInfo android.Path 123 targetFilesZip android.Path 124 updatePackage android.Path 125} 126 127func AndroidDeviceFactory() android.Module { 128 module := &androidDevice{} 129 module.AddProperties(&module.partitionProps, &module.deviceProps) 130 android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibFirst) 131 return module 132} 133 134var numMainAndroidDevicesOnceKey android.OnceKey = android.NewOnceKey("num_auto_generated_anroid_devices") 135 136type partitionDepTagType struct { 137 blueprint.BaseDependencyTag 138} 139 140type superPartitionDepTagType struct { 141 blueprint.BaseDependencyTag 142} 143type targetFilesMetadataDepTagType struct { 144 blueprint.BaseDependencyTag 145} 146 147var superPartitionDepTag superPartitionDepTagType 148var filesystemDepTag partitionDepTagType 149var targetFilesMetadataDepTag targetFilesMetadataDepTagType 150 151func (a *androidDevice) DepsMutator(ctx android.BottomUpMutatorContext) { 152 addDependencyIfDefined := func(dep *string) { 153 if dep != nil { 154 ctx.AddDependency(ctx.Module(), filesystemDepTag, proptools.String(dep)) 155 } 156 } 157 158 if a.partitionProps.Super_partition_name != nil { 159 ctx.AddDependency(ctx.Module(), superPartitionDepTag, *a.partitionProps.Super_partition_name) 160 } 161 addDependencyIfDefined(a.partitionProps.Boot_partition_name) 162 addDependencyIfDefined(a.partitionProps.Init_boot_partition_name) 163 addDependencyIfDefined(a.partitionProps.Vendor_boot_partition_name) 164 addDependencyIfDefined(a.partitionProps.System_partition_name) 165 addDependencyIfDefined(a.partitionProps.System_ext_partition_name) 166 addDependencyIfDefined(a.partitionProps.Product_partition_name) 167 addDependencyIfDefined(a.partitionProps.Vendor_partition_name) 168 addDependencyIfDefined(a.partitionProps.Odm_partition_name) 169 addDependencyIfDefined(a.partitionProps.Userdata_partition_name) 170 addDependencyIfDefined(a.partitionProps.System_dlkm_partition_name) 171 addDependencyIfDefined(a.partitionProps.Vendor_dlkm_partition_name) 172 addDependencyIfDefined(a.partitionProps.Odm_dlkm_partition_name) 173 addDependencyIfDefined(a.partitionProps.Recovery_partition_name) 174 for _, vbmetaPartition := range a.partitionProps.Vbmeta_partitions { 175 ctx.AddDependency(ctx.Module(), filesystemDepTag, vbmetaPartition) 176 } 177 a.addDepsForTargetFilesMetadata(ctx) 178} 179 180func (a *androidDevice) addDepsForTargetFilesMetadata(ctx android.BottomUpMutatorContext) { 181 ctx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), targetFilesMetadataDepTag, "liblz4") // host variant 182} 183 184func (a *androidDevice) GenerateAndroidBuildActions(ctx android.ModuleContext) { 185 if proptools.Bool(a.deviceProps.Main_device) { 186 numMainAndroidDevices := ctx.Config().Once(numMainAndroidDevicesOnceKey, func() interface{} { 187 return &atomic.Int32{} 188 }).(*atomic.Int32) 189 total := numMainAndroidDevices.Add(1) 190 if total > 1 { 191 // There should only be 1 main android_device module. That one will be 192 // made the default thing to build in soong-only builds. 193 ctx.ModuleErrorf("There cannot be more than 1 main android_device module") 194 } 195 } 196 197 allInstalledModules := a.allInstalledModules(ctx) 198 199 a.apkCertsInfo = a.buildApkCertsInfo(ctx, allInstalledModules) 200 a.kernelVersion, a.kernelConfig = a.extractKernelVersionAndConfigs(ctx) 201 a.miscInfo = a.addMiscInfo(ctx) 202 a.buildTargetFilesZip(ctx, allInstalledModules) 203 a.buildProguardZips(ctx, allInstalledModules) 204 a.buildUpdatePackage(ctx) 205 206 var deps []android.Path 207 if proptools.String(a.partitionProps.Super_partition_name) != "" { 208 superImage := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag) 209 if info, ok := android.OtherModuleProvider(ctx, superImage, SuperImageProvider); ok { 210 assertUnset := func(prop *string, propName string) { 211 if prop != nil && *prop != "" { 212 ctx.PropertyErrorf(propName, "Cannot be set because it's already part of the super image") 213 } 214 } 215 for _, subPartitionType := range android.SortedKeys(info.SubImageInfo) { 216 switch subPartitionType { 217 case "system": 218 assertUnset(a.partitionProps.System_partition_name, "system_partition_name") 219 case "system_ext": 220 assertUnset(a.partitionProps.System_ext_partition_name, "system_ext_partition_name") 221 case "system_dlkm": 222 assertUnset(a.partitionProps.System_dlkm_partition_name, "system_dlkm_partition_name") 223 case "system_other": 224 // TODO 225 case "product": 226 assertUnset(a.partitionProps.Product_partition_name, "product_partition_name") 227 case "vendor": 228 assertUnset(a.partitionProps.Vendor_partition_name, "vendor_partition_name") 229 case "vendor_dlkm": 230 assertUnset(a.partitionProps.Vendor_dlkm_partition_name, "vendor_dlkm_partition_name") 231 case "odm": 232 assertUnset(a.partitionProps.Odm_partition_name, "odm_partition_name") 233 case "odm_dlkm": 234 assertUnset(a.partitionProps.Odm_dlkm_partition_name, "odm_dlkm_partition_name") 235 default: 236 ctx.ModuleErrorf("Unsupported sub-partition of super partition: %q", subPartitionType) 237 } 238 } 239 240 deps = append(deps, info.SuperImage) 241 } else { 242 ctx.ModuleErrorf("Expected super image dep to provide SuperImageProvider") 243 } 244 } 245 ctx.VisitDirectDepsProxyWithTag(filesystemDepTag, func(m android.ModuleProxy) { 246 imageOutput, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider) 247 if !ok { 248 ctx.ModuleErrorf("Partition module %s doesn't set OutputfilesProvider", m.Name()) 249 } 250 if len(imageOutput.DefaultOutputFiles) != 1 { 251 ctx.ModuleErrorf("Partition module %s should provide exact 1 output file", m.Name()) 252 } 253 deps = append(deps, imageOutput.DefaultOutputFiles[0]) 254 }) 255 256 allImagesZip := android.PathForModuleOut(ctx, "all_images.zip") 257 allImagesZipBuilder := android.NewRuleBuilder(pctx, ctx) 258 cmd := allImagesZipBuilder.Command().BuiltTool("soong_zip") 259 for _, dep := range deps { 260 cmd.FlagWithArg("-e ", dep.Base()) 261 cmd.FlagWithInput("-f ", dep) 262 } 263 cmd.FlagWithOutput("-o ", allImagesZip) 264 allImagesZipBuilder.Build("soong_all_images_zip", "all_images.zip") 265 a.allImagesZip = allImagesZip 266 267 allImagesStamp := android.PathForModuleOut(ctx, "all_images_stamp") 268 var validations android.Paths 269 if !ctx.Config().KatiEnabled() && proptools.Bool(a.deviceProps.Main_device) { 270 // In soong-only builds, build this module by default. 271 // This is the analogue to this make code: 272 // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/main.mk;l=1396;drc=6595459cdd8164a6008335f6372c9f97b9094060 273 ctx.Phony("droidcore-unbundled", allImagesStamp) 274 275 deps = append(deps, a.copyFilesToProductOutForSoongOnly(ctx)) 276 } 277 278 ctx.Build(pctx, android.BuildParams{ 279 Rule: android.Touch, 280 Output: allImagesStamp, 281 Implicits: deps, 282 Validations: validations, 283 }) 284 285 // Checkbuilding it causes soong to make a phony, so you can say `m <module name>` 286 ctx.CheckbuildFile(allImagesStamp) 287 288 a.setVbmetaPhonyTargets(ctx) 289 290 a.distFiles(ctx) 291 292 android.SetProvider(ctx, android.AndroidDeviceInfoProvider, android.AndroidDeviceInfo{ 293 Main_device: android.Bool(a.deviceProps.Main_device), 294 }) 295 296 if proptools.String(a.partitionProps.Super_partition_name) != "" { 297 buildComplianceMetadata(ctx, superPartitionDepTag, filesystemDepTag) 298 } else { 299 buildComplianceMetadata(ctx, filesystemDepTag) 300 } 301} 302 303func buildComplianceMetadata(ctx android.ModuleContext, tags ...blueprint.DependencyTag) { 304 // Collect metadata from deps 305 filesContained := make([]string, 0) 306 prebuiltFilesCopied := make([]string, 0) 307 for _, tag := range tags { 308 ctx.VisitDirectDepsProxyWithTag(tag, func(m android.ModuleProxy) { 309 if complianceMetadataInfo, ok := android.OtherModuleProvider(ctx, m, android.ComplianceMetadataProvider); ok { 310 filesContained = append(filesContained, complianceMetadataInfo.GetFilesContained()...) 311 prebuiltFilesCopied = append(prebuiltFilesCopied, complianceMetadataInfo.GetPrebuiltFilesCopied()...) 312 } 313 }) 314 } 315 // Merge to module's ComplianceMetadataInfo 316 complianceMetadataInfo := ctx.ComplianceMetadataInfo() 317 filesContained = append(filesContained, complianceMetadataInfo.GetFilesContained()...) 318 sort.Strings(filesContained) 319 complianceMetadataInfo.SetFilesContained(filesContained) 320 321 prebuiltFilesCopied = append(prebuiltFilesCopied, complianceMetadataInfo.GetPrebuiltFilesCopied()...) 322 sort.Strings(prebuiltFilesCopied) 323 complianceMetadataInfo.SetPrebuiltFilesCopied(prebuiltFilesCopied) 324} 325 326// Returns a list of modules that are installed, which are collected from the dependency 327// filesystem and super_image modules. 328func (a *androidDevice) allInstalledModules(ctx android.ModuleContext) []android.Module { 329 fsInfoMap := a.getFsInfos(ctx) 330 allOwners := make(map[string][]string) 331 for _, partition := range android.SortedKeys(fsInfoMap) { 332 fsInfo := fsInfoMap[partition] 333 for _, owner := range fsInfo.Owners { 334 allOwners[owner.Name] = append(allOwners[owner.Name], owner.Variation) 335 } 336 } 337 338 ret := []android.Module{} 339 ctx.WalkDepsProxy(func(mod, _ android.ModuleProxy) bool { 340 if variations, ok := allOwners[ctx.OtherModuleName(mod)]; ok && android.InList(ctx.OtherModuleSubDir(mod), variations) { 341 ret = append(ret, mod) 342 } 343 return true 344 }) 345 346 // Remove duplicates 347 ret = android.FirstUniqueFunc(ret, func(a, b android.Module) bool { 348 return a.String() == b.String() 349 }) 350 351 // Sort the modules by their names and variants 352 slices.SortFunc(ret, func(a, b android.Module) int { 353 return cmp.Compare(a.String(), b.String()) 354 }) 355 return ret 356} 357 358func insertBeforeExtension(file, insertion string) string { 359 ext := filepath.Ext(file) 360 return strings.TrimSuffix(file, ext) + insertion + ext 361} 362 363func (a *androidDevice) distInstalledFiles(ctx android.ModuleContext) { 364 distInstalledFilesJsonAndTxt := func(installedFiles InstalledFilesStruct) { 365 if installedFiles.Json != nil { 366 ctx.DistForGoal("droidcore-unbundled", installedFiles.Json) 367 } 368 if installedFiles.Txt != nil { 369 ctx.DistForGoal("droidcore-unbundled", installedFiles.Txt) 370 } 371 } 372 373 fsInfoMap := a.getFsInfos(ctx) 374 for _, partition := range android.SortedKeys(fsInfoMap) { 375 // installed-files-*{.txt | .json} is not disted for userdata partition 376 if partition == "userdata" { 377 continue 378 } 379 fsInfo := fsInfoMap[partition] 380 for _, installedFiles := range fsInfo.InstalledFilesDepSet.ToList() { 381 distInstalledFilesJsonAndTxt(installedFiles) 382 } 383 } 384} 385 386func (a *androidDevice) distFiles(ctx android.ModuleContext) { 387 if !ctx.Config().KatiEnabled() && proptools.Bool(a.deviceProps.Main_device) { 388 a.distInstalledFiles(ctx) 389 390 namePrefix := "" 391 if ctx.Config().HasDeviceProduct() { 392 namePrefix = ctx.Config().DeviceProduct() + "-" 393 } 394 ctx.DistForGoalWithFilename("droidcore-unbundled", a.proguardDictZip, namePrefix+insertBeforeExtension(a.proguardDictZip.Base(), "-FILE_NAME_TAG_PLACEHOLDER")) 395 ctx.DistForGoalWithFilename("droidcore-unbundled", a.proguardDictMapping, namePrefix+insertBeforeExtension(a.proguardDictMapping.Base(), "-FILE_NAME_TAG_PLACEHOLDER")) 396 ctx.DistForGoalWithFilename("droidcore-unbundled", a.proguardUsageZip, namePrefix+insertBeforeExtension(a.proguardUsageZip.Base(), "-FILE_NAME_TAG_PLACEHOLDER")) 397 398 if a.deviceProps.Android_info != nil { 399 ctx.DistForGoal("droidcore-unbundled", android.PathForModuleSrc(ctx, *a.deviceProps.Android_info)) 400 } 401 if a.miscInfo != nil { 402 ctx.DistForGoal("droidcore-unbundled", a.miscInfo) 403 if a.partitionProps.Super_partition_name != nil { 404 ctx.DistForGoalWithFilename("dist_files", a.miscInfo, "super_misc_info.txt") 405 } 406 } 407 if a.targetFilesZip != nil { 408 ctx.DistForGoalWithFilename("target-files-package", a.targetFilesZip, namePrefix+insertBeforeExtension(a.targetFilesZip.Base(), "-FILE_NAME_TAG_PLACEHOLDER")) 409 } 410 if a.updatePackage != nil { 411 ctx.DistForGoalWithFilename("updatepackage", a.updatePackage, namePrefix+insertBeforeExtension(a.updatePackage.Base(), "-FILE_NAME_TAG_PLACEHOLDER")) 412 } 413 414 } 415} 416 417func (a *androidDevice) MakeVars(_ android.MakeVarsModuleContext) []android.ModuleMakeVarsValue { 418 if proptools.Bool(a.deviceProps.Main_device) { 419 return []android.ModuleMakeVarsValue{{"SOONG_ONLY_ALL_IMAGES_ZIP", a.allImagesZip.String()}} 420 } 421 return nil 422} 423 424func (a *androidDevice) buildProguardZips(ctx android.ModuleContext, allInstalledModules []android.Module) { 425 dictZip := android.PathForModuleOut(ctx, "proguard-dict.zip") 426 dictZipBuilder := android.NewRuleBuilder(pctx, ctx) 427 dictZipCmd := dictZipBuilder.Command().BuiltTool("soong_zip").Flag("-d").FlagWithOutput("-o ", dictZip) 428 429 dictMapping := android.PathForModuleOut(ctx, "proguard-dict-mapping.textproto") 430 dictMappingBuilder := android.NewRuleBuilder(pctx, ctx) 431 dictMappingCmd := dictMappingBuilder.Command().BuiltTool("symbols_map").Flag("-merge").Output(dictMapping) 432 433 protosDir := android.PathForModuleOut(ctx, "proguard_mapping_protos") 434 435 usageZip := android.PathForModuleOut(ctx, "proguard-usage.zip") 436 usageZipBuilder := android.NewRuleBuilder(pctx, ctx) 437 usageZipCmd := usageZipBuilder.Command().BuiltTool("merge_zips").Output(usageZip) 438 439 for _, mod := range allInstalledModules { 440 if proguardInfo, ok := android.OtherModuleProvider(ctx, mod, java.ProguardProvider); ok { 441 // Maintain these out/target/common paths for backwards compatibility. They may be able 442 // to be changed if tools look up file locations from the protobuf, but I'm not 443 // exactly sure how that works. 444 dictionaryFakePath := fmt.Sprintf("out/target/common/obj/%s/%s_intermediates/proguard_dictionary", proguardInfo.Class, proguardInfo.ModuleName) 445 dictZipCmd.FlagWithArg("-e ", dictionaryFakePath) 446 dictZipCmd.FlagWithInput("-f ", proguardInfo.ProguardDictionary) 447 dictZipCmd.Textf("-e out/target/common/obj/%s/%s_intermediates/classes.jar", proguardInfo.Class, proguardInfo.ModuleName) 448 dictZipCmd.FlagWithInput("-f ", proguardInfo.ClassesJar) 449 450 protoFile := protosDir.Join(ctx, filepath.Dir(dictionaryFakePath), "proguard_dictionary.textproto") 451 ctx.Build(pctx, android.BuildParams{ 452 Rule: proguardDictToProto, 453 Input: proguardInfo.ProguardDictionary, 454 Output: protoFile, 455 Args: map[string]string{ 456 "location": dictionaryFakePath, 457 }, 458 }) 459 dictMappingCmd.Input(protoFile) 460 461 usageZipCmd.Input(proguardInfo.ProguardUsageZip) 462 } 463 } 464 465 dictZipBuilder.Build("proguard_dict_zip", "Building proguard dictionary zip") 466 dictMappingBuilder.Build("proguard_dict_mapping_proto", "Building proguard mapping proto") 467 usageZipBuilder.Build("proguard_usage_zip", "Building proguard usage zip") 468 469 a.proguardDictZip = dictZip 470 a.proguardDictMapping = dictMapping 471 a.proguardUsageZip = usageZip 472} 473 474// Helper structs for target_files.zip creation 475type targetFilesZipCopy struct { 476 srcModule *string 477 destSubdir string 478} 479 480type targetFilesystemZipCopy struct { 481 fsInfo FilesystemInfo 482 destSubdir string 483} 484 485func (a *androidDevice) buildTargetFilesZip(ctx android.ModuleContext, allInstalledModules []android.Module) { 486 targetFilesDir := android.PathForModuleOut(ctx, "target_files_dir") 487 targetFilesZip := android.PathForModuleOut(ctx, "target_files.zip") 488 489 builder := android.NewRuleBuilder(pctx, ctx) 490 builder.Command().Textf("rm -rf %s", targetFilesDir.String()) 491 builder.Command().Textf("mkdir -p %s", targetFilesDir.String()) 492 toCopy := []targetFilesZipCopy{ 493 targetFilesZipCopy{a.partitionProps.System_partition_name, "SYSTEM"}, 494 targetFilesZipCopy{a.partitionProps.System_ext_partition_name, "SYSTEM_EXT"}, 495 targetFilesZipCopy{a.partitionProps.Product_partition_name, "PRODUCT"}, 496 targetFilesZipCopy{a.partitionProps.Vendor_partition_name, "VENDOR"}, 497 targetFilesZipCopy{a.partitionProps.Odm_partition_name, "ODM"}, 498 targetFilesZipCopy{a.partitionProps.System_dlkm_partition_name, "SYSTEM_DLKM"}, 499 targetFilesZipCopy{a.partitionProps.Vendor_dlkm_partition_name, "VENDOR_DLKM"}, 500 targetFilesZipCopy{a.partitionProps.Odm_dlkm_partition_name, "ODM_DLKM"}, 501 targetFilesZipCopy{a.partitionProps.Init_boot_partition_name, "BOOT/RAMDISK"}, 502 targetFilesZipCopy{a.partitionProps.Init_boot_partition_name, "INIT_BOOT/RAMDISK"}, 503 targetFilesZipCopy{a.partitionProps.Vendor_boot_partition_name, "VENDOR_BOOT/RAMDISK"}, 504 } 505 506 filesystemsToCopy := []targetFilesystemZipCopy{} 507 for _, zipCopy := range toCopy { 508 if zipCopy.srcModule == nil { 509 continue 510 } 511 filesystemsToCopy = append( 512 filesystemsToCopy, 513 targetFilesystemZipCopy{a.getFilesystemInfo(ctx, *zipCopy.srcModule), zipCopy.destSubdir}, 514 ) 515 } 516 // Get additional filesystems from super_partition dependency 517 if a.partitionProps.Super_partition_name != nil { 518 superPartition := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag) 519 if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok { 520 for _, partition := range android.SortedKeys(info.SubImageInfo) { 521 filesystemsToCopy = append( 522 filesystemsToCopy, 523 targetFilesystemZipCopy{info.SubImageInfo[partition], strings.ToUpper(partition)}, 524 ) 525 } 526 } else { 527 ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name()) 528 } 529 } 530 531 for _, toCopy := range filesystemsToCopy { 532 rootDirString := toCopy.fsInfo.RootDir.String() 533 if toCopy.destSubdir == "SYSTEM" { 534 rootDirString = rootDirString + "/system" 535 } 536 builder.Command().Textf("mkdir -p %s/%s", targetFilesDir.String(), toCopy.destSubdir) 537 builder.Command(). 538 BuiltTool("acp"). 539 Textf("-rd %s/. %s/%s", rootDirString, targetFilesDir, toCopy.destSubdir). 540 Implicit(toCopy.fsInfo.Output) // so that the staging dir is built 541 for _, extraRootDir := range toCopy.fsInfo.ExtraRootDirs { 542 builder.Command(). 543 BuiltTool("acp"). 544 Textf("-rd %s/. %s/%s", extraRootDir, targetFilesDir, toCopy.destSubdir). 545 Implicit(toCopy.fsInfo.Output) // so that the staging dir is built 546 } 547 548 if toCopy.destSubdir == "SYSTEM" { 549 // Create the ROOT partition in target_files.zip 550 builder.Command().Textf("rsync --links --exclude=system/* %s/ -r %s/ROOT", toCopy.fsInfo.RootDir, targetFilesDir.String()) 551 // Add a duplicate rule to assemble the ROOT/ directory in separate intermediates. 552 // The output timestamp will be an input to a separate fs_config call. 553 a.rootDirForFsConfig = android.PathForModuleOut(ctx, "root_dir_for_fs_config").String() 554 rootDirBuilder := android.NewRuleBuilder(pctx, ctx) 555 rootDirForFsConfigTimestamp := android.PathForModuleOut(ctx, "root_dir_for_fs_config.timestamp") 556 rootDirBuilder.Command().Textf("rsync --links --exclude=system/* %s/ -r %s", toCopy.fsInfo.RootDir, a.rootDirForFsConfig). 557 Implicit(toCopy.fsInfo.Output). 558 Text("&& touch"). 559 Output(rootDirForFsConfigTimestamp) 560 rootDirBuilder.Build("assemble_root_dir_for_fs_config", "Assemble ROOT/ for fs_config") 561 a.rootDirForFsConfigTimestamp = rootDirForFsConfigTimestamp 562 } 563 } 564 // Copy cmdline, kernel etc. files of boot images 565 if a.partitionProps.Vendor_boot_partition_name != nil { 566 bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(a.partitionProps.Vendor_boot_partition_name), filesystemDepTag) 567 bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider) 568 builder.Command().Textf("echo %s > %s/VENDOR_BOOT/cmdline", proptools.ShellEscape(strings.Join(bootImgInfo.Cmdline, " ")), targetFilesDir) 569 builder.Command().Textf("echo %s > %s/VENDOR_BOOT/vendor_cmdline", proptools.ShellEscape(strings.Join(bootImgInfo.Cmdline, " ")), targetFilesDir) 570 if bootImgInfo.Dtb != nil { 571 builder.Command().Textf("cp ").Input(bootImgInfo.Dtb).Textf(" %s/VENDOR_BOOT/dtb", targetFilesDir) 572 } 573 if bootImgInfo.Bootconfig != nil { 574 builder.Command().Textf("cp ").Input(bootImgInfo.Bootconfig).Textf(" %s/VENDOR_BOOT/vendor_bootconfig", targetFilesDir) 575 } 576 } 577 if a.partitionProps.Boot_partition_name != nil { 578 bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(a.partitionProps.Boot_partition_name), filesystemDepTag) 579 bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider) 580 builder.Command().Textf("echo %s > %s/BOOT/cmdline", proptools.ShellEscape(strings.Join(bootImgInfo.Cmdline, " ")), targetFilesDir) 581 if bootImgInfo.Dtb != nil { 582 builder.Command().Textf("cp ").Input(bootImgInfo.Dtb).Textf(" %s/BOOT/dtb", targetFilesDir) 583 } 584 if bootImgInfo.Kernel != nil { 585 builder.Command().Textf("cp ").Input(bootImgInfo.Kernel).Textf(" %s/BOOT/kernel", targetFilesDir) 586 // Even though kernel is not used to build vendor_boot, copy the kernel to VENDOR_BOOT to match the behavior of make packaging. 587 builder.Command().Textf("cp ").Input(bootImgInfo.Kernel).Textf(" %s/VENDOR_BOOT/kernel", targetFilesDir) 588 } 589 if bootImgInfo.Bootconfig != nil { 590 builder.Command().Textf("cp ").Input(bootImgInfo.Bootconfig).Textf(" %s/BOOT/bootconfig", targetFilesDir) 591 } 592 } 593 594 if a.deviceProps.Android_info != nil { 595 builder.Command().Textf("mkdir -p %s/OTA", targetFilesDir) 596 builder.Command().Textf("cp ").Input(android.PathForModuleSrc(ctx, *a.deviceProps.Android_info)).Textf(" %s/OTA/android-info.txt", targetFilesDir) 597 } 598 599 a.copyImagesToTargetZip(ctx, builder, targetFilesDir) 600 a.copyMetadataToTargetZip(ctx, builder, targetFilesDir, allInstalledModules) 601 602 a.targetFilesZip = targetFilesZip 603 builder.Command(). 604 BuiltTool("soong_zip"). 605 Text("-d"). 606 FlagWithOutput("-o ", targetFilesZip). 607 FlagWithArg("-C ", targetFilesDir.String()). 608 FlagWithArg("-D ", targetFilesDir.String()). 609 Text("-sha256") 610 builder.Build("target_files_"+ctx.ModuleName(), "Build target_files.zip") 611} 612 613func (a *androidDevice) copyImagesToTargetZip(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir android.WritablePath) { 614 // Create an IMAGES/ subdirectory 615 builder.Command().Textf("mkdir -p %s/IMAGES", targetFilesDir.String()) 616 if a.deviceProps.Bootloader != nil { 617 builder.Command().Textf("cp ").Input(android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Bootloader))).Textf(" %s/IMAGES/bootloader", targetFilesDir.String()) 618 } 619 // Copy the filesystem ,boot and vbmeta img files to IMAGES/ 620 ctx.VisitDirectDepsProxyWithTag(filesystemDepTag, func(child android.ModuleProxy) { 621 if strings.Contains(child.Name(), "recovery") { 622 return // skip recovery.img to match the make packaging behavior 623 } 624 if info, ok := android.OtherModuleProvider(ctx, child, BootimgInfoProvider); ok { 625 // Check Boot img first so that the boot.img is copied and not its dep ramdisk.img 626 builder.Command().Textf("cp ").Input(info.Output).Textf(" %s/IMAGES/", targetFilesDir.String()) 627 } else if info, ok := android.OtherModuleProvider(ctx, child, FilesystemProvider); ok { 628 builder.Command().Textf("cp ").Input(info.Output).Textf(" %s/IMAGES/", targetFilesDir.String()) 629 } else if info, ok := android.OtherModuleProvider(ctx, child, vbmetaPartitionProvider); ok { 630 builder.Command().Textf("cp ").Input(info.Output).Textf(" %s/IMAGES/", targetFilesDir.String()) 631 } else { 632 ctx.ModuleErrorf("Module %s does not provide an .img file output for target_files.zip", child.Name()) 633 } 634 }) 635 636 if a.partitionProps.Super_partition_name != nil { 637 superPartition := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag) 638 if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok { 639 for _, partition := range android.SortedKeys(info.SubImageInfo) { 640 if info.SubImageInfo[partition].OutputHermetic != nil { 641 builder.Command().Textf("cp ").Input(info.SubImageInfo[partition].OutputHermetic).Textf(" %s/IMAGES/", targetFilesDir.String()) 642 } 643 if info.SubImageInfo[partition].MapFile != nil { 644 builder.Command().Textf("cp ").Input(info.SubImageInfo[partition].MapFile).Textf(" %s/IMAGES/", targetFilesDir.String()) 645 } 646 } 647 // super_empty.img 648 if info.SuperEmptyImage != nil { 649 builder.Command().Textf("cp ").Input(info.SuperEmptyImage).Textf(" %s/IMAGES/", targetFilesDir.String()) 650 } 651 } else { 652 ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name()) 653 } 654 } 655} 656 657func (a *androidDevice) copyMetadataToTargetZip(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir android.WritablePath, allInstalledModules []android.Module) { 658 // Create a META/ subdirectory 659 builder.Command().Textf("mkdir -p %s/META", targetFilesDir.String()) 660 if proptools.Bool(a.deviceProps.Ab_ota_updater) { 661 ctx.VisitDirectDepsProxyWithTag(targetFilesMetadataDepTag, func(child android.ModuleProxy) { 662 info, _ := android.OtherModuleProvider(ctx, child, android.OutputFilesProvider) 663 builder.Command().Textf("cp").Inputs(info.DefaultOutputFiles).Textf(" %s/META/", targetFilesDir.String()) 664 }) 665 builder.Command().Textf("cp").Input(android.PathForSource(ctx, "external/zucchini/version_info.h")).Textf(" %s/META/zucchini_config.txt", targetFilesDir.String()) 666 builder.Command().Textf("cp").Input(android.PathForSource(ctx, "system/update_engine/update_engine.conf")).Textf(" %s/META/update_engine_config.txt", targetFilesDir.String()) 667 if a.getFsInfos(ctx)["system"].ErofsCompressHints != nil { 668 builder.Command().Textf("cp").Input(a.getFsInfos(ctx)["system"].ErofsCompressHints).Textf(" %s/META/erofs_default_compress_hints.txt", targetFilesDir.String()) 669 } 670 // ab_partitions.txt 671 abPartitionsSorted := android.SortedUniqueStrings(a.deviceProps.Ab_ota_partitions) 672 abPartitionsSortedString := proptools.ShellEscape(strings.Join(abPartitionsSorted, "\\n")) 673 builder.Command().Textf("echo -e").Flag(abPartitionsSortedString).Textf(" > %s/META/ab_partitions.txt", targetFilesDir.String()) 674 // otakeys.txt 675 abOtaKeysSorted := android.SortedUniqueStrings(a.deviceProps.Ab_ota_keys) 676 abOtaKeysSortedString := proptools.ShellEscape(strings.Join(abOtaKeysSorted, "\\n")) 677 builder.Command().Textf("echo -e").Flag(abOtaKeysSortedString).Textf(" > %s/META/otakeys.txt", targetFilesDir.String()) 678 // postinstall_config.txt 679 abOtaPostInstallConfigString := proptools.ShellEscape(strings.Join(a.deviceProps.Ab_ota_postinstall_config, "\\n")) 680 builder.Command().Textf("echo -e").Flag(abOtaPostInstallConfigString).Textf(" > %s/META/postinstall_config.txt", targetFilesDir.String()) 681 // selinuxfc 682 if a.getFsInfos(ctx)["system"].SelinuxFc != nil { 683 builder.Command().Textf("cp").Input(a.getFsInfos(ctx)["system"].SelinuxFc).Textf(" %s/META/file_contexts.bin", targetFilesDir.String()) 684 } 685 } 686 // Copy $partition_filesystem_config.txt 687 fsInfos := a.getFsInfos(ctx) 688 for _, partition := range android.SortedKeys(fsInfos) { 689 if fsInfos[partition].FilesystemConfig == nil { 690 continue 691 } 692 if android.InList(partition, []string{"userdata"}) { 693 continue 694 } 695 if partition != "vendor_ramdisk" { 696 // vendor_ramdisk will be handled separately. 697 builder.Command().Textf("cp").Input(fsInfos[partition].FilesystemConfig).Textf(" %s/META/%s", targetFilesDir.String(), a.filesystemConfigNameForTargetFiles(partition)) 698 } 699 if partition == "ramdisk" { 700 // Create an additional copy at boot_filesystem_config.txt 701 builder.Command().Textf("cp").Input(fsInfos[partition].FilesystemConfig).Textf(" %s/META/boot_filesystem_config.txt", targetFilesDir.String()) 702 } 703 if partition == "system" { 704 // Create root_filesystem_config from the assembled ROOT/ intermediates directory 705 a.generateFilesystemConfigForTargetFiles(ctx, builder, a.rootDirForFsConfigTimestamp, targetFilesDir.String(), a.rootDirForFsConfig, "root_filesystem_config.txt") 706 } 707 if partition == "vendor_ramdisk" { 708 // Create vendor_boot_filesystem_config from the assembled VENDOR_BOOT/RAMDISK intermediates directory 709 vendorRamdiskStagingDir := targetFilesDir.String() + "/VENDOR_BOOT/RAMDISK" 710 vendorRamdiskFsConfigOut := targetFilesDir.String() + "/META/vendor_boot_filesystem_config.txt" 711 fsConfigBin := ctx.Config().HostToolPath(ctx, "fs_config") 712 builder.Command().Textf( 713 `(cd %s; find . -type d | sed 's,$,/,'; find . \! -type d) | cut -c 3- | sort | sed 's,^,,' | %s -C -D %s -R \"\" > %s`, 714 vendorRamdiskStagingDir, fsConfigBin, vendorRamdiskStagingDir, vendorRamdiskFsConfigOut). 715 Implicit(fsConfigBin) 716 } 717 } 718 // Copy ramdisk_node_list 719 if ramdiskNodeList := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Ramdisk_node_list)); ramdiskNodeList != nil { 720 builder.Command().Textf("cp").Input(ramdiskNodeList).Textf(" %s/META/", targetFilesDir.String()) 721 } 722 // Copy releasetools.py 723 if releaseTools := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Releasetools_extension)); releaseTools != nil { 724 builder.Command().Textf("cp").Input(releaseTools).Textf(" %s/META/", targetFilesDir.String()) 725 } 726 // apexkeys.txt 727 var installedApexKeys []android.Path 728 for _, installedModule := range allInstalledModules { 729 if info, ok := android.OtherModuleProvider(ctx, installedModule, ApexKeyPathInfoProvider); ok { 730 installedApexKeys = append(installedApexKeys, info.ApexKeyPath) 731 } 732 } 733 installedApexKeys = android.SortedUniquePaths(installedApexKeys) // Sort by keypath to match make 734 builder.Command().Text("cat").Inputs(installedApexKeys).Textf(" >> %s/META/apexkeys.txt", targetFilesDir.String()) 735 // apkcerts.txt 736 builder.Command().Textf("cp").Input(a.apkCertsInfo).Textf(" %s/META/", targetFilesDir.String()) 737 738 // Copy fastboot-info.txt 739 if fastbootInfo := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.FastbootInfo)); fastbootInfo != nil { 740 // TODO (b/399788523): Autogenerate fastboot-info.txt if there is no source fastboot-info.txt 741 // https://cs.android.com/android/_/android/platform/build/+/80b9546f8f69e78b8fe1870e0e745d70fc18dfcd:core/Makefile;l=5831-5893;drc=077490384423dff9eac954da5c001c6f0be3fa6e;bpv=0;bpt=0 742 builder.Command().Textf("cp").Input(fastbootInfo).Textf(" %s/META/fastboot-info.txt", targetFilesDir.String()) 743 } 744 745 // kernel_configs.txt and kernel_version.txt 746 if a.kernelConfig != nil { 747 builder.Command().Textf("cp").Input(a.kernelConfig).Textf(" %s/META/", targetFilesDir.String()) 748 } 749 if a.kernelVersion != nil { 750 builder.Command().Textf("cp").Input(a.kernelVersion).Textf(" %s/META/", targetFilesDir.String()) 751 } 752 // misc_info.txt 753 if a.miscInfo != nil { 754 builder.Command().Textf("cp").Input(a.miscInfo).Textf(" %s/META/", targetFilesDir.String()) 755 } 756 // apex_info.pb, care_map.pb, vbmeta_digest.txt 757 a.addImgToTargetFiles(ctx, builder, targetFilesDir.String()) 758 759 if a.partitionProps.Super_partition_name != nil { 760 superPartition := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag) 761 if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok { 762 // dynamic_partitions_info.txt 763 // TODO (b/390192334): Add `building_super_empty_partition=true` 764 builder.Command().Text("cp").Input(info.DynamicPartitionsInfo).Textf(" %s/META/", targetFilesDir.String()) 765 } else { 766 ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name()) 767 } 768 } 769 770} 771 772var ( 773 // https://cs.android.com/android/_/android/platform/build/+/30f05352c3e6f4333c77d4af66c253572d3ea6c9:core/Makefile;l=2111-2120;drc=519f75666431ee2926e0ec8991c682b28a4c9521;bpv=1;bpt=0 774 defaultTargetRecoveryFstypeMountOptions = "ext4=max_batch_time=0,commit=1,data=ordered,barrier=1,errors=panic,nodelalloc" 775) 776 777// A partial implementation of make's $PRODUCT_OUT/misc_info.txt 778// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=5894?q=misc_info.txt%20f:build%2Fmake%2Fcore%2FMakefile&ss=android%2Fplatform%2Fsuperproject%2Fmain 779// This file is subsequently used by add_img_to_target_files to create additioanl metadata files like apex_info.pb 780// TODO (b/399788119): Complete the migration of misc_info.txt 781func (a *androidDevice) addMiscInfo(ctx android.ModuleContext) android.Path { 782 buildType := func() string { 783 if ctx.Config().Debuggable() { 784 return "userdebug" 785 } else if ctx.Config().Eng() { 786 return "eng" 787 } else { 788 return "user" 789 } 790 } 791 defaultAppCertificate := func() string { 792 pem, _ := ctx.Config().DefaultAppCertificate(ctx) 793 return strings.TrimSuffix(pem.String(), ".x509.pem") 794 } 795 796 builder := android.NewRuleBuilder(pctx, ctx) 797 miscInfo := android.PathForModuleOut(ctx, "misc_info.txt") 798 builder.Command(). 799 Textf("rm -f %s", miscInfo). 800 Textf("&& echo recovery_api_version=%s >> %s", ctx.Config().VendorConfig("recovery").String("recovery_api_version"), miscInfo). 801 Textf("&& echo fstab_version=%s >> %s", ctx.Config().VendorConfig("recovery").String("recovery_fstab_version"), miscInfo). 802 Textf("&& echo build_type=%s >> %s", buildType(), miscInfo). 803 Textf("&& echo default_system_dev_certificate=%s >> %s", defaultAppCertificate(), miscInfo). 804 Textf("&& echo root_dir=%s >> %s", android.PathForModuleInPartitionInstall(ctx, "root"), miscInfo). 805 ImplicitOutput(miscInfo) 806 if len(ctx.Config().ExtraOtaRecoveryKeys()) > 0 { 807 builder.Command().Textf(`echo "extra_recovery_keys=%s" >> %s`, strings.Join(ctx.Config().ExtraOtaRecoveryKeys(), ""), miscInfo) 808 } else { 809 if a.partitionProps.Boot_partition_name != nil { 810 builder.Command(). 811 Textf("echo mkbootimg_args='--header_version %s' >> %s", a.getBootimgHeaderVersion(ctx, a.partitionProps.Boot_partition_name), miscInfo). 812 // TODO: Use boot's header version for recovery for now since cuttlefish does not set `BOARD_RECOVERY_MKBOOTIMG_ARGS` 813 Textf(" && echo recovery_mkbootimg_args='--header_version %s' >> %s", a.getBootimgHeaderVersion(ctx, a.partitionProps.Boot_partition_name), miscInfo) 814 } 815 if a.partitionProps.Init_boot_partition_name != nil { 816 builder.Command(). 817 Textf("echo mkbootimg_init_args='--header_version' %s >> %s", a.getBootimgHeaderVersion(ctx, a.partitionProps.Init_boot_partition_name), miscInfo) 818 } 819 builder.Command(). 820 Textf("echo mkbootimg_version_args='--os_version %s --os_patch_level %s' >> %s", ctx.Config().PlatformVersionLastStable(), ctx.Config().PlatformSecurityPatch(), miscInfo). 821 Textf(" && echo multistage_support=1 >> %s", miscInfo). 822 Textf(" && echo blockimgdiff_versions=3,4 >> %s", miscInfo) 823 } 824 fsInfos := a.getFsInfos(ctx) 825 if _, ok := fsInfos["vendor"]; ok { 826 builder.Command().Textf("echo board_uses_vendorimage=true >> %s", miscInfo) 827 } 828 if fsInfos["system"].ErofsCompressHints != nil { 829 builder.Command().Textf("echo erofs_default_compress_hints=%s >> %s", fsInfos["system"].ErofsCompressHints, miscInfo) 830 } 831 if releaseTools := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Releasetools_extension)); releaseTools != nil { 832 builder.Command().Textf("echo tool_extensions=%s >> %s", filepath.Dir(releaseTools.String()), miscInfo) 833 } 834 // ramdisk uses `compressed_cpio` fs_type 835 // https://cs.android.com/android/_/android/platform/build/+/30f05352c3e6f4333c77d4af66c253572d3ea6c9:core/Makefile;l=5923-5925;drc=519f75666431ee2926e0ec8991c682b28a4c9521;bpv=1;bpt=0 836 if _, ok := fsInfos["ramdisk"]; ok { 837 builder.Command().Textf("echo lz4_ramdisks=true >> %s", miscInfo) 838 } 839 // recovery_mount_options 840 // TODO: Add support for TARGET_RECOVERY_FSTYPE_MOUNT_OPTIONS which can be used to override the default 841 builder.Command().Textf("echo recovery_mount_options=%s >> %s", defaultTargetRecoveryFstypeMountOptions, miscInfo) 842 843 // vintf information 844 if proptools.Bool(ctx.Config().ProductVariables().Enforce_vintf_manifest) { 845 builder.Command().Textf("echo vintf_enforce=true >> %s", miscInfo) 846 } 847 if len(ctx.Config().DeviceManifestFiles()) > 0 { 848 builder.Command().Textf("echo vintf_include_empty_vendor_sku=true >> %s", miscInfo) 849 } 850 851 if a.partitionProps.Recovery_partition_name == nil { 852 builder.Command().Textf("echo no_recovery=true >> %s", miscInfo) 853 } 854 for _, partition := range android.SortedKeys(fsInfos) { 855 if fsInfos[partition].PropFileForMiscInfo != nil { 856 builder.Command().Text("cat").Input(fsInfos[partition].PropFileForMiscInfo).Textf(" >> %s", miscInfo) 857 } 858 } 859 if len(a.partitionProps.Vbmeta_partitions) > 0 { 860 builder.Command(). 861 Textf("echo avb_enable=true >> %s", miscInfo). 862 Textf("&& echo avb_building_vbmeta_image=true >> %s", miscInfo). 863 Textf("&& echo avb_avbtool=avbtool >> %s", miscInfo) 864 865 var allChainedVbmetaPartitionTypes []string 866 for _, vbmetaPartitionName := range a.partitionProps.Vbmeta_partitions { 867 img := ctx.GetDirectDepProxyWithTag(vbmetaPartitionName, filesystemDepTag) 868 if provider, ok := android.OtherModuleProvider(ctx, img, vbmetaPartitionProvider); ok { 869 builder.Command().Text("cat").Input(provider.PropFileForMiscInfo).Textf(" >> %s", miscInfo) 870 if provider.FilesystemPartitionType != "" { // the top-level vbmeta.img 871 allChainedVbmetaPartitionTypes = append(allChainedVbmetaPartitionTypes, provider.FilesystemPartitionType) 872 } 873 } else { 874 ctx.ModuleErrorf("vbmeta dep %s does not set vbmetaPartitionProvider\n", vbmetaPartitionName) 875 } 876 } 877 // Determine the custom vbmeta partitions by removing system and vendor 878 customVbmetaPartitionTypes := android.RemoveListFromList(allChainedVbmetaPartitionTypes, []string{"system", "vendor"}) 879 builder.Command().Textf("echo avb_custom_vbmeta_images_partition_list=%s >> %s", 880 strings.Join(android.SortedUniqueStrings(customVbmetaPartitionTypes), " "), 881 miscInfo, 882 ) 883 884 } 885 if a.partitionProps.Boot_partition_name != nil { 886 builder.Command().Textf("echo boot_images=boot.img >> %s", miscInfo) 887 } 888 889 if a.partitionProps.Super_partition_name != nil { 890 superPartition := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag) 891 if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok { 892 // cat dynamic_partition_info.txt 893 builder.Command().Text("cat").Input(info.DynamicPartitionsInfo).Textf(" >> %s", miscInfo) 894 if info.AbUpdate { 895 builder.Command().Textf("echo ab_update=true >> %s", miscInfo) 896 } 897 898 } else { 899 ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name()) 900 } 901 } 902 bootImgNames := []*string{ 903 a.partitionProps.Boot_partition_name, 904 a.partitionProps.Init_boot_partition_name, 905 a.partitionProps.Vendor_boot_partition_name, 906 } 907 for _, bootImgName := range bootImgNames { 908 if bootImgName == nil { 909 continue 910 } 911 912 bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(bootImgName), filesystemDepTag) 913 bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider) 914 // cat avb_ metadata of the boot images 915 builder.Command().Text("cat").Input(bootImgInfo.PropFileForMiscInfo).Textf(" >> %s", miscInfo) 916 } 917 918 builder.Command().Textf("echo blocksize=%s >> %s", proptools.String(a.deviceProps.Flash_block_size), miscInfo) 919 if proptools.Bool(a.deviceProps.Bootloader_in_update_package) { 920 builder.Command().Textf("echo bootloader_in_update_package=true >> %s", miscInfo) 921 } 922 if len(a.deviceProps.Partial_ota_update_partitions) > 0 { 923 builder.Command().Textf("echo partial_ota_update_partitions_list=%s >> %s", strings.Join(a.deviceProps.Partial_ota_update_partitions, " "), miscInfo) 924 } 925 926 // Sort and dedup 927 builder.Command().Textf("sort -u %s -o %s", miscInfo, miscInfo) 928 929 builder.Build("misc_info", "Building misc_info") 930 931 return miscInfo 932} 933 934func (a *androidDevice) getBootimgHeaderVersion(ctx android.ModuleContext, bootImgName *string) string { 935 bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(bootImgName), filesystemDepTag) 936 bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider) 937 return bootImgInfo.HeaderVersion 938} 939 940// addImgToTargetFiles invokes `add_img_to_target_files` and creates the following files in META/ 941// - apex_info.pb 942// - care_map.pb 943// - vbmeta_digest.txt 944func (a *androidDevice) addImgToTargetFiles(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir string) { 945 mkbootimg := ctx.Config().HostToolPath(ctx, "mkbootimg") 946 builder.Command(). 947 Textf("PATH=%s:$PATH", ctx.Config().HostToolDir()). 948 Textf("MKBOOTIMG=%s", mkbootimg). 949 Implicit(mkbootimg). 950 BuiltTool("add_img_to_target_files"). 951 Flag("-a -v -p"). 952 Flag(ctx.Config().HostToolDir()). 953 Text(targetFilesDir) 954} 955 956func (a *androidDevice) buildUpdatePackage(ctx android.ModuleContext) { 957 var exclusions []string 958 fsInfos := a.getFsInfos(ctx) 959 // Exclude the partitions that are not supported by flashall 960 for _, partition := range android.SortedKeys(fsInfos) { 961 if fsInfos[partition].NoFlashall { 962 exclusions = append(exclusions, fmt.Sprintf("IMAGES/%s.img", partition)) 963 exclusions = append(exclusions, fmt.Sprintf("IMAGES/%s.map", partition)) 964 } 965 } 966 967 updatePackage := android.PathForModuleOut(ctx, "img.zip") 968 rule := android.NewRuleBuilder(pctx, ctx) 969 970 buildSuperImage := ctx.Config().HostToolPath(ctx, "build_super_image") 971 zip2zip := ctx.Config().HostToolPath(ctx, "zip2zip") 972 973 rule.Command(). 974 BuiltTool("img_from_target_files"). 975 Text("--additional IMAGES/VerifiedBootParams.textproto:VerifiedBootParams.textproto"). 976 FlagForEachArg("--exclude ", exclusions). 977 FlagWithArg("--build_super_image ", buildSuperImage.String()). 978 Implicit(buildSuperImage). 979 Implicit(zip2zip). 980 Input(a.targetFilesZip). 981 Output(updatePackage) 982 983 rule.Build("updatepackage", "Building updatepackage") 984 985 a.updatePackage = updatePackage 986} 987 988type ApexKeyPathInfo struct { 989 ApexKeyPath android.Path 990} 991 992var ApexKeyPathInfoProvider = blueprint.NewProvider[ApexKeyPathInfo]() 993 994func (a *androidDevice) generateFilesystemConfigForTargetFiles(ctx android.ModuleContext, builder *android.RuleBuilder, stagingDirTimestamp android.Path, targetFilesDir, stagingDir, filename string) { 995 fsConfigOut := android.PathForModuleOut(ctx, filename) 996 ctx.Build(pctx, android.BuildParams{ 997 Rule: fsConfigRule, 998 Implicit: stagingDirTimestamp, 999 Output: fsConfigOut, 1000 Args: map[string]string{ 1001 "rootDir": stagingDir, 1002 "prefix": "", 1003 }, 1004 }) 1005 builder.Command().Textf("cp").Input(fsConfigOut).Textf(" %s/META/", targetFilesDir) 1006} 1007 1008// Filenames for the partition specific fs_config files. 1009// Hardcode the ramdisk files to their boot image prefix 1010func (a *androidDevice) filesystemConfigNameForTargetFiles(partition string) string { 1011 name := partition + "_filesystem_config.txt" 1012 if partition == "system" { 1013 name = "filesystem_config.txt" 1014 } else if partition == "ramdisk" { 1015 name = "init_boot_filesystem_config.txt" 1016 } 1017 return name 1018} 1019 1020func (a *androidDevice) getFilesystemInfo(ctx android.ModuleContext, depName string) FilesystemInfo { 1021 fsMod := ctx.GetDirectDepProxyWithTag(depName, filesystemDepTag) 1022 fsInfo, ok := android.OtherModuleProvider(ctx, fsMod, FilesystemProvider) 1023 if !ok { 1024 ctx.ModuleErrorf("Expected dependency %s to be a filesystem", depName) 1025 } 1026 return fsInfo 1027} 1028 1029func (a *androidDevice) setVbmetaPhonyTargets(ctx android.ModuleContext) { 1030 if !proptools.Bool(a.deviceProps.Main_device) { 1031 return 1032 } 1033 1034 if !ctx.Config().KatiEnabled() { 1035 for _, vbmetaPartitionName := range a.partitionProps.Vbmeta_partitions { 1036 img := ctx.GetDirectDepProxyWithTag(vbmetaPartitionName, filesystemDepTag) 1037 if provider, ok := android.OtherModuleProvider(ctx, img, vbmetaPartitionProvider); ok { 1038 // make generates `vbmetasystemimage` phony target instead of `vbmeta_systemimage` phony target. 1039 partitionName := strings.ReplaceAll(provider.Name, "_", "") 1040 ctx.Phony(fmt.Sprintf("%simage", partitionName), provider.Output) 1041 } 1042 } 1043 } 1044} 1045 1046func (a *androidDevice) getKernel(ctx android.ModuleContext) android.Path { 1047 if a.partitionProps.Boot_partition_name != nil { 1048 bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(a.partitionProps.Boot_partition_name), filesystemDepTag) 1049 bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider) 1050 return bootImgInfo.Kernel 1051 } 1052 return nil 1053} 1054 1055// Gets the kernel version and configs from the actual kernel file itself. Roughly equivalent to 1056// this make code: https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=5443;drc=c0b66fc59de069e06ce0ffd703d4d21613be30c6 1057// However, it is a simplified version of that make code. Differences include: 1058// - Not handling BOARD_KERNEL_CONFIG_FILE because BOARD_KERNEL_CONFIG_FILE was never used. 1059// - Not unpacking the bootimage, as we should be able to just always export the kernel directly 1060// in the BootimgInfo. We don't currently support prebuilt boot images, but even if we add that 1061// in the future, it can be done in a prebuilt_bootimage module type that still exports the same 1062// BootimgInfo. 1063// - We don't print a warning and output '<unknown-kernel>' to kernel_version_for_uffd_gc.txt 1064// because we expect the kernel to always be present. If it's not, we will get an error that 1065// kernel_version_for_uffd_gc.txt doesn't exist. This may require later tweaking to the 1066// dexpreopt rules so that they don't attempt to access that file in builds that don't have 1067// a kernel. 1068func (a *androidDevice) extractKernelVersionAndConfigs(ctx android.ModuleContext) (android.Path, android.Path) { 1069 kernel := a.getKernel(ctx) 1070 // If there's no kernel, don't create kernel version / kernel config files. Reverse dependencies 1071 // on those files have to account for this, for example by disabling dexpreopt in unbundled 1072 // builds. 1073 if kernel == nil { 1074 return nil, nil 1075 } 1076 1077 lz4tool := ctx.Config().HostToolPath(ctx, "lz4") 1078 1079 extractedVersionFile := android.PathForModuleOut(ctx, "kernel_version.txt") 1080 extractedConfigsFile := android.PathForModuleOut(ctx, "kernel_configs.txt") 1081 builder := android.NewRuleBuilder(pctx, ctx) 1082 builder.Command().BuiltTool("extract_kernel"). 1083 Flag("--tools lz4:"+lz4tool.String()).Implicit(lz4tool). 1084 FlagWithInput("--input ", kernel). 1085 FlagWithOutput("--output-release ", extractedVersionFile). 1086 FlagWithOutput("--output-configs ", extractedConfigsFile). 1087 Textf(`&& printf "\n" >> %s`, extractedVersionFile) 1088 1089 if specifiedVersion := proptools.String(a.deviceProps.Kernel_version); specifiedVersion != "" { 1090 specifiedVersionFile := android.PathForModuleOut(ctx, "specified_kernel_version.txt") 1091 android.WriteFileRule(ctx, specifiedVersionFile, specifiedVersion) 1092 builder.Command().Text("diff -q"). 1093 Input(specifiedVersionFile). 1094 Input(extractedVersionFile). 1095 Textf(`|| (echo "Specified kernel version '$(cat %s)' does not match actual kernel version '$(cat %s)'"; exit 1)`, specifiedVersionFile, extractedVersionFile) 1096 } 1097 1098 builder.Build("extract_kernel_info", "Extract kernel version and configs") 1099 1100 if proptools.Bool(a.deviceProps.Main_device) && !ctx.Config().KatiEnabled() { 1101 if ctx.Config().EnableUffdGc() == "default" { 1102 kernelVersionFile := android.PathForOutput(ctx, "dexpreopt/kernel_version_for_uffd_gc.txt") 1103 ctx.Build(pctx, android.BuildParams{ 1104 Rule: android.CpIfChanged, 1105 Input: extractedVersionFile, 1106 Output: kernelVersionFile, 1107 }) 1108 } 1109 1110 ctx.DistForGoal("droid_targets", extractedVersionFile) 1111 } 1112 1113 return extractedVersionFile, extractedConfigsFile 1114} 1115 1116func (a *androidDevice) buildApkCertsInfo(ctx android.ModuleContext, allInstalledModules []android.Module) android.Path { 1117 // TODO (spandandas): Add compressed 1118 formatLine := func(cert java.Certificate, name, partition string) string { 1119 pem := cert.AndroidMkString() 1120 var key string 1121 if cert.Key == nil { 1122 key = "" 1123 } else { 1124 key = cert.Key.String() 1125 } 1126 return fmt.Sprintf(`name="%s" certificate="%s" private_key="%s" partition="%s"`, name, pem, key, partition) 1127 } 1128 1129 apkCerts := []string{} 1130 var apkCertsFiles android.Paths 1131 for _, installedModule := range allInstalledModules { 1132 partition := "" 1133 if commonInfo, ok := android.OtherModuleProvider(ctx, installedModule, android.CommonModuleInfoProvider); ok { 1134 partition = commonInfo.PartitionTag 1135 } else { 1136 ctx.ModuleErrorf("%s does not set CommonModuleInfoKey", installedModule.Name()) 1137 } 1138 if info, ok := android.OtherModuleProvider(ctx, installedModule, java.AppInfoProvider); ok { 1139 if info.AppSet { 1140 apkCertsFiles = append(apkCertsFiles, info.ApkCertsFile) 1141 } else { 1142 apkCerts = append(apkCerts, formatLine(info.Certificate, info.InstallApkName+".apk", partition)) 1143 } 1144 } else if info, ok := android.OtherModuleProvider(ctx, installedModule, java.AppInfosProvider); ok { 1145 for _, certInfo := range info { 1146 // Partition information of apk-in-apex is not exported to the legacy Make packaging system. 1147 // Hardcode the partition to "system" 1148 apkCerts = append(apkCerts, formatLine(certInfo.Certificate, certInfo.InstallApkName+".apk", "system")) 1149 } 1150 } else if info, ok := android.OtherModuleProvider(ctx, installedModule, java.RuntimeResourceOverlayInfoProvider); ok { 1151 apkCerts = append(apkCerts, formatLine(info.Certificate, info.OutputFile.Base(), partition)) 1152 } 1153 } 1154 slices.Sort(apkCerts) // sort by name 1155 fsInfos := a.getFsInfos(ctx) 1156 if fsInfos["system"].HasFsverity { 1157 defaultPem, defaultKey := ctx.Config().DefaultAppCertificate(ctx) 1158 apkCerts = append(apkCerts, formatLine(java.Certificate{Pem: defaultPem, Key: defaultKey}, "BuildManifest.apk", "system")) 1159 if info, ok := fsInfos["system_ext"]; ok && info.HasFsverity { 1160 apkCerts = append(apkCerts, formatLine(java.Certificate{Pem: defaultPem, Key: defaultKey}, "BuildManifestSystemExt.apk", "system_ext")) 1161 } 1162 } 1163 1164 apkCertsInfoWithoutAppSets := android.PathForModuleOut(ctx, "apkcerts_without_app_sets.txt") 1165 android.WriteFileRuleVerbatim(ctx, apkCertsInfoWithoutAppSets, strings.Join(apkCerts, "\n")+"\n") 1166 apkCertsInfo := android.PathForModuleOut(ctx, "apkcerts.txt") 1167 ctx.Build(pctx, android.BuildParams{ 1168 Rule: android.Cat, 1169 Description: "combine apkcerts.txt", 1170 Output: apkCertsInfo, 1171 Inputs: append(apkCertsFiles, apkCertsInfoWithoutAppSets), 1172 }) 1173 return apkCertsInfo 1174} 1175