| mrziwang | 79730d4 | 2024-12-02 22:13:59 -0800 | [diff] [blame] | 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 |  | 
|  | 15 | package filesystem | 
|  | 16 |  | 
|  | 17 | import ( | 
|  | 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 |  | 
|  | 28 | func init() { | 
|  | 29 | android.RegisterModuleType("super_image", SuperImageFactory) | 
|  | 30 | } | 
|  | 31 |  | 
|  | 32 | type superImage struct { | 
|  | 33 | android.ModuleBase | 
|  | 34 |  | 
|  | 35 | properties     SuperImageProperties | 
|  | 36 | partitionProps SuperImagePartitionNameProperties | 
|  | 37 |  | 
|  | 38 | installDir android.InstallPath | 
|  | 39 | } | 
|  | 40 |  | 
|  | 41 | type 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 | 
| mrziwang | f3c8ddf | 2024-12-05 17:15:11 -0800 | [diff] [blame] | 47 | Block_devices []string | 
| mrziwang | 79730d4 | 2024-12-02 22:13:59 -0800 | [diff] [blame] | 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 |  | 
|  | 64 | type PartitionGroupsInfo struct { | 
|  | 65 | Name          string | 
|  | 66 | GroupSize     string | 
|  | 67 | PartitionList []string | 
|  | 68 | } | 
|  | 69 |  | 
|  | 70 | type 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 |  | 
|  | 91 | func 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 |  | 
|  | 98 | type superImageDepTagType struct { | 
|  | 99 | blueprint.BaseDependencyTag | 
|  | 100 | } | 
|  | 101 |  | 
|  | 102 | var superImageDepTag superImageDepTagType | 
|  | 103 |  | 
|  | 104 | func (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 |  | 
|  | 122 | func (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 |  | 
|  | 139 | func (s *superImage) installFileName() string { | 
|  | 140 | return s.BaseModuleName() + ".img" | 
|  | 141 | } | 
|  | 142 |  | 
|  | 143 | func (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)) | 
| mrziwang | f3c8ddf | 2024-12-05 17:15:11 -0800 | [diff] [blame] | 156 | if len(s.properties.Block_devices) > 0 { | 
|  | 157 | addStr("super_block_devices", strings.Join(s.properties.Block_devices, " ")) | 
|  | 158 | } | 
| mrziwang | 79730d4 | 2024-12-02 22:13:59 -0800 | [diff] [blame] | 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 | } |