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 fsgen 16 17import ( 18 "crypto/sha256" 19 "fmt" 20 "path/filepath" 21 "slices" 22 "strconv" 23 "strings" 24 25 "android/soong/android" 26 "android/soong/filesystem" 27 "android/soong/kernel" 28 29 "github.com/google/blueprint" 30 "github.com/google/blueprint/parser" 31 "github.com/google/blueprint/proptools" 32) 33 34var pctx = android.NewPackageContext("android/soong/fsgen") 35 36func init() { 37 registerBuildComponents(android.InitRegistrationContext) 38} 39 40func registerBuildComponents(ctx android.RegistrationContext) { 41 ctx.RegisterModuleType("soong_filesystem_creator", filesystemCreatorFactory) 42 ctx.PreDepsMutators(RegisterCollectFileSystemDepsMutators) 43} 44 45type generatedPartitionData struct { 46 partitionType string 47 moduleName string 48 // supported is true if the module was created successfully, false if there was some problem 49 // and the module couldn't be created. 50 supported bool 51 handwritten bool 52} 53 54type allGeneratedPartitionData []generatedPartitionData 55 56func (d allGeneratedPartitionData) moduleNames() []string { 57 var result []string 58 for _, data := range d { 59 if data.supported { 60 result = append(result, data.moduleName) 61 } 62 } 63 return result 64} 65 66func (d allGeneratedPartitionData) types() []string { 67 var result []string 68 for _, data := range d { 69 if data.supported { 70 result = append(result, data.partitionType) 71 } 72 } 73 return result 74} 75 76func (d allGeneratedPartitionData) unsupportedTypes() []string { 77 var result []string 78 for _, data := range d { 79 if !data.supported { 80 result = append(result, data.partitionType) 81 } 82 } 83 return result 84} 85 86func (d allGeneratedPartitionData) names() []string { 87 var result []string 88 for _, data := range d { 89 if data.supported { 90 result = append(result, data.moduleName) 91 } 92 } 93 return result 94} 95 96func (d allGeneratedPartitionData) nameForType(ty string) string { 97 for _, data := range d { 98 if data.supported && data.partitionType == ty { 99 return data.moduleName 100 } 101 } 102 return "" 103} 104 105func (d allGeneratedPartitionData) typeForName(name string) string { 106 for _, data := range d { 107 if data.supported && data.moduleName == name { 108 return data.partitionType 109 } 110 } 111 return "" 112} 113 114func (d allGeneratedPartitionData) isHandwritten(name string) bool { 115 for _, data := range d { 116 if data.supported && data.moduleName == name { 117 return data.handwritten 118 } 119 } 120 return false 121} 122 123type filesystemCreatorProps struct { 124 Unsupported_partition_types []string `blueprint:"mutated"` 125 126 Vbmeta_module_names []string `blueprint:"mutated"` 127 Vbmeta_partition_names []string `blueprint:"mutated"` 128 129 Boot_image string `blueprint:"mutated" android:"path_device_first"` 130 Vendor_boot_image string `blueprint:"mutated" android:"path_device_first"` 131 Init_boot_image string `blueprint:"mutated" android:"path_device_first"` 132 Super_image string `blueprint:"mutated" android:"path_device_first"` 133} 134 135type filesystemCreator struct { 136 android.ModuleBase 137 138 properties filesystemCreatorProps 139} 140 141func filesystemCreatorFactory() android.Module { 142 module := &filesystemCreator{} 143 144 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) 145 module.AddProperties(&module.properties) 146 android.AddLoadHook(module, func(ctx android.LoadHookContext) { 147 generatedPrebuiltEtcModuleNames := createPrebuiltEtcModules(ctx) 148 avbpubkeyGenerated := createAvbpubkeyModule(ctx) 149 createFsGenState(ctx, generatedPrebuiltEtcModuleNames, avbpubkeyGenerated) 150 module.createAvbKeyFilegroups(ctx) 151 module.createMiscFilegroups(ctx) 152 module.createInternalModules(ctx) 153 }) 154 155 return module 156} 157 158func generatedPartitions(ctx android.EarlyModuleContext) allGeneratedPartitionData { 159 partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse 160 161 var result allGeneratedPartitionData 162 addGenerated := func(ty string) { 163 result = append(result, generatedPartitionData{ 164 partitionType: ty, 165 moduleName: generatedModuleNameForPartition(ctx.Config(), ty), 166 supported: true, 167 }) 168 } 169 170 if ctx.Config().UseSoongSystemImage() { 171 if ctx.Config().SoongDefinedSystemImage() == "" { 172 panic("PRODUCT_SOONG_DEFINED_SYSTEM_IMAGE must be set if USE_SOONG_DEFINED_SYSTEM_IMAGE is true") 173 } 174 result = append(result, generatedPartitionData{ 175 partitionType: "system", 176 moduleName: ctx.Config().SoongDefinedSystemImage(), 177 supported: true, 178 handwritten: true, 179 }) 180 } else { 181 addGenerated("system") 182 } 183 if ctx.DeviceConfig().SystemExtPath() == "system_ext" { 184 addGenerated("system_ext") 185 } 186 if ctx.DeviceConfig().BuildingVendorImage() && ctx.DeviceConfig().VendorPath() == "vendor" { 187 addGenerated("vendor") 188 } 189 if ctx.DeviceConfig().BuildingProductImage() && ctx.DeviceConfig().ProductPath() == "product" { 190 addGenerated("product") 191 } 192 if ctx.DeviceConfig().BuildingOdmImage() && ctx.DeviceConfig().OdmPath() == "odm" { 193 addGenerated("odm") 194 } 195 if ctx.DeviceConfig().BuildingUserdataImage() && ctx.DeviceConfig().UserdataPath() == "data" { 196 addGenerated("userdata") 197 } 198 if partitionVars.BuildingSystemDlkmImage { 199 addGenerated("system_dlkm") 200 } 201 if partitionVars.BuildingVendorDlkmImage { 202 addGenerated("vendor_dlkm") 203 } 204 if partitionVars.BuildingOdmDlkmImage { 205 addGenerated("odm_dlkm") 206 } 207 if partitionVars.BuildingRamdiskImage { 208 addGenerated("ramdisk") 209 } 210 if buildingVendorBootImage(partitionVars) { 211 addGenerated("vendor_ramdisk") 212 } 213 if ctx.DeviceConfig().BuildingRecoveryImage() && ctx.DeviceConfig().RecoveryPath() == "recovery" { 214 addGenerated("recovery") 215 } 216 return result 217} 218 219func (f *filesystemCreator) createInternalModules(ctx android.LoadHookContext) { 220 partitions := generatedPartitions(ctx) 221 for i := range partitions { 222 f.createPartition(ctx, partitions, &partitions[i]) 223 } 224 // Create android_info.prop 225 f.createAndroidInfo(ctx) 226 227 partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse 228 dtbImg := createDtbImgFilegroup(ctx) 229 230 if buildingBootImage(partitionVars) { 231 if createBootImage(ctx, dtbImg) { 232 f.properties.Boot_image = ":" + generatedModuleNameForPartition(ctx.Config(), "boot") 233 } else { 234 f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, "boot") 235 } 236 } 237 if buildingVendorBootImage(partitionVars) { 238 if createVendorBootImage(ctx, dtbImg) { 239 f.properties.Vendor_boot_image = ":" + generatedModuleNameForPartition(ctx.Config(), "vendor_boot") 240 } else { 241 f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, "vendor_boot") 242 } 243 } 244 if buildingInitBootImage(partitionVars) { 245 if createInitBootImage(ctx) { 246 f.properties.Init_boot_image = ":" + generatedModuleNameForPartition(ctx.Config(), "init_boot") 247 } else { 248 f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, "init_boot") 249 } 250 } 251 252 var systemOtherImageName string 253 if buildingSystemOtherImage(partitionVars) { 254 systemModule := partitions.nameForType("system") 255 systemOtherImageName = generatedModuleNameForPartition(ctx.Config(), "system_other") 256 ctx.CreateModule( 257 filesystem.SystemOtherImageFactory, 258 &filesystem.SystemOtherImageProperties{ 259 System_image: &systemModule, 260 Preinstall_dexpreopt_files_from: partitions.moduleNames(), 261 }, 262 &struct { 263 Name *string 264 }{ 265 Name: proptools.StringPtr(systemOtherImageName), 266 }, 267 ) 268 } 269 270 for _, x := range f.createVbmetaPartitions(ctx, partitions) { 271 f.properties.Vbmeta_module_names = append(f.properties.Vbmeta_module_names, x.moduleName) 272 f.properties.Vbmeta_partition_names = append(f.properties.Vbmeta_partition_names, x.partitionName) 273 } 274 275 var superImageSubpartitions []string 276 if buildingSuperImage(partitionVars) { 277 superImageSubpartitions = createSuperImage(ctx, partitions, partitionVars, systemOtherImageName) 278 f.properties.Super_image = ":" + generatedModuleNameForPartition(ctx.Config(), "super") 279 } 280 281 ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).soongGeneratedPartitions = partitions 282 f.createDeviceModule(ctx, partitions, f.properties.Vbmeta_module_names, superImageSubpartitions) 283} 284 285func generatedModuleName(cfg android.Config, suffix string) string { 286 prefix := "soong" 287 if cfg.HasDeviceProduct() { 288 prefix = cfg.DeviceProduct() 289 } 290 return fmt.Sprintf("%s_generated_%s", prefix, suffix) 291} 292 293func generatedModuleNameForPartition(cfg android.Config, partitionType string) string { 294 return generatedModuleName(cfg, fmt.Sprintf("%s_image", partitionType)) 295} 296 297func buildingSystemOtherImage(partitionVars android.PartitionVariables) bool { 298 // TODO: Recreate this logic from make instead of just depending on the final result variable: 299 // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/board_config.mk;l=429;drc=15a0df840e7093f65518003ab80cf24a3d9e8e6a 300 return partitionVars.BuildingSystemOtherImage 301} 302 303func (f *filesystemCreator) createBootloaderFilegroup(ctx android.LoadHookContext) (string, bool) { 304 bootloaderPath := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.PrebuiltBootloader 305 if len(bootloaderPath) == 0 { 306 return "", false 307 } 308 309 bootloaderFilegroupName := generatedModuleName(ctx.Config(), "bootloader") 310 filegroupProps := &struct { 311 Name *string 312 Srcs []string 313 Visibility []string 314 }{ 315 Name: proptools.StringPtr(bootloaderFilegroupName), 316 Srcs: []string{bootloaderPath}, 317 Visibility: []string{"//visibility:public"}, 318 } 319 ctx.CreateModuleInDirectory(android.FileGroupFactory, ".", filegroupProps) 320 return bootloaderFilegroupName, true 321} 322 323func (f *filesystemCreator) createReleaseToolsFilegroup(ctx android.LoadHookContext) (string, bool) { 324 releaseToolsDir := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.ReleaseToolsExtensionDir 325 if releaseToolsDir == "" { 326 return "", false 327 } 328 329 releaseToolsFilegroupName := generatedModuleName(ctx.Config(), "releasetools") 330 filegroupProps := &struct { 331 Name *string 332 Srcs []string 333 Visibility []string 334 }{ 335 Name: proptools.StringPtr(releaseToolsFilegroupName), 336 Srcs: []string{"releasetools.py"}, 337 Visibility: []string{"//visibility:public"}, 338 } 339 ctx.CreateModuleInDirectory(android.FileGroupFactory, releaseToolsDir, filegroupProps) 340 return releaseToolsFilegroupName, true 341} 342 343func (f *filesystemCreator) createFastbootInfoFilegroup(ctx android.LoadHookContext) (string, bool) { 344 fastbootInfoFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BoardFastbootInfoFile 345 if fastbootInfoFile == "" { 346 return "", false 347 } 348 349 fastbootInfoFilegroupName := generatedModuleName(ctx.Config(), "fastboot") 350 filegroupProps := &struct { 351 Name *string 352 Srcs []string 353 Visibility []string 354 }{ 355 Name: proptools.StringPtr(fastbootInfoFilegroupName), 356 Srcs: []string{fastbootInfoFile}, 357 Visibility: []string{"//visibility:public"}, 358 } 359 ctx.CreateModuleInDirectory(android.FileGroupFactory, ".", filegroupProps) 360 return fastbootInfoFilegroupName, true 361} 362 363func (f *filesystemCreator) createDeviceModule( 364 ctx android.LoadHookContext, 365 partitions allGeneratedPartitionData, 366 vbmetaPartitions []string, 367 superImageSubPartitions []string, 368) { 369 baseProps := &struct { 370 Name *string 371 }{ 372 Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "device")), 373 } 374 375 // Currently, only the system and system_ext partition module is created. 376 partitionProps := &filesystem.PartitionNameProperties{} 377 if f.properties.Super_image != "" { 378 partitionProps.Super_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "super")) 379 } 380 if modName := partitions.nameForType("system"); modName != "" && !android.InList("system", superImageSubPartitions) { 381 partitionProps.System_partition_name = proptools.StringPtr(modName) 382 } 383 if modName := partitions.nameForType("system_ext"); modName != "" && !android.InList("system_ext", superImageSubPartitions) { 384 partitionProps.System_ext_partition_name = proptools.StringPtr(modName) 385 } 386 if modName := partitions.nameForType("vendor"); modName != "" && !android.InList("vendor", superImageSubPartitions) { 387 partitionProps.Vendor_partition_name = proptools.StringPtr(modName) 388 } 389 if modName := partitions.nameForType("product"); modName != "" && !android.InList("product", superImageSubPartitions) { 390 partitionProps.Product_partition_name = proptools.StringPtr(modName) 391 } 392 if modName := partitions.nameForType("odm"); modName != "" && !android.InList("odm", superImageSubPartitions) { 393 partitionProps.Odm_partition_name = proptools.StringPtr(modName) 394 } 395 if modName := partitions.nameForType("userdata"); modName != "" { 396 partitionProps.Userdata_partition_name = proptools.StringPtr(modName) 397 } 398 if modName := partitions.nameForType("recovery"); modName != "" && !ctx.DeviceConfig().BoardMoveRecoveryResourcesToVendorBoot() { 399 partitionProps.Recovery_partition_name = proptools.StringPtr(modName) 400 } 401 if modName := partitions.nameForType("system_dlkm"); modName != "" && !android.InList("system_dlkm", superImageSubPartitions) { 402 partitionProps.System_dlkm_partition_name = proptools.StringPtr(modName) 403 } 404 if modName := partitions.nameForType("vendor_dlkm"); modName != "" && !android.InList("vendor_dlkm", superImageSubPartitions) { 405 partitionProps.Vendor_dlkm_partition_name = proptools.StringPtr(modName) 406 } 407 if modName := partitions.nameForType("odm_dlkm"); modName != "" && !android.InList("odm_dlkm", superImageSubPartitions) { 408 partitionProps.Odm_dlkm_partition_name = proptools.StringPtr(modName) 409 } 410 if f.properties.Boot_image != "" { 411 partitionProps.Boot_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "boot")) 412 } 413 if f.properties.Vendor_boot_image != "" { 414 partitionProps.Vendor_boot_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "vendor_boot")) 415 } 416 if f.properties.Init_boot_image != "" { 417 partitionProps.Init_boot_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "init_boot")) 418 } 419 partitionProps.Vbmeta_partitions = vbmetaPartitions 420 421 deviceProps := &filesystem.DeviceProperties{ 422 Main_device: proptools.BoolPtr(true), 423 Ab_ota_updater: proptools.BoolPtr(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.AbOtaUpdater), 424 Ab_ota_partitions: ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.AbOtaPartitions, 425 Ab_ota_postinstall_config: ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.AbOtaPostInstallConfig, 426 Ramdisk_node_list: proptools.StringPtr(":ramdisk_node_list"), 427 Android_info: proptools.StringPtr(":" + generatedModuleName(ctx.Config(), "android_info.prop{.txt}")), 428 Kernel_version: ctx.Config().ProductVariables().BoardKernelVersion, 429 Partial_ota_update_partitions: ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BoardPartialOtaUpdatePartitionsList, 430 Flash_block_size: proptools.StringPtr(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BoardFlashBlockSize), 431 Bootloader_in_update_package: proptools.BoolPtr(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BootloaderInUpdatePackage), 432 } 433 434 if bootloader, ok := f.createBootloaderFilegroup(ctx); ok { 435 deviceProps.Bootloader = proptools.StringPtr(":" + bootloader) 436 } 437 if releaseTools, ok := f.createReleaseToolsFilegroup(ctx); ok { 438 deviceProps.Releasetools_extension = proptools.StringPtr(":" + releaseTools) 439 } 440 if fastbootInfo, ok := f.createFastbootInfoFilegroup(ctx); ok { 441 deviceProps.FastbootInfo = proptools.StringPtr(":" + fastbootInfo) 442 } 443 444 ctx.CreateModule(filesystem.AndroidDeviceFactory, baseProps, partitionProps, deviceProps) 445} 446 447func partitionSpecificFsProps(ctx android.EarlyModuleContext, partitions allGeneratedPartitionData, fsProps *filesystem.FilesystemProperties, partitionType string) { 448 partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse 449 switch partitionType { 450 case "system": 451 fsProps.Build_logtags = proptools.BoolPtr(true) 452 // https://source.corp.google.com/h/googleplex-android/platform/build//639d79f5012a6542ab1f733b0697db45761ab0f3:core/packaging/flags.mk;l=21;drc=5ba8a8b77507f93aa48cc61c5ba3f31a4d0cbf37;bpv=1;bpt=0 453 fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true) 454 // Identical to that of the aosp_shared_system_image 455 if partitionVars.ProductFsverityGenerateMetadata { 456 fsProps.Fsverity.Inputs = proptools.NewSimpleConfigurable([]string{ 457 "etc/boot-image.prof", 458 "etc/dirty-image-objects", 459 "etc/preloaded-classes", 460 "etc/classpaths/*.pb", 461 "framework/*", 462 "framework/*/*", // framework/{arch} 463 "framework/oat/*/*", // framework/oat/{arch} 464 }) 465 fsProps.Fsverity.Libs = proptools.NewSimpleConfigurable([]string{":framework-res{.export-package.apk}"}) 466 } 467 fsProps.Symlinks = commonSymlinksFromRoot 468 fsProps.Symlinks = append(fsProps.Symlinks, 469 []filesystem.SymlinkDefinition{ 470 { 471 Target: proptools.StringPtr("/data/cache"), 472 Name: proptools.StringPtr("cache"), 473 }, 474 { 475 Target: proptools.StringPtr("/storage/self/primary"), 476 Name: proptools.StringPtr("sdcard"), 477 }, 478 { 479 Target: proptools.StringPtr("/system_dlkm/lib/modules"), 480 Name: proptools.StringPtr("system/lib/modules"), 481 }, 482 { 483 Target: proptools.StringPtr("/product"), 484 Name: proptools.StringPtr("system/product"), 485 }, 486 { 487 Target: proptools.StringPtr("/system_ext"), 488 Name: proptools.StringPtr("system/system_ext"), 489 }, 490 { 491 Target: proptools.StringPtr("/vendor"), 492 Name: proptools.StringPtr("system/vendor"), 493 }, 494 }..., 495 ) 496 fsProps.Base_dir = proptools.StringPtr("system") 497 fsProps.Dirs = proptools.NewSimpleConfigurable(commonPartitionDirs) 498 fsProps.Security_patch = proptools.StringPtr(ctx.Config().PlatformSecurityPatch()) 499 fsProps.Stem = proptools.StringPtr("system.img") 500 case "system_ext": 501 if partitionVars.ProductFsverityGenerateMetadata { 502 fsProps.Fsverity.Inputs = proptools.NewSimpleConfigurable([]string{ 503 "framework/*", 504 "framework/*/*", // framework/{arch} 505 "framework/oat/*/*", // framework/oat/{arch} 506 }) 507 fsProps.Fsverity.Libs = proptools.NewSimpleConfigurable([]string{":framework-res{.export-package.apk}"}) 508 } 509 fsProps.Security_patch = proptools.StringPtr(ctx.Config().PlatformSecurityPatch()) 510 fsProps.Stem = proptools.StringPtr("system_ext.img") 511 fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true) 512 case "product": 513 fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true) 514 fsProps.Android_filesystem_deps.System = proptools.StringPtr(partitions.nameForType("system")) 515 if systemExtName := partitions.nameForType("system_ext"); systemExtName != "" { 516 fsProps.Android_filesystem_deps.System_ext = proptools.StringPtr(systemExtName) 517 } 518 fsProps.Security_patch = proptools.StringPtr(ctx.Config().PlatformSecurityPatch()) 519 fsProps.Stem = proptools.StringPtr("product.img") 520 case "vendor": 521 fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true) 522 fsProps.Symlinks = []filesystem.SymlinkDefinition{ 523 filesystem.SymlinkDefinition{ 524 Target: proptools.StringPtr("/odm"), 525 Name: proptools.StringPtr("odm"), 526 }, 527 filesystem.SymlinkDefinition{ 528 Target: proptools.StringPtr("/vendor_dlkm/lib/modules"), 529 Name: proptools.StringPtr("lib/modules"), 530 }, 531 } 532 fsProps.Android_filesystem_deps.System = proptools.StringPtr(partitions.nameForType("system")) 533 if systemExtName := partitions.nameForType("system_ext"); systemExtName != "" { 534 fsProps.Android_filesystem_deps.System_ext = proptools.StringPtr(systemExtName) 535 } 536 fsProps.Security_patch = proptools.StringPtr(partitionVars.VendorSecurityPatch) 537 fsProps.Stem = proptools.StringPtr("vendor.img") 538 case "odm": 539 fsProps.Symlinks = []filesystem.SymlinkDefinition{ 540 filesystem.SymlinkDefinition{ 541 Target: proptools.StringPtr("/odm_dlkm/lib/modules"), 542 Name: proptools.StringPtr("lib/modules"), 543 }, 544 } 545 fsProps.Security_patch = proptools.StringPtr(partitionVars.OdmSecurityPatch) 546 fsProps.Stem = proptools.StringPtr("odm.img") 547 case "userdata": 548 fsProps.Stem = proptools.StringPtr("userdata.img") 549 if vars, ok := partitionVars.PartitionQualifiedVariables["userdata"]; ok { 550 parsed, err := strconv.ParseInt(vars.BoardPartitionSize, 10, 64) 551 if err != nil { 552 panic(fmt.Sprintf("Partition size must be an int, got %s", vars.BoardPartitionSize)) 553 } 554 fsProps.Partition_size = &parsed 555 // Disable avb for userdata partition 556 fsProps.Use_avb = nil 557 } 558 // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2265;drc=7f50a123045520f2c5e18e9eb4e83f92244a1459 559 if s, err := strconv.ParseBool(partitionVars.ProductFsCasefold); err == nil { 560 fsProps.Support_casefolding = proptools.BoolPtr(s) 561 } else if len(partitionVars.ProductFsCasefold) > 0 { 562 ctx.ModuleErrorf("Unrecognized PRODUCT_FS_CASEFOLD value %s", partitionVars.ProductFsCasefold) 563 } 564 if s, err := strconv.ParseBool(partitionVars.ProductQuotaProjid); err == nil { 565 fsProps.Support_project_quota = proptools.BoolPtr(s) 566 } else if len(partitionVars.ProductQuotaProjid) > 0 { 567 ctx.ModuleErrorf("Unrecognized PRODUCT_QUOTA_PROJID value %s", partitionVars.ProductQuotaProjid) 568 } 569 if s, err := strconv.ParseBool(partitionVars.ProductFsCompression); err == nil { 570 fsProps.Enable_compression = proptools.BoolPtr(s) 571 } else if len(partitionVars.ProductFsCompression) > 0 { 572 ctx.ModuleErrorf("Unrecognized PRODUCT_FS_COMPRESSION value %s", partitionVars.ProductFsCompression) 573 } 574 575 case "ramdisk": 576 // Following the logic in https://cs.android.com/android/platform/superproject/main/+/c3c5063df32748a8806ce5da5dd0db158eab9ad9:build/make/core/Makefile;l=1307 577 fsProps.Dirs = android.NewSimpleConfigurable([]string{ 578 "debug_ramdisk", 579 "dev", 580 "metadata", 581 "mnt", 582 "proc", 583 "second_stage_resources", 584 "sys", 585 }) 586 if partitionVars.BoardUsesGenericKernelImage { 587 fsProps.Dirs.AppendSimpleValue([]string{ 588 "first_stage_ramdisk/debug_ramdisk", 589 "first_stage_ramdisk/dev", 590 "first_stage_ramdisk/metadata", 591 "first_stage_ramdisk/mnt", 592 "first_stage_ramdisk/proc", 593 "first_stage_ramdisk/second_stage_resources", 594 "first_stage_ramdisk/sys", 595 }) 596 } 597 fsProps.Stem = proptools.StringPtr("ramdisk.img") 598 case "recovery": 599 dirs := append(commonPartitionDirs, []string{ 600 "sdcard", 601 }...) 602 603 dirsWithRoot := make([]string, len(dirs)) 604 for i, dir := range dirs { 605 dirsWithRoot[i] = filepath.Join("root", dir) 606 } 607 608 fsProps.Dirs = proptools.NewSimpleConfigurable(dirsWithRoot) 609 fsProps.Symlinks = symlinksWithNamePrefix(append(commonSymlinksFromRoot, filesystem.SymlinkDefinition{ 610 Target: proptools.StringPtr("prop.default"), 611 Name: proptools.StringPtr("default.prop"), 612 }), "root") 613 fsProps.Stem = proptools.StringPtr("recovery.img") 614 case "system_dlkm": 615 fsProps.Security_patch = proptools.StringPtr(partitionVars.SystemDlkmSecurityPatch) 616 fsProps.Stem = proptools.StringPtr("system_dlkm.img") 617 case "vendor_dlkm": 618 fsProps.Security_patch = proptools.StringPtr(partitionVars.VendorDlkmSecurityPatch) 619 fsProps.Stem = proptools.StringPtr("vendor_dlkm.img") 620 case "odm_dlkm": 621 fsProps.Security_patch = proptools.StringPtr(partitionVars.OdmDlkmSecurityPatch) 622 fsProps.Stem = proptools.StringPtr("odm_dlkm.img") 623 case "vendor_ramdisk": 624 if recoveryName := partitions.nameForType("recovery"); recoveryName != "" { 625 fsProps.Include_files_of = []string{recoveryName} 626 } 627 fsProps.Stem = proptools.StringPtr("vendor_ramdisk.img") 628 } 629} 630 631var ( 632 dlkmPartitions = []string{ 633 "system_dlkm", 634 "vendor_dlkm", 635 "odm_dlkm", 636 } 637) 638 639// Creates a soong module to build the given partition. 640func (f *filesystemCreator) createPartition(ctx android.LoadHookContext, partitions allGeneratedPartitionData, partition *generatedPartitionData) { 641 // Nextgen team's handwritten soong system image, don't need to create anything ourselves 642 if partition.partitionType == "system" && ctx.Config().UseSoongSystemImage() { 643 return 644 } 645 646 baseProps := generateBaseProps(proptools.StringPtr(partition.moduleName)) 647 648 fsProps, supported := generateFsProps(ctx, partitions, partition.partitionType) 649 if !supported { 650 partition.supported = false 651 return 652 } 653 654 partitionType := partition.partitionType 655 if partitionType == "vendor" || partitionType == "product" || partitionType == "system" { 656 fsProps.Linker_config.Gen_linker_config = proptools.BoolPtr(true) 657 if partitionType != "system" { 658 fsProps.Linker_config.Linker_config_srcs = f.createLinkerConfigSourceFilegroups(ctx, partitionType) 659 } 660 } 661 662 if android.InList(partitionType, append(dlkmPartitions, "vendor_ramdisk")) { 663 f.createPrebuiltKernelModules(ctx, partitionType) 664 } 665 666 var module android.Module 667 if partitionType == "system" { 668 module = ctx.CreateModule(filesystem.SystemImageFactory, baseProps, fsProps) 669 } else { 670 // Explicitly set the partition. 671 fsProps.Partition_type = proptools.StringPtr(partitionType) 672 module = ctx.CreateModule(filesystem.FilesystemFactory, baseProps, fsProps) 673 } 674 module.HideFromMake() 675 if partitionType == "vendor" { 676 f.createVendorBuildProp(ctx) 677 } 678} 679 680// Creates filegroups for the files specified in BOARD_(partition_)AVB_KEY_PATH 681func (f *filesystemCreator) createAvbKeyFilegroups(ctx android.LoadHookContext) { 682 partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse 683 var files []string 684 685 if len(partitionVars.BoardAvbKeyPath) > 0 { 686 files = append(files, partitionVars.BoardAvbKeyPath) 687 } 688 for _, partition := range android.SortedKeys(partitionVars.PartitionQualifiedVariables) { 689 specificPartitionVars := partitionVars.PartitionQualifiedVariables[partition] 690 if len(specificPartitionVars.BoardAvbKeyPath) > 0 { 691 files = append(files, specificPartitionVars.BoardAvbKeyPath) 692 } 693 } 694 695 fsGenState := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState) 696 for _, file := range files { 697 if _, ok := fsGenState.avbKeyFilegroups[file]; ok { 698 continue 699 } 700 if file == "external/avb/test/data/testkey_rsa4096.pem" { 701 // There already exists a checked-in filegroup for this commonly-used key, just use that 702 fsGenState.avbKeyFilegroups[file] = "avb_testkey_rsa4096" 703 continue 704 } 705 dir := filepath.Dir(file) 706 base := filepath.Base(file) 707 name := fmt.Sprintf("avb_key_%x", strings.ReplaceAll(file, "/", "_")) 708 ctx.CreateModuleInDirectory( 709 android.FileGroupFactory, 710 dir, 711 &struct { 712 Name *string 713 Srcs []string 714 Visibility []string 715 }{ 716 Name: proptools.StringPtr(name), 717 Srcs: []string{base}, 718 Visibility: []string{"//visibility:public"}, 719 }, 720 ) 721 fsGenState.avbKeyFilegroups[file] = name 722 } 723} 724 725// Creates filegroups for miscellaneous other files 726func (f *filesystemCreator) createMiscFilegroups(ctx android.LoadHookContext) { 727 partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse 728 729 if partitionVars.BoardErofsCompressorHints != "" { 730 dir := filepath.Dir(partitionVars.BoardErofsCompressorHints) 731 base := filepath.Base(partitionVars.BoardErofsCompressorHints) 732 ctx.CreateModuleInDirectory( 733 android.FileGroupFactory, 734 dir, 735 &struct { 736 Name *string 737 Srcs []string 738 Visibility []string 739 }{ 740 Name: proptools.StringPtr("soong_generated_board_erofs_compress_hints_filegroup"), 741 Srcs: []string{base}, 742 Visibility: []string{"//visibility:public"}, 743 }, 744 ) 745 } 746} 747 748// createPrebuiltKernelModules creates `prebuilt_kernel_modules`. These modules will be added to deps of the 749// autogenerated *_dlkm filsystem modules. Each _dlkm partition should have a single prebuilt_kernel_modules dependency. 750// This ensures that the depmod artifacts (modules.* installed in /lib/modules/) are generated with a complete view. 751func (f *filesystemCreator) createPrebuiltKernelModules(ctx android.LoadHookContext, partitionType string) { 752 fsGenState := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState) 753 name := generatedModuleName(ctx.Config(), fmt.Sprintf("%s-kernel-modules", partitionType)) 754 props := &struct { 755 Name *string 756 Srcs []string 757 System_deps []string 758 System_dlkm_specific *bool 759 Vendor_dlkm_specific *bool 760 Odm_dlkm_specific *bool 761 Vendor_ramdisk *bool 762 Load_by_default *bool 763 Blocklist_file *string 764 Options_file *string 765 Strip_debug_symbols *bool 766 }{ 767 Name: proptools.StringPtr(name), 768 Strip_debug_symbols: proptools.BoolPtr(false), 769 } 770 switch partitionType { 771 case "system_dlkm": 772 props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelModules).Strings() 773 props.System_dlkm_specific = proptools.BoolPtr(true) 774 if len(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelLoadModules) == 0 { 775 // Create empty modules.load file for system 776 // https://source.corp.google.com/h/googleplex-android/platform/build/+/ef55daac9954896161b26db4f3ef1781b5a5694c:core/Makefile;l=695-700;drc=549fe2a5162548bd8b47867d35f907eb22332023;bpv=1;bpt=0 777 props.Load_by_default = proptools.BoolPtr(false) 778 } 779 if blocklistFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelBlocklistFile; blocklistFile != "" { 780 props.Blocklist_file = proptools.StringPtr(blocklistFile) 781 } 782 case "vendor_dlkm": 783 props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorKernelModules).Strings() 784 if len(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelModules) > 0 { 785 props.System_deps = []string{":" + generatedModuleName(ctx.Config(), "system_dlkm-kernel-modules") + "{.modules}"} 786 } 787 props.Vendor_dlkm_specific = proptools.BoolPtr(true) 788 if blocklistFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorKernelBlocklistFile; blocklistFile != "" { 789 props.Blocklist_file = proptools.StringPtr(blocklistFile) 790 } 791 case "odm_dlkm": 792 props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.OdmKernelModules).Strings() 793 props.Odm_dlkm_specific = proptools.BoolPtr(true) 794 if blocklistFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.OdmKernelBlocklistFile; blocklistFile != "" { 795 props.Blocklist_file = proptools.StringPtr(blocklistFile) 796 } 797 case "vendor_ramdisk": 798 props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorRamdiskKernelModules).Strings() 799 props.Vendor_ramdisk = proptools.BoolPtr(true) 800 if blocklistFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorRamdiskKernelBlocklistFile; blocklistFile != "" { 801 props.Blocklist_file = proptools.StringPtr(blocklistFile) 802 } 803 if optionsFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorRamdiskKernelOptionsFile; optionsFile != "" { 804 props.Options_file = proptools.StringPtr(optionsFile) 805 } 806 807 default: 808 ctx.ModuleErrorf("DLKM is not supported for %s\n", partitionType) 809 } 810 811 if len(props.Srcs) == 0 { 812 return // do not generate `prebuilt_kernel_modules` if there are no sources 813 } 814 815 kernelModule := ctx.CreateModuleInDirectory( 816 kernel.PrebuiltKernelModulesFactory, 817 ".", // create in root directory for now 818 props, 819 ) 820 kernelModule.HideFromMake() 821 // Add to deps 822 (*fsGenState.fsDeps[partitionType])[name] = defaultDepCandidateProps(ctx.Config()) 823} 824 825// Create an android_info module. This will be used to create /vendor/build.prop 826func (f *filesystemCreator) createAndroidInfo(ctx android.LoadHookContext) { 827 // Create a android_info for vendor 828 // The board info files might be in a directory outside the root soong namespace, so create 829 // the module in "." 830 partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse 831 androidInfoProps := &struct { 832 Name *string 833 Board_info_files []string 834 Bootloader_board_name *string 835 Stem *string 836 }{ 837 Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "android_info.prop")), 838 Board_info_files: partitionVars.BoardInfoFiles, 839 Stem: proptools.StringPtr("android-info.txt"), 840 } 841 if len(androidInfoProps.Board_info_files) == 0 { 842 androidInfoProps.Bootloader_board_name = proptools.StringPtr(partitionVars.BootLoaderBoardName) 843 } 844 androidInfoProp := ctx.CreateModuleInDirectory( 845 android.AndroidInfoFactory, 846 ".", 847 androidInfoProps, 848 ) 849 androidInfoProp.HideFromMake() 850} 851 852func (f *filesystemCreator) createVendorBuildProp(ctx android.LoadHookContext) { 853 vendorBuildProps := &struct { 854 Name *string 855 Vendor *bool 856 Stem *string 857 Product_config *string 858 Android_info *string 859 Licenses []string 860 Dist android.Dist 861 }{ 862 Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "vendor-build.prop")), 863 Vendor: proptools.BoolPtr(true), 864 Stem: proptools.StringPtr("build.prop"), 865 Product_config: proptools.StringPtr(":product_config"), 866 Android_info: proptools.StringPtr(":" + generatedModuleName(ctx.Config(), "android_info.prop")), 867 Dist: android.Dist{ 868 Targets: []string{"droidcore-unbundled"}, 869 Dest: proptools.StringPtr("build.prop-vendor"), 870 }, 871 Licenses: []string{"Android-Apache-2.0"}, 872 } 873 vendorBuildProp := ctx.CreateModule( 874 android.BuildPropFactory, 875 vendorBuildProps, 876 ) 877 // We don't want this to conflict with the make-built vendor build.prop, but unfortunately 878 // calling HideFromMake() prevents disting files, even in soong-only mode. So only call 879 // HideFromMake() on soong+make builds. 880 if ctx.Config().KatiEnabled() { 881 vendorBuildProp.HideFromMake() 882 } 883} 884 885func createRecoveryBuildProp(ctx android.LoadHookContext) string { 886 moduleName := generatedModuleName(ctx.Config(), "recovery-prop.default") 887 888 var vendorBuildProp *string 889 if ctx.DeviceConfig().BuildingVendorImage() && ctx.DeviceConfig().VendorPath() == "vendor" { 890 vendorBuildProp = proptools.StringPtr(":" + generatedModuleName(ctx.Config(), "vendor-build.prop")) 891 } 892 893 recoveryBuildProps := &struct { 894 Name *string 895 System_build_prop *string 896 Vendor_build_prop *string 897 Odm_build_prop *string 898 Product_build_prop *string 899 System_ext_build_prop *string 900 901 Recovery *bool 902 No_full_install *bool 903 Visibility []string 904 }{ 905 Name: proptools.StringPtr(moduleName), 906 System_build_prop: proptools.StringPtr(":system-build.prop"), 907 Vendor_build_prop: vendorBuildProp, 908 Odm_build_prop: proptools.StringPtr(":odm-build.prop"), 909 Product_build_prop: proptools.StringPtr(":product-build.prop"), 910 System_ext_build_prop: proptools.StringPtr(":system_ext-build.prop"), 911 912 Recovery: proptools.BoolPtr(true), 913 No_full_install: proptools.BoolPtr(true), 914 Visibility: []string{"//visibility:public"}, 915 } 916 917 ctx.CreateModule(android.RecoveryBuildPropModuleFactory, recoveryBuildProps) 918 919 return moduleName 920} 921 922// createLinkerConfigSourceFilegroups creates filegroup modules to generate linker.config.pb for the following partitions 923// 1. vendor: Using PRODUCT_VENDOR_LINKER_CONFIG_FRAGMENTS (space separated file list) 924// 1. product: Using PRODUCT_PRODUCT_LINKER_CONFIG_FRAGMENTS (space separated file list) 925// It creates a filegroup for each file in the fragment list 926// The filegroup modules are then added to `linker_config_srcs` of the autogenerated vendor `android_filesystem`. 927func (f *filesystemCreator) createLinkerConfigSourceFilegroups(ctx android.LoadHookContext, partitionType string) []string { 928 ret := []string{} 929 partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse 930 var linkerConfigSrcs []string 931 if partitionType == "vendor" { 932 linkerConfigSrcs = android.FirstUniqueStrings(partitionVars.VendorLinkerConfigSrcs) 933 } else if partitionType == "product" { 934 linkerConfigSrcs = android.FirstUniqueStrings(partitionVars.ProductLinkerConfigSrcs) 935 } else { 936 ctx.ModuleErrorf("linker.config.pb is only supported for vendor and product partitions. For system partition, use `android_system_image`") 937 } 938 939 if len(linkerConfigSrcs) > 0 { 940 // Create a filegroup, and add `:<filegroup_name>` to ret. 941 for index, linkerConfigSrc := range linkerConfigSrcs { 942 dir := filepath.Dir(linkerConfigSrc) 943 base := filepath.Base(linkerConfigSrc) 944 fgName := generatedModuleName(ctx.Config(), fmt.Sprintf("%s-linker-config-src%s", partitionType, strconv.Itoa(index))) 945 srcs := []string{base} 946 fgProps := &struct { 947 Name *string 948 Srcs proptools.Configurable[[]string] 949 }{ 950 Name: proptools.StringPtr(fgName), 951 Srcs: proptools.NewSimpleConfigurable(srcs), 952 } 953 ctx.CreateModuleInDirectory( 954 android.FileGroupFactory, 955 dir, 956 fgProps, 957 ) 958 ret = append(ret, ":"+fgName) 959 } 960 } 961 return ret 962} 963 964type filesystemBaseProperty struct { 965 Name *string 966 Compile_multilib *string 967 Visibility []string 968} 969 970func generateBaseProps(namePtr *string) *filesystemBaseProperty { 971 return &filesystemBaseProperty{ 972 Name: namePtr, 973 Compile_multilib: proptools.StringPtr("both"), 974 // The vbmeta modules are currently in the root directory and depend on the partitions 975 Visibility: []string{"//.", "//build/soong:__subpackages__"}, 976 } 977} 978 979func generateFsProps(ctx android.EarlyModuleContext, partitions allGeneratedPartitionData, partitionType string) (*filesystem.FilesystemProperties, bool) { 980 fsProps := &filesystem.FilesystemProperties{} 981 982 partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse 983 var avbInfo avbInfo 984 var fsType string 985 if strings.Contains(partitionType, "ramdisk") { 986 fsType = "compressed_cpio" 987 } else { 988 specificPartitionVars := partitionVars.PartitionQualifiedVariables[partitionType] 989 fsType = specificPartitionVars.BoardFileSystemType 990 avbInfo = getAvbInfo(ctx.Config(), partitionType) 991 if fsType == "" { 992 fsType = "ext4" //default 993 } 994 } 995 996 fsProps.Type = proptools.StringPtr(fsType) 997 if filesystem.GetFsTypeFromString(ctx, *fsProps.Type).IsUnknown() { 998 // Currently the android_filesystem module type only supports a handful of FS types like ext4, erofs 999 return nil, false 1000 } 1001 1002 if *fsProps.Type == "erofs" { 1003 if partitionVars.BoardErofsCompressor != "" { 1004 fsProps.Erofs.Compressor = proptools.StringPtr(partitionVars.BoardErofsCompressor) 1005 } 1006 if partitionVars.BoardErofsCompressorHints != "" { 1007 fsProps.Erofs.Compress_hints = proptools.StringPtr(":soong_generated_board_erofs_compress_hints_filegroup") 1008 } 1009 } 1010 1011 // Don't build this module on checkbuilds, the soong-built partitions are still in-progress 1012 // and sometimes don't build. 1013 fsProps.Unchecked_module = proptools.BoolPtr(true) 1014 1015 // BOARD_AVB_ENABLE 1016 fsProps.Use_avb = avbInfo.avbEnable 1017 // BOARD_AVB_KEY_PATH 1018 fsProps.Avb_private_key = avbInfo.avbkeyFilegroup 1019 // BOARD_AVB_ALGORITHM 1020 fsProps.Avb_algorithm = avbInfo.avbAlgorithm 1021 // BOARD_AVB_SYSTEM_ROLLBACK_INDEX 1022 fsProps.Rollback_index = avbInfo.avbRollbackIndex 1023 // BOARD_AVB_SYSTEM_ROLLBACK_INDEX_LOCATION 1024 fsProps.Rollback_index_location = avbInfo.avbRollbackIndexLocation 1025 fsProps.Avb_hash_algorithm = avbInfo.avbHashAlgorithm 1026 1027 fsProps.Partition_name = proptools.StringPtr(partitionType) 1028 1029 switch partitionType { 1030 // The partitions that support file_contexts came from here: 1031 // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2270;drc=ad7cfb56010cb22c3aa0e70cf71c804352553526 1032 case "system", "userdata", "cache", "vendor", "product", "system_ext", "odm", "vendor_dlkm", "odm_dlkm", "system_dlkm", "oem": 1033 fsProps.Precompiled_file_contexts = proptools.StringPtr(":file_contexts_bin_gen") 1034 } 1035 1036 fsProps.Is_auto_generated = proptools.BoolPtr(true) 1037 if partitionType != "system" { 1038 mountPoint := proptools.StringPtr(partitionType) 1039 // https://cs.android.com/android/platform/superproject/main/+/main:build/make/tools/releasetools/build_image.py;l=1012;drc=3f576a753594bad3fc838ccb8b1b72f7efac1d50 1040 if partitionType == "userdata" { 1041 mountPoint = proptools.StringPtr("data") 1042 } 1043 fsProps.Mount_point = mountPoint 1044 1045 } 1046 1047 partitionSpecificFsProps(ctx, partitions, fsProps, partitionType) 1048 1049 return fsProps, true 1050} 1051 1052type avbInfo struct { 1053 avbEnable *bool 1054 avbKeyPath *string 1055 avbkeyFilegroup *string 1056 avbAlgorithm *string 1057 avbRollbackIndex *int64 1058 avbRollbackIndexLocation *int64 1059 avbMode *string 1060 avbHashAlgorithm *string 1061} 1062 1063func getAvbInfo(config android.Config, partitionType string) avbInfo { 1064 partitionVars := config.ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse 1065 specificPartitionVars := partitionVars.PartitionQualifiedVariables[partitionType] 1066 var result avbInfo 1067 boardAvbEnable := partitionVars.BoardAvbEnable 1068 if boardAvbEnable { 1069 result.avbEnable = proptools.BoolPtr(true) 1070 // There are "global" and "specific" copies of a lot of these variables. Sometimes they 1071 // choose the specific and then fall back to the global one if it's not set, other times 1072 // the global one actually only applies to the vbmeta partition. 1073 if partitionType == "vbmeta" { 1074 if partitionVars.BoardAvbKeyPath != "" { 1075 result.avbKeyPath = proptools.StringPtr(partitionVars.BoardAvbKeyPath) 1076 } 1077 if partitionVars.BoardAvbRollbackIndex != "" { 1078 parsed, err := strconv.ParseInt(partitionVars.BoardAvbRollbackIndex, 10, 64) 1079 if err != nil { 1080 panic(fmt.Sprintf("Rollback index must be an int, got %s", partitionVars.BoardAvbRollbackIndex)) 1081 } 1082 result.avbRollbackIndex = &parsed 1083 } 1084 } 1085 if specificPartitionVars.BoardAvbKeyPath != "" { 1086 result.avbKeyPath = proptools.StringPtr(specificPartitionVars.BoardAvbKeyPath) 1087 } 1088 if specificPartitionVars.BoardAvbAlgorithm != "" { 1089 result.avbAlgorithm = proptools.StringPtr(specificPartitionVars.BoardAvbAlgorithm) 1090 } else if partitionVars.BoardAvbAlgorithm != "" { 1091 result.avbAlgorithm = proptools.StringPtr(partitionVars.BoardAvbAlgorithm) 1092 } 1093 if specificPartitionVars.BoardAvbRollbackIndex != "" { 1094 parsed, err := strconv.ParseInt(specificPartitionVars.BoardAvbRollbackIndex, 10, 64) 1095 if err != nil { 1096 panic(fmt.Sprintf("Rollback index must be an int, got %s", specificPartitionVars.BoardAvbRollbackIndex)) 1097 } 1098 result.avbRollbackIndex = &parsed 1099 } 1100 if specificPartitionVars.BoardAvbRollbackIndexLocation != "" { 1101 parsed, err := strconv.ParseInt(specificPartitionVars.BoardAvbRollbackIndexLocation, 10, 64) 1102 if err != nil { 1103 panic(fmt.Sprintf("Rollback index location must be an int, got %s", specificPartitionVars.BoardAvbRollbackIndexLocation)) 1104 } 1105 result.avbRollbackIndexLocation = &parsed 1106 } 1107 1108 // Make allows you to pass arbitrary arguments to avbtool via this variable, but in practice 1109 // it's only used for --hash_algorithm. The soong module has a dedicated property for the 1110 // hashtree algorithm, and doesn't allow custom arguments, so just extract the hashtree 1111 // algorithm out of the arbitrary arguments. 1112 addHashtreeFooterArgs := strings.Split(specificPartitionVars.BoardAvbAddHashtreeFooterArgs, " ") 1113 if i := slices.Index(addHashtreeFooterArgs, "--hash_algorithm"); i >= 0 { 1114 result.avbHashAlgorithm = &addHashtreeFooterArgs[i+1] 1115 } 1116 1117 result.avbMode = proptools.StringPtr("make_legacy") 1118 } 1119 if result.avbKeyPath != nil { 1120 fsGenState := config.Get(fsGenStateOnceKey).(*FsGenState) 1121 filegroup := fsGenState.avbKeyFilegroups[*result.avbKeyPath] 1122 result.avbkeyFilegroup = proptools.StringPtr(":" + filegroup) 1123 } 1124 return result 1125} 1126 1127func (f *filesystemCreator) createFileListDiffTest(ctx android.ModuleContext, partitionType string, partitionModuleName string) android.Path { 1128 partitionImage := ctx.GetDirectDepWithTag(partitionModuleName, generatedFilesystemDepTag) 1129 filesystemInfo, ok := android.OtherModuleProvider(ctx, partitionImage, filesystem.FilesystemProvider) 1130 if !ok { 1131 ctx.ModuleErrorf("Expected module %s to provide FileysystemInfo", partitionModuleName) 1132 return nil 1133 } 1134 makeFileList := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/obj/PACKAGING/%s_intermediates/file_list.txt", ctx.Config().DeviceName(), partitionType)) 1135 diffTestResultFile := android.PathForModuleOut(ctx, fmt.Sprintf("diff_test_%s.txt", partitionModuleName)) 1136 1137 builder := android.NewRuleBuilder(pctx, ctx) 1138 builder.Command().BuiltTool("file_list_diff"). 1139 Input(makeFileList). 1140 Input(filesystemInfo.FileListFile). 1141 Text(partitionModuleName) 1142 builder.Command().Text("touch").Output(diffTestResultFile) 1143 builder.Build(partitionModuleName+" diff test", partitionModuleName+" diff test") 1144 return diffTestResultFile 1145} 1146 1147func createFailingCommand(ctx android.ModuleContext, message string) android.Path { 1148 hasher := sha256.New() 1149 hasher.Write([]byte(message)) 1150 filename := fmt.Sprintf("failing_command_%x.txt", hasher.Sum(nil)) 1151 file := android.PathForModuleOut(ctx, filename) 1152 builder := android.NewRuleBuilder(pctx, ctx) 1153 builder.Command().Textf("echo %s", proptools.NinjaAndShellEscape(message)) 1154 builder.Command().Text("exit 1 #").Output(file) 1155 builder.Build("failing command "+filename, "failing command "+filename) 1156 return file 1157} 1158 1159func createVbmetaDiff(ctx android.ModuleContext, vbmetaModuleName string, vbmetaPartitionName string) android.Path { 1160 vbmetaModule := ctx.GetDirectDepWithTag(vbmetaModuleName, generatedVbmetaPartitionDepTag) 1161 outputFilesProvider, ok := android.OtherModuleProvider(ctx, vbmetaModule, android.OutputFilesProvider) 1162 if !ok { 1163 ctx.ModuleErrorf("Expected module %s to provide OutputFiles", vbmetaModule) 1164 } 1165 if len(outputFilesProvider.DefaultOutputFiles) != 1 { 1166 ctx.ModuleErrorf("Expected 1 output file from module %s", vbmetaModule) 1167 } 1168 soongVbMetaFile := outputFilesProvider.DefaultOutputFiles[0] 1169 makeVbmetaFile := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/%s.img", ctx.Config().DeviceName(), vbmetaPartitionName)) 1170 1171 diffTestResultFile := android.PathForModuleOut(ctx, fmt.Sprintf("diff_test_%s.txt", vbmetaModuleName)) 1172 createDiffTest(ctx, diffTestResultFile, soongVbMetaFile, makeVbmetaFile) 1173 return diffTestResultFile 1174} 1175 1176func createDiffTest(ctx android.ModuleContext, diffTestResultFile android.WritablePath, file1 android.Path, file2 android.Path) { 1177 builder := android.NewRuleBuilder(pctx, ctx) 1178 builder.Command().Text("diff"). 1179 Input(file1). 1180 Input(file2) 1181 builder.Command().Text("touch").Output(diffTestResultFile) 1182 builder.Build("diff test "+diffTestResultFile.String(), "diff test") 1183} 1184 1185type imageDepTagType struct { 1186 blueprint.BaseDependencyTag 1187} 1188 1189var generatedFilesystemDepTag imageDepTagType 1190var generatedVbmetaPartitionDepTag imageDepTagType 1191 1192func (f *filesystemCreator) DepsMutator(ctx android.BottomUpMutatorContext) { 1193 for _, name := range ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).soongGeneratedPartitions.names() { 1194 ctx.AddDependency(ctx.Module(), generatedFilesystemDepTag, name) 1195 } 1196 for _, vbmetaModule := range f.properties.Vbmeta_module_names { 1197 ctx.AddDependency(ctx.Module(), generatedVbmetaPartitionDepTag, vbmetaModule) 1198 } 1199} 1200 1201func (f *filesystemCreator) GenerateAndroidBuildActions(ctx android.ModuleContext) { 1202 if ctx.ModuleDir() != "build/soong/fsgen" { 1203 ctx.ModuleErrorf("There can only be one soong_filesystem_creator in build/soong/fsgen") 1204 } 1205 f.HideFromMake() 1206 1207 partitions := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).soongGeneratedPartitions 1208 1209 var content strings.Builder 1210 generatedBp := android.PathForModuleOut(ctx, "soong_generated_product_config.bp") 1211 for _, partition := range partitions.types() { 1212 content.WriteString(generateBpContent(ctx, partition)) 1213 content.WriteString("\n") 1214 } 1215 android.WriteFileRule(ctx, generatedBp, content.String()) 1216 1217 ctx.Phony("product_config_to_bp", generatedBp) 1218 1219 if !ctx.Config().KatiEnabled() { 1220 // Cannot diff since the kati packaging rules will not be created. 1221 return 1222 } 1223 var diffTestFiles []android.Path 1224 for _, partitionType := range partitions.types() { 1225 diffTestFile := f.createFileListDiffTest(ctx, partitionType, partitions.nameForType(partitionType)) 1226 diffTestFiles = append(diffTestFiles, diffTestFile) 1227 ctx.Phony(fmt.Sprintf("soong_generated_%s_filesystem_test", partitionType), diffTestFile) 1228 } 1229 for _, partitionType := range slices.Concat(partitions.unsupportedTypes(), f.properties.Unsupported_partition_types) { 1230 diffTestFile := createFailingCommand(ctx, fmt.Sprintf("Couldn't build %s partition", partitionType)) 1231 diffTestFiles = append(diffTestFiles, diffTestFile) 1232 ctx.Phony(fmt.Sprintf("soong_generated_%s_filesystem_test", partitionType), diffTestFile) 1233 } 1234 for i, vbmetaModule := range f.properties.Vbmeta_module_names { 1235 diffTestFile := createVbmetaDiff(ctx, vbmetaModule, f.properties.Vbmeta_partition_names[i]) 1236 diffTestFiles = append(diffTestFiles, diffTestFile) 1237 ctx.Phony(fmt.Sprintf("soong_generated_%s_filesystem_test", f.properties.Vbmeta_partition_names[i]), diffTestFile) 1238 } 1239 if f.properties.Boot_image != "" { 1240 diffTestFile := android.PathForModuleOut(ctx, "boot_diff_test.txt") 1241 soongBootImg := android.PathForModuleSrc(ctx, f.properties.Boot_image) 1242 makeBootImage := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/boot.img", ctx.Config().DeviceName())) 1243 createDiffTest(ctx, diffTestFile, soongBootImg, makeBootImage) 1244 diffTestFiles = append(diffTestFiles, diffTestFile) 1245 ctx.Phony("soong_generated_boot_filesystem_test", diffTestFile) 1246 } 1247 if f.properties.Vendor_boot_image != "" { 1248 diffTestFile := android.PathForModuleOut(ctx, "vendor_boot_diff_test.txt") 1249 soongBootImg := android.PathForModuleSrc(ctx, f.properties.Vendor_boot_image) 1250 makeBootImage := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/vendor_boot.img", ctx.Config().DeviceName())) 1251 createDiffTest(ctx, diffTestFile, soongBootImg, makeBootImage) 1252 diffTestFiles = append(diffTestFiles, diffTestFile) 1253 ctx.Phony("soong_generated_vendor_boot_filesystem_test", diffTestFile) 1254 } 1255 if f.properties.Init_boot_image != "" { 1256 diffTestFile := android.PathForModuleOut(ctx, "init_boot_diff_test.txt") 1257 soongBootImg := android.PathForModuleSrc(ctx, f.properties.Init_boot_image) 1258 makeBootImage := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/init_boot.img", ctx.Config().DeviceName())) 1259 createDiffTest(ctx, diffTestFile, soongBootImg, makeBootImage) 1260 diffTestFiles = append(diffTestFiles, diffTestFile) 1261 ctx.Phony("soong_generated_init_boot_filesystem_test", diffTestFile) 1262 } 1263 if f.properties.Super_image != "" { 1264 diffTestFile := android.PathForModuleOut(ctx, "super_diff_test.txt") 1265 soongSuperImg := android.PathForModuleSrc(ctx, f.properties.Super_image) 1266 makeSuperImage := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/super.img", ctx.Config().DeviceName())) 1267 createDiffTest(ctx, diffTestFile, soongSuperImg, makeSuperImage) 1268 diffTestFiles = append(diffTestFiles, diffTestFile) 1269 ctx.Phony("soong_generated_super_filesystem_test", diffTestFile) 1270 } 1271 ctx.Phony("soong_generated_filesystem_tests", diffTestFiles...) 1272} 1273 1274func generateBpContent(ctx android.EarlyModuleContext, partitionType string) string { 1275 fsGenState := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState) 1276 fsProps, fsTypeSupported := generateFsProps(ctx, fsGenState.soongGeneratedPartitions, partitionType) 1277 if !fsTypeSupported { 1278 return "" 1279 } 1280 1281 baseProps := generateBaseProps(proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), partitionType))) 1282 deps := fsGenState.fsDeps[partitionType] 1283 highPriorityDeps := fsGenState.generatedPrebuiltEtcModuleNames 1284 depProps := generateDepStruct(*deps, highPriorityDeps) 1285 1286 result, err := proptools.RepackProperties([]interface{}{baseProps, fsProps, depProps}) 1287 if err != nil { 1288 ctx.ModuleErrorf("%s", err.Error()) 1289 return "" 1290 } 1291 1292 moduleType := "android_filesystem" 1293 if partitionType == "system" { 1294 moduleType = "android_system_image" 1295 } 1296 1297 file := &parser.File{ 1298 Defs: []parser.Definition{ 1299 &parser.Module{ 1300 Type: moduleType, 1301 Map: *result, 1302 }, 1303 }, 1304 } 1305 bytes, err := parser.Print(file) 1306 if err != nil { 1307 ctx.ModuleErrorf(err.Error()) 1308 } 1309 return strings.TrimSpace(string(bytes)) 1310} 1311