xref: /aosp_15_r20/build/soong/filesystem/super_image.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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
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	if len(s.properties.Block_devices) > 0 {
157		addStr("super_block_devices", strings.Join(s.properties.Block_devices, " "))
158	}
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}
237