blob: 594c40482d1e6793ffa8ca9a39d2f1b5cb65f876 [file] [log] [blame]
Cole Faust3552eb62024-11-06 18:07:26 -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 fsgen
16
17import (
18 "android/soong/android"
19 "android/soong/filesystem"
Cole Faust3552eb62024-11-06 18:07:26 -080020 "strconv"
21
22 "github.com/google/blueprint/proptools"
23)
24
25type vbmetaModuleInfo struct {
26 // The name of the generated vbmeta module
27 moduleName string
28 // The name of the module that avb understands. This is the name passed to --chain_partition,
29 // and also the basename of the output file. (the output file is called partitionName + ".img")
30 partitionName string
31}
32
Jihoon Kang2f0d1932025-01-17 19:22:44 +000033// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4849;drc=62e20f0d218f60bae563b4ee742d88cca1fc1901
34var avbPartitions = []string{
35 "boot",
36 "init_boot",
37 "vendor_boot",
38 "vendor_kernel_boot",
39 "system",
40 "vendor",
41 "product",
42 "system_ext",
43 "odm",
44 "vendor_dlkm",
45 "odm_dlkm",
46 "system_dlkm",
47 "dtbo",
48 "pvmfw",
49 "recovery",
50 "vbmeta_system",
51 "vbmeta_vendor",
52}
53
Cole Faust3552eb62024-11-06 18:07:26 -080054// Creates the vbmeta partition and the chained vbmeta partitions. Returns the list of module names
55// that the function created. May return nil if the product isn't using avb.
56//
57// AVB is Android Verified Boot: https://source.android.com/docs/security/features/verifiedboot
58// It works by signing all the partitions, but then also including an extra metadata paritition
59// called vbmeta that depends on all the other signed partitions. This creates a requirement
60// that you update all those partitions and the vbmeta partition together, so in order to relax
61// that requirement products can set up "chained" vbmeta partitions, where a chained partition
62// like vbmeta_system might contain the avb metadata for just a few products. In cuttlefish
63// vbmeta_system contains metadata about product, system, and system_ext. Using chained partitions,
64// that group of partitions can be updated independently from the other signed partitions.
Cole Faust76e8aa12025-01-27 18:21:31 -080065func (f *filesystemCreator) createVbmetaPartitions(ctx android.LoadHookContext, partitions allGeneratedPartitionData) []vbmetaModuleInfo {
Cole Faust3552eb62024-11-06 18:07:26 -080066 partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
67 // Some products seem to have BuildingVbmetaImage as true even when BoardAvbEnable is false
68 if !partitionVars.BuildingVbmetaImage || !partitionVars.BoardAvbEnable {
69 return nil
70 }
71
72 var result []vbmetaModuleInfo
73
Jihoon Kang2f0d1932025-01-17 19:22:44 +000074 // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4593;drc=62e20f0d218f60bae563b4ee742d88cca1fc1901
75 var internalAvbPartitionsInChainedVbmetaImages []string
76 var chainedPartitionTypes []string
Cole Faust481a7252024-11-13 11:46:22 -080077 for _, chainedName := range android.SortedKeys(partitionVars.ChainedVbmetaPartitions) {
78 props := partitionVars.ChainedVbmetaPartitions[chainedName]
Spandan Das1bf169a2025-03-21 16:56:06 +000079 filesystemPartitionType := chainedName
Cole Faust3552eb62024-11-06 18:07:26 -080080 chainedName = "vbmeta_" + chainedName
81 if len(props.Partitions) == 0 {
82 continue
83 }
Jihoon Kang2f0d1932025-01-17 19:22:44 +000084 internalAvbPartitionsInChainedVbmetaImages = append(internalAvbPartitionsInChainedVbmetaImages, props.Partitions...)
Cole Faust3552eb62024-11-06 18:07:26 -080085 if len(props.Key) == 0 {
86 ctx.ModuleErrorf("No key found for chained avb partition %q", chainedName)
87 continue
88 }
89 if len(props.Algorithm) == 0 {
90 ctx.ModuleErrorf("No algorithm found for chained avb partition %q", chainedName)
91 continue
92 }
93 if len(props.RollbackIndex) == 0 {
94 ctx.ModuleErrorf("No rollback index found for chained avb partition %q", chainedName)
95 continue
96 }
97 ril, err := strconv.ParseInt(props.RollbackIndexLocation, 10, 32)
98 if err != nil {
99 ctx.ModuleErrorf("Rollback index location must be an int, got %q", props.RollbackIndexLocation)
100 continue
101 }
102 // The default is to use the PlatformSecurityPatch, and a lot of product config files
103 // just set it to the platform security patch, so detect that and don't set the property
104 // in soong.
105 var rollbackIndex *int64
106 if props.RollbackIndex != ctx.Config().PlatformSecurityPatch() {
107 i, err := strconv.ParseInt(props.RollbackIndex, 10, 32)
108 if err != nil {
109 ctx.ModuleErrorf("Rollback index must be an int, got %q", props.RollbackIndex)
110 continue
111 }
112 rollbackIndex = &i
113 }
114
115 var partitionModules []string
116 for _, partition := range props.Partitions {
Cole Faust76e8aa12025-01-27 18:21:31 -0800117 if modName := partitions.nameForType(partition); modName != "" {
118 partitionModules = append(partitionModules, modName)
Cole Faust3552eb62024-11-06 18:07:26 -0800119 }
Cole Faust3552eb62024-11-06 18:07:26 -0800120 }
121
Jihoon Kang2f0d1932025-01-17 19:22:44 +0000122 name := generatedModuleNameForPartition(ctx.Config(), chainedName)
Cole Faust3552eb62024-11-06 18:07:26 -0800123 ctx.CreateModuleInDirectory(
124 filesystem.VbmetaFactory,
125 ".", // Create in the root directory for now so its easy to get the key
126 &filesystem.VbmetaProperties{
Spandan Das1bf169a2025-03-21 16:56:06 +0000127 Partition_name: proptools.StringPtr(chainedName),
128 Filesystem_partition_type: proptools.StringPtr(filesystemPartitionType),
129 Stem: proptools.StringPtr(chainedName + ".img"),
130 Private_key: proptools.StringPtr(props.Key),
131 Algorithm: &props.Algorithm,
132 Rollback_index: rollbackIndex,
133 Rollback_index_location: &ril,
134 Partitions: proptools.NewSimpleConfigurable(partitionModules),
Cole Faust3552eb62024-11-06 18:07:26 -0800135 }, &struct {
136 Name *string
137 }{
138 Name: &name,
139 },
140 ).HideFromMake()
141
Cole Faust3552eb62024-11-06 18:07:26 -0800142 result = append(result, vbmetaModuleInfo{
143 moduleName: name,
144 partitionName: chainedName,
145 })
Jihoon Kang2f0d1932025-01-17 19:22:44 +0000146
147 chainedPartitionTypes = append(chainedPartitionTypes, chainedName)
Cole Faust3552eb62024-11-06 18:07:26 -0800148 }
149
Jihoon Kang2f0d1932025-01-17 19:22:44 +0000150 vbmetaModuleName := generatedModuleNameForPartition(ctx.Config(), "vbmeta")
Cole Faust3552eb62024-11-06 18:07:26 -0800151
152 var algorithm *string
153 var ri *int64
154 var key *string
155 if len(partitionVars.BoardAvbKeyPath) == 0 {
156 // Match make's defaults: https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4568;drc=5b55f926830963c02ab1d2d91e46442f04ba3af0
157 key = proptools.StringPtr("external/avb/test/data/testkey_rsa4096.pem")
158 algorithm = proptools.StringPtr("SHA256_RSA4096")
159 } else {
160 key = proptools.StringPtr(partitionVars.BoardAvbKeyPath)
161 algorithm = proptools.StringPtr(partitionVars.BoardAvbAlgorithm)
162 }
163 if len(partitionVars.BoardAvbRollbackIndex) > 0 {
164 parsedRi, err := strconv.ParseInt(partitionVars.BoardAvbRollbackIndex, 10, 32)
165 if err != nil {
166 ctx.ModuleErrorf("Rollback index location must be an int, got %q", partitionVars.BoardAvbRollbackIndex)
167 }
168 ri = &parsedRi
169 }
170
Jihoon Kang2f0d1932025-01-17 19:22:44 +0000171 // --chain_partition argument is only set for partitions that set
172 // `BOARD_AVB_<partition name>_KEY_PATH` value and is not "recovery"
173 // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4823;drc=62e20f0d218f60bae563b4ee742d88cca1fc1901
174 includeAsChainedPartitionInVbmeta := func(partition string) bool {
175 val, ok := partitionVars.PartitionQualifiedVariables[partition]
176 return ok && len(val.BoardAvbKeyPath) > 0 && partition != "recovery"
177 }
178
179 // --include_descriptors_from_image is passed if both conditions are met:
180 // - `BOARD_AVB_<partition name>_KEY_PATH` value is not set
181 // - not included in INTERNAL_AVB_PARTITIONS_IN_CHAINED_VBMETA_IMAGES
182 // for partitions that set INSTALLED_<partition name>IMAGE_TARGET
183 // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4827;drc=62e20f0d218f60bae563b4ee742d88cca1fc1901
184 includeAsIncludedPartitionInVbmeta := func(partition string) bool {
185 if android.InList(partition, internalAvbPartitionsInChainedVbmetaImages) {
186 // Already handled by chained vbmeta partitions
187 return false
188 }
189 partitionQualifiedVars := partitionVars.PartitionQualifiedVariables[partition]
190
191 // The return logic in the switch cases below are identical to
192 // ifdef INSTALLED_<partition name>IMAGE_TARGET
193 switch partition {
194 case "boot":
195 return partitionQualifiedVars.BuildingImage || partitionQualifiedVars.PrebuiltImage || partitionVars.BoardUsesRecoveryAsBoot
196 case "vendor_kernel_boot", "dtbo":
197 return partitionQualifiedVars.PrebuiltImage
198 case "system":
199 return partitionQualifiedVars.BuildingImage
200 case "init_boot", "vendor_boot", "vendor", "product", "system_ext", "odm", "vendor_dlkm", "odm_dlkm", "system_dlkm":
201 return partitionQualifiedVars.BuildingImage || partitionQualifiedVars.PrebuiltImage
202 // TODO: Import BOARD_USES_PVMFWIMAGE
203 // ifeq ($(BOARD_USES_PVMFWIMAGE),true)
204 // case "pvmfw":
205 case "recovery":
206 // ifdef INSTALLED_RECOVERYIMAGE_TARGET
207 return !ctx.DeviceConfig().BoardUsesRecoveryAsBoot() && !ctx.DeviceConfig().BoardMoveRecoveryResourcesToVendorBoot()
208 // Technically these partitions are determined based on len(BOARD_AVB_VBMETA_SYSTEM) and
209 // len(BOARD_AVB_VBMETA_VENDOR) but if these are non empty these partitions are
210 // already included in the chained partitions.
211 case "vbmeta_system", "vbmeta_vendor":
212 return false
213 default:
214 return false
215 }
216 }
217
218 var chainedPartitionModules []string
219 var includePartitionModules []string
Cole Faust76e8aa12025-01-27 18:21:31 -0800220 allGeneratedPartitionTypes := append(partitions.types(),
Jihoon Kang2f0d1932025-01-17 19:22:44 +0000221 chainedPartitionTypes...,
222 )
223 if len(f.properties.Boot_image) > 0 {
224 allGeneratedPartitionTypes = append(allGeneratedPartitionTypes, "boot")
225 }
226 if len(f.properties.Init_boot_image) > 0 {
227 allGeneratedPartitionTypes = append(allGeneratedPartitionTypes, "init_boot")
228 }
229 if len(f.properties.Vendor_boot_image) > 0 {
230 allGeneratedPartitionTypes = append(allGeneratedPartitionTypes, "vendor_boot")
231 }
232
233 // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4919;drc=62e20f0d218f60bae563b4ee742d88cca1fc1901
234 for _, partitionType := range android.SortedUniqueStrings(append(avbPartitions, chainedPartitionTypes...)) {
235 if !android.InList(partitionType, allGeneratedPartitionTypes) {
236 // Skip if the partition is not auto generated
Cole Faust3552eb62024-11-06 18:07:26 -0800237 continue
238 }
Cole Faustf1fcf172025-01-30 15:54:41 -0800239 name := partitions.nameForType(partitionType)
240 if name == "" {
241 name = generatedModuleNameForPartition(ctx.Config(), partitionType)
242 }
Jihoon Kang2f0d1932025-01-17 19:22:44 +0000243 if includeAsChainedPartitionInVbmeta(partitionType) {
Cole Faustf1fcf172025-01-30 15:54:41 -0800244 chainedPartitionModules = append(chainedPartitionModules, name)
Jihoon Kang2f0d1932025-01-17 19:22:44 +0000245 } else if includeAsIncludedPartitionInVbmeta(partitionType) {
Cole Faustf1fcf172025-01-30 15:54:41 -0800246 includePartitionModules = append(includePartitionModules, name)
Cole Faust76a6e952024-11-07 16:56:45 -0800247 }
Cole Faust3552eb62024-11-06 18:07:26 -0800248 }
249
250 ctx.CreateModuleInDirectory(
251 filesystem.VbmetaFactory,
252 ".", // Create in the root directory for now so its easy to get the key
253 &filesystem.VbmetaProperties{
254 Stem: proptools.StringPtr("vbmeta.img"),
255 Algorithm: algorithm,
256 Private_key: key,
257 Rollback_index: ri,
Jihoon Kang2f0d1932025-01-17 19:22:44 +0000258 Chained_partitions: chainedPartitionModules,
259 Partitions: proptools.NewSimpleConfigurable(includePartitionModules),
Cole Faust11fda332025-01-14 16:47:19 -0800260 Partition_name: proptools.StringPtr("vbmeta"),
Cole Faust3552eb62024-11-06 18:07:26 -0800261 }, &struct {
262 Name *string
263 }{
264 Name: &vbmetaModuleName,
265 },
266 ).HideFromMake()
267
268 result = append(result, vbmetaModuleInfo{
269 moduleName: vbmetaModuleName,
270 partitionName: "vbmeta",
271 })
272 return result
273}