blob: f21774443cfed006896b12ba5632be99d4c950e7 [file] [log] [blame]
Jihoon Kangadd2bb22024-11-05 22:29:34 +00001// 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/etc"
20 "fmt"
21 "path/filepath"
22 "strings"
23
24 "github.com/google/blueprint/proptools"
25)
26
27type srcBaseFileInstallBaseFileTuple struct {
28 srcBaseFile string
29 installBaseFile string
30}
31
32// prebuilt src files grouped by the install partitions.
33// Each groups are a mapping of the relative install path to the name of the files
34type prebuiltSrcGroupByInstallPartition struct {
35 system map[string][]srcBaseFileInstallBaseFileTuple
36 system_ext map[string][]srcBaseFileInstallBaseFileTuple
37 product map[string][]srcBaseFileInstallBaseFileTuple
38 vendor map[string][]srcBaseFileInstallBaseFileTuple
39}
40
41func newPrebuiltSrcGroupByInstallPartition() *prebuiltSrcGroupByInstallPartition {
42 return &prebuiltSrcGroupByInstallPartition{
43 system: map[string][]srcBaseFileInstallBaseFileTuple{},
44 system_ext: map[string][]srcBaseFileInstallBaseFileTuple{},
45 product: map[string][]srcBaseFileInstallBaseFileTuple{},
46 vendor: map[string][]srcBaseFileInstallBaseFileTuple{},
47 }
48}
49
50func isSubdirectory(parent, child string) bool {
51 rel, err := filepath.Rel(parent, child)
52 if err != nil {
53 return false
54 }
55 return !strings.HasPrefix(rel, "..")
56}
57
58func appendIfCorrectInstallPartition(partitionToInstallPathList []partitionToInstallPath, destPath, srcPath string, srcGroup *prebuiltSrcGroupByInstallPartition) {
59 for _, part := range partitionToInstallPathList {
60 partition := part.name
61 installPath := part.installPath
62
63 if isSubdirectory(installPath, destPath) {
64 relativeInstallPath, _ := filepath.Rel(installPath, destPath)
65 relativeInstallDir := filepath.Dir(relativeInstallPath)
66 var srcMap map[string][]srcBaseFileInstallBaseFileTuple
67 switch partition {
68 case "system":
69 srcMap = srcGroup.system
70 case "system_ext":
71 srcMap = srcGroup.system_ext
72 case "product":
73 srcMap = srcGroup.product
74 case "vendor":
75 srcMap = srcGroup.vendor
76 }
77 if srcMap != nil {
78 srcMap[relativeInstallDir] = append(srcMap[relativeInstallDir], srcBaseFileInstallBaseFileTuple{
79 srcBaseFile: filepath.Base(srcPath),
80 installBaseFile: filepath.Base(destPath),
81 })
82 }
83 return
84 }
85 }
86}
87
Jihoon Kang3a8759c2024-11-08 19:35:09 +000088// Create a map of source files to the list of destination files from PRODUCT_COPY_FILES entries.
89// Note that the value of the map is a list of string, given that a single source file can be
90// copied to multiple files.
91// This function also checks the existence of the source files, and validates that there is no
92// multiple source files copying to the same dest file.
93func uniqueExistingProductCopyFileMap(ctx android.LoadHookContext) map[string][]string {
Jihoon Kangadd2bb22024-11-05 22:29:34 +000094 seen := make(map[string]bool)
Jihoon Kang3a8759c2024-11-08 19:35:09 +000095 filtered := make(map[string][]string)
Jihoon Kangadd2bb22024-11-05 22:29:34 +000096
Jihoon Kang3a8759c2024-11-08 19:35:09 +000097 for _, copyFilePair := range ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.ProductCopyFiles {
98 srcDestList := strings.Split(copyFilePair, ":")
99 if len(srcDestList) < 2 {
100 ctx.ModuleErrorf("PRODUCT_COPY_FILES must follow the format \"src:dest\", got: %s", copyFilePair)
101 }
102 src, dest := srcDestList[0], srcDestList[1]
Jihoon Kangf27c3a52024-11-12 21:27:09 +0000103
104 // Some downstream branches use absolute path as entries in PRODUCT_COPY_FILES.
105 // Convert them to relative path from top and check if they do not escape the tree root.
106 relSrc := android.ToRelativeSourcePath(ctx, src)
107
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000108 if _, ok := seen[dest]; !ok {
Jihoon Kangf27c3a52024-11-12 21:27:09 +0000109 if optionalPath := android.ExistentPathForSource(ctx, relSrc); optionalPath.Valid() {
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000110 seen[dest] = true
Jihoon Kangf27c3a52024-11-12 21:27:09 +0000111 filtered[relSrc] = append(filtered[relSrc], dest)
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000112 }
113 }
114 }
115
116 return filtered
117}
118
119type partitionToInstallPath struct {
120 name string
121 installPath string
122}
123
124func processProductCopyFiles(ctx android.LoadHookContext) map[string]*prebuiltSrcGroupByInstallPartition {
125 // Filter out duplicate dest entries and non existing src entries
126 productCopyFileMap := uniqueExistingProductCopyFileMap(ctx)
127
128 // System is intentionally added at the last to consider the scenarios where
129 // non-system partitions are installed as part of the system partition
130 partitionToInstallPathList := []partitionToInstallPath{
131 {name: "vendor", installPath: ctx.DeviceConfig().VendorPath()},
132 {name: "product", installPath: ctx.DeviceConfig().ProductPath()},
133 {name: "system_ext", installPath: ctx.DeviceConfig().SystemExtPath()},
134 {name: "system", installPath: "system"},
135 }
136
137 groupedSources := map[string]*prebuiltSrcGroupByInstallPartition{}
138 for _, src := range android.SortedKeys(productCopyFileMap) {
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000139 destFiles := productCopyFileMap[src]
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000140 srcFileDir := filepath.Dir(src)
141 if _, ok := groupedSources[srcFileDir]; !ok {
142 groupedSources[srcFileDir] = newPrebuiltSrcGroupByInstallPartition()
143 }
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000144 for _, dest := range destFiles {
145 appendIfCorrectInstallPartition(partitionToInstallPathList, dest, filepath.Base(src), groupedSources[srcFileDir])
146 }
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000147 }
148
149 return groupedSources
150}
151
152type prebuiltModuleProperties struct {
153 Name *string
154
155 Soc_specific *bool
156 Product_specific *bool
157 System_ext_specific *bool
158
159 Srcs []string
160 Dsts []string
161
162 No_full_install *bool
163
164 NamespaceExportedToMake bool
165
166 Visibility []string
167}
168
169// Split relative_install_path to a separate struct, because it is not supported for every
170// modules listed in [etcInstallPathToFactoryMap]
171type prebuiltSubdirProperties struct {
172 // If the base file name of the src and dst all match, dsts property does not need to be
173 // set, and only relative_install_path can be set.
174 Relative_install_path *string
175}
176
177var (
178 etcInstallPathToFactoryList = map[string]android.ModuleFactory{
179 "": etc.PrebuiltRootFactory,
180 "avb": etc.PrebuiltAvbFactory,
181 "bin": etc.PrebuiltBinaryFactory,
182 "bt_firmware": etc.PrebuiltBtFirmwareFactory,
183 "cacerts": etc.PrebuiltEtcCaCertsFactory,
184 "dsp": etc.PrebuiltDSPFactory,
185 "etc": etc.PrebuiltEtcFactory,
186 "etc/dsp": etc.PrebuiltDSPFactory,
187 "etc/firmware": etc.PrebuiltFirmwareFactory,
188 "firmware": etc.PrebuiltFirmwareFactory,
189 "fonts": etc.PrebuiltFontFactory,
190 "framework": etc.PrebuiltFrameworkFactory,
191 "lib": etc.PrebuiltRenderScriptBitcodeFactory,
192 "lib64": etc.PrebuiltRenderScriptBitcodeFactory,
193 "lib/rfsa": etc.PrebuiltRFSAFactory,
194 "media": etc.PrebuiltMediaFactory,
195 "odm": etc.PrebuiltOdmFactory,
Jihoon Kangdca2f2b2024-11-06 18:43:19 +0000196 "optee": etc.PrebuiltOpteeFactory,
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000197 "overlay": etc.PrebuiltOverlayFactory,
198 "priv-app": etc.PrebuiltPrivAppFactory,
199 "res": etc.PrebuiltResFactory,
200 "rfs": etc.PrebuiltRfsFactory,
201 "tts": etc.PrebuiltVoicepackFactory,
Jihoon Kangecf76dd2024-11-12 05:24:46 +0000202 "tvconfig": etc.PrebuiltTvConfigFactory,
Jihoon Kangdca2f2b2024-11-06 18:43:19 +0000203 "tvservice": etc.PrebuiltTvServiceFactory,
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000204 "usr/share": etc.PrebuiltUserShareFactory,
205 "usr/hyphen-data": etc.PrebuiltUserHyphenDataFactory,
206 "usr/keylayout": etc.PrebuiltUserKeyLayoutFactory,
207 "usr/keychars": etc.PrebuiltUserKeyCharsFactory,
208 "usr/srec": etc.PrebuiltUserSrecFactory,
209 "usr/idc": etc.PrebuiltUserIdcFactory,
Jihoon Kang3ca07a12024-12-02 19:14:30 +0000210 "vendor": etc.PrebuiltVendorFactory,
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000211 "vendor_dlkm": etc.PrebuiltVendorDlkmFactory,
212 "wallpaper": etc.PrebuiltWallpaperFactory,
213 "wlc_upt": etc.PrebuiltWlcUptFactory,
214 }
215)
216
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000217func generatedPrebuiltEtcModuleName(partition, srcDir, destDir string, count int) string {
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000218 // generated module name follows the pattern:
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000219 // <install partition>-<src file path>-<relative install path from partition root>-<number>
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000220 // Note that all path separators are replaced with "_" in the name
221 moduleName := partition
222 if !android.InList(srcDir, []string{"", "."}) {
223 moduleName += fmt.Sprintf("-%s", strings.ReplaceAll(srcDir, string(filepath.Separator), "_"))
224 }
225 if !android.InList(destDir, []string{"", "."}) {
226 moduleName += fmt.Sprintf("-%s", strings.ReplaceAll(destDir, string(filepath.Separator), "_"))
227 }
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000228 moduleName += fmt.Sprintf("-%d", count)
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000229
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000230 return moduleName
231}
232
233func groupDestFilesBySrc(destFiles []srcBaseFileInstallBaseFileTuple) (ret map[string][]srcBaseFileInstallBaseFileTuple, maxLen int) {
234 ret = map[string][]srcBaseFileInstallBaseFileTuple{}
235 maxLen = 0
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000236 for _, tuple := range destFiles {
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000237 if _, ok := ret[tuple.srcBaseFile]; !ok {
238 ret[tuple.srcBaseFile] = []srcBaseFileInstallBaseFileTuple{}
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000239 }
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000240 ret[tuple.srcBaseFile] = append(ret[tuple.srcBaseFile], tuple)
241 maxLen = max(maxLen, len(ret[tuple.srcBaseFile]))
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000242 }
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000243 return ret, maxLen
244}
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000245
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000246func prebuiltEtcModuleProps(moduleName, partition string) prebuiltModuleProperties {
247 moduleProps := prebuiltModuleProperties{}
248 moduleProps.Name = proptools.StringPtr(moduleName)
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000249
250 // Set partition specific properties
251 switch partition {
252 case "system_ext":
253 moduleProps.System_ext_specific = proptools.BoolPtr(true)
254 case "product":
255 moduleProps.Product_specific = proptools.BoolPtr(true)
256 case "vendor":
257 moduleProps.Soc_specific = proptools.BoolPtr(true)
258 }
259
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000260 moduleProps.No_full_install = proptools.BoolPtr(true)
261 moduleProps.NamespaceExportedToMake = true
262 moduleProps.Visibility = []string{"//visibility:public"}
263
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000264 return moduleProps
265}
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000266
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000267func createPrebuiltEtcModulesInDirectory(ctx android.LoadHookContext, partition, srcDir, destDir string, destFiles []srcBaseFileInstallBaseFileTuple) (moduleNames []string) {
268 groupedDestFiles, maxLen := groupDestFilesBySrc(destFiles)
269
270 // Find out the most appropriate module type to generate
271 var etcInstallPathKey string
272 for _, etcInstallPath := range android.SortedKeys(etcInstallPathToFactoryList) {
273 // Do not break when found but iterate until the end to find a module with more
274 // specific install path
275 if strings.HasPrefix(destDir, etcInstallPath) {
276 etcInstallPathKey = etcInstallPath
277 }
278 }
279 relDestDirFromInstallDirBase, _ := filepath.Rel(etcInstallPathKey, destDir)
280
281 for fileIndex := range maxLen {
282 srcTuple := []srcBaseFileInstallBaseFileTuple{}
Jihoon Kang47dadd92024-11-13 01:00:57 +0000283 for _, srcFile := range android.SortedKeys(groupedDestFiles) {
284 groupedDestFile := groupedDestFiles[srcFile]
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000285 if len(groupedDestFile) > fileIndex {
286 srcTuple = append(srcTuple, groupedDestFile[fileIndex])
287 }
288 }
289
290 moduleName := generatedPrebuiltEtcModuleName(partition, srcDir, destDir, fileIndex)
291 moduleProps := prebuiltEtcModuleProps(moduleName, partition)
292 modulePropsPtr := &moduleProps
293 propsList := []interface{}{modulePropsPtr}
294
295 allCopyFileNamesUnchanged := true
296 var srcBaseFiles, installBaseFiles []string
297 for _, tuple := range srcTuple {
298 if tuple.srcBaseFile != tuple.installBaseFile {
299 allCopyFileNamesUnchanged = false
300 }
301 srcBaseFiles = append(srcBaseFiles, tuple.srcBaseFile)
302 installBaseFiles = append(installBaseFiles, tuple.installBaseFile)
303 }
304
305 // Set appropriate srcs, dsts, and releative_install_path based on
306 // the source and install file names
307 if allCopyFileNamesUnchanged {
308 modulePropsPtr.Srcs = srcBaseFiles
309
310 // Specify relative_install_path if it is not installed in the root directory of the
311 // partition
312 if !android.InList(relDestDirFromInstallDirBase, []string{"", "."}) {
313 propsList = append(propsList, &prebuiltSubdirProperties{
314 Relative_install_path: proptools.StringPtr(relDestDirFromInstallDirBase),
315 })
316 }
317 } else {
318 modulePropsPtr.Srcs = srcBaseFiles
319 dsts := []string{}
320 for _, installBaseFile := range installBaseFiles {
321 dsts = append(dsts, filepath.Join(relDestDirFromInstallDirBase, installBaseFile))
322 }
323 modulePropsPtr.Dsts = dsts
324 }
325
326 ctx.CreateModuleInDirectory(etcInstallPathToFactoryList[etcInstallPathKey], srcDir, propsList...)
327 moduleNames = append(moduleNames, moduleName)
328 }
329
330 return moduleNames
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000331}
332
333func createPrebuiltEtcModulesForPartition(ctx android.LoadHookContext, partition, srcDir string, destDirFilesMap map[string][]srcBaseFileInstallBaseFileTuple) (ret []string) {
334 for _, destDir := range android.SortedKeys(destDirFilesMap) {
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000335 ret = append(ret, createPrebuiltEtcModulesInDirectory(ctx, partition, srcDir, destDir, destDirFilesMap[destDir])...)
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000336 }
337 return ret
338}
339
340// Creates prebuilt_* modules based on the install paths and returns the list of generated
341// module names
342func createPrebuiltEtcModules(ctx android.LoadHookContext) (ret []string) {
343 groupedSources := processProductCopyFiles(ctx)
344 for _, srcDir := range android.SortedKeys(groupedSources) {
345 groupedSource := groupedSources[srcDir]
346 ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system", srcDir, groupedSource.system)...)
347 ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system_ext", srcDir, groupedSource.system_ext)...)
348 ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "product", srcDir, groupedSource.product)...)
349 ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "vendor", srcDir, groupedSource.vendor)...)
350 }
351
352 return ret
353}
Jihoon Kang04f12c92024-11-12 23:03:08 +0000354
355func createAvbpubkeyModule(ctx android.LoadHookContext) bool {
356 avbKeyPath := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BoardAvbKeyPath
357 if avbKeyPath == "" {
358 return false
359 }
360 ctx.CreateModuleInDirectory(
361 etc.AvbpubkeyModuleFactory,
362 ".",
363 &struct {
364 Name *string
365 Product_specific *bool
366 Private_key *string
367 No_full_install *bool
368 Visibility []string
369 }{
370 Name: proptools.StringPtr("system_other_avbpubkey"),
371 Product_specific: proptools.BoolPtr(true),
372 Private_key: proptools.StringPtr(avbKeyPath),
373 No_full_install: proptools.BoolPtr(true),
374 Visibility: []string{"//visibility:public"},
375 },
376 )
377 return true
378}