blob: f73f0dcbae7de72543bc7e405c510777068eb335 [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"
Cole Faust498ffc12025-01-15 14:19:32 -080020 "regexp"
mrziwang79730d42024-12-02 22:13:59 -080021 "strconv"
22 "strings"
23
24 "android/soong/android"
Cole Faust2bdc5e52025-01-10 10:29:36 -080025
mrziwang79730d42024-12-02 22:13:59 -080026 "github.com/google/blueprint"
27 "github.com/google/blueprint/proptools"
28)
29
30func init() {
31 android.RegisterModuleType("super_image", SuperImageFactory)
32}
33
34type superImage struct {
35 android.ModuleBase
36
37 properties SuperImageProperties
38 partitionProps SuperImagePartitionNameProperties
39
40 installDir android.InstallPath
41}
42
43type SuperImageProperties struct {
44 // the size of the super partition
45 Size *int64
46 // the block device where metadata for dynamic partitions is stored
47 Metadata_device *string
48 // the super partition block device list
mrziwangf3c8ddf2024-12-05 17:15:11 -080049 Block_devices []string
mrziwang79730d42024-12-02 22:13:59 -080050 // whether A/B updater is used
51 Ab_update *bool
52 // whether dynamic partitions is enabled on devices that were launched without this support
53 Retrofit *bool
mrziwang79730d42024-12-02 22:13:59 -080054 // whether the output is a sparse image
55 Sparse *bool
56 // information about how partitions within the super partition are grouped together
57 Partition_groups []PartitionGroupsInfo
58 // whether dynamic partitions is used
59 Use_dynamic_partitions *bool
Cole Faust498ffc12025-01-15 14:19:32 -080060 Virtual_ab struct {
61 // whether virtual A/B seamless update is enabled
62 Enable *bool
63 // whether retrofitting virtual A/B seamless update is enabled
64 Retrofit *bool
65 // If set, device uses virtual A/B Compression
66 Compression *bool
67 // This value controls the compression algorithm used for VABC.
68 // Valid options are defined in system/core/fs_mgr/libsnapshot/cow_writer.cpp
69 // e.g. "none", "gz", "brotli"
70 Compression_method *string
71 // Specifies maximum bytes to be compressed at once during ota. Options: 4096, 8192, 16384, 32768, 65536, 131072, 262144.
72 Compression_factor *int64
73 // Specifies COW version to be used by update_engine and libsnapshot. If this value is not
74 // specified we default to COW version 2 in update_engine for backwards compatibility
75 Cow_version *int64
76 }
mrziwang79730d42024-12-02 22:13:59 -080077}
78
79type PartitionGroupsInfo struct {
80 Name string
81 GroupSize string
82 PartitionList []string
83}
84
85type SuperImagePartitionNameProperties struct {
86 // Name of the System partition filesystem module
87 System_partition *string
88 // Name of the System_ext partition filesystem module
89 System_ext_partition *string
90 // Name of the System_dlkm partition filesystem module
91 System_dlkm_partition *string
92 // Name of the System_other partition filesystem module
93 System_other_partition *string
94 // Name of the Product partition filesystem module
95 Product_partition *string
96 // Name of the Vendor partition filesystem module
97 Vendor_partition *string
98 // Name of the Vendor_dlkm partition filesystem module
99 Vendor_dlkm_partition *string
100 // Name of the Odm partition filesystem module
101 Odm_partition *string
102 // Name of the Odm_dlkm partition filesystem module
103 Odm_dlkm_partition *string
104}
105
Cole Faust2bdc5e52025-01-10 10:29:36 -0800106type SuperImageInfo struct {
107 // The built super.img file, which contains the sub-partitions
108 SuperImage android.Path
109
110 // Mapping from the sub-partition type to its re-exported FileSystemInfo providers from the
111 // sub-partitions.
112 SubImageInfo map[string]FilesystemInfo
113}
114
115var SuperImageProvider = blueprint.NewProvider[SuperImageInfo]()
116
mrziwang79730d42024-12-02 22:13:59 -0800117func SuperImageFactory() android.Module {
118 module := &superImage{}
119 module.AddProperties(&module.properties, &module.partitionProps)
120 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
121 return module
122}
123
124type superImageDepTagType struct {
125 blueprint.BaseDependencyTag
126}
127
Cole Faust2bdc5e52025-01-10 10:29:36 -0800128var subImageDepTag superImageDepTagType
mrziwang79730d42024-12-02 22:13:59 -0800129
130func (s *superImage) DepsMutator(ctx android.BottomUpMutatorContext) {
131 addDependencyIfDefined := func(dep *string) {
132 if dep != nil {
Cole Faust2bdc5e52025-01-10 10:29:36 -0800133 ctx.AddDependency(ctx.Module(), subImageDepTag, proptools.String(dep))
mrziwang79730d42024-12-02 22:13:59 -0800134 }
135 }
136
137 addDependencyIfDefined(s.partitionProps.System_partition)
138 addDependencyIfDefined(s.partitionProps.System_ext_partition)
139 addDependencyIfDefined(s.partitionProps.System_dlkm_partition)
140 addDependencyIfDefined(s.partitionProps.System_other_partition)
141 addDependencyIfDefined(s.partitionProps.Product_partition)
142 addDependencyIfDefined(s.partitionProps.Vendor_partition)
143 addDependencyIfDefined(s.partitionProps.Vendor_dlkm_partition)
144 addDependencyIfDefined(s.partitionProps.Odm_partition)
145 addDependencyIfDefined(s.partitionProps.Odm_dlkm_partition)
146}
147
148func (s *superImage) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Cole Faust2bdc5e52025-01-10 10:29:36 -0800149 miscInfo, deps, subImageInfos := s.buildMiscInfo(ctx)
mrziwang79730d42024-12-02 22:13:59 -0800150 builder := android.NewRuleBuilder(pctx, ctx)
151 output := android.PathForModuleOut(ctx, s.installFileName())
152 lpMake := ctx.Config().HostToolPath(ctx, "lpmake")
153 lpMakeDir := filepath.Dir(lpMake.String())
154 deps = append(deps, lpMake)
155 builder.Command().Textf("PATH=%s:\\$PATH", lpMakeDir).
156 BuiltTool("build_super_image").
157 Text("-v").
158 Input(miscInfo).
159 Implicits(deps).
160 Output(output)
161 builder.Build("build_super_image", fmt.Sprintf("Creating super image %s", s.BaseModuleName()))
Cole Faust2bdc5e52025-01-10 10:29:36 -0800162 android.SetProvider(ctx, SuperImageProvider, SuperImageInfo{
163 SuperImage: output,
164 SubImageInfo: subImageInfos,
165 })
mrziwang79730d42024-12-02 22:13:59 -0800166 ctx.SetOutputFiles([]android.Path{output}, "")
Cole Faust2bdc5e52025-01-10 10:29:36 -0800167 ctx.CheckbuildFile(output)
mrziwang79730d42024-12-02 22:13:59 -0800168}
169
170func (s *superImage) installFileName() string {
171 return s.BaseModuleName() + ".img"
172}
173
Cole Faust2bdc5e52025-01-10 10:29:36 -0800174func (s *superImage) buildMiscInfo(ctx android.ModuleContext) (android.Path, android.Paths, map[string]FilesystemInfo) {
mrziwang79730d42024-12-02 22:13:59 -0800175 var miscInfoString strings.Builder
176 addStr := func(name string, value string) {
177 miscInfoString.WriteString(name)
178 miscInfoString.WriteRune('=')
179 miscInfoString.WriteString(value)
180 miscInfoString.WriteRune('\n')
181 }
182
Cole Faust498ffc12025-01-15 14:19:32 -0800183 addStr("build_super_partition", "true")
mrziwang79730d42024-12-02 22:13:59 -0800184 addStr("use_dynamic_partitions", strconv.FormatBool(proptools.Bool(s.properties.Use_dynamic_partitions)))
Cole Faust498ffc12025-01-15 14:19:32 -0800185 if proptools.Bool(s.properties.Retrofit) {
186 addStr("dynamic_partition_retrofit", "true")
187 }
mrziwang79730d42024-12-02 22:13:59 -0800188 addStr("lpmake", "lpmake")
189 addStr("super_metadata_device", proptools.String(s.properties.Metadata_device))
mrziwangf3c8ddf2024-12-05 17:15:11 -0800190 if len(s.properties.Block_devices) > 0 {
191 addStr("super_block_devices", strings.Join(s.properties.Block_devices, " "))
192 }
Cole Faust498ffc12025-01-15 14:19:32 -0800193 addStr("super_partition_size", strconv.Itoa(proptools.Int(s.properties.Size)))
194 // TODO: In make, there's more complicated logic than just this surrounding super_*_device_size
mrziwang79730d42024-12-02 22:13:59 -0800195 addStr("super_super_device_size", strconv.Itoa(proptools.Int(s.properties.Size)))
196 var groups, partitionList []string
197 for _, groupInfo := range s.properties.Partition_groups {
198 groups = append(groups, groupInfo.Name)
199 partitionList = append(partitionList, groupInfo.PartitionList...)
200 addStr("super_"+groupInfo.Name+"_group_size", groupInfo.GroupSize)
201 addStr("super_"+groupInfo.Name+"_partition_list", strings.Join(groupInfo.PartitionList, " "))
202 }
Cole Faust2bdc5e52025-01-10 10:29:36 -0800203 initialPartitionListLen := len(partitionList)
204 partitionList = android.SortedUniqueStrings(partitionList)
205 if len(partitionList) != initialPartitionListLen {
206 ctx.ModuleErrorf("Duplicate partitions found in the partition_groups property")
207 }
mrziwang79730d42024-12-02 22:13:59 -0800208 addStr("super_partition_groups", strings.Join(groups, " "))
209 addStr("dynamic_partition_list", strings.Join(partitionList, " "))
210
mrziwang79730d42024-12-02 22:13:59 -0800211 addStr("ab_update", strconv.FormatBool(proptools.Bool(s.properties.Ab_update)))
Cole Faust498ffc12025-01-15 14:19:32 -0800212
213 if proptools.Bool(s.properties.Virtual_ab.Enable) {
214 addStr("virtual_ab", "true")
215 if proptools.Bool(s.properties.Virtual_ab.Retrofit) {
216 addStr("virtual_ab_retrofit", "true")
217 }
218 addStr("virtual_ab_compression", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab.Compression)))
219 if s.properties.Virtual_ab.Compression_method != nil {
220 matched, _ := regexp.MatchString("^[a-zA-Z0-9_-]+$", *s.properties.Virtual_ab.Compression_method)
221 if !matched {
222 ctx.PropertyErrorf("virtual_ab.compression_method", "compression_method cannot have special characters")
223 }
224 addStr("virtual_ab_compression_method", *s.properties.Virtual_ab.Compression_method)
225 }
226 if s.properties.Virtual_ab.Compression_factor != nil {
227 addStr("virtual_ab_compression_factor", strconv.FormatInt(*s.properties.Virtual_ab.Compression_factor, 10))
228 }
229 if s.properties.Virtual_ab.Cow_version != nil {
230 addStr("virtual_ab_cow_version", strconv.FormatInt(*s.properties.Virtual_ab.Cow_version, 10))
231 }
232
233 } else {
234 if s.properties.Virtual_ab.Retrofit != nil {
235 ctx.PropertyErrorf("virtual_ab.retrofix", "This property cannot be set when virtual_ab is disabled")
236 }
237 if s.properties.Virtual_ab.Compression != nil {
238 ctx.PropertyErrorf("virtual_ab.compression", "This property cannot be set when virtual_ab is disabled")
239 }
240 if s.properties.Virtual_ab.Compression_method != nil {
241 ctx.PropertyErrorf("virtual_ab.compression_method", "This property cannot be set when virtual_ab is disabled")
242 }
243 if s.properties.Virtual_ab.Compression_factor != nil {
244 ctx.PropertyErrorf("virtual_ab.compression_factor", "This property cannot be set when virtual_ab is disabled")
245 }
246 }
mrziwang79730d42024-12-02 22:13:59 -0800247
Cole Faust2bdc5e52025-01-10 10:29:36 -0800248 subImageInfo := make(map[string]FilesystemInfo)
249 var deps android.Paths
250
251 missingPartitionErrorMessage := ""
252 handleSubPartition := func(partitionType string, name *string) {
253 if proptools.String(name) == "" {
254 missingPartitionErrorMessage += fmt.Sprintf("%s image listed in partition groups, but its module was not specified. ", partitionType)
255 return
mrziwang79730d42024-12-02 22:13:59 -0800256 }
Cole Faust2bdc5e52025-01-10 10:29:36 -0800257 mod := ctx.GetDirectDepWithTag(*name, subImageDepTag)
258 if mod == nil {
259 ctx.ModuleErrorf("Could not get dep %q", *name)
260 return
261 }
262 info, ok := android.OtherModuleProvider(ctx, mod, FilesystemProvider)
263 if !ok {
264 ctx.ModuleErrorf("Expected dep %q to provide FilesystemInfo", *name)
265 return
266 }
267 addStr(partitionType+"_image", info.Output.String())
268 deps = append(deps, info.Output)
269 if _, ok := subImageInfo[partitionType]; ok {
270 ctx.ModuleErrorf("Already set subimageInfo for %q", partitionType)
271 }
272 subImageInfo[partitionType] = info
mrziwang79730d42024-12-02 22:13:59 -0800273 }
274
275 // Build partitionToImagePath, because system partition may need system_other
276 // partition image path
277 for _, p := range partitionList {
mrziwang79730d42024-12-02 22:13:59 -0800278 switch p {
279 case "system":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800280 handleSubPartition("system", s.partitionProps.System_partition)
281 // TODO: add system_other to deps after it can be generated
282 //getFsInfo("system_other", s.partitionProps.System_other_partition, &subImageInfo.System_other)
mrziwang79730d42024-12-02 22:13:59 -0800283 case "system_dlkm":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800284 handleSubPartition("system_dlkm", s.partitionProps.System_dlkm_partition)
mrziwang79730d42024-12-02 22:13:59 -0800285 case "system_ext":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800286 handleSubPartition("system_ext", s.partitionProps.System_ext_partition)
mrziwang79730d42024-12-02 22:13:59 -0800287 case "product":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800288 handleSubPartition("product", s.partitionProps.Product_partition)
mrziwang79730d42024-12-02 22:13:59 -0800289 case "vendor":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800290 handleSubPartition("vendor", s.partitionProps.Vendor_partition)
mrziwang79730d42024-12-02 22:13:59 -0800291 case "vendor_dlkm":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800292 handleSubPartition("vendor_dlkm", s.partitionProps.Vendor_dlkm_partition)
mrziwang79730d42024-12-02 22:13:59 -0800293 case "odm":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800294 handleSubPartition("odm", s.partitionProps.Odm_partition)
mrziwang79730d42024-12-02 22:13:59 -0800295 case "odm_dlkm":
Cole Faust2bdc5e52025-01-10 10:29:36 -0800296 handleSubPartition("odm_dlkm", s.partitionProps.Odm_dlkm_partition)
mrziwang79730d42024-12-02 22:13:59 -0800297 default:
Cole Faust2bdc5e52025-01-10 10:29:36 -0800298 ctx.ModuleErrorf("partition %q is not a super image supported partition", p)
mrziwang79730d42024-12-02 22:13:59 -0800299 }
300 }
301
Cole Faust2bdc5e52025-01-10 10:29:36 -0800302 // Delay the error message until execution time because on aosp-main-future-without-vendor,
303 // BUILDING_VENDOR_IMAGE is false so we don't get the vendor image, but it's still listed in
304 // BOARD_GOOGLE_DYNAMIC_PARTITIONS_PARTITION_LIST.
305 missingPartitionErrorMessageFile := android.PathForModuleOut(ctx, "missing_partition_error.txt")
306 if missingPartitionErrorMessage != "" {
307 ctx.Build(pctx, android.BuildParams{
308 Rule: android.ErrorRule,
309 Output: missingPartitionErrorMessageFile,
310 Args: map[string]string{
311 "error": missingPartitionErrorMessage,
312 },
313 })
314 } else {
315 ctx.Build(pctx, android.BuildParams{
316 Rule: android.Touch,
317 Output: missingPartitionErrorMessageFile,
318 })
Naresh Kumar Podishetty (xWF)4173c5b2025-01-09 20:20:32 -0800319 }
320
mrziwang79730d42024-12-02 22:13:59 -0800321 miscInfo := android.PathForModuleOut(ctx, "misc_info.txt")
Cole Faust2bdc5e52025-01-10 10:29:36 -0800322 android.WriteFileRule(ctx, miscInfo, miscInfoString.String(), missingPartitionErrorMessageFile)
323 return miscInfo, deps, subImageInfo
mrziwang79730d42024-12-02 22:13:59 -0800324}