blob: 0f8f614b455e882edd073d10436db9814edb98ba [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"
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
mrziwangf3c8ddf2024-12-05 17:15:11 -080047 Block_devices []string
mrziwang79730d42024-12-02 22:13:59 -080048 // 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))
mrziwangf3c8ddf2024-12-05 17:15:11 -0800156 if len(s.properties.Block_devices) > 0 {
157 addStr("super_block_devices", strings.Join(s.properties.Block_devices, " "))
158 }
mrziwang79730d42024-12-02 22:13:59 -0800159 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}