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 | } |