blob: 362ac31b811e6d9fa6f689b99ebc7c8746a6991d [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
88func uniqueExistingProductCopyFileMap(ctx android.LoadHookContext) map[string]string {
89 seen := make(map[string]bool)
90 filtered := make(map[string]string)
91
92 for src, dest := range ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.ProductCopyFiles {
93 if _, ok := seen[dest]; !ok {
94 if optionalPath := android.ExistentPathForSource(ctx, src); optionalPath.Valid() {
95 seen[dest] = true
96 filtered[src] = dest
97 }
98 }
99 }
100
101 return filtered
102}
103
104type partitionToInstallPath struct {
105 name string
106 installPath string
107}
108
109func processProductCopyFiles(ctx android.LoadHookContext) map[string]*prebuiltSrcGroupByInstallPartition {
110 // Filter out duplicate dest entries and non existing src entries
111 productCopyFileMap := uniqueExistingProductCopyFileMap(ctx)
112
113 // System is intentionally added at the last to consider the scenarios where
114 // non-system partitions are installed as part of the system partition
115 partitionToInstallPathList := []partitionToInstallPath{
116 {name: "vendor", installPath: ctx.DeviceConfig().VendorPath()},
117 {name: "product", installPath: ctx.DeviceConfig().ProductPath()},
118 {name: "system_ext", installPath: ctx.DeviceConfig().SystemExtPath()},
119 {name: "system", installPath: "system"},
120 }
121
122 groupedSources := map[string]*prebuiltSrcGroupByInstallPartition{}
123 for _, src := range android.SortedKeys(productCopyFileMap) {
124 dest := productCopyFileMap[src]
125 srcFileDir := filepath.Dir(src)
126 if _, ok := groupedSources[srcFileDir]; !ok {
127 groupedSources[srcFileDir] = newPrebuiltSrcGroupByInstallPartition()
128 }
129 appendIfCorrectInstallPartition(partitionToInstallPathList, dest, filepath.Base(src), groupedSources[srcFileDir])
130 }
131
132 return groupedSources
133}
134
135type prebuiltModuleProperties struct {
136 Name *string
137
138 Soc_specific *bool
139 Product_specific *bool
140 System_ext_specific *bool
141
142 Srcs []string
143 Dsts []string
144
145 No_full_install *bool
146
147 NamespaceExportedToMake bool
148
149 Visibility []string
150}
151
152// Split relative_install_path to a separate struct, because it is not supported for every
153// modules listed in [etcInstallPathToFactoryMap]
154type prebuiltSubdirProperties struct {
155 // If the base file name of the src and dst all match, dsts property does not need to be
156 // set, and only relative_install_path can be set.
157 Relative_install_path *string
158}
159
160var (
161 etcInstallPathToFactoryList = map[string]android.ModuleFactory{
162 "": etc.PrebuiltRootFactory,
163 "avb": etc.PrebuiltAvbFactory,
164 "bin": etc.PrebuiltBinaryFactory,
165 "bt_firmware": etc.PrebuiltBtFirmwareFactory,
166 "cacerts": etc.PrebuiltEtcCaCertsFactory,
167 "dsp": etc.PrebuiltDSPFactory,
168 "etc": etc.PrebuiltEtcFactory,
169 "etc/dsp": etc.PrebuiltDSPFactory,
170 "etc/firmware": etc.PrebuiltFirmwareFactory,
171 "firmware": etc.PrebuiltFirmwareFactory,
172 "fonts": etc.PrebuiltFontFactory,
173 "framework": etc.PrebuiltFrameworkFactory,
174 "lib": etc.PrebuiltRenderScriptBitcodeFactory,
175 "lib64": etc.PrebuiltRenderScriptBitcodeFactory,
176 "lib/rfsa": etc.PrebuiltRFSAFactory,
177 "media": etc.PrebuiltMediaFactory,
178 "odm": etc.PrebuiltOdmFactory,
Jihoon Kangdca2f2b2024-11-06 18:43:19 +0000179 "optee": etc.PrebuiltOpteeFactory,
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000180 "overlay": etc.PrebuiltOverlayFactory,
181 "priv-app": etc.PrebuiltPrivAppFactory,
182 "res": etc.PrebuiltResFactory,
183 "rfs": etc.PrebuiltRfsFactory,
184 "tts": etc.PrebuiltVoicepackFactory,
Jihoon Kangdca2f2b2024-11-06 18:43:19 +0000185 "tvservice": etc.PrebuiltTvServiceFactory,
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000186 "usr/share": etc.PrebuiltUserShareFactory,
187 "usr/hyphen-data": etc.PrebuiltUserHyphenDataFactory,
188 "usr/keylayout": etc.PrebuiltUserKeyLayoutFactory,
189 "usr/keychars": etc.PrebuiltUserKeyCharsFactory,
190 "usr/srec": etc.PrebuiltUserSrecFactory,
191 "usr/idc": etc.PrebuiltUserIdcFactory,
192 "vendor_dlkm": etc.PrebuiltVendorDlkmFactory,
193 "wallpaper": etc.PrebuiltWallpaperFactory,
194 "wlc_upt": etc.PrebuiltWlcUptFactory,
195 }
196)
197
198func createPrebuiltEtcModule(ctx android.LoadHookContext, partition, srcDir, destDir string, destFiles []srcBaseFileInstallBaseFileTuple) string {
199 moduleProps := &prebuiltModuleProperties{}
200 propsList := []interface{}{moduleProps}
201
202 // generated module name follows the pattern:
203 // <install partition>-<src file path>-<relative install path from partition root>-<install file extension>
204 // Note that all path separators are replaced with "_" in the name
205 moduleName := partition
206 if !android.InList(srcDir, []string{"", "."}) {
207 moduleName += fmt.Sprintf("-%s", strings.ReplaceAll(srcDir, string(filepath.Separator), "_"))
208 }
209 if !android.InList(destDir, []string{"", "."}) {
210 moduleName += fmt.Sprintf("-%s", strings.ReplaceAll(destDir, string(filepath.Separator), "_"))
211 }
212 if len(destFiles) > 0 {
213 if ext := filepath.Ext(destFiles[0].srcBaseFile); ext != "" {
214 moduleName += fmt.Sprintf("-%s", strings.TrimPrefix(ext, "."))
215 }
216 }
217 moduleProps.Name = proptools.StringPtr(moduleName)
218
219 allCopyFileNamesUnchanged := true
220 var srcBaseFiles, installBaseFiles []string
221 for _, tuple := range destFiles {
222 if tuple.srcBaseFile != tuple.installBaseFile {
223 allCopyFileNamesUnchanged = false
224 }
225 srcBaseFiles = append(srcBaseFiles, tuple.srcBaseFile)
226 installBaseFiles = append(installBaseFiles, tuple.installBaseFile)
227 }
228
229 // Find out the most appropriate module type to generate
230 var etcInstallPathKey string
231 for _, etcInstallPath := range android.SortedKeys(etcInstallPathToFactoryList) {
232 // Do not break when found but iterate until the end to find a module with more
233 // specific install path
234 if strings.HasPrefix(destDir, etcInstallPath) {
235 etcInstallPathKey = etcInstallPath
236 }
237 }
238 destDir, _ = filepath.Rel(etcInstallPathKey, destDir)
239
240 // Set partition specific properties
241 switch partition {
242 case "system_ext":
243 moduleProps.System_ext_specific = proptools.BoolPtr(true)
244 case "product":
245 moduleProps.Product_specific = proptools.BoolPtr(true)
246 case "vendor":
247 moduleProps.Soc_specific = proptools.BoolPtr(true)
248 }
249
250 // Set appropriate srcs, dsts, and releative_install_path based on
251 // the source and install file names
252 if allCopyFileNamesUnchanged {
253 moduleProps.Srcs = srcBaseFiles
254
255 // Specify relative_install_path if it is not installed in the root directory of the
256 // partition
257 if !android.InList(destDir, []string{"", "."}) {
258 propsList = append(propsList, &prebuiltSubdirProperties{
259 Relative_install_path: proptools.StringPtr(destDir),
260 })
261 }
262 } else {
263 moduleProps.Srcs = srcBaseFiles
264 dsts := []string{}
265 for _, installBaseFile := range installBaseFiles {
266 dsts = append(dsts, filepath.Join(destDir, installBaseFile))
267 }
268 moduleProps.Dsts = dsts
269 }
270
271 moduleProps.No_full_install = proptools.BoolPtr(true)
272 moduleProps.NamespaceExportedToMake = true
273 moduleProps.Visibility = []string{"//visibility:public"}
274
275 ctx.CreateModuleInDirectory(etcInstallPathToFactoryList[etcInstallPathKey], srcDir, propsList...)
276
277 return moduleName
278}
279
280func createPrebuiltEtcModulesForPartition(ctx android.LoadHookContext, partition, srcDir string, destDirFilesMap map[string][]srcBaseFileInstallBaseFileTuple) (ret []string) {
281 for _, destDir := range android.SortedKeys(destDirFilesMap) {
282 ret = append(ret, createPrebuiltEtcModule(ctx, partition, srcDir, destDir, destDirFilesMap[destDir]))
283 }
284 return ret
285}
286
287// Creates prebuilt_* modules based on the install paths and returns the list of generated
288// module names
289func createPrebuiltEtcModules(ctx android.LoadHookContext) (ret []string) {
290 groupedSources := processProductCopyFiles(ctx)
291 for _, srcDir := range android.SortedKeys(groupedSources) {
292 groupedSource := groupedSources[srcDir]
293 ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system", srcDir, groupedSource.system)...)
294 ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system_ext", srcDir, groupedSource.system_ext)...)
295 ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "product", srcDir, groupedSource.product)...)
296 ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "vendor", srcDir, groupedSource.vendor)...)
297 }
298
299 return ret
300}