blob: 1583c0b4f1e1ad2cf2438d14e903b0b8109189bd [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
47 Block_devices *string
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
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))
156 addStr("super_block_devices", proptools.String(s.properties.Block_devices))
157 addStr("super_super_device_size", strconv.Itoa(proptools.Int(s.properties.Size)))
158 var groups, partitionList []string
159 for _, groupInfo := range s.properties.Partition_groups {
160 groups = append(groups, groupInfo.Name)
161 partitionList = append(partitionList, groupInfo.PartitionList...)
162 addStr("super_"+groupInfo.Name+"_group_size", groupInfo.GroupSize)
163 addStr("super_"+groupInfo.Name+"_partition_list", strings.Join(groupInfo.PartitionList, " "))
164 }
165 addStr("super_partition_groups", strings.Join(groups, " "))
166 addStr("dynamic_partition_list", strings.Join(partitionList, " "))
167
168 addStr("virtual_ab", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab)))
169 addStr("virtual_ab_retrofit", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab_retrofit)))
170 addStr("ab_update", strconv.FormatBool(proptools.Bool(s.properties.Ab_update)))
171 addStr("build_non_sparse_super_partition", strconv.FormatBool(!proptools.Bool(s.properties.Sparse)))
172
173 partitionToImagePath := make(map[string]string)
174 nameToPartition := make(map[string]string)
175 var systemOtherPartitionNameNeeded string
176 addEntryToPartitionToName := func(p string, s *string) {
177 if proptools.String(s) != "" {
178 nameToPartition[*s] = p
179 }
180 }
181
182 // Build partitionToImagePath, because system partition may need system_other
183 // partition image path
184 for _, p := range partitionList {
185 if _, ok := nameToPartition[p]; ok {
186 continue
187 }
188 switch p {
189 case "system":
190 addEntryToPartitionToName(p, s.partitionProps.System_partition)
191 systemOtherPartitionNameNeeded = proptools.String(s.partitionProps.System_other_partition)
192 case "system_dlkm":
193 addEntryToPartitionToName(p, s.partitionProps.System_dlkm_partition)
194 case "system_ext":
195 addEntryToPartitionToName(p, s.partitionProps.System_ext_partition)
196 case "product":
197 addEntryToPartitionToName(p, s.partitionProps.Product_partition)
198 case "vendor":
199 addEntryToPartitionToName(p, s.partitionProps.Vendor_partition)
200 case "vendor_dlkm":
201 addEntryToPartitionToName(p, s.partitionProps.Vendor_dlkm_partition)
202 case "odm":
203 addEntryToPartitionToName(p, s.partitionProps.Odm_partition)
204 case "odm_dlkm":
205 addEntryToPartitionToName(p, s.partitionProps.Odm_dlkm_partition)
206 default:
207 ctx.ModuleErrorf("current partition %s not a super image supported partition", p)
208 }
209 }
210
211 var deps android.Paths
212 ctx.VisitDirectDeps(func(m android.Module) {
213 if p, ok := nameToPartition[m.Name()]; ok {
214 if output, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider); ok {
215 partitionToImagePath[p] = output.DefaultOutputFiles[0].String()
216 deps = append(deps, output.DefaultOutputFiles[0])
217 }
218 } else if systemOtherPartitionNameNeeded != "" && m.Name() == systemOtherPartitionNameNeeded {
219 if output, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider); ok {
220 partitionToImagePath["system_other"] = output.DefaultOutputFiles[0].String()
221 // TODO: add system_other to deps after it can be generated
222 // deps = append(deps, output.DefaultOutputFiles[0])
223 }
224 }
225 })
226
227 for _, p := range android.SortedKeys(partitionToImagePath) {
228 addStr(p+"_image", partitionToImagePath[p])
229 }
230
231 miscInfo := android.PathForModuleOut(ctx, "misc_info.txt")
232 android.WriteFileRule(ctx, miscInfo, miscInfoString.String())
233 return miscInfo, deps
234}