blob: 20d9622dca6a0aefd119136c4db515b977087275 [file] [log] [blame]
Jiyong Parkb89e5e72021-02-24 01:41:21 +09001// Copyright (C) 2021 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 "strconv"
20
21 "github.com/google/blueprint/proptools"
22
23 "android/soong/android"
24)
25
26func init() {
27 android.RegisterModuleType("logical_partition", logicalPartitionFactory)
28}
29
30type logicalPartition struct {
31 android.ModuleBase
32
33 properties logicalPartitionProperties
34
35 output android.OutputPath
36 installDir android.InstallPath
37}
38
39type logicalPartitionProperties struct {
40 // Set the name of the output. Defaults to <module_name>.img.
41 Stem *string
42
43 // Total size of the logical partition
44 Size *string
45
46 // List of groups. A group defines a fixed sized region. It can host one or more logical
47 // partitions and their total size is limited by the size of the group they are in.
48 Groups []groupProperties
49
50 // Whether the output is a sparse image or not. Default is false.
51 Sparse *bool
52}
53
54type groupProperties struct {
55 // Name of the partition group
56 Name *string
57
58 // Size of the partition group
59 Size *string
60
61 // List of logical partitions in this group
62 Partitions []partitionProperties
63}
64
65type partitionProperties struct {
66 // Name of the partition
67 Name *string
68
69 // Filesystem that is placed on the partition
70 Filesystem *string `android:"path"`
71}
72
73// logical_partition is a partition image which has one or more logical partitions in it.
74func logicalPartitionFactory() android.Module {
75 module := &logicalPartition{}
76 module.AddProperties(&module.properties)
77 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
78 return module
79}
80
81func (l *logicalPartition) DepsMutator(ctx android.BottomUpMutatorContext) {
82 // do nothing
83}
84
85func (l *logicalPartition) installFileName() string {
86 return proptools.StringDefault(l.properties.Stem, l.BaseModuleName()+".img")
87}
88
89func (l *logicalPartition) GenerateAndroidBuildActions(ctx android.ModuleContext) {
90 builder := android.NewRuleBuilder(pctx, ctx)
91
92 // Sparse the filesystem images and calculate their sizes
93 sparseImages := make(map[string]android.OutputPath)
94 sparseImageSizes := make(map[string]android.OutputPath)
95 for _, group := range l.properties.Groups {
96 for _, part := range group.Partitions {
97 sparseImg, sizeTxt := sparseFilesystem(ctx, part, builder)
98 pName := proptools.String(part.Name)
99 sparseImages[pName] = sparseImg
100 sparseImageSizes[pName] = sizeTxt
101 }
102 }
103
104 cmd := builder.Command().BuiltTool("lpmake")
105
106 size := proptools.String(l.properties.Size)
107 if size == "" {
108 ctx.PropertyErrorf("size", "must be set")
109 }
110 if _, err := strconv.Atoi(size); err != nil {
111 ctx.PropertyErrorf("size", "must be a number")
112 }
113 cmd.FlagWithArg("--device-size=", size)
114
115 // TODO(jiyong): consider supporting A/B devices. Then we need to adjust num of slots.
116 cmd.FlagWithArg("--metadata-slots=", "2")
117 cmd.FlagWithArg("--metadata-size=", "65536")
118
119 if proptools.Bool(l.properties.Sparse) {
120 cmd.Flag("--sparse")
121 }
122
123 groupNames := make(map[string]bool)
124 partitionNames := make(map[string]bool)
125
126 for _, group := range l.properties.Groups {
127 gName := proptools.String(group.Name)
128 if gName == "" {
129 ctx.PropertyErrorf("groups.name", "must be set")
130 }
131 if _, ok := groupNames[gName]; ok {
132 ctx.PropertyErrorf("group.name", "already exists")
133 } else {
134 groupNames[gName] = true
135 }
136 gSize := proptools.String(group.Size)
137 if gSize == "" {
138 ctx.PropertyErrorf("groups.size", "must be set")
139 }
140 if _, err := strconv.Atoi(gSize); err != nil {
141 ctx.PropertyErrorf("groups.size", "must be a number")
142 }
143 cmd.FlagWithArg("--group=", gName+":"+gSize)
144
145 for _, part := range group.Partitions {
146 pName := proptools.String(part.Name)
147 if pName == "" {
148 ctx.PropertyErrorf("groups.partitions.name", "must be set")
149 }
150 if _, ok := partitionNames[pName]; ok {
151 ctx.PropertyErrorf("groups.partitions.name", "already exists")
152 } else {
153 partitionNames[pName] = true
154 }
155 // Get size of the partition by reading the -size.txt file
156 pSize := fmt.Sprintf("$(cat %s)", sparseImageSizes[pName])
157 cmd.FlagWithArg("--partition=", fmt.Sprintf("%s:readonly:%s:%s", pName, pSize, gName))
158 cmd.FlagWithInput("--image="+pName+"=", sparseImages[pName])
159 }
160 }
161
162 l.output = android.PathForModuleOut(ctx, l.installFileName()).OutputPath
163 cmd.FlagWithOutput("--output=", l.output)
164
165 builder.Build("build_logical_partition", fmt.Sprintf("Creating %s", l.BaseModuleName()))
166
167 l.installDir = android.PathForModuleInstall(ctx, "etc")
168 ctx.InstallFile(l.installDir, l.installFileName(), l.output)
169}
170
171// Add a rule that converts the filesystem for the given partition to the given rule builder. The
172// path to the sparse file and the text file having the size of the partition are returned.
173func sparseFilesystem(ctx android.ModuleContext, p partitionProperties, builder *android.RuleBuilder) (sparseImg android.OutputPath, sizeTxt android.OutputPath) {
174 img := android.PathForModuleSrc(ctx, proptools.String(p.Filesystem))
175 name := proptools.String(p.Name)
176 sparseImg = android.PathForModuleOut(ctx, name+".img").OutputPath
177
178 builder.Temporary(sparseImg)
179 builder.Command().BuiltTool("img2simg").Input(img).Output(sparseImg)
180
181 sizeTxt = android.PathForModuleOut(ctx, name+"-size.txt").OutputPath
182 builder.Temporary(sizeTxt)
183 builder.Command().BuiltTool("sparse_img").Flag("--get_partition_size").Input(sparseImg).
184 Text("| ").Text("tr").FlagWithArg("-d ", "'\n'").
185 Text("> ").Output(sizeTxt)
186
187 return sparseImg, sizeTxt
188}
189
190var _ android.AndroidMkEntriesProvider = (*logicalPartition)(nil)
191
192// Implements android.AndroidMkEntriesProvider
193func (l *logicalPartition) AndroidMkEntries() []android.AndroidMkEntries {
194 return []android.AndroidMkEntries{android.AndroidMkEntries{
195 Class: "ETC",
196 OutputFile: android.OptionalPathForPath(l.output),
197 ExtraEntries: []android.AndroidMkExtraEntriesFunc{
198 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
199 entries.SetString("LOCAL_MODULE_PATH", l.installDir.ToMakePath().String())
200 entries.SetString("LOCAL_INSTALLED_MODULE_STEM", l.installFileName())
201 },
202 },
203 }}
204}
205
206var _ Filesystem = (*logicalPartition)(nil)
207
208func (l *logicalPartition) OutputPath() android.Path {
209 return l.output
210}
Jiyong Parkb0eb3192021-03-09 20:29:07 +0900211
Jiyong Park972e06c2021-03-15 23:32:49 +0900212func (l *logicalPartition) SignedOutputPath() android.Path {
213 return nil // logical partition is not signed by itself
214}
215
Jiyong Parkb0eb3192021-03-09 20:29:07 +0900216var _ android.OutputFileProducer = (*logicalPartition)(nil)
217
218// Implements android.OutputFileProducer
219func (l *logicalPartition) OutputFiles(tag string) (android.Paths, error) {
220 if tag == "" {
221 return []android.Path{l.output}, nil
222 }
223 return nil, fmt.Errorf("unsupported module reference tag %q", tag)
224}