blob: b85813587f4ad9cfcc2179fde213af8c5dab40a9 [file] [log] [blame]
Jiyong Park09d77522019-11-18 11:16:27 +09001// Copyright (C) 2019 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 (
Jiyong Parkbd159612020-02-28 15:22:21 +090018 "encoding/json"
Jiyong Park09d77522019-11-18 11:16:27 +090019 "fmt"
Jooyung Han580eb4f2020-06-24 19:33:06 +090020 "path"
Jiyong Park09d77522019-11-18 11:16:27 +090021 "path/filepath"
22 "runtime"
23 "sort"
Nikita Ioffe5335bc42020-10-20 00:02:15 +010024 "strconv"
Jiyong Park09d77522019-11-18 11:16:27 +090025 "strings"
26
27 "android/soong/android"
28 "android/soong/java"
29
30 "github.com/google/blueprint"
31 "github.com/google/blueprint/proptools"
32)
33
34var (
35 pctx = android.NewPackageContext("android/apex")
36)
37
38func init() {
39 pctx.Import("android/soong/android")
40 pctx.Import("android/soong/java")
41 pctx.HostBinToolVariable("apexer", "apexer")
42 // ART minimal builds (using the master-art manifest) do not have the "frameworks/base"
Jiyong Parkb81b9902020-11-24 19:51:18 +090043 // projects, and hence cannot build 'aapt2'. Use the SDK prebuilt instead.
Jiyong Park09d77522019-11-18 11:16:27 +090044 hostBinToolVariableWithPrebuilt := func(name, prebuiltDir, tool string) {
45 pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
46 if !ctx.Config().FrameworksBaseDirExists(ctx) {
47 return filepath.Join(prebuiltDir, runtime.GOOS, "bin", tool)
48 } else {
Martin Stjernholm7260d062019-12-09 21:47:14 +000049 return ctx.Config().HostToolPath(ctx, tool).String()
Jiyong Park09d77522019-11-18 11:16:27 +090050 }
51 })
52 }
53 hostBinToolVariableWithPrebuilt("aapt2", "prebuilts/sdk/tools", "aapt2")
54 pctx.HostBinToolVariable("avbtool", "avbtool")
55 pctx.HostBinToolVariable("e2fsdroid", "e2fsdroid")
56 pctx.HostBinToolVariable("merge_zips", "merge_zips")
57 pctx.HostBinToolVariable("mke2fs", "mke2fs")
58 pctx.HostBinToolVariable("resize2fs", "resize2fs")
59 pctx.HostBinToolVariable("sefcontext_compile", "sefcontext_compile")
60 pctx.HostBinToolVariable("soong_zip", "soong_zip")
61 pctx.HostBinToolVariable("zip2zip", "zip2zip")
62 pctx.HostBinToolVariable("zipalign", "zipalign")
63 pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
64 pctx.HostBinToolVariable("conv_apex_manifest", "conv_apex_manifest")
Jaewoong Jungfa00c062020-05-14 14:15:24 -070065 pctx.HostBinToolVariable("extract_apks", "extract_apks")
Theotime Combes4ba38c12020-06-12 12:46:59 +000066 pctx.HostBinToolVariable("make_f2fs", "make_f2fs")
67 pctx.HostBinToolVariable("sload_f2fs", "sload_f2fs")
Jiyong Park09d77522019-11-18 11:16:27 +090068}
69
70var (
71 // Create a canned fs config file where all files and directories are
72 // by default set to (uid/gid/mode) = (1000/1000/0644)
73 // TODO(b/113082813) make this configurable using config.fs syntax
74 generateFsConfig = pctx.StaticRule("generateFsConfig", blueprint.RuleParams{
Sasha Smundak18d98bc2020-05-27 16:36:07 -070075 Command: `( echo '/ 1000 1000 0755' ` +
76 `&& for i in ${ro_paths}; do echo "/$$i 1000 1000 0644"; done ` +
77 `&& for i in ${exec_paths}; do echo "/$$i 0 2000 0755"; done ` +
78 `&& ( tr ' ' '\n' <${out}.apklist | for i in ${apk_paths}; do read apk; echo "/$$i 0 2000 0755"; zipinfo -1 $$apk | sed "s:\(.*\):/$$i/\1 1000 1000 0644:"; done ) ) > ${out}`,
79 Description: "fs_config ${out}",
80 Rspfile: "$out.apklist",
81 RspfileContent: "$in",
82 }, "ro_paths", "exec_paths", "apk_paths")
Jiyong Park09d77522019-11-18 11:16:27 +090083
84 apexManifestRule = pctx.StaticRule("apexManifestRule", blueprint.RuleParams{
85 Command: `rm -f $out && ${jsonmodify} $in ` +
86 `-a provideNativeLibs ${provideNativeLibs} ` +
87 `-a requireNativeLibs ${requireNativeLibs} ` +
88 `${opt} ` +
89 `-o $out`,
90 CommandDeps: []string{"${jsonmodify}"},
91 Description: "prepare ${out}",
92 }, "provideNativeLibs", "requireNativeLibs", "opt")
93
94 stripApexManifestRule = pctx.StaticRule("stripApexManifestRule", blueprint.RuleParams{
95 Command: `rm -f $out && ${conv_apex_manifest} strip $in -o $out`,
96 CommandDeps: []string{"${conv_apex_manifest}"},
97 Description: "strip ${in}=>${out}",
98 })
99
100 pbApexManifestRule = pctx.StaticRule("pbApexManifestRule", blueprint.RuleParams{
101 Command: `rm -f $out && ${conv_apex_manifest} proto $in -o $out`,
102 CommandDeps: []string{"${conv_apex_manifest}"},
103 Description: "convert ${in}=>${out}",
104 })
105
106 // TODO(b/113233103): make sure that file_contexts is sane, i.e., validate
107 // against the binary policy using sefcontext_compiler -p <policy>.
108
109 // TODO(b/114327326): automate the generation of file_contexts
110 apexRule = pctx.StaticRule("apexRule", blueprint.RuleParams{
111 Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
112 `(. ${out}.copy_commands) && ` +
113 `APEXER_TOOL_PATH=${tool_path} ` +
114 `${apexer} --force --manifest ${manifest} ` +
Jiyong Park09d77522019-11-18 11:16:27 +0900115 `--file_contexts ${file_contexts} ` +
116 `--canned_fs_config ${canned_fs_config} ` +
Dario Freni0f4ae072020-01-02 15:24:12 +0000117 `--include_build_info ` +
Jiyong Park09d77522019-11-18 11:16:27 +0900118 `--payload_type image ` +
119 `--key ${key} ${opt_flags} ${image_dir} ${out} `,
120 CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}",
Theotime Combes4ba38c12020-06-12 12:46:59 +0000121 "${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}", "${sload_f2fs}",
Jiyong Park09d77522019-11-18 11:16:27 +0900122 "${soong_zip}", "${zipalign}", "${aapt2}", "prebuilts/sdk/current/public/android.jar"},
123 Rspfile: "${out}.copy_commands",
124 RspfileContent: "${copy_commands}",
125 Description: "APEX ${image_dir} => ${out}",
Theotime Combes4ba38c12020-06-12 12:46:59 +0000126 }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest", "payload_fs_type")
Jiyong Park09d77522019-11-18 11:16:27 +0900127
128 zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
129 Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
130 `(. ${out}.copy_commands) && ` +
131 `APEXER_TOOL_PATH=${tool_path} ` +
Jooyung Han214bf372019-11-12 13:03:50 +0900132 `${apexer} --force --manifest ${manifest} ` +
Jiyong Park09d77522019-11-18 11:16:27 +0900133 `--payload_type zip ` +
134 `${image_dir} ${out} `,
135 CommandDeps: []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
136 Rspfile: "${out}.copy_commands",
137 RspfileContent: "${copy_commands}",
138 Description: "ZipAPEX ${image_dir} => ${out}",
Jooyung Han214bf372019-11-12 13:03:50 +0900139 }, "tool_path", "image_dir", "copy_commands", "manifest")
Jiyong Park09d77522019-11-18 11:16:27 +0900140
141 apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule",
142 blueprint.RuleParams{
143 Command: `${aapt2} convert --output-format proto $in -o $out`,
144 CommandDeps: []string{"${aapt2}"},
145 })
146
147 apexBundleRule = pctx.StaticRule("apexBundleRule", blueprint.RuleParams{
Jiyong Parkbd159612020-02-28 15:22:21 +0900148 Command: `${zip2zip} -i $in -o $out.base ` +
Jiyong Park09d77522019-11-18 11:16:27 +0900149 `apex_payload.img:apex/${abi}.img ` +
Dario Frenida1aefe2020-03-02 21:47:09 +0000150 `apex_build_info.pb:apex/${abi}.build_info.pb ` +
Jiyong Park09d77522019-11-18 11:16:27 +0900151 `apex_manifest.json:root/apex_manifest.json ` +
Jiyong Park53ae3342019-12-08 02:06:24 +0900152 `apex_manifest.pb:root/apex_manifest.pb ` +
Jiyong Park09d77522019-11-18 11:16:27 +0900153 `AndroidManifest.xml:manifest/AndroidManifest.xml ` +
Jiyong Parkbd159612020-02-28 15:22:21 +0900154 `assets/NOTICE.html.gz:assets/NOTICE.html.gz &&` +
155 `${soong_zip} -o $out.config -C $$(dirname ${config}) -f ${config} && ` +
156 `${merge_zips} $out $out.base $out.config`,
157 CommandDeps: []string{"${zip2zip}", "${soong_zip}", "${merge_zips}"},
Jiyong Park09d77522019-11-18 11:16:27 +0900158 Description: "app bundle",
Jiyong Parkbd159612020-02-28 15:22:21 +0900159 }, "abi", "config")
Jiyong Park09d77522019-11-18 11:16:27 +0900160
161 emitApexContentRule = pctx.StaticRule("emitApexContentRule", blueprint.RuleParams{
162 Command: `rm -f ${out} && touch ${out} && (. ${out}.emit_commands)`,
163 Rspfile: "${out}.emit_commands",
164 RspfileContent: "${emit_commands}",
165 Description: "Emit APEX image content",
166 }, "emit_commands")
167
168 diffApexContentRule = pctx.StaticRule("diffApexContentRule", blueprint.RuleParams{
169 Command: `diff --unchanged-group-format='' \` +
170 `--changed-group-format='%<' \` +
Colin Cross440e0d02020-06-11 11:32:11 -0700171 `${image_content_file} ${allowed_files_file} || (` +
Jiyong Park09d77522019-11-18 11:16:27 +0900172 `echo -e "New unexpected files were added to ${apex_module_name}." ` +
173 ` "To fix the build run following command:" && ` +
Colin Cross440e0d02020-06-11 11:32:11 -0700174 `echo "system/apex/tools/update_allowed_list.sh ${allowed_files_file} ${image_content_file}" && ` +
Dan Willemsen81e43c52020-01-28 15:40:19 -0800175 `exit 1); touch ${out}`,
Colin Cross440e0d02020-06-11 11:32:11 -0700176 Description: "Diff ${image_content_file} and ${allowed_files_file}",
177 }, "image_content_file", "allowed_files_file", "apex_module_name")
Jiyong Parkb81b9902020-11-24 19:51:18 +0900178
179 // Don't add more rules here. Consider using android.NewRuleBuilder instead.
Jiyong Park09d77522019-11-18 11:16:27 +0900180)
181
Jiyong Parkb81b9902020-11-24 19:51:18 +0900182// buildManifest creates buile rules to modify the input apex_manifest.json to add information
183// gathered by the build system such as provided/required native libraries. Two output files having
184// different formats are generated. a.manifestJsonOut is JSON format for Q devices, and
185// a.manifest.PbOut is protobuf format for R+ devices.
186// TODO(jiyong): make this to return paths instead of directly storing the paths to apexBundle
Jiyong Park09d77522019-11-18 11:16:27 +0900187func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, requireNativeLibs []string) {
Jiyong Parkb81b9902020-11-24 19:51:18 +0900188 src := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
Jiyong Park09d77522019-11-18 11:16:27 +0900189
Jiyong Parkb81b9902020-11-24 19:51:18 +0900190 // Put dependency({provide|require}NativeLibs) in apex_manifest.json
Jiyong Park09d77522019-11-18 11:16:27 +0900191 provideNativeLibs = android.SortedUniqueStrings(provideNativeLibs)
192 requireNativeLibs = android.SortedUniqueStrings(android.RemoveListFromList(requireNativeLibs, provideNativeLibs))
193
Jiyong Parkb81b9902020-11-24 19:51:18 +0900194 // APEX name can be overridden
Jiyong Park09d77522019-11-18 11:16:27 +0900195 optCommands := []string{}
196 if a.properties.Apex_name != nil {
197 optCommands = append(optCommands, "-v name "+*a.properties.Apex_name)
198 }
199
Jiyong Parkb81b9902020-11-24 19:51:18 +0900200 // Collect jniLibs. Notice that a.filesInfo is already sorted
Jooyung Han643adc42020-02-27 13:50:06 +0900201 var jniLibs []string
202 for _, fi := range a.filesInfo {
Jiyong Parkc0ec6f92020-11-19 23:00:52 +0900203 if fi.isJniLib && !android.InList(fi.stem(), jniLibs) {
204 jniLibs = append(jniLibs, fi.stem())
Jooyung Han643adc42020-02-27 13:50:06 +0900205 }
206 }
207 if len(jniLibs) > 0 {
208 optCommands = append(optCommands, "-a jniLibs "+strings.Join(jniLibs, " "))
209 }
210
Jiyong Parkb81b9902020-11-24 19:51:18 +0900211 manifestJsonFullOut := android.PathForModuleOut(ctx, "apex_manifest_full.json")
Jiyong Park09d77522019-11-18 11:16:27 +0900212 ctx.Build(pctx, android.BuildParams{
213 Rule: apexManifestRule,
Jiyong Parkb81b9902020-11-24 19:51:18 +0900214 Input: src,
Jooyung Han214bf372019-11-12 13:03:50 +0900215 Output: manifestJsonFullOut,
Jiyong Park09d77522019-11-18 11:16:27 +0900216 Args: map[string]string{
217 "provideNativeLibs": strings.Join(provideNativeLibs, " "),
218 "requireNativeLibs": strings.Join(requireNativeLibs, " "),
219 "opt": strings.Join(optCommands, " "),
220 },
221 })
222
Jiyong Parkb81b9902020-11-24 19:51:18 +0900223 // b/143654022 Q apexd can't understand newly added keys in apex_manifest.json prepare
224 // stripped-down version so that APEX modules built from R+ can be installed to Q
Dan Albertc8060532020-07-22 22:32:17 -0700225 minSdkVersion := a.minSdkVersion(ctx)
226 if minSdkVersion.EqualTo(android.SdkVersion_Android10) {
Jooyung Han214bf372019-11-12 13:03:50 +0900227 a.manifestJsonOut = android.PathForModuleOut(ctx, "apex_manifest.json")
228 ctx.Build(pctx, android.BuildParams{
229 Rule: stripApexManifestRule,
230 Input: manifestJsonFullOut,
231 Output: a.manifestJsonOut,
232 })
233 }
Jiyong Park09d77522019-11-18 11:16:27 +0900234
Jiyong Parkb81b9902020-11-24 19:51:18 +0900235 // From R+, protobuf binary format (.pb) is the standard format for apex_manifest
Jiyong Park09d77522019-11-18 11:16:27 +0900236 a.manifestPbOut = android.PathForModuleOut(ctx, "apex_manifest.pb")
237 ctx.Build(pctx, android.BuildParams{
238 Rule: pbApexManifestRule,
Jooyung Han214bf372019-11-12 13:03:50 +0900239 Input: manifestJsonFullOut,
Jiyong Park09d77522019-11-18 11:16:27 +0900240 Output: a.manifestPbOut,
241 })
242}
243
Jiyong Parkb81b9902020-11-24 19:51:18 +0900244// buildFileContexts create build rules to append an entry for apex_manifest.pb to the file_contexts
245// file for this APEX which is either from /systme/sepolicy/apex/<apexname>-file_contexts or from
246// the file_contexts property of this APEX. This is to make sure that the manifest file is correctly
247// labeled as system_file.
248func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.OutputPath {
Jooyung Han580eb4f2020-06-24 19:33:06 +0900249 var fileContexts android.Path
250 if a.properties.File_contexts == nil {
251 fileContexts = android.PathForSource(ctx, "system/sepolicy/apex", ctx.ModuleName()+"-file_contexts")
252 } else {
253 fileContexts = android.PathForModuleSrc(ctx, *a.properties.File_contexts)
254 }
255 if a.Platform() {
256 if matched, err := path.Match("system/sepolicy/**/*", fileContexts.String()); err != nil || !matched {
257 ctx.PropertyErrorf("file_contexts", "should be under system/sepolicy, but %q", fileContexts)
Jooyung Han580eb4f2020-06-24 19:33:06 +0900258 }
259 }
260 if !android.ExistentPathForSource(ctx, fileContexts.String()).Valid() {
Jiyong Parkb81b9902020-11-24 19:51:18 +0900261 ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", fileContexts.String())
Jooyung Han580eb4f2020-06-24 19:33:06 +0900262 }
263
264 output := android.PathForModuleOut(ctx, "file_contexts")
265 rule := android.NewRuleBuilder()
Jooyung Han7f146c02020-09-23 19:15:55 +0900266
Jiyong Parkb81b9902020-11-24 19:51:18 +0900267 switch a.properties.ApexType {
268 case imageApex:
Jooyung Han7f146c02020-09-23 19:15:55 +0900269 // remove old file
270 rule.Command().Text("rm").FlagWithOutput("-f ", output)
271 // copy file_contexts
272 rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
273 // new line
274 rule.Command().Text("echo").Text(">>").Output(output)
275 // force-label /apex_manifest.pb and / as system_file so that apexd can read them
276 rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
277 rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output)
Jiyong Parkb81b9902020-11-24 19:51:18 +0900278 case flattenedApex:
Jooyung Han7f146c02020-09-23 19:15:55 +0900279 // For flattened apexes, install path should be prepended.
280 // File_contexts file should be emiited to make via LOCAL_FILE_CONTEXTS
281 // so that it can be merged into file_contexts.bin
282 apexPath := android.InstallPathToOnDevicePath(ctx, a.installDir.Join(ctx, a.Name()))
283 apexPath = strings.ReplaceAll(apexPath, ".", `\\.`)
284 // remove old file
285 rule.Command().Text("rm").FlagWithOutput("-f ", output)
286 // copy file_contexts
287 rule.Command().Text("awk").Text(`'/object_r/{printf("` + apexPath + `%s\n", $0)}'`).Input(fileContexts).Text(">").Output(output)
288 // new line
289 rule.Command().Text("echo").Text(">>").Output(output)
290 // force-label /apex_manifest.pb and / as system_file so that apexd can read them
291 rule.Command().Text("echo").Flag(apexPath + `/apex_manifest\\.pb u:object_r:system_file:s0`).Text(">>").Output(output)
292 rule.Command().Text("echo").Flag(apexPath + "/ u:object_r:system_file:s0").Text(">>").Output(output)
Jiyong Parkb81b9902020-11-24 19:51:18 +0900293 default:
294 panic(fmt.Errorf("unsupported type %v", a.properties.ApexType))
Jooyung Han7f146c02020-09-23 19:15:55 +0900295 }
296
Jooyung Han580eb4f2020-06-24 19:33:06 +0900297 rule.Build(pctx, ctx, "file_contexts."+a.Name(), "Generate file_contexts")
Jiyong Parkb81b9902020-11-24 19:51:18 +0900298 return output.OutputPath
Jooyung Han580eb4f2020-06-24 19:33:06 +0900299}
300
Jiyong Parkb81b9902020-11-24 19:51:18 +0900301// buildNoticeFiles creates a buile rule for aggregating notice files from the modules that
302// contributes to this APEX. The notice files are merged into a big notice file.
Jiyong Park19972c72020-01-28 20:05:29 +0900303func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName string) android.NoticeOutputs {
Jiyong Park9918e1a2020-03-17 19:16:40 +0900304 var noticeFiles android.Paths
305
Jooyung Han749dc692020-04-15 11:03:39 +0900306 a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
Jiyong Park9918e1a2020-03-17 19:16:40 +0900307 if externalDep {
Paul Duffinbe5a5be2020-03-30 15:54:08 +0100308 // As soon as the dependency graph crosses the APEX boundary, don't go further.
309 return false
Jiyong Park09d77522019-11-18 11:16:27 +0900310 }
Jiyong Parkb81b9902020-11-24 19:51:18 +0900311 noticeFiles = append(noticeFiles, to.NoticeFiles()...)
Paul Duffinbe5a5be2020-03-30 15:54:08 +0100312 return true
Jiyong Park9918e1a2020-03-17 19:16:40 +0900313 })
Jiyong Park09d77522019-11-18 11:16:27 +0900314
Jiyong Parkb81b9902020-11-24 19:51:18 +0900315 // TODO(jiyong): why do we need this? WalkPayloadDeps should have already covered this.
Jiyong Park41f637d2020-09-09 13:18:02 +0900316 for _, fi := range a.filesInfo {
317 noticeFiles = append(noticeFiles, fi.noticeFiles...)
318 }
319
Jiyong Park09d77522019-11-18 11:16:27 +0900320 if len(noticeFiles) == 0 {
Jiyong Park19972c72020-01-28 20:05:29 +0900321 return android.NoticeOutputs{}
Jiyong Park09d77522019-11-18 11:16:27 +0900322 }
323
Jiyong Park33c77362020-05-29 22:00:16 +0900324 return android.BuildNoticeOutput(ctx, a.installDir, apexFileName, android.SortedUniquePaths(noticeFiles))
Jiyong Park09d77522019-11-18 11:16:27 +0900325}
326
Jiyong Parkb81b9902020-11-24 19:51:18 +0900327// buildInstalledFilesFile creates a build rule for the installed-files.txt file where the list of
328// files included in this APEX is shown. The text file is dist'ed so that people can see what's
329// included in the APEX without actually downloading and extracting it.
Jiyong Park3a1602e2020-01-14 14:39:19 +0900330func (a *apexBundle) buildInstalledFilesFile(ctx android.ModuleContext, builtApex android.Path, imageDir android.Path) android.OutputPath {
331 output := android.PathForModuleOut(ctx, "installed-files.txt")
332 rule := android.NewRuleBuilder()
333 rule.Command().
334 Implicit(builtApex).
335 Text("(cd " + imageDir.String() + " ; ").
Jiyong Parkbd63a102020-02-08 12:40:05 +0900336 Text("find . \\( -type f -o -type l \\) -printf \"%s %p\\n\") ").
Jiyong Park3a1602e2020-01-14 14:39:19 +0900337 Text(" | sort -nr > ").
338 Output(output)
339 rule.Build(pctx, ctx, "installed-files."+a.Name(), "Installed files")
340 return output.OutputPath
341}
342
Jiyong Parkb81b9902020-11-24 19:51:18 +0900343// buildBundleConfig creates a build rule for the bundle config file that will control the bundle
344// creation process.
Jiyong Parkbd159612020-02-28 15:22:21 +0900345func (a *apexBundle) buildBundleConfig(ctx android.ModuleContext) android.OutputPath {
346 output := android.PathForModuleOut(ctx, "bundle_config.json")
347
Jiyong Parkcfaa1642020-02-28 16:51:07 +0900348 type ApkConfig struct {
349 Package_name string `json:"package_name"`
350 Apk_path string `json:"path"`
351 }
Jiyong Parkbd159612020-02-28 15:22:21 +0900352 config := struct {
353 Compression struct {
354 Uncompressed_glob []string `json:"uncompressed_glob"`
355 } `json:"compression"`
Jiyong Parkcfaa1642020-02-28 16:51:07 +0900356 Apex_config struct {
357 Apex_embedded_apk_config []ApkConfig `json:"apex_embedded_apk_config,omitempty"`
358 } `json:"apex_config,omitempty"`
Jiyong Parkbd159612020-02-28 15:22:21 +0900359 }{}
360
361 config.Compression.Uncompressed_glob = []string{
362 "apex_payload.img",
363 "apex_manifest.*",
364 }
Jiyong Parkcfaa1642020-02-28 16:51:07 +0900365
Jiyong Parkb81b9902020-11-24 19:51:18 +0900366 // Collect the manifest names and paths of android apps if their manifest names are
367 // overridden.
Jiyong Parkcfaa1642020-02-28 16:51:07 +0900368 for _, fi := range a.filesInfo {
Sasha Smundak18d98bc2020-05-27 16:36:07 -0700369 if fi.class != app && fi.class != appSet {
Jiyong Parkcfaa1642020-02-28 16:51:07 +0900370 continue
371 }
372 packageName := fi.overriddenPackageName
373 if packageName != "" {
374 config.Apex_config.Apex_embedded_apk_config = append(
375 config.Apex_config.Apex_embedded_apk_config,
376 ApkConfig{
377 Package_name: packageName,
Jiyong Parkc0ec6f92020-11-19 23:00:52 +0900378 Apk_path: fi.path(),
Jiyong Parkcfaa1642020-02-28 16:51:07 +0900379 })
380 }
381 }
382
Jiyong Parkbd159612020-02-28 15:22:21 +0900383 j, err := json.Marshal(config)
384 if err != nil {
385 panic(fmt.Errorf("error while marshalling to %q: %#v", output, err))
386 }
387
Colin Crosscf371cc2020-11-13 11:48:42 -0800388 android.WriteFileRule(ctx, output, string(j))
Jiyong Parkbd159612020-02-28 15:22:21 +0900389
390 return output.OutputPath
391}
392
Jiyong Parkb81b9902020-11-24 19:51:18 +0900393// buildUnflattendApex creates build rules to build an APEX using apexer.
Jiyong Park09d77522019-11-18 11:16:27 +0900394func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
Jiyong Park09d77522019-11-18 11:16:27 +0900395 apexType := a.properties.ApexType
396 suffix := apexType.suffix()
Jiyong Park09d77522019-11-18 11:16:27 +0900397
Jiyong Parkb81b9902020-11-24 19:51:18 +0900398 ////////////////////////////////////////////////////////////////////////////////////////////
399 // Step 1: copy built files to appropriate directories under the image directory
400
401 imageDir := android.PathForModuleOut(ctx, "image"+suffix)
402
403 // TODO(jiyong): use the RuleBuilder
Jiyong Park7cd10e32020-01-14 09:22:18 +0900404 var copyCommands []string
Jiyong Parkb81b9902020-11-24 19:51:18 +0900405 var implicitInputs []android.Path
Jiyong Park7cd10e32020-01-14 09:22:18 +0900406 for _, fi := range a.filesInfo {
Jiyong Parkb81b9902020-11-24 19:51:18 +0900407 destPath := imageDir.Join(ctx, fi.path()).String()
408
409 // Prepare the destination path
Sasha Smundak18d98bc2020-05-27 16:36:07 -0700410 destPathDir := filepath.Dir(destPath)
411 if fi.class == appSet {
412 copyCommands = append(copyCommands, "rm -rf "+destPathDir)
413 }
414 copyCommands = append(copyCommands, "mkdir -p "+destPathDir)
Jiyong Parkb81b9902020-11-24 19:51:18 +0900415
416 // Copy the built file to the directory. But if the symlink optimization is turned
417 // on, place a symlink to the corresponding file in /system partition instead.
Jiyong Parkc0ec6f92020-11-19 23:00:52 +0900418 if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
Jiyong Park7cd10e32020-01-14 09:22:18 +0900419 // TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here
Jiyong Parkc0ec6f92020-11-19 23:00:52 +0900420 pathOnDevice := filepath.Join("/system", fi.path())
Jiyong Park7cd10e32020-01-14 09:22:18 +0900421 copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath)
422 } else {
Sasha Smundak18d98bc2020-05-27 16:36:07 -0700423 if fi.class == appSet {
424 copyCommands = append(copyCommands,
Colin Crossd783bbb2020-07-11 22:30:45 -0700425 fmt.Sprintf("unzip -qDD -d %s %s", destPathDir, fi.builtFile.String()))
Sasha Smundak18d98bc2020-05-27 16:36:07 -0700426 } else {
427 copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
428 }
Jiyong Park7cd10e32020-01-14 09:22:18 +0900429 implicitInputs = append(implicitInputs, fi.builtFile)
430 }
Jiyong Parkb81b9902020-11-24 19:51:18 +0900431
432 // Create additional symlinks pointing the file inside the APEX (if any). Note that
433 // this is independent from the symlink optimization.
Jiyong Parkc0ec6f92020-11-19 23:00:52 +0900434 for _, symlinkPath := range fi.symlinkPaths() {
Jiyong Parkb81b9902020-11-24 19:51:18 +0900435 symlinkDest := imageDir.Join(ctx, symlinkPath).String()
Tim Joinesc1ef1bb2020-03-18 18:00:41 +0000436 copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
Jiyong Park7cd10e32020-01-14 09:22:18 +0900437 }
Jiyong Parkb81b9902020-11-24 19:51:18 +0900438
439 // Copy the test files (if any)
Liz Kammer1c14a212020-05-12 15:26:55 -0700440 for _, d := range fi.dataPaths {
441 // TODO(eakammer): This is now the third repetition of ~this logic for test paths, refactoring should be possible
Chris Parsons216e10a2020-07-09 17:12:52 -0400442 relPath := d.SrcPath.Rel()
443 dataPath := d.SrcPath.String()
Liz Kammer1c14a212020-05-12 15:26:55 -0700444 if !strings.HasSuffix(dataPath, relPath) {
445 panic(fmt.Errorf("path %q does not end with %q", dataPath, relPath))
446 }
447
Jiyong Parkb81b9902020-11-24 19:51:18 +0900448 dataDest := imageDir.Join(ctx, fi.apexRelativePath(relPath), d.RelativeInstallPath).String()
Liz Kammer1c14a212020-05-12 15:26:55 -0700449
Chris Parsons216e10a2020-07-09 17:12:52 -0400450 copyCommands = append(copyCommands, "cp -f "+d.SrcPath.String()+" "+dataDest)
451 implicitInputs = append(implicitInputs, d.SrcPath)
Liz Kammer1c14a212020-05-12 15:26:55 -0700452 }
Jiyong Park09d77522019-11-18 11:16:27 +0900453 }
Jooyung Han214bf372019-11-12 13:03:50 +0900454 implicitInputs = append(implicitInputs, a.manifestPbOut)
Jiyong Park09d77522019-11-18 11:16:27 +0900455
Jiyong Parkb81b9902020-11-24 19:51:18 +0900456 ////////////////////////////////////////////////////////////////////////////////////////////
457 // Step 1.a: Write the list of files in this APEX to a txt file and compare it against
458 // the allowed list given via the allowed_files property. Build fails when the two lists
459 // differ.
460 //
461 // TODO(jiyong): consider removing this. Nobody other than com.android.apex.cts.shim.* seems
462 // to be using this at this moment. Furthermore, this looks very similar to what
463 // buildInstalledFilesFile does. At least, move this to somewhere else so that this doesn't
464 // hurt readability.
465 // TODO(jiyong): use RuleBuilder
Jooyung Han938b5932020-06-20 12:47:47 +0900466 if a.overridableProperties.Allowed_files != nil {
Jiyong Parkb81b9902020-11-24 19:51:18 +0900467 // Build content.txt
468 var emitCommands []string
469 imageContentFile := android.PathForModuleOut(ctx, "content.txt")
470 emitCommands = append(emitCommands, "echo ./apex_manifest.pb >> "+imageContentFile.String())
471 minSdkVersion := a.minSdkVersion(ctx)
472 if minSdkVersion.EqualTo(android.SdkVersion_Android10) {
473 emitCommands = append(emitCommands, "echo ./apex_manifest.json >> "+imageContentFile.String())
474 }
475 for _, fi := range a.filesInfo {
476 emitCommands = append(emitCommands, "echo './"+fi.path()+"' >> "+imageContentFile.String())
477 }
478 emitCommands = append(emitCommands, "sort -o "+imageContentFile.String()+" "+imageContentFile.String())
Jiyong Park09d77522019-11-18 11:16:27 +0900479 ctx.Build(pctx, android.BuildParams{
480 Rule: emitApexContentRule,
481 Implicits: implicitInputs,
482 Output: imageContentFile,
483 Description: "emit apex image content",
484 Args: map[string]string{
485 "emit_commands": strings.Join(emitCommands, " && "),
486 },
487 })
488 implicitInputs = append(implicitInputs, imageContentFile)
Jiyong Park09d77522019-11-18 11:16:27 +0900489
Jiyong Parkb81b9902020-11-24 19:51:18 +0900490 // Compare content.txt against allowed_files.
491 allowedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.overridableProperties.Allowed_files))
Jaewoong Jung1670ca02019-11-22 14:50:42 -0800492 phonyOutput := android.PathForModuleOut(ctx, a.Name()+"-diff-phony-output")
Jiyong Park09d77522019-11-18 11:16:27 +0900493 ctx.Build(pctx, android.BuildParams{
494 Rule: diffApexContentRule,
495 Implicits: implicitInputs,
496 Output: phonyOutput,
497 Description: "diff apex image content",
498 Args: map[string]string{
Colin Cross440e0d02020-06-11 11:32:11 -0700499 "allowed_files_file": allowedFilesFile.String(),
500 "image_content_file": imageContentFile.String(),
501 "apex_module_name": a.Name(),
Jiyong Park09d77522019-11-18 11:16:27 +0900502 },
503 })
Jiyong Park09d77522019-11-18 11:16:27 +0900504 implicitInputs = append(implicitInputs, phonyOutput)
505 }
506
Jiyong Parkb81b9902020-11-24 19:51:18 +0900507 unsignedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix+".unsigned")
Jiyong Park09d77522019-11-18 11:16:27 +0900508 outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String()
509 prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
510
511 if apexType == imageApex {
Jiyong Parkb81b9902020-11-24 19:51:18 +0900512 ////////////////////////////////////////////////////////////////////////////////////
513 // Step 2: create canned_fs_config which encodes filemode,uid,gid of each files
514 // in this APEX. The file will be used by apexer in later steps.
515 // TODO(jiyong): make this as a function
516 // TODO(jiyong): use the RuleBuilder
Jiyong Park09d77522019-11-18 11:16:27 +0900517 var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"}
518 var executablePaths []string // this also includes dirs
Sasha Smundak18d98bc2020-05-27 16:36:07 -0700519 var extractedAppSetPaths android.Paths
520 var extractedAppSetDirs []string
Jiyong Park09d77522019-11-18 11:16:27 +0900521 for _, f := range a.filesInfo {
Jiyong Parkc0ec6f92020-11-19 23:00:52 +0900522 pathInApex := f.path()
Jiyong Park09d77522019-11-18 11:16:27 +0900523 if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") {
524 executablePaths = append(executablePaths, pathInApex)
Liz Kammer1c14a212020-05-12 15:26:55 -0700525 for _, d := range f.dataPaths {
Liz Kammer0a51aa22020-07-21 11:13:17 -0700526 readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, d.RelativeInstallPath, d.SrcPath.Rel()))
Liz Kammer1c14a212020-05-12 15:26:55 -0700527 }
Jiyong Park09d77522019-11-18 11:16:27 +0900528 for _, s := range f.symlinks {
529 executablePaths = append(executablePaths, filepath.Join(f.installDir, s))
530 }
Sasha Smundak18d98bc2020-05-27 16:36:07 -0700531 } else if f.class == appSet {
532 extractedAppSetPaths = append(extractedAppSetPaths, f.builtFile)
533 extractedAppSetDirs = append(extractedAppSetDirs, f.installDir)
Jiyong Park09d77522019-11-18 11:16:27 +0900534 } else {
535 readOnlyPaths = append(readOnlyPaths, pathInApex)
536 }
537 dir := f.installDir
538 for !android.InList(dir, executablePaths) && dir != "" {
539 executablePaths = append(executablePaths, dir)
540 dir, _ = filepath.Split(dir) // move up to the parent
541 if len(dir) > 0 {
542 // remove trailing slash
543 dir = dir[:len(dir)-1]
544 }
545 }
546 }
547 sort.Strings(readOnlyPaths)
548 sort.Strings(executablePaths)
549 cannedFsConfig := android.PathForModuleOut(ctx, "canned_fs_config")
550 ctx.Build(pctx, android.BuildParams{
551 Rule: generateFsConfig,
552 Output: cannedFsConfig,
553 Description: "generate fs config",
Sasha Smundak18d98bc2020-05-27 16:36:07 -0700554 Inputs: extractedAppSetPaths,
Jiyong Park09d77522019-11-18 11:16:27 +0900555 Args: map[string]string{
556 "ro_paths": strings.Join(readOnlyPaths, " "),
557 "exec_paths": strings.Join(executablePaths, " "),
Sasha Smundak18d98bc2020-05-27 16:36:07 -0700558 "apk_paths": strings.Join(extractedAppSetDirs, " "),
Jiyong Park09d77522019-11-18 11:16:27 +0900559 },
560 })
Jiyong Parkb81b9902020-11-24 19:51:18 +0900561 implicitInputs = append(implicitInputs, cannedFsConfig)
Jiyong Park09d77522019-11-18 11:16:27 +0900562
Jiyong Parkb81b9902020-11-24 19:51:18 +0900563 ////////////////////////////////////////////////////////////////////////////////////
564 // Step 3: Prepare option flags for apexer and invoke it to create an unsigned APEX.
565 // TODO(jiyong): use the RuleBuilder
Jiyong Park09d77522019-11-18 11:16:27 +0900566 optFlags := []string{}
567
Jiyong Parkb81b9902020-11-24 19:51:18 +0900568 fileContexts := a.buildFileContexts(ctx)
569 implicitInputs = append(implicitInputs, fileContexts)
570
571 implicitInputs = append(implicitInputs, a.private_key_file, a.public_key_file)
Jiyong Park09d77522019-11-18 11:16:27 +0900572 optFlags = append(optFlags, "--pubkey "+a.public_key_file.String())
573
Jooyung Han27151d92019-12-16 17:45:32 +0900574 manifestPackageName := a.getOverrideManifestPackageName(ctx)
575 if manifestPackageName != "" {
Jiyong Park09d77522019-11-18 11:16:27 +0900576 optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName)
577 }
578
579 if a.properties.AndroidManifest != nil {
580 androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))
581 implicitInputs = append(implicitInputs, androidManifestFile)
582 optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
583 }
584
Jiyong Parkb81b9902020-11-24 19:51:18 +0900585 // Determine target/min sdk version from the context
586 // TODO(jiyong): make this as a function
Dan Albertc8060532020-07-22 22:32:17 -0700587 moduleMinSdkVersion := a.minSdkVersion(ctx)
Nikita Ioffe5335bc42020-10-20 00:02:15 +0100588 minSdkVersion := moduleMinSdkVersion.String()
589
Jiyong Parkb81b9902020-11-24 19:51:18 +0900590 // bundletool doesn't understand what "current" is. We need to transform it to
591 // codename
Nikita Ioffe5335bc42020-10-20 00:02:15 +0100592 if moduleMinSdkVersion.IsCurrent() {
593 minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
Nikita Ioffe5d600c92020-02-20 00:43:27 +0000594 }
Jiyong Parkb81b9902020-11-24 19:51:18 +0900595 // apex module doesn't have a concept of target_sdk_version, hence for the time
596 // being targetSdkVersion == default targetSdkVersion of the branch.
Nikita Ioffe5335bc42020-10-20 00:02:15 +0100597 targetSdkVersion := strconv.Itoa(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt())
Nikita Ioffe5d600c92020-02-20 00:43:27 +0000598
Nikita Ioffe1f4f3452020-03-02 16:58:11 +0000599 if java.UseApiFingerprint(ctx) {
600 targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
Baligh Uddinf6201372020-01-24 23:15:44 +0000601 implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
602 }
Nikita Ioffe1f4f3452020-03-02 16:58:11 +0000603 if java.UseApiFingerprint(ctx) {
604 minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
Baligh Uddinf6201372020-01-24 23:15:44 +0000605 implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
Jiyong Park09d77522019-11-18 11:16:27 +0900606 }
607 optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
Baligh Uddinf6201372020-01-24 23:15:44 +0000608 optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion)
Jiyong Park09d77522019-11-18 11:16:27 +0900609
Baligh Uddin004d7172020-02-19 21:29:28 -0800610 if a.overridableProperties.Logging_parent != "" {
611 optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent)
612 }
613
Jiyong Park19972c72020-01-28 20:05:29 +0900614 a.mergedNotices = a.buildNoticeFiles(ctx, a.Name()+suffix)
615 if a.mergedNotices.HtmlGzOutput.Valid() {
Jiyong Park09d77522019-11-18 11:16:27 +0900616 // If there's a NOTICE file, embed it as an asset file in the APEX.
Jiyong Park19972c72020-01-28 20:05:29 +0900617 implicitInputs = append(implicitInputs, a.mergedNotices.HtmlGzOutput.Path())
618 optFlags = append(optFlags, "--assets_dir "+filepath.Dir(a.mergedNotices.HtmlGzOutput.String()))
Jiyong Park09d77522019-11-18 11:16:27 +0900619 }
620
Nikita Ioffeb4b44c02020-01-02 23:01:39 +0000621 if ctx.ModuleDir() != "system/apex/apexd/apexd_testdata" && ctx.ModuleDir() != "system/apex/shim/build" && a.testOnlyShouldSkipHashtreeGeneration() {
Nikita Ioffec72b5dd2019-12-07 17:30:22 +0000622 ctx.PropertyErrorf("test_only_no_hashtree", "not available")
623 return
624 }
Dan Albertc8060532020-07-22 22:32:17 -0700625 if moduleMinSdkVersion.GreaterThan(android.SdkVersion_Android10) || a.testOnlyShouldSkipHashtreeGeneration() {
Jiyong Park09d77522019-11-18 11:16:27 +0900626 // Apexes which are supposed to be installed in builtin dirs(/system, etc)
627 // don't need hashtree for activation. Therefore, by removing hashtree from
628 // apex bundle (filesystem image in it, to be specific), we can save storage.
629 optFlags = append(optFlags, "--no_hashtree")
630 }
631
Dario Frenica913392020-04-27 18:21:11 +0100632 if a.testOnlyShouldSkipPayloadSign() {
633 optFlags = append(optFlags, "--unsigned_payload")
634 }
635
Jiyong Park09d77522019-11-18 11:16:27 +0900636 if a.properties.Apex_name != nil {
Jiyong Parkb81b9902020-11-24 19:51:18 +0900637 // If apex_name is set, apexer can skip checking if key name matches with
638 // apex name. Note that apex_manifest is also mended.
Jiyong Park09d77522019-11-18 11:16:27 +0900639 optFlags = append(optFlags, "--do_not_check_keyname")
640 }
641
Dan Albertc8060532020-07-22 22:32:17 -0700642 if moduleMinSdkVersion == android.SdkVersion_Android10 {
Jooyung Han214bf372019-11-12 13:03:50 +0900643 implicitInputs = append(implicitInputs, a.manifestJsonOut)
644 optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String())
645 }
646
Theotime Combes4ba38c12020-06-12 12:46:59 +0000647 optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string())
648
Jiyong Park09d77522019-11-18 11:16:27 +0900649 ctx.Build(pctx, android.BuildParams{
650 Rule: apexRule,
651 Implicits: implicitInputs,
652 Output: unsignedOutputFile,
653 Description: "apex (" + apexType.name() + ")",
654 Args: map[string]string{
Jooyung Han214bf372019-11-12 13:03:50 +0900655 "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
Jiyong Park3a1602e2020-01-14 14:39:19 +0900656 "image_dir": imageDir.String(),
Jooyung Han214bf372019-11-12 13:03:50 +0900657 "copy_commands": strings.Join(copyCommands, " && "),
658 "manifest": a.manifestPbOut.String(),
Jiyong Parkb81b9902020-11-24 19:51:18 +0900659 "file_contexts": fileContexts.String(),
Jooyung Han214bf372019-11-12 13:03:50 +0900660 "canned_fs_config": cannedFsConfig.String(),
661 "key": a.private_key_file.String(),
662 "opt_flags": strings.Join(optFlags, " "),
Jiyong Park09d77522019-11-18 11:16:27 +0900663 },
664 })
665
Jiyong Parkb81b9902020-11-24 19:51:18 +0900666 // TODO(jiyong): make the two rules below as separate functions
Jaewoong Jung1670ca02019-11-22 14:50:42 -0800667 apexProtoFile := android.PathForModuleOut(ctx, a.Name()+".pb"+suffix)
668 bundleModuleFile := android.PathForModuleOut(ctx, a.Name()+suffix+"-base.zip")
Jiyong Park09d77522019-11-18 11:16:27 +0900669 a.bundleModuleFile = bundleModuleFile
670
671 ctx.Build(pctx, android.BuildParams{
672 Rule: apexProtoConvertRule,
673 Input: unsignedOutputFile,
674 Output: apexProtoFile,
675 Description: "apex proto convert",
676 })
677
Jiyong Parkbd159612020-02-28 15:22:21 +0900678 bundleConfig := a.buildBundleConfig(ctx)
679
Jiyong Parkb81b9902020-11-24 19:51:18 +0900680 var abis []string
681 for _, target := range ctx.MultiTargets() {
682 if len(target.Arch.Abi) > 0 {
683 abis = append(abis, target.Arch.Abi[0])
684 }
685 }
686
687 abis = android.FirstUniqueStrings(abis)
688
Jiyong Park09d77522019-11-18 11:16:27 +0900689 ctx.Build(pctx, android.BuildParams{
690 Rule: apexBundleRule,
691 Input: apexProtoFile,
Jiyong Parkbd159612020-02-28 15:22:21 +0900692 Implicit: bundleConfig,
Jiyong Park09d77522019-11-18 11:16:27 +0900693 Output: a.bundleModuleFile,
694 Description: "apex bundle module",
695 Args: map[string]string{
Jiyong Parkbd159612020-02-28 15:22:21 +0900696 "abi": strings.Join(abis, "."),
697 "config": bundleConfig.String(),
Jiyong Park09d77522019-11-18 11:16:27 +0900698 },
699 })
Jiyong Parkb81b9902020-11-24 19:51:18 +0900700 } else { // zipApex
Jiyong Park09d77522019-11-18 11:16:27 +0900701 ctx.Build(pctx, android.BuildParams{
702 Rule: zipApexRule,
703 Implicits: implicitInputs,
704 Output: unsignedOutputFile,
705 Description: "apex (" + apexType.name() + ")",
706 Args: map[string]string{
Jooyung Han214bf372019-11-12 13:03:50 +0900707 "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
Jiyong Park3a1602e2020-01-14 14:39:19 +0900708 "image_dir": imageDir.String(),
Jooyung Han214bf372019-11-12 13:03:50 +0900709 "copy_commands": strings.Join(copyCommands, " && "),
710 "manifest": a.manifestPbOut.String(),
Jiyong Park09d77522019-11-18 11:16:27 +0900711 },
712 })
713 }
714
Jiyong Parkb81b9902020-11-24 19:51:18 +0900715 ////////////////////////////////////////////////////////////////////////////////////
716 // Step 4: Sign the APEX using signapk
Jaewoong Jung1670ca02019-11-22 14:50:42 -0800717 a.outputFile = android.PathForModuleOut(ctx, a.Name()+suffix)
Jiyong Parkb81b9902020-11-24 19:51:18 +0900718
719 pem, key := a.getCertificateAndPrivateKey(ctx)
Kousik Kumar309b1c02020-05-28 06:13:33 -0700720 rule := java.Signapk
721 args := map[string]string{
Jiyong Parkb81b9902020-11-24 19:51:18 +0900722 "certificates": pem.String() + " " + key.String(),
Kousik Kumar309b1c02020-05-28 06:13:33 -0700723 "flags": "-a 4096", //alignment
724 }
Jiyong Parkb81b9902020-11-24 19:51:18 +0900725 implicits := android.Paths{pem, key}
Ramy Medhat16f23a42020-09-03 01:29:49 -0400726 if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
Kousik Kumar309b1c02020-05-28 06:13:33 -0700727 rule = java.SignapkRE
728 args["implicits"] = strings.Join(implicits.Strings(), ",")
729 args["outCommaList"] = a.outputFile.String()
730 }
Jiyong Park09d77522019-11-18 11:16:27 +0900731 ctx.Build(pctx, android.BuildParams{
Kousik Kumar309b1c02020-05-28 06:13:33 -0700732 Rule: rule,
Jiyong Park09d77522019-11-18 11:16:27 +0900733 Description: "signapk",
734 Output: a.outputFile,
735 Input: unsignedOutputFile,
Kousik Kumar309b1c02020-05-28 06:13:33 -0700736 Implicits: implicits,
737 Args: args,
Jiyong Park09d77522019-11-18 11:16:27 +0900738 })
739
740 // Install to $OUT/soong/{target,host}/.../apex
741 if a.installable() {
Jaewoong Jung1670ca02019-11-22 14:50:42 -0800742 ctx.InstallFile(a.installDir, a.Name()+suffix, a.outputFile)
Jiyong Park09d77522019-11-18 11:16:27 +0900743 }
Jiyong Park3a1602e2020-01-14 14:39:19 +0900744
745 // installed-files.txt is dist'ed
746 a.installedFilesFile = a.buildInstalledFilesFile(ctx, a.outputFile, imageDir)
Jiyong Park09d77522019-11-18 11:16:27 +0900747}
748
Jiyong Parkc0ec6f92020-11-19 23:00:52 +0900749// Context "decorator", overriding the InstallBypassMake method to always reply `true`.
750type flattenedApexContext struct {
751 android.ModuleContext
752}
753
754func (c *flattenedApexContext) InstallBypassMake() bool {
755 return true
756}
757
Jiyong Parkb81b9902020-11-24 19:51:18 +0900758// buildFlattenedApex creates rules for a flattened APEX. Flattened APEX actually doesn't have a
759// single output file. It is a phony target for all the files under /system/apex/<name> directory.
760// This function creates the installation rules for the files.
Jiyong Park09d77522019-11-18 11:16:27 +0900761func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) {
Jiyong Parkb81b9902020-11-24 19:51:18 +0900762 bundleName := a.Name()
Jiyong Park09d77522019-11-18 11:16:27 +0900763 if a.installable() {
Jiyong Parkb81b9902020-11-24 19:51:18 +0900764 for _, fi := range a.filesInfo {
765 dir := filepath.Join("apex", bundleName, fi.installDir)
766 target := ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.stem(), fi.builtFile)
767 for _, sym := range fi.symlinks {
768 ctx.InstallSymlink(android.PathForModuleInstall(ctx, dir), sym, target)
Jiyong Park09d77522019-11-18 11:16:27 +0900769 }
770 }
771 }
Jiyong Parkb81b9902020-11-24 19:51:18 +0900772
773 a.fileContexts = a.buildFileContexts(ctx)
774
775 // Temporarily wrap the original `ctx` into a `flattenedApexContext` to have it reply true
776 // to `InstallBypassMake()` (thus making the call `android.PathForModuleInstall` below use
777 // `android.pathForInstallInMakeDir` instead of `android.PathForOutput`) to return the
778 // correct path to the flattened APEX (as its contents is installed by Make, not Soong).
779 // TODO(jiyong): Why do we need to set outputFile for flattened APEX? We don't seem to use
780 // it and it actually points to a path that can never be built. Remove this.
781 factx := flattenedApexContext{ctx}
782 a.outputFile = android.PathForModuleInstall(&factx, "apex", bundleName)
783}
784
785// getCertificateAndPrivateKey retrieves the cert and the private key that will be used to sign
786// the zip container of this APEX. See the description of the 'certificate' property for how
787// the cert and the private key are found.
788func (a *apexBundle) getCertificateAndPrivateKey(ctx android.PathContext) (pem, key android.Path) {
789 if a.container_certificate_file != nil {
790 return a.container_certificate_file, a.container_private_key_file
791 }
792
793 cert := String(a.properties.Certificate)
794 if cert == "" {
795 return ctx.Config().DefaultAppCertificate(ctx)
796 }
797
798 defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
799 pem = defaultDir.Join(ctx, cert+".x509.pem")
800 key = defaultDir.Join(ctx, cert+".pk8")
801 return pem, key
Jiyong Park09d77522019-11-18 11:16:27 +0900802}
Jooyung Han27151d92019-12-16 17:45:32 +0900803
804func (a *apexBundle) getOverrideManifestPackageName(ctx android.ModuleContext) string {
805 // For VNDK APEXes, check "com.android.vndk" in PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES
806 // to see if it should be overridden because their <apex name> is dynamically generated
807 // according to its VNDK version.
808 if a.vndkApex {
809 overrideName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(vndkApexName)
810 if overridden {
811 return strings.Replace(*a.properties.Apex_name, vndkApexName, overrideName, 1)
812 }
813 return ""
814 }
Baligh Uddin5b57dba2020-03-15 13:01:05 -0700815 if a.overridableProperties.Package_name != "" {
816 return a.overridableProperties.Package_name
817 }
Jiyong Park20bacab2020-03-03 11:45:41 +0900818 manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName())
Jooyung Han27151d92019-12-16 17:45:32 +0900819 if overridden {
820 return manifestPackageName
821 }
822 return ""
823}
Jiyong Park83dc74b2020-01-14 18:38:44 +0900824
825func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) {
826 if !a.primaryApexType {
827 return
828 }
829
830 if a.properties.IsCoverageVariant {
831 // Otherwise, we will have duplicated rules for coverage and
832 // non-coverage variants of the same APEX
833 return
834 }
835
836 if ctx.Host() {
837 // No need to generate dependency info for host variant
838 return
839 }
840
Artur Satayev872a1442020-04-27 17:08:37 +0100841 depInfos := android.DepNameToDepInfoMap{}
Jooyung Han749dc692020-04-15 11:03:39 +0900842 a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
Artur Satayev872a1442020-04-27 17:08:37 +0100843 if from.Name() == to.Name() {
844 // This can happen for cc.reuseObjTag. We are not interested in tracking this.
845 // As soon as the dependency graph crosses the APEX boundary, don't go further.
846 return !externalDep
Jiyong Park678c8812020-02-07 17:25:49 +0900847 }
Jiyong Park83dc74b2020-01-14 18:38:44 +0900848
Artur Satayev872a1442020-04-27 17:08:37 +0100849 if info, exists := depInfos[to.Name()]; exists {
850 if !android.InList(from.Name(), info.From) {
851 info.From = append(info.From, from.Name())
852 }
853 info.IsExternal = info.IsExternal && externalDep
854 depInfos[to.Name()] = info
855 } else {
Artur Satayev480e25b2020-04-27 18:53:18 +0100856 toMinSdkVersion := "(no version)"
857 if m, ok := to.(interface{ MinSdkVersion() string }); ok {
858 if v := m.MinSdkVersion(); v != "" {
859 toMinSdkVersion = v
860 }
861 }
862
Artur Satayev872a1442020-04-27 17:08:37 +0100863 depInfos[to.Name()] = android.ApexModuleDepInfo{
Artur Satayev480e25b2020-04-27 18:53:18 +0100864 To: to.Name(),
865 From: []string{from.Name()},
866 IsExternal: externalDep,
867 MinSdkVersion: toMinSdkVersion,
Artur Satayev872a1442020-04-27 17:08:37 +0100868 }
869 }
870
871 // As soon as the dependency graph crosses the APEX boundary, don't go further.
872 return !externalDep
Jiyong Park83dc74b2020-01-14 18:38:44 +0900873 })
874
Artur Satayev480e25b2020-04-27 18:53:18 +0100875 a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, proptools.String(a.properties.Min_sdk_version), depInfos)
Artur Satayev872a1442020-04-27 17:08:37 +0100876
Jiyong Park83dc74b2020-01-14 18:38:44 +0900877 ctx.Build(pctx, android.BuildParams{
878 Rule: android.Phony,
879 Output: android.PathForPhony(ctx, a.Name()+"-deps-info"),
Artur Satayeva8bd1132020-04-27 18:07:06 +0100880 Inputs: []android.Path{
881 a.ApexBundleDepsInfo.FullListPath(),
882 a.ApexBundleDepsInfo.FlatListPath(),
883 },
Jiyong Park83dc74b2020-01-14 18:38:44 +0900884 })
885}
Colin Cross08dca382020-07-21 20:31:17 -0700886
887func (a *apexBundle) buildLintReports(ctx android.ModuleContext) {
888 depSetsBuilder := java.NewLintDepSetBuilder()
889 for _, fi := range a.filesInfo {
890 depSetsBuilder.Transitive(fi.lintDepSets)
891 }
892
893 a.lintReports = java.BuildModuleLintReportZips(ctx, depSetsBuilder.Build())
894}