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 "fmt" 19 "path/filepath" 20 "strconv" 21 "strings" 22 23 "android/soong/android" 24 "github.com/google/blueprint" 25 "github.com/google/blueprint/proptools" 26) 27 28func init() { 29 android.RegisterModuleType("super_image", SuperImageFactory) 30} 31 32type superImage struct { 33 android.ModuleBase 34 35 properties SuperImageProperties 36 partitionProps SuperImagePartitionNameProperties 37 38 installDir android.InstallPath 39} 40 41type SuperImageProperties struct { 42 // the size of the super partition 43 Size *int64 44 // the block device where metadata for dynamic partitions is stored 45 Metadata_device *string 46 // the super partition block device list 47 Block_devices []string 48 // whether A/B updater is used 49 Ab_update *bool 50 // whether dynamic partitions is enabled on devices that were launched without this support 51 Retrofit *bool 52 // whether virtual A/B seamless update is enabled 53 Virtual_ab *bool 54 // whether retrofitting virtual A/B seamless update is enabled 55 Virtual_ab_retrofit *bool 56 // whether the output is a sparse image 57 Sparse *bool 58 // information about how partitions within the super partition are grouped together 59 Partition_groups []PartitionGroupsInfo 60 // whether dynamic partitions is used 61 Use_dynamic_partitions *bool 62} 63 64type PartitionGroupsInfo struct { 65 Name string 66 GroupSize string 67 PartitionList []string 68} 69 70type SuperImagePartitionNameProperties struct { 71 // Name of the System partition filesystem module 72 System_partition *string 73 // Name of the System_ext partition filesystem module 74 System_ext_partition *string 75 // Name of the System_dlkm partition filesystem module 76 System_dlkm_partition *string 77 // Name of the System_other partition filesystem module 78 System_other_partition *string 79 // Name of the Product partition filesystem module 80 Product_partition *string 81 // Name of the Vendor partition filesystem module 82 Vendor_partition *string 83 // Name of the Vendor_dlkm partition filesystem module 84 Vendor_dlkm_partition *string 85 // Name of the Odm partition filesystem module 86 Odm_partition *string 87 // Name of the Odm_dlkm partition filesystem module 88 Odm_dlkm_partition *string 89} 90 91func SuperImageFactory() android.Module { 92 module := &superImage{} 93 module.AddProperties(&module.properties, &module.partitionProps) 94 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) 95 return module 96} 97 98type superImageDepTagType struct { 99 blueprint.BaseDependencyTag 100} 101 102var superImageDepTag superImageDepTagType 103 104func (s *superImage) DepsMutator(ctx android.BottomUpMutatorContext) { 105 addDependencyIfDefined := func(dep *string) { 106 if dep != nil { 107 ctx.AddDependency(ctx.Module(), superImageDepTag, proptools.String(dep)) 108 } 109 } 110 111 addDependencyIfDefined(s.partitionProps.System_partition) 112 addDependencyIfDefined(s.partitionProps.System_ext_partition) 113 addDependencyIfDefined(s.partitionProps.System_dlkm_partition) 114 addDependencyIfDefined(s.partitionProps.System_other_partition) 115 addDependencyIfDefined(s.partitionProps.Product_partition) 116 addDependencyIfDefined(s.partitionProps.Vendor_partition) 117 addDependencyIfDefined(s.partitionProps.Vendor_dlkm_partition) 118 addDependencyIfDefined(s.partitionProps.Odm_partition) 119 addDependencyIfDefined(s.partitionProps.Odm_dlkm_partition) 120} 121 122func (s *superImage) GenerateAndroidBuildActions(ctx android.ModuleContext) { 123 miscInfo, deps := s.buildMiscInfo(ctx) 124 builder := android.NewRuleBuilder(pctx, ctx) 125 output := android.PathForModuleOut(ctx, s.installFileName()) 126 lpMake := ctx.Config().HostToolPath(ctx, "lpmake") 127 lpMakeDir := filepath.Dir(lpMake.String()) 128 deps = append(deps, lpMake) 129 builder.Command().Textf("PATH=%s:\\$PATH", lpMakeDir). 130 BuiltTool("build_super_image"). 131 Text("-v"). 132 Input(miscInfo). 133 Implicits(deps). 134 Output(output) 135 builder.Build("build_super_image", fmt.Sprintf("Creating super image %s", s.BaseModuleName())) 136 ctx.SetOutputFiles([]android.Path{output}, "") 137} 138 139func (s *superImage) installFileName() string { 140 return s.BaseModuleName() + ".img" 141} 142 143func (s *superImage) buildMiscInfo(ctx android.ModuleContext) (android.Path, android.Paths) { 144 var miscInfoString strings.Builder 145 addStr := func(name string, value string) { 146 miscInfoString.WriteString(name) 147 miscInfoString.WriteRune('=') 148 miscInfoString.WriteString(value) 149 miscInfoString.WriteRune('\n') 150 } 151 152 addStr("use_dynamic_partitions", strconv.FormatBool(proptools.Bool(s.properties.Use_dynamic_partitions))) 153 addStr("dynamic_partition_retrofit", strconv.FormatBool(proptools.Bool(s.properties.Retrofit))) 154 addStr("lpmake", "lpmake") 155 addStr("super_metadata_device", proptools.String(s.properties.Metadata_device)) 156 if len(s.properties.Block_devices) > 0 { 157 addStr("super_block_devices", strings.Join(s.properties.Block_devices, " ")) 158 } 159 addStr("super_super_device_size", strconv.Itoa(proptools.Int(s.properties.Size))) 160 var groups, partitionList []string 161 for _, groupInfo := range s.properties.Partition_groups { 162 groups = append(groups, groupInfo.Name) 163 partitionList = append(partitionList, groupInfo.PartitionList...) 164 addStr("super_"+groupInfo.Name+"_group_size", groupInfo.GroupSize) 165 addStr("super_"+groupInfo.Name+"_partition_list", strings.Join(groupInfo.PartitionList, " ")) 166 } 167 addStr("super_partition_groups", strings.Join(groups, " ")) 168 addStr("dynamic_partition_list", strings.Join(partitionList, " ")) 169 170 addStr("virtual_ab", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab))) 171 addStr("virtual_ab_retrofit", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab_retrofit))) 172 addStr("ab_update", strconv.FormatBool(proptools.Bool(s.properties.Ab_update))) 173 addStr("build_non_sparse_super_partition", strconv.FormatBool(!proptools.Bool(s.properties.Sparse))) 174 175 partitionToImagePath := make(map[string]string) 176 nameToPartition := make(map[string]string) 177 var systemOtherPartitionNameNeeded string 178 addEntryToPartitionToName := func(p string, s *string) { 179 if proptools.String(s) != "" { 180 nameToPartition[*s] = p 181 } 182 } 183 184 // Build partitionToImagePath, because system partition may need system_other 185 // partition image path 186 for _, p := range partitionList { 187 if _, ok := nameToPartition[p]; ok { 188 continue 189 } 190 switch p { 191 case "system": 192 addEntryToPartitionToName(p, s.partitionProps.System_partition) 193 systemOtherPartitionNameNeeded = proptools.String(s.partitionProps.System_other_partition) 194 case "system_dlkm": 195 addEntryToPartitionToName(p, s.partitionProps.System_dlkm_partition) 196 case "system_ext": 197 addEntryToPartitionToName(p, s.partitionProps.System_ext_partition) 198 case "product": 199 addEntryToPartitionToName(p, s.partitionProps.Product_partition) 200 case "vendor": 201 addEntryToPartitionToName(p, s.partitionProps.Vendor_partition) 202 case "vendor_dlkm": 203 addEntryToPartitionToName(p, s.partitionProps.Vendor_dlkm_partition) 204 case "odm": 205 addEntryToPartitionToName(p, s.partitionProps.Odm_partition) 206 case "odm_dlkm": 207 addEntryToPartitionToName(p, s.partitionProps.Odm_dlkm_partition) 208 default: 209 ctx.ModuleErrorf("current partition %s not a super image supported partition", p) 210 } 211 } 212 213 var deps android.Paths 214 ctx.VisitDirectDeps(func(m android.Module) { 215 if p, ok := nameToPartition[m.Name()]; ok { 216 if output, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider); ok { 217 partitionToImagePath[p] = output.DefaultOutputFiles[0].String() 218 deps = append(deps, output.DefaultOutputFiles[0]) 219 } 220 } else if systemOtherPartitionNameNeeded != "" && m.Name() == systemOtherPartitionNameNeeded { 221 if output, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider); ok { 222 partitionToImagePath["system_other"] = output.DefaultOutputFiles[0].String() 223 // TODO: add system_other to deps after it can be generated 224 // deps = append(deps, output.DefaultOutputFiles[0]) 225 } 226 } 227 }) 228 229 for _, p := range android.SortedKeys(partitionToImagePath) { 230 addStr(p+"_image", partitionToImagePath[p]) 231 } 232 233 miscInfo := android.PathForModuleOut(ctx, "misc_info.txt") 234 android.WriteFileRule(ctx, miscInfo, miscInfoString.String()) 235 return miscInfo, deps 236} 237