blob: d8c7345ee8a948e1e151a845f0259a30d040fbb5 [file] [log] [blame]
mrziwang79730d42024-12-02 22:13:59 -08001// 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"
Cole Faust2bdc5e52025-01-10 10:29:36 -080024
mrziwang79730d42024-12-02 22:13:59 -080025 "github.com/google/blueprint"
26 "github.com/google/blueprint/proptools"
27)
28
29func init() {
30 android.RegisterModuleType("super_image", SuperImageFactory)
31}
32
33type superImage struct {
34 android.ModuleBase
35
36 properties SuperImageProperties
37 partitionProps SuperImagePartitionNameProperties
38
39 installDir android.InstallPath
40}
41
42type SuperImageProperties struct {
43 // the size of the super partition
44 Size *int64
45 // the block device where metadata for dynamic partitions is stored
46 Metadata_device *string
47 // the super partition block device list
mrziwangf3c8ddf2024-12-05 17:15:11 -080048 Block_devices []string
mrziwang79730d42024-12-02 22:13:59 -080049 // whether A/B updater is used
50 Ab_update *bool
51 // whether dynamic partitions is enabled on devices that were launched without this support
52 Retrofit *bool
53 // whether virtual A/B seamless update is enabled
54 Virtual_ab *bool
55 // whether retrofitting virtual A/B seamless update is enabled
56 Virtual_ab_retrofit *bool
57 // whether the output is a sparse image
58 Sparse *bool
59 // information about how partitions within the super partition are grouped together
60 Partition_groups []PartitionGroupsInfo
61 // whether dynamic partitions is used
62 Use_dynamic_partitions *bool
63}
64
65type PartitionGroupsInfo struct {
66 Name string
67 GroupSize string
68 PartitionList []string
69}
70
71type SuperImagePartitionNameProperties struct {
72 // Name of the System partition filesystem module
73 System_partition *string
74 // Name of the System_ext partition filesystem module
75 System_ext_partition *string
76 // Name of the System_dlkm partition filesystem module
77 System_dlkm_partition *string
78 // Name of the System_other partition filesystem module
79 System_other_partition *string
80 // Name of the Product partition filesystem module
81 Product_partition *string
82 // Name of the Vendor partition filesystem module
83 Vendor_partition *string
84 // Name of the Vendor_dlkm partition filesystem module
85 Vendor_dlkm_partition *string
86 // Name of the Odm partition filesystem module
87 Odm_partition *string
88 // Name of the Odm_dlkm partition filesystem module
89 Odm_dlkm_partition *string
90}
91
Cole Faust2bdc5e52025-01-10 10:29:36 -080092type SuperImageInfo struct {
93 // The built super.img file, which contains the sub-partitions
94 SuperImage android.Path
95
96 // Mapping from the sub-partition type to its re-exported FileSystemInfo providers from the
97 // sub-partitions.
98 SubImageInfo map[string]FilesystemInfo
99}
100
101var SuperImageProvider = blueprint.NewProvider[SuperImageInfo]()
102
mrziwang79730d42024-12-02 22:13:59 -0800103func SuperImageFactory() android.Module {
104 module := &superImage{}
105 module.AddProperties(&module.properties, &module.partitionProps)
106 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
107 return module
108}
109
110type superImageDepTagType struct {
111 blueprint.BaseDependencyTag
112}
113
Cole Faust2bdc5e52025-01-10 10:29:36 -0800114var subImageDepTag superImageDepTagType
mrziwang79730d42024-12-02 22:13:59 -0800115
116func (s *superImage) DepsMutator(ctx android.BottomUpMutatorContext) {
117 addDependencyIfDefined := func(dep *string) {
118 if dep != nil {
Cole Faust2bdc5e52025-01-10 10:29:36 -0800119 ctx.AddDependency(ctx.Module(), subImageDepTag, proptools.String(dep))
mrziwang79730d42024-12-02 22:13:59 -0800120 }
121 }
122
123 addDependencyIfDefined(s.partitionProps.System_partition)
124 addDependencyIfDefined(s.partitionProps.System_ext_partition)
125 addDependencyIfDefined(s.partitionProps.System_dlkm_partition)
126 addDependencyIfDefined(s.partitionProps.System_other_partition)
127 addDependencyIfDefined(s.partitionProps.Product_partition)
128 addDependencyIfDefined(s.partitionProps.Vendor_partition)
129 addDependencyIfDefined(s.partitionProps.Vendor_dlkm_partition)
130 addDependencyIfDefined(s.partitionProps.Odm_partition)
131 addDependencyIfDefined(s.partitionProps.Odm_dlkm_partition)
132}
133
134func (s *superImage) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Cole Faust2bdc5e52025-01-10 10:29:36 -0800135 miscInfo, deps, subImageInfos := s.buildMiscInfo(ctx)
mrziwang79730d42024-12-02 22:13:59 -0800136 builder := android.NewRuleBuilder(pctx, ctx)
137 output := android.PathForModuleOut(ctx, s.installFileName())
138 lpMake := ctx.Config().HostToolPath(ctx, "lpmake")
139 lpMakeDir := filepath.Dir(lpMake.String())
140 deps = append(deps, lpMake)
141 builder.Command().Textf("PATH=%s:\\$PATH", lpMakeDir).
142 BuiltTool("build_super_image").
143 Text("-v").
144 Input(miscInfo).
145 Implicits(deps).
146 Output(output)
147 builder.Build("build_super_image", fmt.Sprintf("Creating super image %s", s.BaseModuleName()))
Cole Faust2bdc5e52025-01-10 10:29:36 -0800148 android.SetProvider(ctx, SuperImageProvider, SuperImageInfo{
149 SuperImage: output,
150 SubImageInfo: subImageInfos,
151 })
mrziwang79730d42024-12-02 22:13:59 -0800152 ctx.SetOutputFiles([]android.Path{output}, "")
Cole Faust2bdc5e52025-01-10 10:29:36 -0800153 ctx.CheckbuildFile(output)
mrziwang79730d42024-12-02 22:13:59 -0800154}
155
156func (s *superImage) installFileName() string {
157 return s.BaseModuleName() + ".img"
158}
159
Cole Faust2bdc5e52025-01-10 10:29:36 -0800160func (s *superImage) buildMiscInfo(ctx android.ModuleContext) (android.Path, android.Paths, map[string]FilesystemInfo) {
mrziwang79730d42024-12-02 22:13:59 -0800161 var miscInfoString strings.Builder
162 addStr := func(name string, value string) {
163 miscInfoString.WriteString(name)
164 miscInfoString.WriteRune('=')
165 miscInfoString.WriteString(value)
166 miscInfoString.WriteRune('\n')
167 }
168
169 addStr("use_dynamic_partitions", strconv.FormatBool(proptools.Bool(s.properties.Use_dynamic_partitions)))
170 addStr("dynamic_partition_retrofit", strconv.FormatBool(proptools.Bool(s.properties.Retrofit)))
171 addStr("lpmake", "lpmake")
172 addStr("super_metadata_device", proptools.String(s.properties.Metadata_device))
mrziwangf3c8ddf2024-12-05 17:15:11 -0800173 if len(s.properties.Block_devices) > 0 {
174 addStr("super_block_devices", strings.Join(s.properties.Block_devices, " "))
175 }
mrziwang79730d42024-12-02 22:13:59 -0800176 addStr("super_super_device_size", strconv.Itoa(proptools.Int(s.properties.Size)))
177 var groups, partitionList []string
178 for _, groupInfo := range s.properties.Partition_groups {
179 groups = append(groups, groupInfo.Name)
180 partitionList = append(partitionList, groupInfo.PartitionList...)
181 addStr("super_"+groupInfo.Name+"_group_size", groupInfo.GroupSize)
182 addStr("super_"+groupInfo.Name+"_partition_list", strings.Join(groupInfo.PartitionList, " "))
183 }
Cole Faust2bdc5e52025-01-10 10:29:36 -0800184 initialPartitionListLen := len(partitionList)
185 partitionList = android.SortedUniqueStrings(partitionList)
186 if len(partitionList) != initialPartitionListLen {
187 ctx.ModuleErrorf("Duplicate partitions found in the partition_groups property")
188 }
mrziwang79730d42024-12-02 22:13:59 -0800189 addStr("super_partition_groups", strings.Join(groups, " "))
190 addStr("dynamic_partition_list", strings.Join(partitionList, " "))
191
192 addStr("virtual_ab", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab)))
193 addStr("virtual_ab_retrofit", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab_retrofit)))
194 addStr("ab_update", strconv.FormatBool(proptools.Bool(s.properties.Ab_update)))
195 addStr("build_non_sparse_super_partition", strconv.FormatBool(!proptools.Bool(s.properties.Sparse)))
196
Cole Faust2bdc5e52025-01-10 10:29:36 -0800197 subImageInfo := make(map[string]FilesystemInfo)
198 var deps android.Paths
199
200 missingPartitionErrorMessage := ""
201 handleSubPartition := func(partitionType string, name *string) {
202 if proptools.String(name) == "" {
203 missingPartitionErrorMessage += fmt.Sprintf("%s image listed in partition groups, but its module was not specified. ", partitionType)
204 return
mrziwang79730d42024-12-02 22:13:59 -0800205 }
Cole Faust2bdc5e52025-01-10 10:29:36 -0800206 mod := ctx.GetDirectDepWithTag(*name, subImageDepTag)
207 if mod == nil {
208 ctx.ModuleErrorf("Could not get dep %q", *name)
209 return
210 }
211 info, ok := android.OtherModuleProvider(ctx, mod, FilesystemProvider)
212 if !ok {
213 ctx.ModuleErrorf("Expected dep %q to provide FilesystemInfo", *name)
214 return
215 }
216 addStr(partitionType+"_image", info.Output.String())
217 deps = append(deps, info.Output)
218 if _, ok := subImageInfo[partitionType]; ok {
219 ctx.ModuleErrorf("Already set subimageInfo for %q", partitionType)
220 }
221 subImageInfo[partitionType] = info
mrziwang79730d42024-12-02 22:13:59 -0800222 }
223
224 // Build partitionToImagePath, because system partition may need system_other
225 // partition image path
226 for _, p := range partitionList {
mrziwang79730d42024-12-02 22:13:59 -0800227 switch p {
228 case "system":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800229 handleSubPartition("system", s.partitionProps.System_partition)
230 // TODO: add system_other to deps after it can be generated
231 //getFsInfo("system_other", s.partitionProps.System_other_partition, &subImageInfo.System_other)
mrziwang79730d42024-12-02 22:13:59 -0800232 case "system_dlkm":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800233 handleSubPartition("system_dlkm", s.partitionProps.System_dlkm_partition)
mrziwang79730d42024-12-02 22:13:59 -0800234 case "system_ext":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800235 handleSubPartition("system_ext", s.partitionProps.System_ext_partition)
mrziwang79730d42024-12-02 22:13:59 -0800236 case "product":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800237 handleSubPartition("product", s.partitionProps.Product_partition)
mrziwang79730d42024-12-02 22:13:59 -0800238 case "vendor":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800239 handleSubPartition("vendor", s.partitionProps.Vendor_partition)
mrziwang79730d42024-12-02 22:13:59 -0800240 case "vendor_dlkm":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800241 handleSubPartition("vendor_dlkm", s.partitionProps.Vendor_dlkm_partition)
mrziwang79730d42024-12-02 22:13:59 -0800242 case "odm":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800243 handleSubPartition("odm", s.partitionProps.Odm_partition)
mrziwang79730d42024-12-02 22:13:59 -0800244 case "odm_dlkm":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800245 handleSubPartition("odm_dlkm", s.partitionProps.Odm_dlkm_partition)
mrziwang79730d42024-12-02 22:13:59 -0800246 default:
Cole Faust2bdc5e52025-01-10 10:29:36 -0800247 ctx.ModuleErrorf("partition %q is not a super image supported partition", p)
mrziwang79730d42024-12-02 22:13:59 -0800248 }
249 }
250
Cole Faust2bdc5e52025-01-10 10:29:36 -0800251 // Delay the error message until execution time because on aosp-main-future-without-vendor,
252 // BUILDING_VENDOR_IMAGE is false so we don't get the vendor image, but it's still listed in
253 // BOARD_GOOGLE_DYNAMIC_PARTITIONS_PARTITION_LIST.
254 missingPartitionErrorMessageFile := android.PathForModuleOut(ctx, "missing_partition_error.txt")
255 if missingPartitionErrorMessage != "" {
256 ctx.Build(pctx, android.BuildParams{
257 Rule: android.ErrorRule,
258 Output: missingPartitionErrorMessageFile,
259 Args: map[string]string{
260 "error": missingPartitionErrorMessage,
261 },
262 })
263 } else {
264 ctx.Build(pctx, android.BuildParams{
265 Rule: android.Touch,
266 Output: missingPartitionErrorMessageFile,
267 })
Naresh Kumar Podishetty (xWF)4173c5b2025-01-09 20:20:32 -0800268 }
269
mrziwang79730d42024-12-02 22:13:59 -0800270 miscInfo := android.PathForModuleOut(ctx, "misc_info.txt")
Cole Faust2bdc5e52025-01-10 10:29:36 -0800271 android.WriteFileRule(ctx, miscInfo, miscInfoString.String(), missingPartitionErrorMessageFile)
272 return miscInfo, deps, subImageInfo
mrziwang79730d42024-12-02 22:13:59 -0800273}