Add super_image module type and create super image module in fsgen
fsgen processes the variables exported from make and create
the super image module. This module generates the misc-info.txt,
which is used by build_super_image.py to build the super image.
Test: CI
Bug: 376726109
Change-Id: I74a3e68d697704f36a770b3c83e5f8821b3ac128
diff --git a/filesystem/super_image.go b/filesystem/super_image.go
new file mode 100644
index 0000000..1583c0b
--- /dev/null
+++ b/filesystem/super_image.go
@@ -0,0 +1,234 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package filesystem
+
+import (
+ "fmt"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "android/soong/android"
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+func init() {
+ android.RegisterModuleType("super_image", SuperImageFactory)
+}
+
+type superImage struct {
+ android.ModuleBase
+
+ properties SuperImageProperties
+ partitionProps SuperImagePartitionNameProperties
+
+ installDir android.InstallPath
+}
+
+type SuperImageProperties struct {
+ // the size of the super partition
+ Size *int64
+ // the block device where metadata for dynamic partitions is stored
+ Metadata_device *string
+ // the super partition block device list
+ Block_devices *string
+ // whether A/B updater is used
+ Ab_update *bool
+ // whether dynamic partitions is enabled on devices that were launched without this support
+ Retrofit *bool
+ // whether virtual A/B seamless update is enabled
+ Virtual_ab *bool
+ // whether retrofitting virtual A/B seamless update is enabled
+ Virtual_ab_retrofit *bool
+ // whether the output is a sparse image
+ Sparse *bool
+ // information about how partitions within the super partition are grouped together
+ Partition_groups []PartitionGroupsInfo
+ // whether dynamic partitions is used
+ Use_dynamic_partitions *bool
+}
+
+type PartitionGroupsInfo struct {
+ Name string
+ GroupSize string
+ PartitionList []string
+}
+
+type SuperImagePartitionNameProperties struct {
+ // Name of the System partition filesystem module
+ System_partition *string
+ // Name of the System_ext partition filesystem module
+ System_ext_partition *string
+ // Name of the System_dlkm partition filesystem module
+ System_dlkm_partition *string
+ // Name of the System_other partition filesystem module
+ System_other_partition *string
+ // Name of the Product partition filesystem module
+ Product_partition *string
+ // Name of the Vendor partition filesystem module
+ Vendor_partition *string
+ // Name of the Vendor_dlkm partition filesystem module
+ Vendor_dlkm_partition *string
+ // Name of the Odm partition filesystem module
+ Odm_partition *string
+ // Name of the Odm_dlkm partition filesystem module
+ Odm_dlkm_partition *string
+}
+
+func SuperImageFactory() android.Module {
+ module := &superImage{}
+ module.AddProperties(&module.properties, &module.partitionProps)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ return module
+}
+
+type superImageDepTagType struct {
+ blueprint.BaseDependencyTag
+}
+
+var superImageDepTag superImageDepTagType
+
+func (s *superImage) DepsMutator(ctx android.BottomUpMutatorContext) {
+ addDependencyIfDefined := func(dep *string) {
+ if dep != nil {
+ ctx.AddDependency(ctx.Module(), superImageDepTag, proptools.String(dep))
+ }
+ }
+
+ addDependencyIfDefined(s.partitionProps.System_partition)
+ addDependencyIfDefined(s.partitionProps.System_ext_partition)
+ addDependencyIfDefined(s.partitionProps.System_dlkm_partition)
+ addDependencyIfDefined(s.partitionProps.System_other_partition)
+ addDependencyIfDefined(s.partitionProps.Product_partition)
+ addDependencyIfDefined(s.partitionProps.Vendor_partition)
+ addDependencyIfDefined(s.partitionProps.Vendor_dlkm_partition)
+ addDependencyIfDefined(s.partitionProps.Odm_partition)
+ addDependencyIfDefined(s.partitionProps.Odm_dlkm_partition)
+}
+
+func (s *superImage) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ miscInfo, deps := s.buildMiscInfo(ctx)
+ builder := android.NewRuleBuilder(pctx, ctx)
+ output := android.PathForModuleOut(ctx, s.installFileName())
+ lpMake := ctx.Config().HostToolPath(ctx, "lpmake")
+ lpMakeDir := filepath.Dir(lpMake.String())
+ deps = append(deps, lpMake)
+ builder.Command().Textf("PATH=%s:\\$PATH", lpMakeDir).
+ BuiltTool("build_super_image").
+ Text("-v").
+ Input(miscInfo).
+ Implicits(deps).
+ Output(output)
+ builder.Build("build_super_image", fmt.Sprintf("Creating super image %s", s.BaseModuleName()))
+ ctx.SetOutputFiles([]android.Path{output}, "")
+}
+
+func (s *superImage) installFileName() string {
+ return s.BaseModuleName() + ".img"
+}
+
+func (s *superImage) buildMiscInfo(ctx android.ModuleContext) (android.Path, android.Paths) {
+ var miscInfoString strings.Builder
+ addStr := func(name string, value string) {
+ miscInfoString.WriteString(name)
+ miscInfoString.WriteRune('=')
+ miscInfoString.WriteString(value)
+ miscInfoString.WriteRune('\n')
+ }
+
+ addStr("use_dynamic_partitions", strconv.FormatBool(proptools.Bool(s.properties.Use_dynamic_partitions)))
+ addStr("dynamic_partition_retrofit", strconv.FormatBool(proptools.Bool(s.properties.Retrofit)))
+ addStr("lpmake", "lpmake")
+ addStr("super_metadata_device", proptools.String(s.properties.Metadata_device))
+ addStr("super_block_devices", proptools.String(s.properties.Block_devices))
+ addStr("super_super_device_size", strconv.Itoa(proptools.Int(s.properties.Size)))
+ var groups, partitionList []string
+ for _, groupInfo := range s.properties.Partition_groups {
+ groups = append(groups, groupInfo.Name)
+ partitionList = append(partitionList, groupInfo.PartitionList...)
+ addStr("super_"+groupInfo.Name+"_group_size", groupInfo.GroupSize)
+ addStr("super_"+groupInfo.Name+"_partition_list", strings.Join(groupInfo.PartitionList, " "))
+ }
+ addStr("super_partition_groups", strings.Join(groups, " "))
+ addStr("dynamic_partition_list", strings.Join(partitionList, " "))
+
+ addStr("virtual_ab", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab)))
+ addStr("virtual_ab_retrofit", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab_retrofit)))
+ addStr("ab_update", strconv.FormatBool(proptools.Bool(s.properties.Ab_update)))
+ addStr("build_non_sparse_super_partition", strconv.FormatBool(!proptools.Bool(s.properties.Sparse)))
+
+ partitionToImagePath := make(map[string]string)
+ nameToPartition := make(map[string]string)
+ var systemOtherPartitionNameNeeded string
+ addEntryToPartitionToName := func(p string, s *string) {
+ if proptools.String(s) != "" {
+ nameToPartition[*s] = p
+ }
+ }
+
+ // Build partitionToImagePath, because system partition may need system_other
+ // partition image path
+ for _, p := range partitionList {
+ if _, ok := nameToPartition[p]; ok {
+ continue
+ }
+ switch p {
+ case "system":
+ addEntryToPartitionToName(p, s.partitionProps.System_partition)
+ systemOtherPartitionNameNeeded = proptools.String(s.partitionProps.System_other_partition)
+ case "system_dlkm":
+ addEntryToPartitionToName(p, s.partitionProps.System_dlkm_partition)
+ case "system_ext":
+ addEntryToPartitionToName(p, s.partitionProps.System_ext_partition)
+ case "product":
+ addEntryToPartitionToName(p, s.partitionProps.Product_partition)
+ case "vendor":
+ addEntryToPartitionToName(p, s.partitionProps.Vendor_partition)
+ case "vendor_dlkm":
+ addEntryToPartitionToName(p, s.partitionProps.Vendor_dlkm_partition)
+ case "odm":
+ addEntryToPartitionToName(p, s.partitionProps.Odm_partition)
+ case "odm_dlkm":
+ addEntryToPartitionToName(p, s.partitionProps.Odm_dlkm_partition)
+ default:
+ ctx.ModuleErrorf("current partition %s not a super image supported partition", p)
+ }
+ }
+
+ var deps android.Paths
+ ctx.VisitDirectDeps(func(m android.Module) {
+ if p, ok := nameToPartition[m.Name()]; ok {
+ if output, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider); ok {
+ partitionToImagePath[p] = output.DefaultOutputFiles[0].String()
+ deps = append(deps, output.DefaultOutputFiles[0])
+ }
+ } else if systemOtherPartitionNameNeeded != "" && m.Name() == systemOtherPartitionNameNeeded {
+ if output, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider); ok {
+ partitionToImagePath["system_other"] = output.DefaultOutputFiles[0].String()
+ // TODO: add system_other to deps after it can be generated
+ // deps = append(deps, output.DefaultOutputFiles[0])
+ }
+ }
+ })
+
+ for _, p := range android.SortedKeys(partitionToImagePath) {
+ addStr(p+"_image", partitionToImagePath[p])
+ }
+
+ miscInfo := android.PathForModuleOut(ctx, "misc_info.txt")
+ android.WriteFileRule(ctx, miscInfo, miscInfoString.String())
+ return miscInfo, deps
+}