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