blob: 177856e61721afffc99c4298913f37ca664228d7 [file] [log] [blame]
Jiyong Park48ca7dc2018-10-10 14:01:00 +09001// Copyright (C) 2018 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 apex
16
17import (
18 "fmt"
19 "io"
20 "path/filepath"
21 "runtime"
Jiyong Parkab3ceb32018-10-10 14:05:29 +090022 "sort"
Jiyong Park48ca7dc2018-10-10 14:01:00 +090023 "strings"
24
25 "android/soong/android"
26 "android/soong/cc"
27 "android/soong/java"
28
29 "github.com/google/blueprint"
30 "github.com/google/blueprint/proptools"
31)
32
33var (
34 pctx = android.NewPackageContext("android/apex")
35
36 // Create a canned fs config file where all files and directories are
37 // by default set to (uid/gid/mode) = (1000/1000/0644)
38 // TODO(b/113082813) make this configurable using config.fs syntax
39 generateFsConfig = pctx.StaticRule("generateFsConfig", blueprint.RuleParams{
Roland Levillain2b11f742018-11-02 11:50:42 +000040 Command: `echo '/ 1000 1000 0755' > ${out} && ` +
Jiyong Park48ca7dc2018-10-10 14:01:00 +090041 `echo '/manifest.json 1000 1000 0644' >> ${out} && ` +
Jiyong Park92905d62018-10-11 13:23:09 +090042 `echo ${ro_paths} | tr ' ' '\n' | awk '{print "/"$$1 " 1000 1000 0644"}' >> ${out} && ` +
43 `echo ${exec_paths} | tr ' ' '\n' | awk '{print "/"$$1 " 1000 1000 0755"}' >> ${out}`,
Jiyong Park48ca7dc2018-10-10 14:01:00 +090044 Description: "fs_config ${out}",
Jiyong Park92905d62018-10-11 13:23:09 +090045 }, "ro_paths", "exec_paths")
Jiyong Park48ca7dc2018-10-10 14:01:00 +090046
47 // TODO(b/113233103): make sure that file_contexts is sane, i.e., validate
48 // against the binary policy using sefcontext_compiler -p <policy>.
49
50 // TODO(b/114327326): automate the generation of file_contexts
51 apexRule = pctx.StaticRule("apexRule", blueprint.RuleParams{
52 Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
53 `(${copy_commands}) && ` +
54 `APEXER_TOOL_PATH=${tool_path} ` +
55 `${apexer} --verbose --force --manifest ${manifest} ` +
56 `--file_contexts ${file_contexts} ` +
57 `--canned_fs_config ${canned_fs_config} ` +
58 `--key ${key} ${image_dir} ${out} `,
59 CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}",
60 "${mke2fs}", "${resize2fs}", "${sefcontext_compile}",
61 "${soong_zip}", "${zipalign}", "${aapt2}"},
62 Description: "APEX ${image_dir} => ${out}",
63 }, "tool_path", "image_dir", "copy_commands", "manifest", "file_contexts", "canned_fs_config", "key")
64)
65
66var apexSuffix = ".apex"
67
68type dependencyTag struct {
69 blueprint.BaseDependencyTag
70 name string
71}
72
73var (
Jiyong Parkc00cbd92018-10-30 21:20:05 +090074 sharedLibTag = dependencyTag{name: "sharedLib"}
75 executableTag = dependencyTag{name: "executable"}
76 javaLibTag = dependencyTag{name: "javaLib"}
77 prebuiltTag = dependencyTag{name: "prebuilt"}
78 keyTag = dependencyTag{name: "key"}
79 certificateTag = dependencyTag{name: "certificate"}
Jiyong Park48ca7dc2018-10-10 14:01:00 +090080)
81
82func init() {
83 pctx.Import("android/soong/common")
Jiyong Parkc00cbd92018-10-30 21:20:05 +090084 pctx.Import("android/soong/java")
Jiyong Park48ca7dc2018-10-10 14:01:00 +090085 pctx.HostBinToolVariable("apexer", "apexer")
Roland Levillain54bdfda2018-10-05 19:34:32 +010086 // ART minimal builds (using the master-art manifest) do not have the "frameworks/base"
87 // projects, and hence cannot built 'aapt2'. Use the SDK prebuilt instead.
88 hostBinToolVariableWithPrebuilt := func(name, prebuiltDir, tool string) {
89 pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
90 if !android.ExistentPathForSource(ctx, "frameworks/base").Valid() {
91 return filepath.Join(prebuiltDir, runtime.GOOS, "bin", tool)
92 } else {
93 return pctx.HostBinToolPath(ctx, tool).String()
94 }
95 })
96 }
97 hostBinToolVariableWithPrebuilt("aapt2", "prebuilts/sdk/tools", "aapt2")
Jiyong Park48ca7dc2018-10-10 14:01:00 +090098 pctx.HostBinToolVariable("avbtool", "avbtool")
99 pctx.HostBinToolVariable("e2fsdroid", "e2fsdroid")
100 pctx.HostBinToolVariable("merge_zips", "merge_zips")
101 pctx.HostBinToolVariable("mke2fs", "mke2fs")
102 pctx.HostBinToolVariable("resize2fs", "resize2fs")
103 pctx.HostBinToolVariable("sefcontext_compile", "sefcontext_compile")
104 pctx.HostBinToolVariable("soong_zip", "soong_zip")
105 pctx.HostBinToolVariable("zipalign", "zipalign")
106
107 android.RegisterModuleType("apex", apexBundleFactory)
108
109 android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
110 ctx.TopDown("apex_deps", apexDepsMutator)
111 ctx.BottomUp("apex", apexMutator)
112 })
113}
114
115// maps a module name to set of apex bundle names that the module should be built for
116func apexBundleNamesFor(config android.Config) map[string]map[string]bool {
117 return config.Once("apexBundleNames", func() interface{} {
118 return make(map[string]map[string]bool)
119 }).(map[string]map[string]bool)
120}
121
122// Mark the direct and transitive dependencies of apex bundles so that they
123// can be built for the apex bundles.
124func apexDepsMutator(mctx android.TopDownMutatorContext) {
125 if _, ok := mctx.Module().(*apexBundle); ok {
126 apexBundleName := mctx.Module().Name()
127 mctx.WalkDeps(func(child, parent android.Module) bool {
128 if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() {
Jiyong Park678529e2018-10-23 23:58:01 +0900129 moduleName := am.Name() + "-" + am.Target().String()
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900130 bundleNames, ok := apexBundleNamesFor(mctx.Config())[moduleName]
131 if !ok {
132 bundleNames = make(map[string]bool)
133 apexBundleNamesFor(mctx.Config())[moduleName] = bundleNames
134 }
135 bundleNames[apexBundleName] = true
136 return true
137 } else {
138 return false
139 }
140 })
141 }
142}
143
144// Create apex variations if a module is included in APEX(s).
145func apexMutator(mctx android.BottomUpMutatorContext) {
146 if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
Jiyong Park678529e2018-10-23 23:58:01 +0900147 moduleName := am.Name() + "-" + am.Target().String()
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900148 if bundleNames, ok := apexBundleNamesFor(mctx.Config())[moduleName]; ok {
149 variations := []string{"platform"}
150 for bn := range bundleNames {
151 variations = append(variations, bn)
152 }
153 modules := mctx.CreateVariations(variations...)
154 for i, m := range modules {
155 if i == 0 {
156 continue // platform
157 }
158 m.(android.ApexModule).BuildForApex(variations[i])
159 }
160 }
161 } else if _, ok := mctx.Module().(*apexBundle); ok {
162 // apex bundle itself is mutated so that it and its modules have same
163 // apex variant.
164 apexBundleName := mctx.ModuleName()
165 mctx.CreateVariations(apexBundleName)
166 }
167}
168
169type apexBundleProperties struct {
170 // Json manifest file describing meta info of this APEX bundle. Default:
171 // "manifest.json"
172 Manifest *string
173
Jiyong Parkd0a65ba2018-11-10 06:37:15 +0900174 // Determines the file contexts file for setting security context to each file in this APEX bundle.
175 // Specifically, when this is set to <value>, /system/sepolicy/apex/<value>_file_contexts file is
176 // used.
177 // Default: <name_of_this_module>
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900178 File_contexts *string
179
180 // List of native shared libs that are embedded inside this APEX bundle
181 Native_shared_libs []string
182
183 // List of native executables that are embedded inside this APEX bundle
184 Binaries []string
185
186 // List of java libraries that are embedded inside this APEX bundle
187 Java_libs []string
188
189 // List of prebuilt files that are embedded inside this APEX bundle
190 Prebuilts []string
Jiyong Parkff1458f2018-10-12 21:49:38 +0900191
192 // Name of the apex_key module that provides the private key to sign APEX
193 Key *string
Jiyong Park397e55e2018-10-24 21:09:55 +0900194
Jiyong Parkc00cbd92018-10-30 21:20:05 +0900195 // The name of a certificate in the default certificate directory, blank to use the default product certificate,
196 // or an android_app_certificate module name in the form ":module".
197 Certificate *string
198
Jiyong Park397e55e2018-10-24 21:09:55 +0900199 Multilib struct {
200 First struct {
201 // List of native libraries whose compile_multilib is "first"
202 Native_shared_libs []string
203 // List of native executables whose compile_multilib is "first"
204 Binaries []string
205 }
206 Both struct {
207 // List of native libraries whose compile_multilib is "both"
208 Native_shared_libs []string
209 // List of native executables whose compile_multilib is "both"
210 Binaries []string
211 }
212 Prefer32 struct {
213 // List of native libraries whose compile_multilib is "prefer32"
214 Native_shared_libs []string
215 // List of native executables whose compile_multilib is "prefer32"
216 Binaries []string
217 }
218 Lib32 struct {
219 // List of native libraries whose compile_multilib is "32"
220 Native_shared_libs []string
221 // List of native executables whose compile_multilib is "32"
222 Binaries []string
223 }
224 Lib64 struct {
225 // List of native libraries whose compile_multilib is "64"
226 Native_shared_libs []string
227 // List of native executables whose compile_multilib is "64"
228 Binaries []string
229 }
230 }
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900231}
232
Jiyong Park8fd61922018-11-08 02:50:25 +0900233type apexFileClass int
234
235const (
236 etc apexFileClass = iota
237 nativeSharedLib
238 nativeExecutable
239 javaSharedLib
240)
241
242func (class apexFileClass) NameInMake() string {
243 switch class {
244 case etc:
245 return "ETC"
246 case nativeSharedLib:
247 return "SHARED_LIBRARIES"
248 case nativeExecutable:
249 return "EXECUTABLES"
250 case javaSharedLib:
251 return "JAVA_LIBRARIES"
252 default:
253 panic(fmt.Errorf("unkonwn class %d", class))
254 }
255}
256
257type apexFile struct {
258 builtFile android.Path
259 moduleName string
260 archType android.ArchType
261 installDir string
262 class apexFileClass
263}
264
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900265type apexBundle struct {
266 android.ModuleBase
267 android.DefaultableModuleBase
268
269 properties apexBundleProperties
270
271 outputFile android.WritablePath
272 installDir android.OutputPath
Jiyong Park8fd61922018-11-08 02:50:25 +0900273
274 // list of files to be included in this apex
275 filesInfo []apexFile
276
277 flattened bool
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900278}
279
Jiyong Park397e55e2018-10-24 21:09:55 +0900280func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
281 native_shared_libs []string, binaries []string, arch string) {
282 // Use *FarVariation* to be able to depend on modules having
283 // conflicting variations with this module. This is required since
284 // arch variant of an APEX bundle is 'common' but it is 'arm' or 'arm64'
285 // for native shared libs.
286 ctx.AddFarVariationDependencies([]blueprint.Variation{
287 {Mutator: "arch", Variation: arch},
288 {Mutator: "image", Variation: "core"},
289 {Mutator: "link", Variation: "shared"},
290 }, sharedLibTag, native_shared_libs...)
291
292 ctx.AddFarVariationDependencies([]blueprint.Variation{
293 {Mutator: "arch", Variation: arch},
294 {Mutator: "image", Variation: "core"},
295 }, executableTag, binaries...)
296}
297
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900298func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) {
Jiyong Park397e55e2018-10-24 21:09:55 +0900299 targets := ctx.MultiTargets()
300 has32BitTarget := false
301 for _, target := range targets {
302 if target.Arch.ArchType.Multilib == "lib32" {
303 has32BitTarget = true
304 }
305 }
306 for i, target := range targets {
307 // When multilib.* is omitted for native_shared_libs, it implies
308 // multilib.both.
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900309 ctx.AddFarVariationDependencies([]blueprint.Variation{
Jiyong Park397e55e2018-10-24 21:09:55 +0900310 {Mutator: "arch", Variation: target.String()},
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900311 {Mutator: "image", Variation: "core"},
312 {Mutator: "link", Variation: "shared"},
313 }, sharedLibTag, a.properties.Native_shared_libs...)
314
Jiyong Park397e55e2018-10-24 21:09:55 +0900315 // Add native modules targetting both ABIs
316 addDependenciesForNativeModules(ctx,
317 a.properties.Multilib.Both.Native_shared_libs,
318 a.properties.Multilib.Both.Binaries, target.String())
319
320 if i == 0 {
321 // When multilib.* is omitted for binaries, it implies
322 // multilib.first.
323 ctx.AddFarVariationDependencies([]blueprint.Variation{
324 {Mutator: "arch", Variation: target.String()},
325 {Mutator: "image", Variation: "core"},
326 }, executableTag, a.properties.Binaries...)
327
328 // Add native modules targetting the first ABI
329 addDependenciesForNativeModules(ctx,
330 a.properties.Multilib.First.Native_shared_libs,
331 a.properties.Multilib.First.Binaries, target.String())
332 }
333
334 switch target.Arch.ArchType.Multilib {
335 case "lib32":
336 // Add native modules targetting 32-bit ABI
337 addDependenciesForNativeModules(ctx,
338 a.properties.Multilib.Lib32.Native_shared_libs,
339 a.properties.Multilib.Lib32.Binaries, target.String())
340
341 addDependenciesForNativeModules(ctx,
342 a.properties.Multilib.Prefer32.Native_shared_libs,
343 a.properties.Multilib.Prefer32.Binaries, target.String())
344 case "lib64":
345 // Add native modules targetting 64-bit ABI
346 addDependenciesForNativeModules(ctx,
347 a.properties.Multilib.Lib64.Native_shared_libs,
348 a.properties.Multilib.Lib64.Binaries, target.String())
349
350 if !has32BitTarget {
351 addDependenciesForNativeModules(ctx,
352 a.properties.Multilib.Prefer32.Native_shared_libs,
353 a.properties.Multilib.Prefer32.Binaries, target.String())
354 }
355 }
356
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900357 }
358
Jiyong Parkff1458f2018-10-12 21:49:38 +0900359 ctx.AddFarVariationDependencies([]blueprint.Variation{
360 {Mutator: "arch", Variation: "android_common"},
361 }, javaLibTag, a.properties.Java_libs...)
362
363 ctx.AddFarVariationDependencies([]blueprint.Variation{
364 {Mutator: "arch", Variation: "android_common"},
365 }, prebuiltTag, a.properties.Prebuilts...)
366
367 if String(a.properties.Key) == "" {
368 ctx.ModuleErrorf("key is missing")
369 return
370 }
371 ctx.AddDependency(ctx.Module(), keyTag, String(a.properties.Key))
Jiyong Parkc00cbd92018-10-30 21:20:05 +0900372
373 cert := android.SrcIsModule(String(a.properties.Certificate))
374 if cert != "" {
375 ctx.AddDependency(ctx.Module(), certificateTag, cert)
376 }
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900377}
378
379func getCopyManifestForNativeLibrary(cc *cc.Module) (fileToCopy android.Path, dirInApex string) {
380 // Decide the APEX-local directory by the multilib of the library
381 // In the future, we may query this to the module.
382 switch cc.Arch().ArchType.Multilib {
383 case "lib32":
384 dirInApex = "lib"
385 case "lib64":
386 dirInApex = "lib64"
387 }
388 if !cc.Arch().Native {
389 dirInApex = filepath.Join(dirInApex, cc.Arch().ArchType.String())
390 }
391
392 fileToCopy = cc.OutputFile().Path()
393 return
394}
395
396func getCopyManifestForExecutable(cc *cc.Module) (fileToCopy android.Path, dirInApex string) {
397 dirInApex = "bin"
398 fileToCopy = cc.OutputFile().Path()
399 return
400}
401
402func getCopyManifestForJavaLibrary(java *java.Library) (fileToCopy android.Path, dirInApex string) {
403 dirInApex = "javalib"
Jiyong Park8fd61922018-11-08 02:50:25 +0900404 fileToCopy = java.DexJarFile()
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900405 return
406}
407
408func getCopyManifestForPrebuiltEtc(prebuilt *android.PrebuiltEtc) (fileToCopy android.Path, dirInApex string) {
409 dirInApex = filepath.Join("etc", prebuilt.SubDir())
410 fileToCopy = prebuilt.OutputFile()
411 return
412}
413
414func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Jiyong Park8fd61922018-11-08 02:50:25 +0900415 filesInfo := []apexFile{}
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900416
Jiyong Parkff1458f2018-10-12 21:49:38 +0900417 var keyFile android.Path
Jiyong Parkc00cbd92018-10-30 21:20:05 +0900418 var certificate java.Certificate
Jiyong Parkff1458f2018-10-12 21:49:38 +0900419
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900420 ctx.WalkDeps(func(child, parent android.Module) bool {
421 if _, ok := parent.(*apexBundle); ok {
422 // direct dependencies
423 depTag := ctx.OtherModuleDependencyTag(child)
Jiyong Parkff1458f2018-10-12 21:49:38 +0900424 depName := ctx.OtherModuleName(child)
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900425 switch depTag {
426 case sharedLibTag:
427 if cc, ok := child.(*cc.Module); ok {
428 fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc)
Jiyong Park8fd61922018-11-08 02:50:25 +0900429 filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib})
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900430 return true
Jiyong Parkff1458f2018-10-12 21:49:38 +0900431 } else {
432 ctx.PropertyErrorf("native_shared_libs", "%q is not a cc_library or cc_library_shared module", depName)
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900433 }
434 case executableTag:
435 if cc, ok := child.(*cc.Module); ok {
436 fileToCopy, dirInApex := getCopyManifestForExecutable(cc)
Jiyong Park8fd61922018-11-08 02:50:25 +0900437 filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeExecutable})
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900438 return true
Jiyong Parkff1458f2018-10-12 21:49:38 +0900439 } else {
440 ctx.PropertyErrorf("binaries", "%q is not a cc_binary module", depName)
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900441 }
442 case javaLibTag:
443 if java, ok := child.(*java.Library); ok {
444 fileToCopy, dirInApex := getCopyManifestForJavaLibrary(java)
Jiyong Park8fd61922018-11-08 02:50:25 +0900445 if fileToCopy == nil {
446 ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
447 } else {
448 filesInfo = append(filesInfo, apexFile{fileToCopy, depName, java.Arch().ArchType, dirInApex, javaSharedLib})
449 }
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900450 return true
Jiyong Parkff1458f2018-10-12 21:49:38 +0900451 } else {
452 ctx.PropertyErrorf("java_libs", "%q is not a java_library module", depName)
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900453 }
454 case prebuiltTag:
455 if prebuilt, ok := child.(*android.PrebuiltEtc); ok {
456 fileToCopy, dirInApex := getCopyManifestForPrebuiltEtc(prebuilt)
Jiyong Park8fd61922018-11-08 02:50:25 +0900457 filesInfo = append(filesInfo, apexFile{fileToCopy, depName, prebuilt.Arch().ArchType, dirInApex, etc})
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900458 return true
Jiyong Parkff1458f2018-10-12 21:49:38 +0900459 } else {
460 ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
461 }
462 case keyTag:
463 if key, ok := child.(*apexKey); ok {
464 keyFile = key.private_key_file
465 return false
466 } else {
467 ctx.PropertyErrorf("key", "%q is not an apex_key module", depName)
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900468 }
Jiyong Parkc00cbd92018-10-30 21:20:05 +0900469 case certificateTag:
470 if dep, ok := child.(*java.AndroidAppCertificate); ok {
471 certificate = dep.Certificate
472 return false
473 } else {
474 ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", depName)
475 }
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900476 }
477 } else {
478 // indirect dependencies
479 if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && am.IsInstallableToApex() {
480 if cc, ok := child.(*cc.Module); ok {
Jiyong Park8fd61922018-11-08 02:50:25 +0900481 depName := ctx.OtherModuleName(child)
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900482 fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc)
Jiyong Park8fd61922018-11-08 02:50:25 +0900483 filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib})
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900484 return true
485 }
486 }
487 }
488 return false
489 })
490
Jiyong Parkfa0a3732018-11-09 05:52:26 +0900491 if keyFile == nil {
492 ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.properties.Key))
493 return
494 }
495
Jiyong Park8fd61922018-11-08 02:50:25 +0900496 // remove duplicates in filesInfo
497 removeDup := func(filesInfo []apexFile) []apexFile {
498 encountered := make(map[android.Path]bool)
499 result := []apexFile{}
500 for _, f := range filesInfo {
501 if !encountered[f.builtFile] {
502 encountered[f.builtFile] = true
503 result = append(result, f)
504 }
505 }
506 return result
507 }
508 filesInfo = removeDup(filesInfo)
509
510 // to have consistent build rules
511 sort.Slice(filesInfo, func(i, j int) bool {
512 return filesInfo[i].builtFile.String() < filesInfo[j].builtFile.String()
513 })
514
515 // prepend the name of this APEX to the module names. These names will be the names of
516 // modules that will be defined if the APEX is flattened.
517 for i := range filesInfo {
518 filesInfo[i].moduleName = ctx.ModuleName() + "." + filesInfo[i].moduleName
519 }
520
521 a.flattened = ctx.Config().FlattenApex()
522 a.installDir = android.PathForModuleInstall(ctx, "apex")
523 a.filesInfo = filesInfo
524 if ctx.Config().FlattenApex() {
525 a.buildFlattenedApex(ctx)
526 } else {
527 a.buildUnflattenedApex(ctx, keyFile, certificate)
528 }
529}
530
531func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, keyFile android.Path, certificate java.Certificate) {
Jiyong Parkc00cbd92018-10-30 21:20:05 +0900532 cert := String(a.properties.Certificate)
533 if cert != "" && android.SrcIsModule(cert) == "" {
534 defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
535 certificate = java.Certificate{
536 defaultDir.Join(ctx, cert+".x509.pem"),
537 defaultDir.Join(ctx, cert+".pk8"),
538 }
539 } else if cert == "" {
540 pem, key := ctx.Config().DefaultAppCertificate(ctx)
541 certificate = java.Certificate{pem, key}
542 }
543
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900544 // files and dirs that will be created in apex
Jiyong Park92905d62018-10-11 13:23:09 +0900545 var readOnlyPaths []string
546 var executablePaths []string // this also includes dirs
Jiyong Park8fd61922018-11-08 02:50:25 +0900547 for _, f := range a.filesInfo {
548 pathInApex := filepath.Join(f.installDir, f.builtFile.Base())
549 if f.installDir == "bin" {
Jiyong Park92905d62018-10-11 13:23:09 +0900550 executablePaths = append(executablePaths, pathInApex)
551 } else {
552 readOnlyPaths = append(readOnlyPaths, pathInApex)
553 }
Jiyong Park8fd61922018-11-08 02:50:25 +0900554 if !android.InList(f.installDir, executablePaths) {
555 executablePaths = append(executablePaths, f.installDir)
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900556 }
557 }
Jiyong Park92905d62018-10-11 13:23:09 +0900558 sort.Strings(readOnlyPaths)
559 sort.Strings(executablePaths)
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900560 cannedFsConfig := android.PathForModuleOut(ctx, "canned_fs_config")
561 ctx.ModuleBuild(pctx, android.ModuleBuildParams{
562 Rule: generateFsConfig,
563 Output: cannedFsConfig,
564 Args: map[string]string{
Jiyong Park92905d62018-10-11 13:23:09 +0900565 "ro_paths": strings.Join(readOnlyPaths, " "),
566 "exec_paths": strings.Join(executablePaths, " "),
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900567 },
568 })
569
570 manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "manifest.json"))
Jiyong Parkd0a65ba2018-11-10 06:37:15 +0900571
572 fcName := proptools.StringDefault(a.properties.File_contexts, a.ModuleBase.Name())
573 fileContextsPath := "system/sepolicy/apex/" + fcName + "_file_contexts"
574 fileContextsOptionalPath := android.ExistentPathForSource(ctx, fileContextsPath)
575 if !fileContextsOptionalPath.Valid() {
576 ctx.ModuleErrorf("Cannot find file_contexts file: %q", fileContextsPath)
577 return
578 }
579 fileContexts := fileContextsOptionalPath.Path()
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900580
Jiyong Parkc00cbd92018-10-30 21:20:05 +0900581 unsignedOutputFile := android.PathForModuleOut(ctx, a.ModuleBase.Name()+apexSuffix+".unsigned")
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900582
Jiyong Parkab3ceb32018-10-10 14:05:29 +0900583 filesToCopy := []android.Path{}
Jiyong Park8fd61922018-11-08 02:50:25 +0900584 for _, f := range a.filesInfo {
585 filesToCopy = append(filesToCopy, f.builtFile)
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900586 }
Jiyong Parkab3ceb32018-10-10 14:05:29 +0900587
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900588 copyCommands := []string{}
Jiyong Park8fd61922018-11-08 02:50:25 +0900589 for i, src := range filesToCopy {
590 dest := filepath.Join(a.filesInfo[i].installDir, src.Base())
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900591 dest_path := filepath.Join(android.PathForModuleOut(ctx, "image").String(), dest)
592 copyCommands = append(copyCommands, "mkdir -p "+filepath.Dir(dest_path))
593 copyCommands = append(copyCommands, "cp "+src.String()+" "+dest_path)
594 }
Jiyong Parkab3ceb32018-10-10 14:05:29 +0900595 implicitInputs := append(android.Paths(nil), filesToCopy...)
Jiyong Parkff1458f2018-10-12 21:49:38 +0900596 implicitInputs = append(implicitInputs, cannedFsConfig, manifest, fileContexts, keyFile)
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900597 outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String()
598 prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
599 ctx.ModuleBuild(pctx, android.ModuleBuildParams{
600 Rule: apexRule,
601 Implicits: implicitInputs,
Jiyong Parkc00cbd92018-10-30 21:20:05 +0900602 Output: unsignedOutputFile,
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900603 Args: map[string]string{
604 "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
605 "image_dir": android.PathForModuleOut(ctx, "image").String(),
606 "copy_commands": strings.Join(copyCommands, " && "),
607 "manifest": manifest.String(),
608 "file_contexts": fileContexts.String(),
609 "canned_fs_config": cannedFsConfig.String(),
Jiyong Parkff1458f2018-10-12 21:49:38 +0900610 "key": keyFile.String(),
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900611 },
612 })
613
Jiyong Parkc00cbd92018-10-30 21:20:05 +0900614 a.outputFile = android.PathForModuleOut(ctx, a.ModuleBase.Name()+apexSuffix)
615 ctx.Build(pctx, android.BuildParams{
616 Rule: java.Signapk,
617 Description: "signapk",
618 Output: a.outputFile,
619 Input: unsignedOutputFile,
620 Args: map[string]string{
621 "certificates": strings.Join([]string{certificate.Pem.String(), certificate.Key.String()}, " "),
622 },
623 })
Jiyong Park8fd61922018-11-08 02:50:25 +0900624}
Jiyong Parkc00cbd92018-10-30 21:20:05 +0900625
Jiyong Park8fd61922018-11-08 02:50:25 +0900626func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) {
627 // For flattened APEX, do nothing but make sure that manifest.json file is also copied along
628 // with other ordinary files.
629 manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "manifest.json"))
630 a.filesInfo = append(a.filesInfo, apexFile{manifest, a.Name() + ".manifest.json", android.Common, ".", etc})
631
632 for _, fi := range a.filesInfo {
633 dir := filepath.Join("apex", a.Name(), fi.installDir)
634 ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.builtFile.Base(), fi.builtFile)
635 }
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900636}
637
638func (a *apexBundle) AndroidMk() android.AndroidMkData {
Jiyong Park8fd61922018-11-08 02:50:25 +0900639 if a.flattened {
640 return android.AndroidMkData{
641 Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
642 moduleNames := []string{}
643 for _, fi := range a.filesInfo {
644 if !android.InList(fi.moduleName, moduleNames) {
645 moduleNames = append(moduleNames, fi.moduleName)
646 }
647 }
648 fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
649 fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
650 fmt.Fprintln(w, "LOCAL_MODULE :=", name)
651 fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " "))
652 fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
653
654 for _, fi := range a.filesInfo {
655 fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
656 fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
657 fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName)
658 fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString(), name, fi.installDir))
659 fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", fi.builtFile.Base())
660 fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String())
661 fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.NameInMake())
662 archStr := fi.archType.String()
663 if archStr != "common" {
664 fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
665 }
666 if fi.class == javaSharedLib {
667 fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String())
668 fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
669 fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
670 } else {
671 fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
672 }
673 }
674 }}
675 } else {
676 return android.AndroidMkData{
677 Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
678 fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
679 fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
680 fmt.Fprintln(w, "LOCAL_MODULE :=", name)
681 fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class?
682 fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFile.String())
683 fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)", a.installDir.RelPathString()))
684 fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", name+apexSuffix)
685 fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", String(a.properties.Key))
686 fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
687 }}
688 }
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900689}
690
691func apexBundleFactory() android.Module {
692 module := &apexBundle{}
693 module.AddProperties(&module.properties)
Jiyong Park397e55e2018-10-24 21:09:55 +0900694 module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase,
695 class android.OsClass) bool {
696 return class == android.Device && ctx.Config().DevicePrefer32BitExecutables()
697 })
Jiyong Park48ca7dc2018-10-10 14:01:00 +0900698 android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
699 android.InitDefaultableModule(module)
700 return module
701}