xref: /aosp_15_r20/build/soong/filesystem/logical_partition.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1*333d2b36SAndroid Build Coastguard Worker// Copyright (C) 2021 The Android Open Source Project
2*333d2b36SAndroid Build Coastguard Worker//
3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*333d2b36SAndroid Build Coastguard Worker//
7*333d2b36SAndroid Build Coastguard Worker//     http://www.apache.org/licenses/LICENSE-2.0
8*333d2b36SAndroid Build Coastguard Worker//
9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*333d2b36SAndroid Build Coastguard Worker// limitations under the License.
14*333d2b36SAndroid Build Coastguard Worker
15*333d2b36SAndroid Build Coastguard Workerpackage filesystem
16*333d2b36SAndroid Build Coastguard Worker
17*333d2b36SAndroid Build Coastguard Workerimport (
18*333d2b36SAndroid Build Coastguard Worker	"fmt"
19*333d2b36SAndroid Build Coastguard Worker	"strconv"
20*333d2b36SAndroid Build Coastguard Worker
21*333d2b36SAndroid Build Coastguard Worker	"github.com/google/blueprint/proptools"
22*333d2b36SAndroid Build Coastguard Worker
23*333d2b36SAndroid Build Coastguard Worker	"android/soong/android"
24*333d2b36SAndroid Build Coastguard Worker)
25*333d2b36SAndroid Build Coastguard Worker
26*333d2b36SAndroid Build Coastguard Workerfunc init() {
27*333d2b36SAndroid Build Coastguard Worker	android.RegisterModuleType("logical_partition", logicalPartitionFactory)
28*333d2b36SAndroid Build Coastguard Worker}
29*333d2b36SAndroid Build Coastguard Worker
30*333d2b36SAndroid Build Coastguard Workertype logicalPartition struct {
31*333d2b36SAndroid Build Coastguard Worker	android.ModuleBase
32*333d2b36SAndroid Build Coastguard Worker
33*333d2b36SAndroid Build Coastguard Worker	properties logicalPartitionProperties
34*333d2b36SAndroid Build Coastguard Worker
35*333d2b36SAndroid Build Coastguard Worker	output     android.Path
36*333d2b36SAndroid Build Coastguard Worker	installDir android.InstallPath
37*333d2b36SAndroid Build Coastguard Worker}
38*333d2b36SAndroid Build Coastguard Worker
39*333d2b36SAndroid Build Coastguard Workertype logicalPartitionProperties struct {
40*333d2b36SAndroid Build Coastguard Worker	// Set the name of the output. Defaults to <module_name>.img.
41*333d2b36SAndroid Build Coastguard Worker	Stem *string
42*333d2b36SAndroid Build Coastguard Worker
43*333d2b36SAndroid Build Coastguard Worker	// Total size of the logical partition. If set to "auto", total size is automatically
44*333d2b36SAndroid Build Coastguard Worker	// calcaulted as minimum.
45*333d2b36SAndroid Build Coastguard Worker	Size *string
46*333d2b36SAndroid Build Coastguard Worker
47*333d2b36SAndroid Build Coastguard Worker	// List of partitions for default group. Default group has no size limit and automatically
48*333d2b36SAndroid Build Coastguard Worker	// minimized when creating an image.
49*333d2b36SAndroid Build Coastguard Worker	Default_group []partitionProperties
50*333d2b36SAndroid Build Coastguard Worker
51*333d2b36SAndroid Build Coastguard Worker	// List of groups. A group defines a fixed sized region. It can host one or more logical
52*333d2b36SAndroid Build Coastguard Worker	// partitions and their total size is limited by the size of the group they are in.
53*333d2b36SAndroid Build Coastguard Worker	Groups []groupProperties
54*333d2b36SAndroid Build Coastguard Worker
55*333d2b36SAndroid Build Coastguard Worker	// Whether the output is a sparse image or not. Default is false.
56*333d2b36SAndroid Build Coastguard Worker	Sparse *bool
57*333d2b36SAndroid Build Coastguard Worker}
58*333d2b36SAndroid Build Coastguard Worker
59*333d2b36SAndroid Build Coastguard Workertype groupProperties struct {
60*333d2b36SAndroid Build Coastguard Worker	// Name of the partition group. Can't be "default"; use default_group instead.
61*333d2b36SAndroid Build Coastguard Worker	Name *string
62*333d2b36SAndroid Build Coastguard Worker
63*333d2b36SAndroid Build Coastguard Worker	// Size of the partition group
64*333d2b36SAndroid Build Coastguard Worker	Size *string
65*333d2b36SAndroid Build Coastguard Worker
66*333d2b36SAndroid Build Coastguard Worker	// List of logical partitions in this group
67*333d2b36SAndroid Build Coastguard Worker	Partitions []partitionProperties
68*333d2b36SAndroid Build Coastguard Worker}
69*333d2b36SAndroid Build Coastguard Worker
70*333d2b36SAndroid Build Coastguard Workertype partitionProperties struct {
71*333d2b36SAndroid Build Coastguard Worker	// Name of the partition
72*333d2b36SAndroid Build Coastguard Worker	Name *string
73*333d2b36SAndroid Build Coastguard Worker
74*333d2b36SAndroid Build Coastguard Worker	// Filesystem that is placed on the partition
75*333d2b36SAndroid Build Coastguard Worker	Filesystem *string `android:"path"`
76*333d2b36SAndroid Build Coastguard Worker}
77*333d2b36SAndroid Build Coastguard Worker
78*333d2b36SAndroid Build Coastguard Worker// logical_partition is a partition image which has one or more logical partitions in it.
79*333d2b36SAndroid Build Coastguard Workerfunc logicalPartitionFactory() android.Module {
80*333d2b36SAndroid Build Coastguard Worker	module := &logicalPartition{}
81*333d2b36SAndroid Build Coastguard Worker	module.AddProperties(&module.properties)
82*333d2b36SAndroid Build Coastguard Worker	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
83*333d2b36SAndroid Build Coastguard Worker	return module
84*333d2b36SAndroid Build Coastguard Worker}
85*333d2b36SAndroid Build Coastguard Worker
86*333d2b36SAndroid Build Coastguard Workerfunc (l *logicalPartition) DepsMutator(ctx android.BottomUpMutatorContext) {
87*333d2b36SAndroid Build Coastguard Worker	// do nothing
88*333d2b36SAndroid Build Coastguard Worker}
89*333d2b36SAndroid Build Coastguard Worker
90*333d2b36SAndroid Build Coastguard Workerfunc (l *logicalPartition) installFileName() string {
91*333d2b36SAndroid Build Coastguard Worker	return proptools.StringDefault(l.properties.Stem, l.BaseModuleName()+".img")
92*333d2b36SAndroid Build Coastguard Worker}
93*333d2b36SAndroid Build Coastguard Worker
94*333d2b36SAndroid Build Coastguard Workerfunc (l *logicalPartition) GenerateAndroidBuildActions(ctx android.ModuleContext) {
95*333d2b36SAndroid Build Coastguard Worker	builder := android.NewRuleBuilder(pctx, ctx)
96*333d2b36SAndroid Build Coastguard Worker
97*333d2b36SAndroid Build Coastguard Worker	// Sparse the filesystem images and calculate their sizes
98*333d2b36SAndroid Build Coastguard Worker	sparseImages := make(map[string]android.Path)
99*333d2b36SAndroid Build Coastguard Worker	sparseImageSizes := make(map[string]android.Path)
100*333d2b36SAndroid Build Coastguard Worker
101*333d2b36SAndroid Build Coastguard Worker	sparsePartitions := func(partitions []partitionProperties) {
102*333d2b36SAndroid Build Coastguard Worker		for _, part := range partitions {
103*333d2b36SAndroid Build Coastguard Worker			if part.Filesystem == nil {
104*333d2b36SAndroid Build Coastguard Worker				continue
105*333d2b36SAndroid Build Coastguard Worker			}
106*333d2b36SAndroid Build Coastguard Worker			sparseImg, sizeTxt := sparseFilesystem(ctx, part, builder)
107*333d2b36SAndroid Build Coastguard Worker			pName := proptools.String(part.Name)
108*333d2b36SAndroid Build Coastguard Worker			sparseImages[pName] = sparseImg
109*333d2b36SAndroid Build Coastguard Worker			sparseImageSizes[pName] = sizeTxt
110*333d2b36SAndroid Build Coastguard Worker		}
111*333d2b36SAndroid Build Coastguard Worker	}
112*333d2b36SAndroid Build Coastguard Worker
113*333d2b36SAndroid Build Coastguard Worker	for _, group := range l.properties.Groups {
114*333d2b36SAndroid Build Coastguard Worker		sparsePartitions(group.Partitions)
115*333d2b36SAndroid Build Coastguard Worker	}
116*333d2b36SAndroid Build Coastguard Worker
117*333d2b36SAndroid Build Coastguard Worker	sparsePartitions(l.properties.Default_group)
118*333d2b36SAndroid Build Coastguard Worker
119*333d2b36SAndroid Build Coastguard Worker	cmd := builder.Command().BuiltTool("lpmake")
120*333d2b36SAndroid Build Coastguard Worker
121*333d2b36SAndroid Build Coastguard Worker	size := proptools.String(l.properties.Size)
122*333d2b36SAndroid Build Coastguard Worker	if size == "" {
123*333d2b36SAndroid Build Coastguard Worker		ctx.PropertyErrorf("size", "must be set")
124*333d2b36SAndroid Build Coastguard Worker	} else if _, err := strconv.Atoi(size); err != nil && size != "auto" {
125*333d2b36SAndroid Build Coastguard Worker		ctx.PropertyErrorf("size", `must be a number or "auto"`)
126*333d2b36SAndroid Build Coastguard Worker	}
127*333d2b36SAndroid Build Coastguard Worker	cmd.FlagWithArg("--device-size=", size)
128*333d2b36SAndroid Build Coastguard Worker
129*333d2b36SAndroid Build Coastguard Worker	// TODO(jiyong): consider supporting A/B devices. Then we need to adjust num of slots.
130*333d2b36SAndroid Build Coastguard Worker	cmd.FlagWithArg("--metadata-slots=", "2")
131*333d2b36SAndroid Build Coastguard Worker	cmd.FlagWithArg("--metadata-size=", "65536")
132*333d2b36SAndroid Build Coastguard Worker
133*333d2b36SAndroid Build Coastguard Worker	if proptools.Bool(l.properties.Sparse) {
134*333d2b36SAndroid Build Coastguard Worker		cmd.Flag("--sparse")
135*333d2b36SAndroid Build Coastguard Worker	}
136*333d2b36SAndroid Build Coastguard Worker
137*333d2b36SAndroid Build Coastguard Worker	groupNames := make(map[string]bool)
138*333d2b36SAndroid Build Coastguard Worker	partitionNames := make(map[string]bool)
139*333d2b36SAndroid Build Coastguard Worker
140*333d2b36SAndroid Build Coastguard Worker	addPartitionsToGroup := func(partitions []partitionProperties, gName string) {
141*333d2b36SAndroid Build Coastguard Worker		for _, part := range partitions {
142*333d2b36SAndroid Build Coastguard Worker			pName := proptools.String(part.Name)
143*333d2b36SAndroid Build Coastguard Worker			if pName == "" {
144*333d2b36SAndroid Build Coastguard Worker				ctx.PropertyErrorf("groups.partitions.name", "must be set")
145*333d2b36SAndroid Build Coastguard Worker			}
146*333d2b36SAndroid Build Coastguard Worker			if _, ok := partitionNames[pName]; ok {
147*333d2b36SAndroid Build Coastguard Worker				ctx.PropertyErrorf("groups.partitions.name", "already exists")
148*333d2b36SAndroid Build Coastguard Worker			} else {
149*333d2b36SAndroid Build Coastguard Worker				partitionNames[pName] = true
150*333d2b36SAndroid Build Coastguard Worker			}
151*333d2b36SAndroid Build Coastguard Worker			// Get size of the partition by reading the -size.txt file
152*333d2b36SAndroid Build Coastguard Worker			var pSize string
153*333d2b36SAndroid Build Coastguard Worker			if size, hasSize := sparseImageSizes[pName]; hasSize {
154*333d2b36SAndroid Build Coastguard Worker				pSize = fmt.Sprintf("$(cat %s)", size)
155*333d2b36SAndroid Build Coastguard Worker			} else {
156*333d2b36SAndroid Build Coastguard Worker				pSize = "0"
157*333d2b36SAndroid Build Coastguard Worker			}
158*333d2b36SAndroid Build Coastguard Worker			cmd.FlagWithArg("--partition=", fmt.Sprintf("%s:readonly:%s:%s", pName, pSize, gName))
159*333d2b36SAndroid Build Coastguard Worker			if image, hasImage := sparseImages[pName]; hasImage {
160*333d2b36SAndroid Build Coastguard Worker				cmd.FlagWithInput("--image="+pName+"=", image)
161*333d2b36SAndroid Build Coastguard Worker			}
162*333d2b36SAndroid Build Coastguard Worker		}
163*333d2b36SAndroid Build Coastguard Worker	}
164*333d2b36SAndroid Build Coastguard Worker
165*333d2b36SAndroid Build Coastguard Worker	addPartitionsToGroup(l.properties.Default_group, "default")
166*333d2b36SAndroid Build Coastguard Worker
167*333d2b36SAndroid Build Coastguard Worker	for _, group := range l.properties.Groups {
168*333d2b36SAndroid Build Coastguard Worker		gName := proptools.String(group.Name)
169*333d2b36SAndroid Build Coastguard Worker		if gName == "" {
170*333d2b36SAndroid Build Coastguard Worker			ctx.PropertyErrorf("groups.name", "must be set")
171*333d2b36SAndroid Build Coastguard Worker		} else if gName == "default" {
172*333d2b36SAndroid Build Coastguard Worker			ctx.PropertyErrorf("groups.name", `can't use "default" as a group name. Use default_group instead`)
173*333d2b36SAndroid Build Coastguard Worker		}
174*333d2b36SAndroid Build Coastguard Worker		if _, ok := groupNames[gName]; ok {
175*333d2b36SAndroid Build Coastguard Worker			ctx.PropertyErrorf("group.name", "already exists")
176*333d2b36SAndroid Build Coastguard Worker		} else {
177*333d2b36SAndroid Build Coastguard Worker			groupNames[gName] = true
178*333d2b36SAndroid Build Coastguard Worker		}
179*333d2b36SAndroid Build Coastguard Worker		gSize := proptools.String(group.Size)
180*333d2b36SAndroid Build Coastguard Worker		if gSize == "" {
181*333d2b36SAndroid Build Coastguard Worker			ctx.PropertyErrorf("groups.size", "must be set")
182*333d2b36SAndroid Build Coastguard Worker		}
183*333d2b36SAndroid Build Coastguard Worker		if _, err := strconv.Atoi(gSize); err != nil {
184*333d2b36SAndroid Build Coastguard Worker			ctx.PropertyErrorf("groups.size", "must be a number")
185*333d2b36SAndroid Build Coastguard Worker		}
186*333d2b36SAndroid Build Coastguard Worker		cmd.FlagWithArg("--group=", gName+":"+gSize)
187*333d2b36SAndroid Build Coastguard Worker
188*333d2b36SAndroid Build Coastguard Worker		addPartitionsToGroup(group.Partitions, gName)
189*333d2b36SAndroid Build Coastguard Worker	}
190*333d2b36SAndroid Build Coastguard Worker
191*333d2b36SAndroid Build Coastguard Worker	output := android.PathForModuleOut(ctx, l.installFileName())
192*333d2b36SAndroid Build Coastguard Worker	cmd.FlagWithOutput("--output=", output)
193*333d2b36SAndroid Build Coastguard Worker
194*333d2b36SAndroid Build Coastguard Worker	builder.Build("build_logical_partition", fmt.Sprintf("Creating %s", l.BaseModuleName()))
195*333d2b36SAndroid Build Coastguard Worker
196*333d2b36SAndroid Build Coastguard Worker	l.installDir = android.PathForModuleInstall(ctx, "etc")
197*333d2b36SAndroid Build Coastguard Worker	ctx.InstallFile(l.installDir, l.installFileName(), output)
198*333d2b36SAndroid Build Coastguard Worker
199*333d2b36SAndroid Build Coastguard Worker	ctx.SetOutputFiles([]android.Path{output}, "")
200*333d2b36SAndroid Build Coastguard Worker	l.output = output
201*333d2b36SAndroid Build Coastguard Worker}
202*333d2b36SAndroid Build Coastguard Worker
203*333d2b36SAndroid Build Coastguard Worker// Add a rule that converts the filesystem for the given partition to the given rule builder. The
204*333d2b36SAndroid Build Coastguard Worker// path to the sparse file and the text file having the size of the partition are returned.
205*333d2b36SAndroid Build Coastguard Workerfunc sparseFilesystem(ctx android.ModuleContext, p partitionProperties, builder *android.RuleBuilder) (android.Path, android.Path) {
206*333d2b36SAndroid Build Coastguard Worker	img := android.PathForModuleSrc(ctx, *p.Filesystem)
207*333d2b36SAndroid Build Coastguard Worker	name := proptools.String(p.Name)
208*333d2b36SAndroid Build Coastguard Worker
209*333d2b36SAndroid Build Coastguard Worker	sparseImg := android.PathForModuleOut(ctx, name+".img")
210*333d2b36SAndroid Build Coastguard Worker	builder.Temporary(sparseImg)
211*333d2b36SAndroid Build Coastguard Worker	builder.Command().BuiltTool("img2simg").Input(img).Output(sparseImg)
212*333d2b36SAndroid Build Coastguard Worker
213*333d2b36SAndroid Build Coastguard Worker	sizeTxt := android.PathForModuleOut(ctx, name+"-size.txt")
214*333d2b36SAndroid Build Coastguard Worker	builder.Temporary(sizeTxt)
215*333d2b36SAndroid Build Coastguard Worker	builder.Command().BuiltTool("sparse_img").Flag("--get_partition_size").Input(sparseImg).
216*333d2b36SAndroid Build Coastguard Worker		Text("| ").Text("tr").FlagWithArg("-d ", "'\n'").
217*333d2b36SAndroid Build Coastguard Worker		Text("> ").Output(sizeTxt)
218*333d2b36SAndroid Build Coastguard Worker
219*333d2b36SAndroid Build Coastguard Worker	return sparseImg, sizeTxt
220*333d2b36SAndroid Build Coastguard Worker}
221*333d2b36SAndroid Build Coastguard Worker
222*333d2b36SAndroid Build Coastguard Workervar _ android.AndroidMkEntriesProvider = (*logicalPartition)(nil)
223*333d2b36SAndroid Build Coastguard Worker
224*333d2b36SAndroid Build Coastguard Worker// Implements android.AndroidMkEntriesProvider
225*333d2b36SAndroid Build Coastguard Workerfunc (l *logicalPartition) AndroidMkEntries() []android.AndroidMkEntries {
226*333d2b36SAndroid Build Coastguard Worker	return []android.AndroidMkEntries{android.AndroidMkEntries{
227*333d2b36SAndroid Build Coastguard Worker		Class:      "ETC",
228*333d2b36SAndroid Build Coastguard Worker		OutputFile: android.OptionalPathForPath(l.output),
229*333d2b36SAndroid Build Coastguard Worker		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
230*333d2b36SAndroid Build Coastguard Worker			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
231*333d2b36SAndroid Build Coastguard Worker				entries.SetString("LOCAL_MODULE_PATH", l.installDir.String())
232*333d2b36SAndroid Build Coastguard Worker				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", l.installFileName())
233*333d2b36SAndroid Build Coastguard Worker			},
234*333d2b36SAndroid Build Coastguard Worker		},
235*333d2b36SAndroid Build Coastguard Worker	}}
236*333d2b36SAndroid Build Coastguard Worker}
237*333d2b36SAndroid Build Coastguard Worker
238*333d2b36SAndroid Build Coastguard Workervar _ Filesystem = (*logicalPartition)(nil)
239*333d2b36SAndroid Build Coastguard Worker
240*333d2b36SAndroid Build Coastguard Workerfunc (l *logicalPartition) OutputPath() android.Path {
241*333d2b36SAndroid Build Coastguard Worker	return l.output
242*333d2b36SAndroid Build Coastguard Worker}
243*333d2b36SAndroid Build Coastguard Worker
244*333d2b36SAndroid Build Coastguard Workerfunc (l *logicalPartition) SignedOutputPath() android.Path {
245*333d2b36SAndroid Build Coastguard Worker	return nil // logical partition is not signed by itself
246*333d2b36SAndroid Build Coastguard Worker}
247