summaryrefslogtreecommitdiff
path: root/filesystem
diff options
context:
space:
mode:
Diffstat (limited to 'filesystem')
-rw-r--r--filesystem/bootimg.go181
-rw-r--r--filesystem/filesystem.go45
-rw-r--r--filesystem/filesystem_test.go33
3 files changed, 232 insertions, 27 deletions
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index c9bd61788..90409b318 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -26,19 +26,21 @@ import (
)
func init() {
- android.RegisterModuleType("bootimg", bootimgFactory)
+ android.RegisterModuleType("bootimg", BootimgFactory)
}
type bootimg struct {
android.ModuleBase
- properties bootimgProperties
+ properties BootimgProperties
output android.Path
installDir android.InstallPath
+
+ bootImageType bootImageType
}
-type bootimgProperties struct {
+type BootimgProperties struct {
// Set the name of the output. Defaults to <module_name>.img.
Stem *string
@@ -56,9 +58,13 @@ type bootimgProperties struct {
// https://source.android.com/devices/bootloader/boot-image-header
Header_version *string
- // Determines if this image is for the vendor_boot partition. Default is false. Refer to
- // https://source.android.com/devices/bootloader/partitions/vendor-boot-partitions
- Vendor_boot *bool
+ // Determines the specific type of boot image this module is building. Can be boot,
+ // vendor_boot or init_boot. Defaults to boot.
+ // Refer to https://source.android.com/devices/bootloader/partitions/vendor-boot-partitions
+ // for vendor_boot.
+ // Refer to https://source.android.com/docs/core/architecture/partitions/generic-boot for
+ // init_boot.
+ Boot_image_type *string
// Optional kernel commandline arguments
Cmdline []string `android:"arch_variant"`
@@ -67,6 +73,10 @@ type bootimgProperties struct {
// and `header_version` is greater than or equal to 4.
Bootconfig *string `android:"arch_variant,path"`
+ // The size of the partition on the device. It will be a build error if this built partition
+ // image exceeds this size.
+ Partition_size *int64
+
// When set to true, sign the image with avbtool. Default is false.
Use_avb *bool
@@ -79,10 +89,62 @@ type bootimgProperties struct {
// Hash and signing algorithm for avbtool. Default is SHA256_RSA4096.
Avb_algorithm *string
+
+ // The security patch passed to as the com.android.build.<type>.security_patch avb property.
+ // Replacement for the make variables BOOT_SECURITY_PATCH / INIT_BOOT_SECURITY_PATCH.
+ Security_patch *string
+}
+
+type bootImageType int
+
+const (
+ unsupported bootImageType = iota
+ boot
+ vendorBoot
+ initBoot
+)
+
+func toBootImageType(ctx android.ModuleContext, bootImageType string) bootImageType {
+ switch bootImageType {
+ case "boot":
+ return boot
+ case "vendor_boot":
+ return vendorBoot
+ case "init_boot":
+ return initBoot
+ default:
+ ctx.ModuleErrorf("Unknown boot_image_type %s. Must be one of \"boot\", \"vendor_boot\", or \"init_boot\"", bootImageType)
+ }
+ return unsupported
+}
+
+func (b bootImageType) String() string {
+ switch b {
+ case boot:
+ return "boot"
+ case vendorBoot:
+ return "vendor_boot"
+ case initBoot:
+ return "init_boot"
+ default:
+ panic("unknown boot image type")
+ }
+}
+
+func (b bootImageType) isBoot() bool {
+ return b == boot
+}
+
+func (b bootImageType) isVendorBoot() bool {
+ return b == vendorBoot
+}
+
+func (b bootImageType) isInitBoot() bool {
+ return b == initBoot
}
// bootimg is the image for the boot partition. It consists of header, kernel, ramdisk, and dtb.
-func bootimgFactory() android.Module {
+func BootimgFactory() android.Module {
module := &bootimg{}
module.AddProperties(&module.properties)
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
@@ -112,12 +174,40 @@ func (b *bootimg) partitionName() string {
}
func (b *bootimg) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- vendor := proptools.Bool(b.properties.Vendor_boot)
- unsignedOutput := b.buildBootImage(ctx, vendor)
+ b.bootImageType = toBootImageType(ctx, proptools.StringDefault(b.properties.Boot_image_type, "boot"))
+ if b.bootImageType == unsupported {
+ return
+ }
+
+ kernelProp := proptools.String(b.properties.Kernel_prebuilt)
+ if b.bootImageType.isVendorBoot() && kernelProp != "" {
+ ctx.PropertyErrorf("kernel_prebuilt", "vendor_boot partition can't have kernel")
+ return
+ }
+ if b.bootImageType.isBoot() && kernelProp == "" {
+ ctx.PropertyErrorf("kernel_prebuilt", "boot partition must have kernel")
+ return
+ }
+ var kernel android.Path
+ if kernelProp != "" {
+ kernel = android.PathForModuleSrc(ctx, kernelProp)
+ }
+
+ unsignedOutput := b.buildBootImage(ctx, kernel)
output := unsignedOutput
if proptools.Bool(b.properties.Use_avb) {
- output = b.signImage(ctx, unsignedOutput)
+ // This bootimg module supports 2 modes of avb signing, it picks between them based on
+ // if the private key is specified or not. If there is a key, it does a signing process
+ // similar to how the regular partitions (system, product, vendor, etc) are signed.
+ // If the key is not provided, it will just add an avb footer to the image. The avb
+ // footer only signing is how the make-built init_boot, boot, and vendor_boot images are
+ // built.
+ if proptools.String(b.properties.Avb_private_key) != "" {
+ output = b.signImage(ctx, unsignedOutput)
+ } else {
+ output = b.addAvbFooter(ctx, unsignedOutput, kernel)
+ }
}
b.installDir = android.PathForModuleInstall(ctx, "etc")
@@ -127,23 +217,20 @@ func (b *bootimg) GenerateAndroidBuildActions(ctx android.ModuleContext) {
b.output = output
}
-func (b *bootimg) buildBootImage(ctx android.ModuleContext, vendor bool) android.Path {
+func (b *bootimg) buildBootImage(ctx android.ModuleContext, kernel android.Path) android.Path {
output := android.PathForModuleOut(ctx, "unsigned", b.installFileName())
builder := android.NewRuleBuilder(pctx, ctx)
cmd := builder.Command().BuiltTool("mkbootimg")
- kernel := proptools.String(b.properties.Kernel_prebuilt)
- if vendor && kernel != "" {
- ctx.PropertyErrorf("kernel_prebuilt", "vendor_boot partition can't have kernel")
- return output
- }
- if !vendor && kernel == "" {
- ctx.PropertyErrorf("kernel_prebuilt", "boot partition must have kernel")
- return output
+ if kernel != nil {
+ cmd.FlagWithInput("--kernel ", kernel)
}
- if kernel != "" {
- cmd.FlagWithInput("--kernel ", android.PathForModuleSrc(ctx, kernel))
+
+ // These arguments are passed for boot.img and init_boot.img generation
+ if b.bootImageType.isBoot() || b.bootImageType.isInitBoot() {
+ cmd.FlagWithArg("--os_version ", ctx.Config().PlatformVersionLastStable())
+ cmd.FlagWithArg("--os_patch_level ", ctx.Config().PlatformSecurityPatch())
}
dtbName := proptools.String(b.properties.Dtb_prebuilt)
@@ -155,7 +242,7 @@ func (b *bootimg) buildBootImage(ctx android.ModuleContext, vendor bool) android
cmdline := strings.Join(b.properties.Cmdline, " ")
if cmdline != "" {
flag := "--cmdline "
- if vendor {
+ if b.bootImageType.isVendorBoot() {
flag = "--vendor_cmdline "
}
cmd.FlagWithArg(flag, proptools.ShellEscapeIncludingSpaces(cmdline))
@@ -182,7 +269,7 @@ func (b *bootimg) buildBootImage(ctx android.ModuleContext, vendor bool) android
ramdisk := ctx.GetDirectDepWithTag(ramdiskName, bootimgRamdiskDep)
if filesystem, ok := ramdisk.(*filesystem); ok {
flag := "--ramdisk "
- if vendor {
+ if b.bootImageType.isVendorBoot() {
flag = "--vendor_ramdisk "
}
cmd.FlagWithInput(flag, filesystem.OutputPath())
@@ -194,7 +281,7 @@ func (b *bootimg) buildBootImage(ctx android.ModuleContext, vendor bool) android
bootconfig := proptools.String(b.properties.Bootconfig)
if bootconfig != "" {
- if !vendor {
+ if !b.bootImageType.isVendorBoot() {
ctx.PropertyErrorf("bootconfig", "requires vendor_boot: true")
return output
}
@@ -205,16 +292,60 @@ func (b *bootimg) buildBootImage(ctx android.ModuleContext, vendor bool) android
cmd.FlagWithInput("--vendor_bootconfig ", android.PathForModuleSrc(ctx, bootconfig))
}
+ // Output flag for boot.img and init_boot.img
flag := "--output "
- if vendor {
+ if b.bootImageType.isVendorBoot() {
flag = "--vendor_boot "
}
cmd.FlagWithOutput(flag, output)
+ if b.properties.Partition_size != nil {
+ assertMaxImageSize(builder, output, *b.properties.Partition_size, proptools.Bool(b.properties.Use_avb))
+ }
+
builder.Build("build_bootimg", fmt.Sprintf("Creating %s", b.BaseModuleName()))
return output
}
+func (b *bootimg) addAvbFooter(ctx android.ModuleContext, unsignedImage android.Path, kernel android.Path) android.Path {
+ output := android.PathForModuleOut(ctx, b.installFileName())
+ builder := android.NewRuleBuilder(pctx, ctx)
+ builder.Command().Text("cp").Input(unsignedImage).Output(output)
+ cmd := builder.Command().BuiltTool("avbtool").
+ Text("add_hash_footer").
+ FlagWithInput("--image ", output)
+
+ if b.properties.Partition_size != nil {
+ cmd.FlagWithArg("--partition_size ", strconv.FormatInt(*b.properties.Partition_size, 10))
+ } else {
+ cmd.Flag("--dynamic_partition_size")
+ }
+
+ if kernel != nil {
+ cmd.Textf(`--salt $(sha256sum "%s" | cut -d " " -f 1)`, kernel.String())
+ cmd.Implicit(kernel)
+ }
+
+ cmd.FlagWithArg("--partition_name ", b.bootImageType.String())
+
+ if !b.bootImageType.isVendorBoot() {
+ cmd.FlagWithArg("--prop ", proptools.NinjaAndShellEscape(fmt.Sprintf(
+ "com.android.build.%s.os_version:%s", b.bootImageType.String(), ctx.Config().PlatformVersionLastStable())))
+ }
+
+ fingerprintFile := ctx.Config().BuildFingerprintFile(ctx)
+ cmd.FlagWithArg("--prop ", fmt.Sprintf("com.android.build.%s.fingerprint:%s", b.bootImageType.String(), fingerprintFile.String()))
+ cmd.OrderOnly(fingerprintFile)
+
+ if b.properties.Security_patch != nil {
+ cmd.FlagWithArg("--prop ", proptools.NinjaAndShellEscape(fmt.Sprintf(
+ "com.android.build.%s.security_patch:%s", b.bootImageType.String(), *b.properties.Security_patch)))
+ }
+
+ builder.Build("add_avb_footer", fmt.Sprintf("Adding avb footer to %s", b.BaseModuleName()))
+ return output
+}
+
func (b *bootimg) signImage(ctx android.ModuleContext, unsignedImage android.Path) android.Path {
propFile, toolDeps := b.buildPropFile(ctx)
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index c34677060..dadacae3d 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -162,6 +162,10 @@ type FilesystemProperties struct {
// Determines if the module is auto-generated from Soong or not. If the module is
// auto-generated, its deps are exempted from visibility enforcement.
Is_auto_generated *bool
+
+ // Path to the dev nodes description file. This is only needed for building the ramdisk
+ // partition and should not be explicitly specified.
+ Dev_nodes_description_file *string `android:"path" blueprint:"mutated"`
}
// Additional properties required to generate erofs FS partitions.
@@ -210,6 +214,10 @@ func initFilesystemModule(module android.DefaultableModule, filesystemModule *fi
filesystemModule.PackagingBase.AllowHighPriorityDeps = true
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
+
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ filesystemModule.setDevNodesDescriptionProp()
+ })
}
type depTag struct {
@@ -229,6 +237,16 @@ func (t depTagWithVisibilityEnforcementBypass) ExcludeFromVisibilityEnforcement(
var dependencyTagWithVisibilityEnforcementBypass = depTagWithVisibilityEnforcementBypass{}
+// ramdiskDevNodesDescription is the name of the filegroup module that provides the file that
+// contains the description of dev nodes added to the CPIO archive for the ramdisk partition.
+const ramdiskDevNodesDescription = "ramdisk_node_list"
+
+func (f *filesystem) setDevNodesDescriptionProp() {
+ if proptools.String(f.properties.Partition_name) == "ramdisk" {
+ f.properties.Dev_nodes_description_file = proptools.StringPtr(":" + ramdiskDevNodesDescription)
+ }
+}
+
func (f *filesystem) DepsMutator(ctx android.BottomUpMutatorContext) {
if proptools.Bool(f.properties.Is_auto_generated) {
f.AddDeps(ctx, dependencyTagWithVisibilityEnforcementBypass)
@@ -659,6 +677,9 @@ func (f *filesystem) buildCpioImage(ctx android.ModuleContext, compressed bool)
cmd := builder.Command().
BuiltTool("mkbootfs").
Text(rootDir.String()) // input directory
+ if nodeList := f.properties.Dev_nodes_description_file; nodeList != nil {
+ cmd.FlagWithInput("-n ", android.PathForModuleSrc(ctx, proptools.String(nodeList)))
+ }
if compressed {
cmd.Text("|").
BuiltTool("lz4").
@@ -689,6 +710,7 @@ var validPartitions = []string{
"odm_dlkm",
"system_dlkm",
"ramdisk",
+ "vendor_ramdisk",
}
func (f *filesystem) addMakeBuiltFiles(ctx android.ModuleContext, builder *android.RuleBuilder, rootDir android.Path) {
@@ -904,3 +926,26 @@ func (f *filesystem) getLibsForLinkerConfig(ctx android.ModuleContext) ([]androi
return provideModules, requireModules
}
+
+// Checks that the given file doesn't exceed the given size, and will also print a warning
+// if it's nearing the maximum size. Equivalent to assert-max-image-size in make:
+// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/definitions.mk;l=3455;drc=993c4de29a02a6accd60ceaaee153307e1a18d10
+func assertMaxImageSize(builder *android.RuleBuilder, image android.Path, maxSize int64, addAvbLater bool) {
+ if addAvbLater {
+ // The value 69632 is derived from MAX_VBMETA_SIZE + MAX_FOOTER_SIZE in avbtool.
+ // Logic copied from make:
+ // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=228;drc=a6a0007ef24e16c0b79f439beac4a118416717e6
+ maxSize -= 69632
+ }
+ cmd := builder.Command()
+ cmd.Textf(`file="%s"; maxsize="%d";`+
+ `total=$(stat -c "%%s" "$file" | tr -d '\n');`+
+ `if [ "$total" -gt "$maxsize" ]; then `+
+ ` echo "error: $file too large ($total > $maxsize)";`+
+ ` false;`+
+ `elif [ "$total" -gt $((maxsize - 32768)) ]; then `+
+ ` echo "WARNING: $file approaching size limit ($total now; limit $maxsize)";`+
+ `fi`,
+ image, maxSize)
+ cmd.Implicit(image)
+}
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index f325d96ef..746e4de74 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -666,7 +666,9 @@ func TestUseSharedVariationOfNativeLib(t *testing.T) {
partition := result.ModuleForTests("myfilesystem", "android_common")
fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList"))
- android.AssertDeepEquals(t, "cc_library listed in deps", "lib64/libc++.so\nlib64/libc.so\nlib64/libdl.so\nlib64/libfoo.so\nlib64/libm.so\n", fileList)
+ android.AssertDeepEquals(t, "cc_library listed in deps",
+ "lib64/bootstrap/libc.so\nlib64/bootstrap/libdl.so\nlib64/bootstrap/libm.so\nlib64/libc++.so\nlib64/libc.so\nlib64/libdl.so\nlib64/libfoo.so\nlib64/libm.so\n",
+ fileList)
}
// binfoo1 overrides binbar. transitive deps of binbar should not be installed.
@@ -701,7 +703,9 @@ cc_library {
partition := result.ModuleForTests("myfilesystem", "android_common")
fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList"))
- android.AssertDeepEquals(t, "Shared library dep of overridden binary should not be installed", fileList, "bin/binfoo1\nlib64/libc++.so\nlib64/libc.so\nlib64/libdl.so\nlib64/libfoo2.so\nlib64/libm.so\n")
+ android.AssertDeepEquals(t, "Shared library dep of overridden binary should not be installed",
+ "bin/binfoo1\nlib64/bootstrap/libc.so\nlib64/bootstrap/libdl.so\nlib64/bootstrap/libm.so\nlib64/libc++.so\nlib64/libc.so\nlib64/libdl.so\nlib64/libfoo2.so\nlib64/libm.so\n",
+ fileList)
}
func TestInstallLinkerConfigFile(t *testing.T) {
@@ -754,3 +758,28 @@ func TestOverrideModulesInDeps(t *testing.T) {
fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList"))
android.AssertStringEquals(t, "filesystem with override app", "app/myoverrideapp/myoverrideapp.apk\n", fileList)
}
+
+func TestRamdiskPartitionSetsDevNodes(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ fixture,
+ android.FixtureMergeMockFs(android.MockFS{
+ "ramdisk_node_list": nil,
+ }),
+ ).RunTestWithBp(t, `
+ android_filesystem {
+ name: "ramdisk_filesystem",
+ partition_name: "ramdisk",
+ }
+ filegroup {
+ name: "ramdisk_node_list",
+ srcs: ["ramdisk_node_list"],
+ }
+ `)
+
+ android.AssertBoolEquals(
+ t,
+ "Generated ramdisk image expected to depend on \"ramdisk_node_list\" module",
+ true,
+ java.CheckModuleHasDependency(t, result.TestContext, "ramdisk_filesystem", "android_common", "ramdisk_node_list"),
+ )
+}