// 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)) if len(s.properties.Block_devices) > 0 { addStr("super_block_devices", strings.Join(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 }