• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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 (
18	"encoding/json"
19	"fmt"
20	"path/filepath"
21	"runtime"
22	"sort"
23	"strconv"
24	"strings"
25
26	"android/soong/android"
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
37func init() {
38	pctx.Import("android/soong/android")
39	pctx.Import("android/soong/cc/config")
40	pctx.Import("android/soong/java")
41	pctx.HostBinToolVariable("apexer", "apexer")
42	pctx.HostBinToolVariable("apexer_with_DCLA_preprocessing", "apexer_with_DCLA_preprocessing")
43	pctx.HostBinToolVariable("apexer_with_trim_preprocessing", "apexer_with_trim_preprocessing")
44
45	// ART minimal builds (using the master-art manifest) do not have the "frameworks/base"
46	// projects, and hence cannot build 'aapt2'. Use the SDK prebuilt instead.
47	hostBinToolVariableWithPrebuilt := func(name, prebuiltDir, tool string) {
48		pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
49			if !ctx.Config().FrameworksBaseDirExists(ctx) {
50				return filepath.Join(prebuiltDir, runtime.GOOS, "bin", tool)
51			} else {
52				return ctx.Config().HostToolPath(ctx, tool).String()
53			}
54		})
55	}
56	hostBinToolVariableWithPrebuilt("aapt2", "prebuilts/sdk/tools", "aapt2")
57	pctx.HostBinToolVariable("avbtool", "avbtool")
58	pctx.HostBinToolVariable("e2fsdroid", "e2fsdroid")
59	pctx.HostBinToolVariable("merge_zips", "merge_zips")
60	pctx.HostBinToolVariable("mke2fs", "mke2fs")
61	pctx.HostBinToolVariable("resize2fs", "resize2fs")
62	pctx.HostBinToolVariable("sefcontext_compile", "sefcontext_compile")
63	pctx.HostBinToolVariable("soong_zip", "soong_zip")
64	pctx.HostBinToolVariable("zip2zip", "zip2zip")
65	pctx.HostBinToolVariable("zipalign", "zipalign")
66	pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
67	pctx.HostBinToolVariable("conv_apex_manifest", "conv_apex_manifest")
68	pctx.HostBinToolVariable("extract_apks", "extract_apks")
69	pctx.HostBinToolVariable("make_f2fs", "make_f2fs")
70	pctx.HostBinToolVariable("sload_f2fs", "sload_f2fs")
71	pctx.HostBinToolVariable("make_erofs", "make_erofs")
72	pctx.HostBinToolVariable("apex_compression_tool", "apex_compression_tool")
73	pctx.HostBinToolVariable("dexdeps", "dexdeps")
74	pctx.HostBinToolVariable("apex_sepolicy_tests", "apex_sepolicy_tests")
75	pctx.HostBinToolVariable("deapexer", "deapexer")
76	pctx.HostBinToolVariable("debugfs_static", "debugfs_static")
77	pctx.SourcePathVariable("genNdkUsedbyApexPath", "build/soong/scripts/gen_ndk_usedby_apex.sh")
78}
79
80var (
81	apexManifestRule = pctx.StaticRule("apexManifestRule", blueprint.RuleParams{
82		Command: `rm -f $out && ${jsonmodify} $in ` +
83			`-a provideNativeLibs ${provideNativeLibs} ` +
84			`-a requireNativeLibs ${requireNativeLibs} ` +
85			`-se version 0 ${default_version} ` +
86			`${opt} ` +
87			`-o $out`,
88		CommandDeps: []string{"${jsonmodify}"},
89		Description: "prepare ${out}",
90	}, "provideNativeLibs", "requireNativeLibs", "default_version", "opt")
91
92	stripApexManifestRule = pctx.StaticRule("stripApexManifestRule", blueprint.RuleParams{
93		Command:     `rm -f $out && ${conv_apex_manifest} strip $in -o $out`,
94		CommandDeps: []string{"${conv_apex_manifest}"},
95		Description: "strip ${in}=>${out}",
96	})
97
98	pbApexManifestRule = pctx.StaticRule("pbApexManifestRule", blueprint.RuleParams{
99		Command:     `rm -f $out && ${conv_apex_manifest} proto $in -o $out`,
100		CommandDeps: []string{"${conv_apex_manifest}"},
101		Description: "convert ${in}=>${out}",
102	})
103
104	// TODO(b/113233103): make sure that file_contexts is as expected, i.e., validate
105	// against the binary policy using sefcontext_compiler -p <policy>.
106
107	// TODO(b/114327326): automate the generation of file_contexts
108	apexRule = pctx.StaticRule("apexRule", blueprint.RuleParams{
109		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
110			`(. ${out}.copy_commands) && ` +
111			`APEXER_TOOL_PATH=${tool_path} ` +
112			`${apexer} --force --manifest ${manifest} ` +
113			`--file_contexts ${file_contexts} ` +
114			`--canned_fs_config ${canned_fs_config} ` +
115			`--include_build_info ` +
116			`--payload_type image ` +
117			`--key ${key} ${opt_flags} ${image_dir} ${out} `,
118		CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}",
119			"${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}", "${sload_f2fs}", "${make_erofs}",
120			"${soong_zip}", "${zipalign}", "${aapt2}", "prebuilts/sdk/current/public/android.jar"},
121		Rspfile:        "${out}.copy_commands",
122		RspfileContent: "${copy_commands}",
123		Description:    "APEX ${image_dir} => ${out}",
124	}, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key",
125		"opt_flags", "manifest")
126
127	DCLAApexRule = pctx.StaticRule("DCLAApexRule", blueprint.RuleParams{
128		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
129			`(. ${out}.copy_commands) && ` +
130			`APEXER_TOOL_PATH=${tool_path} ` +
131			`${apexer_with_DCLA_preprocessing} ` +
132			`--apexer ${apexer} ` +
133			`--canned_fs_config ${canned_fs_config} ` +
134			`${image_dir} ` +
135			`${out} ` +
136			`-- ` +
137			`--include_build_info ` +
138			`--force ` +
139			`--payload_type image ` +
140			`--key ${key} ` +
141			`--file_contexts ${file_contexts} ` +
142			`--manifest ${manifest} ` +
143			`${opt_flags} `,
144		CommandDeps: []string{"${apexer_with_DCLA_preprocessing}", "${apexer}", "${avbtool}", "${e2fsdroid}",
145			"${merge_zips}", "${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}",
146			"${sload_f2fs}", "${make_erofs}", "${soong_zip}", "${zipalign}", "${aapt2}",
147			"prebuilts/sdk/current/public/android.jar"},
148		Rspfile:        "${out}.copy_commands",
149		RspfileContent: "${copy_commands}",
150		Description:    "APEX ${image_dir} => ${out}",
151	}, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key",
152		"opt_flags", "manifest", "is_DCLA")
153
154	TrimmedApexRule = pctx.StaticRule("TrimmedApexRule", blueprint.RuleParams{
155		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
156			`(. ${out}.copy_commands) && ` +
157			`APEXER_TOOL_PATH=${tool_path} ` +
158			`${apexer_with_trim_preprocessing} ` +
159			`--apexer ${apexer} ` +
160			`--canned_fs_config ${canned_fs_config} ` +
161			`--manifest ${manifest} ` +
162			`--libs_to_trim ${libs_to_trim} ` +
163			`${image_dir} ` +
164			`${out} ` +
165			`-- ` +
166			`--include_build_info ` +
167			`--force ` +
168			`--payload_type image ` +
169			`--key ${key} ` +
170			`--file_contexts ${file_contexts} ` +
171			`${opt_flags} `,
172		CommandDeps: []string{"${apexer_with_trim_preprocessing}", "${apexer}", "${avbtool}", "${e2fsdroid}",
173			"${merge_zips}", "${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}",
174			"${sload_f2fs}", "${make_erofs}", "${soong_zip}", "${zipalign}", "${aapt2}",
175			"prebuilts/sdk/current/public/android.jar"},
176		Rspfile:        "${out}.copy_commands",
177		RspfileContent: "${copy_commands}",
178		Description:    "APEX ${image_dir} => ${out}",
179	}, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key",
180		"opt_flags", "manifest", "libs_to_trim")
181
182	zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
183		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
184			`(. ${out}.copy_commands) && ` +
185			`APEXER_TOOL_PATH=${tool_path} ` +
186			`${apexer} --force --manifest ${manifest} ` +
187			`--payload_type zip ` +
188			`${image_dir} ${out} `,
189		CommandDeps:    []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
190		Rspfile:        "${out}.copy_commands",
191		RspfileContent: "${copy_commands}",
192		Description:    "ZipAPEX ${image_dir} => ${out}",
193	}, "tool_path", "image_dir", "copy_commands", "manifest")
194
195	apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule",
196		blueprint.RuleParams{
197			Command:     `${aapt2} convert --output-format proto $in -o $out`,
198			CommandDeps: []string{"${aapt2}"},
199		})
200
201	apexBundleRule = pctx.StaticRule("apexBundleRule", blueprint.RuleParams{
202		Command: `${zip2zip} -i $in -o $out.base ` +
203			`apex_payload.img:apex/${abi}.img ` +
204			`apex_build_info.pb:apex/${abi}.build_info.pb ` +
205			`apex_manifest.json:root/apex_manifest.json ` +
206			`apex_manifest.pb:root/apex_manifest.pb ` +
207			`AndroidManifest.xml:manifest/AndroidManifest.xml ` +
208			`assets/NOTICE.html.gz:assets/NOTICE.html.gz &&` +
209			`${soong_zip} -o $out.config -C $$(dirname ${config}) -f ${config} && ` +
210			`${merge_zips} $out $out.base $out.config`,
211		CommandDeps: []string{"${zip2zip}", "${soong_zip}", "${merge_zips}"},
212		Description: "app bundle",
213	}, "abi", "config")
214
215	diffApexContentRule = pctx.StaticRule("diffApexContentRule", blueprint.RuleParams{
216		Command: `diff --unchanged-group-format='' \` +
217			`--changed-group-format='%<' \` +
218			`${image_content_file} ${allowed_files_file} || (` +
219			`echo -e "New unexpected files were added to ${apex_module_name}." ` +
220			` "To fix the build run following command:" && ` +
221			`echo "system/apex/tools/update_allowed_list.sh ${allowed_files_file} ${image_content_file}" && ` +
222			`exit 1); touch ${out}`,
223		Description: "Diff ${image_content_file} and ${allowed_files_file}",
224	}, "image_content_file", "allowed_files_file", "apex_module_name")
225
226	generateAPIsUsedbyApexRule = pctx.StaticRule("generateAPIsUsedbyApexRule", blueprint.RuleParams{
227		Command:     "$genNdkUsedbyApexPath ${image_dir} ${readelf} ${out}",
228		CommandDeps: []string{"${genNdkUsedbyApexPath}"},
229		Description: "Generate symbol list used by Apex",
230	}, "image_dir", "readelf")
231
232	apexSepolicyTestsRule = pctx.StaticRule("apexSepolicyTestsRule", blueprint.RuleParams{
233		Command: `${deapexer} --debugfs_path ${debugfs_static} list -Z ${in} > ${out}.fc` +
234			`&& ${apex_sepolicy_tests} -f ${out}.fc && touch ${out}`,
235		CommandDeps: []string{"${apex_sepolicy_tests}", "${deapexer}", "${debugfs_static}"},
236		Description: "run apex_sepolicy_tests",
237	})
238)
239
240// buildManifest creates buile rules to modify the input apex_manifest.json to add information
241// gathered by the build system such as provided/required native libraries. Two output files having
242// different formats are generated. a.manifestJsonOut is JSON format for Q devices, and
243// a.manifest.PbOut is protobuf format for R+ devices.
244// TODO(jiyong): make this to return paths instead of directly storing the paths to apexBundle
245func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, requireNativeLibs []string) {
246	src := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
247
248	// Put dependency({provide|require}NativeLibs) in apex_manifest.json
249	provideNativeLibs = android.SortedUniqueStrings(provideNativeLibs)
250	requireNativeLibs = android.SortedUniqueStrings(android.RemoveListFromList(requireNativeLibs, provideNativeLibs))
251
252	// VNDK APEX name is determined at runtime, so update "name" in apex_manifest
253	optCommands := []string{}
254	if a.vndkApex {
255		apexName := vndkApexNamePrefix + a.vndkVersion(ctx.DeviceConfig())
256		optCommands = append(optCommands, "-v name "+apexName)
257	}
258
259	// Collect jniLibs. Notice that a.filesInfo is already sorted
260	var jniLibs []string
261	for _, fi := range a.filesInfo {
262		if fi.isJniLib && !android.InList(fi.stem(), jniLibs) {
263			jniLibs = append(jniLibs, fi.stem())
264		}
265	}
266	if len(jniLibs) > 0 {
267		optCommands = append(optCommands, "-a jniLibs "+strings.Join(jniLibs, " "))
268	}
269
270	if android.InList(":vndk", requireNativeLibs) {
271		if _, vndkVersion := a.getImageVariationPair(ctx.DeviceConfig()); vndkVersion != "" {
272			optCommands = append(optCommands, "-v vndkVersion "+vndkVersion)
273		}
274	}
275
276	manifestJsonFullOut := android.PathForModuleOut(ctx, "apex_manifest_full.json")
277	defaultVersion := android.DefaultUpdatableModuleVersion
278	if override := ctx.Config().Getenv("OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION"); override != "" {
279		defaultVersion = override
280	}
281	ctx.Build(pctx, android.BuildParams{
282		Rule:   apexManifestRule,
283		Input:  src,
284		Output: manifestJsonFullOut,
285		Args: map[string]string{
286			"provideNativeLibs": strings.Join(provideNativeLibs, " "),
287			"requireNativeLibs": strings.Join(requireNativeLibs, " "),
288			"default_version":   defaultVersion,
289			"opt":               strings.Join(optCommands, " "),
290		},
291	})
292
293	// b/143654022 Q apexd can't understand newly added keys in apex_manifest.json prepare
294	// stripped-down version so that APEX modules built from R+ can be installed to Q
295	minSdkVersion := a.minSdkVersion(ctx)
296	if minSdkVersion.EqualTo(android.SdkVersion_Android10) {
297		a.manifestJsonOut = android.PathForModuleOut(ctx, "apex_manifest.json")
298		ctx.Build(pctx, android.BuildParams{
299			Rule:   stripApexManifestRule,
300			Input:  manifestJsonFullOut,
301			Output: a.manifestJsonOut,
302		})
303	}
304
305	// From R+, protobuf binary format (.pb) is the standard format for apex_manifest
306	a.manifestPbOut = android.PathForModuleOut(ctx, "apex_manifest.pb")
307	ctx.Build(pctx, android.BuildParams{
308		Rule:   pbApexManifestRule,
309		Input:  manifestJsonFullOut,
310		Output: a.manifestPbOut,
311	})
312}
313
314// buildFileContexts create build rules to append an entry for apex_manifest.pb to the file_contexts
315// file for this APEX which is either from /systme/sepolicy/apex/<apexname>-file_contexts or from
316// the file_contexts property of this APEX. This is to make sure that the manifest file is correctly
317// labeled as system_file.
318func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.OutputPath {
319	var fileContexts android.Path
320	var fileContextsDir string
321	if a.properties.File_contexts == nil {
322		fileContexts = android.PathForSource(ctx, "system/sepolicy/apex", ctx.ModuleName()+"-file_contexts")
323	} else {
324		if m, t := android.SrcIsModuleWithTag(*a.properties.File_contexts); m != "" {
325			otherModule := android.GetModuleFromPathDep(ctx, m, t)
326			fileContextsDir = ctx.OtherModuleDir(otherModule)
327		}
328		fileContexts = android.PathForModuleSrc(ctx, *a.properties.File_contexts)
329	}
330	if fileContextsDir == "" {
331		fileContextsDir = filepath.Dir(fileContexts.String())
332	}
333	fileContextsDir += string(filepath.Separator)
334
335	if a.Platform() {
336		if !strings.HasPrefix(fileContextsDir, "system/sepolicy/") {
337			ctx.PropertyErrorf("file_contexts", "should be under system/sepolicy, but found in  %q", fileContextsDir)
338		}
339	}
340	if !android.ExistentPathForSource(ctx, fileContexts.String()).Valid() {
341		ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", fileContexts.String())
342	}
343
344	useFileContextsAsIs := proptools.Bool(a.properties.Use_file_contexts_as_is)
345
346	output := android.PathForModuleOut(ctx, "file_contexts")
347	rule := android.NewRuleBuilder(pctx, ctx)
348
349	switch a.properties.ApexType {
350	case imageApex:
351		// remove old file
352		rule.Command().Text("rm").FlagWithOutput("-f ", output)
353		// copy file_contexts
354		rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
355		// new line
356		rule.Command().Text("echo").Text(">>").Output(output)
357		if !useFileContextsAsIs {
358			// force-label /apex_manifest.pb and / as system_file so that apexd can read them
359			rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
360			rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output)
361		}
362	case flattenedApex:
363		// For flattened apexes, install path should be prepended.
364		// File_contexts file should be emiited to make via LOCAL_FILE_CONTEXTS
365		// so that it can be merged into file_contexts.bin
366		apexPath := android.InstallPathToOnDevicePath(ctx, a.installDir.Join(ctx, a.Name()))
367		apexPath = strings.ReplaceAll(apexPath, ".", `\\.`)
368		// remove old file
369		rule.Command().Text("rm").FlagWithOutput("-f ", output)
370		// copy file_contexts
371		rule.Command().Text("awk").Text(`'/object_r/{printf("` + apexPath + `%s\n", $0)}'`).Input(fileContexts).Text(">").Output(output)
372		// new line
373		rule.Command().Text("echo").Text(">>").Output(output)
374		if !useFileContextsAsIs {
375			// force-label /apex_manifest.pb and / as system_file so that apexd can read them
376			rule.Command().Text("echo").Flag(apexPath + `/apex_manifest\\.pb u:object_r:system_file:s0`).Text(">>").Output(output)
377			rule.Command().Text("echo").Flag(apexPath + "/ u:object_r:system_file:s0").Text(">>").Output(output)
378		}
379	default:
380		panic(fmt.Errorf("unsupported type %v", a.properties.ApexType))
381	}
382
383	rule.Build("file_contexts."+a.Name(), "Generate file_contexts")
384	return output.OutputPath
385}
386
387// buildInstalledFilesFile creates a build rule for the installed-files.txt file where the list of
388// files included in this APEX is shown. The text file is dist'ed so that people can see what's
389// included in the APEX without actually downloading and extracting it.
390func (a *apexBundle) buildInstalledFilesFile(ctx android.ModuleContext, builtApex android.Path, imageDir android.Path) android.OutputPath {
391	output := android.PathForModuleOut(ctx, "installed-files.txt")
392	rule := android.NewRuleBuilder(pctx, ctx)
393	rule.Command().
394		Implicit(builtApex).
395		Text("(cd " + imageDir.String() + " ; ").
396		Text("find . \\( -type f -o -type l \\) -printf \"%s %p\\n\") ").
397		Text(" | sort -nr > ").
398		Output(output)
399	rule.Build("installed-files."+a.Name(), "Installed files")
400	return output.OutputPath
401}
402
403// buildBundleConfig creates a build rule for the bundle config file that will control the bundle
404// creation process.
405func (a *apexBundle) buildBundleConfig(ctx android.ModuleContext) android.OutputPath {
406	output := android.PathForModuleOut(ctx, "bundle_config.json")
407
408	type ApkConfig struct {
409		Package_name string `json:"package_name"`
410		Apk_path     string `json:"path"`
411	}
412	config := struct {
413		Compression struct {
414			Uncompressed_glob []string `json:"uncompressed_glob"`
415		} `json:"compression"`
416		Apex_config struct {
417			Apex_embedded_apk_config []ApkConfig `json:"apex_embedded_apk_config,omitempty"`
418		} `json:"apex_config,omitempty"`
419	}{}
420
421	config.Compression.Uncompressed_glob = []string{
422		"apex_payload.img",
423		"apex_manifest.*",
424	}
425
426	// Collect the manifest names and paths of android apps if their manifest names are
427	// overridden.
428	for _, fi := range a.filesInfo {
429		if fi.class != app && fi.class != appSet {
430			continue
431		}
432		packageName := fi.overriddenPackageName
433		if packageName != "" {
434			config.Apex_config.Apex_embedded_apk_config = append(
435				config.Apex_config.Apex_embedded_apk_config,
436				ApkConfig{
437					Package_name: packageName,
438					Apk_path:     fi.path(),
439				})
440		}
441	}
442
443	j, err := json.Marshal(config)
444	if err != nil {
445		panic(fmt.Errorf("error while marshalling to %q: %#v", output, err))
446	}
447
448	android.WriteFileRule(ctx, output, string(j))
449
450	return output.OutputPath
451}
452
453func markManifestTestOnly(ctx android.ModuleContext, androidManifestFile android.Path) android.Path {
454	return java.ManifestFixer(ctx, androidManifestFile, java.ManifestFixerParams{
455		TestOnly: true,
456	})
457}
458
459// buildUnflattendApex creates build rules to build an APEX using apexer.
460func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
461	apexType := a.properties.ApexType
462	suffix := apexType.suffix()
463	apexName := a.BaseModuleName()
464
465	////////////////////////////////////////////////////////////////////////////////////////////
466	// Step 1: copy built files to appropriate directories under the image directory
467
468	imageDir := android.PathForModuleOut(ctx, "image"+suffix)
469
470	installSymbolFiles := (!ctx.Config().KatiEnabled() || a.ExportedToMake()) && a.installable()
471	// We can't install symbol files when prebuilt is used.
472	if a.IsReplacedByPrebuilt() {
473		installSymbolFiles = false
474	}
475
476	// set of dependency module:location mappings
477	installMapSet := make(map[string]bool)
478
479	// TODO(jiyong): use the RuleBuilder
480	var copyCommands []string
481	var implicitInputs []android.Path
482	apexDir := android.PathForModuleInPartitionInstall(ctx, "apex", apexName)
483	for _, fi := range a.filesInfo {
484		destPath := imageDir.Join(ctx, fi.path()).String()
485		// Prepare the destination path
486		destPathDir := filepath.Dir(destPath)
487		if fi.class == appSet {
488			copyCommands = append(copyCommands, "rm -rf "+destPathDir)
489		}
490		copyCommands = append(copyCommands, "mkdir -p "+destPathDir)
491
492		installMapPath := fi.builtFile
493
494		// Copy the built file to the directory. But if the symlink optimization is turned
495		// on, place a symlink to the corresponding file in /system partition instead.
496		if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
497			pathOnDevice := filepath.Join("/", fi.partition, fi.path())
498			copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath)
499		} else {
500			// Copy the file into APEX
501			copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
502
503			var installedPath android.InstallPath
504			if fi.class == appSet {
505				// In case of AppSet, we need to copy additional APKs as well. They
506				// are zipped. So we need to unzip them.
507				copyCommands = append(copyCommands,
508					fmt.Sprintf("unzip -qDD -d %s %s", destPathDir,
509						fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs().String()))
510				if installSymbolFiles {
511					installedPath = ctx.InstallFileWithExtraFilesZip(apexDir.Join(ctx, fi.installDir),
512						fi.stem(), fi.builtFile, fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs())
513				}
514			} else {
515				if installSymbolFiles {
516					installedPath = ctx.InstallFile(apexDir.Join(ctx, fi.installDir), fi.stem(), fi.builtFile)
517				}
518			}
519			implicitInputs = append(implicitInputs, fi.builtFile)
520
521			// Create additional symlinks pointing the file inside the APEX (if any). Note that
522			// this is independent from the symlink optimization.
523			for _, symlinkPath := range fi.symlinkPaths() {
524				symlinkDest := imageDir.Join(ctx, symlinkPath).String()
525				copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
526				if installSymbolFiles {
527					ctx.InstallSymlink(apexDir.Join(ctx, filepath.Dir(symlinkPath)), filepath.Base(symlinkPath), installedPath)
528				}
529			}
530
531			installMapPath = installedPath
532		}
533
534		// Copy the test files (if any)
535		for _, d := range fi.dataPaths {
536			// TODO(eakammer): This is now the third repetition of ~this logic for test paths, refactoring should be possible
537			relPath := d.SrcPath.Rel()
538			dataPath := d.SrcPath.String()
539			if !strings.HasSuffix(dataPath, relPath) {
540				panic(fmt.Errorf("path %q does not end with %q", dataPath, relPath))
541			}
542
543			dataDest := imageDir.Join(ctx, fi.apexRelativePath(relPath), d.RelativeInstallPath).String()
544
545			copyCommands = append(copyCommands, "cp -f "+d.SrcPath.String()+" "+dataDest)
546			implicitInputs = append(implicitInputs, d.SrcPath)
547		}
548
549		installMapSet[installMapPath.String()+":"+fi.installDir+"/"+fi.builtFile.Base()] = true
550	}
551	implicitInputs = append(implicitInputs, a.manifestPbOut)
552
553	if len(installMapSet) > 0 {
554		var installs []string
555		installs = append(installs, android.SortedKeys(installMapSet)...)
556		a.SetLicenseInstallMap(installs)
557	}
558
559	////////////////////////////////////////////////////////////////////////////////////////////
560	// Step 1.a: Write the list of files in this APEX to a txt file and compare it against
561	// the allowed list given via the allowed_files property. Build fails when the two lists
562	// differ.
563	//
564	// TODO(jiyong): consider removing this. Nobody other than com.android.apex.cts.shim.* seems
565	// to be using this at this moment. Furthermore, this looks very similar to what
566	// buildInstalledFilesFile does. At least, move this to somewhere else so that this doesn't
567	// hurt readability.
568	if a.overridableProperties.Allowed_files != nil {
569		// Build content.txt
570		var contentLines []string
571		imageContentFile := android.PathForModuleOut(ctx, "content.txt")
572		contentLines = append(contentLines, "./apex_manifest.pb")
573		minSdkVersion := a.minSdkVersion(ctx)
574		if minSdkVersion.EqualTo(android.SdkVersion_Android10) {
575			contentLines = append(contentLines, "./apex_manifest.json")
576		}
577		for _, fi := range a.filesInfo {
578			contentLines = append(contentLines, "./"+fi.path())
579		}
580		sort.Strings(contentLines)
581		android.WriteFileRule(ctx, imageContentFile, strings.Join(contentLines, "\n"))
582		implicitInputs = append(implicitInputs, imageContentFile)
583
584		// Compare content.txt against allowed_files.
585		allowedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.overridableProperties.Allowed_files))
586		phonyOutput := android.PathForModuleOut(ctx, a.Name()+"-diff-phony-output")
587		ctx.Build(pctx, android.BuildParams{
588			Rule:        diffApexContentRule,
589			Implicits:   implicitInputs,
590			Output:      phonyOutput,
591			Description: "diff apex image content",
592			Args: map[string]string{
593				"allowed_files_file": allowedFilesFile.String(),
594				"image_content_file": imageContentFile.String(),
595				"apex_module_name":   a.Name(),
596			},
597		})
598		implicitInputs = append(implicitInputs, phonyOutput)
599	}
600
601	unsignedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix+".unsigned")
602	outHostBinDir := ctx.Config().HostToolPath(ctx, "").String()
603	prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
604
605	if apexType == imageApex {
606
607		////////////////////////////////////////////////////////////////////////////////////
608		// Step 2: create canned_fs_config which encodes filemode,uid,gid of each files
609		// in this APEX. The file will be used by apexer in later steps.
610		cannedFsConfig := a.buildCannedFsConfig(ctx)
611		implicitInputs = append(implicitInputs, cannedFsConfig)
612
613		////////////////////////////////////////////////////////////////////////////////////
614		// Step 3: Prepare option flags for apexer and invoke it to create an unsigned APEX.
615		// TODO(jiyong): use the RuleBuilder
616		optFlags := []string{}
617
618		fileContexts := a.buildFileContexts(ctx)
619		implicitInputs = append(implicitInputs, fileContexts)
620
621		implicitInputs = append(implicitInputs, a.privateKeyFile, a.publicKeyFile)
622		optFlags = append(optFlags, "--pubkey "+a.publicKeyFile.String())
623
624		manifestPackageName := a.getOverrideManifestPackageName(ctx)
625		if manifestPackageName != "" {
626			optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName)
627		}
628
629		if a.properties.AndroidManifest != nil {
630			androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))
631
632			if a.testApex {
633				androidManifestFile = markManifestTestOnly(ctx, androidManifestFile)
634			}
635
636			implicitInputs = append(implicitInputs, androidManifestFile)
637			optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
638		} else if a.testApex {
639			optFlags = append(optFlags, "--test_only")
640		}
641
642		// Determine target/min sdk version from the context
643		// TODO(jiyong): make this as a function
644		moduleMinSdkVersion := a.minSdkVersion(ctx)
645		minSdkVersion := moduleMinSdkVersion.String()
646
647		// bundletool doesn't understand what "current" is. We need to transform it to
648		// codename
649		if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() {
650			minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
651
652			if java.UseApiFingerprint(ctx) {
653				minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
654				implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
655			}
656		}
657		// apex module doesn't have a concept of target_sdk_version, hence for the time
658		// being targetSdkVersion == default targetSdkVersion of the branch.
659		targetSdkVersion := strconv.Itoa(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt())
660
661		if java.UseApiFingerprint(ctx) {
662			targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
663			implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
664		}
665		optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
666		optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion)
667
668		if a.overridableProperties.Logging_parent != "" {
669			optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent)
670		}
671
672		// Create a NOTICE file, and embed it as an asset file in the APEX.
673		htmlGzNotice := android.PathForModuleOut(ctx, "NOTICE.html.gz")
674		android.BuildNoticeHtmlOutputFromLicenseMetadata(
675			ctx, htmlGzNotice, "", "",
676			[]string{
677				android.PathForModuleInstall(ctx).String() + "/",
678				android.PathForModuleInPartitionInstall(ctx, "apex").String() + "/",
679			})
680		noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
681		builder := android.NewRuleBuilder(pctx, ctx)
682		builder.Command().Text("cp").
683			Input(htmlGzNotice).
684			Output(noticeAssetPath)
685		builder.Build("notice_dir", "Building notice dir")
686		implicitInputs = append(implicitInputs, noticeAssetPath)
687		optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String()))
688
689		// Apexes which are supposed to be installed in builtin dirs(/system, etc)
690		// don't need hashtree for activation. Therefore, by removing hashtree from
691		// apex bundle (filesystem image in it, to be specific), we can save storage.
692		needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) ||
693			a.shouldGenerateHashtree()
694		if ctx.Config().ApexCompressionEnabled() && a.isCompressable() {
695			needHashTree = true
696		}
697		if !needHashTree {
698			optFlags = append(optFlags, "--no_hashtree")
699		}
700
701		if a.testOnlyShouldSkipPayloadSign() {
702			optFlags = append(optFlags, "--unsigned_payload")
703		}
704
705		if moduleMinSdkVersion == android.SdkVersion_Android10 {
706			implicitInputs = append(implicitInputs, a.manifestJsonOut)
707			optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String())
708		}
709
710		optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string())
711
712		if a.dynamic_common_lib_apex() {
713			ctx.Build(pctx, android.BuildParams{
714				Rule:        DCLAApexRule,
715				Implicits:   implicitInputs,
716				Output:      unsignedOutputFile,
717				Description: "apex (" + apexType.name() + ")",
718				Args: map[string]string{
719					"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
720					"image_dir":        imageDir.String(),
721					"copy_commands":    strings.Join(copyCommands, " && "),
722					"manifest":         a.manifestPbOut.String(),
723					"file_contexts":    fileContexts.String(),
724					"canned_fs_config": cannedFsConfig.String(),
725					"key":              a.privateKeyFile.String(),
726					"opt_flags":        strings.Join(optFlags, " "),
727				},
728			})
729		} else if ctx.Config().ApexTrimEnabled() && len(a.libs_to_trim(ctx)) > 0 {
730			ctx.Build(pctx, android.BuildParams{
731				Rule:        TrimmedApexRule,
732				Implicits:   implicitInputs,
733				Output:      unsignedOutputFile,
734				Description: "apex (" + apexType.name() + ")",
735				Args: map[string]string{
736					"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
737					"image_dir":        imageDir.String(),
738					"copy_commands":    strings.Join(copyCommands, " && "),
739					"manifest":         a.manifestPbOut.String(),
740					"file_contexts":    fileContexts.String(),
741					"canned_fs_config": cannedFsConfig.String(),
742					"key":              a.privateKeyFile.String(),
743					"opt_flags":        strings.Join(optFlags, " "),
744					"libs_to_trim":     strings.Join(a.libs_to_trim(ctx), ","),
745				},
746			})
747		} else {
748			ctx.Build(pctx, android.BuildParams{
749				Rule:        apexRule,
750				Implicits:   implicitInputs,
751				Output:      unsignedOutputFile,
752				Description: "apex (" + apexType.name() + ")",
753				Args: map[string]string{
754					"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
755					"image_dir":        imageDir.String(),
756					"copy_commands":    strings.Join(copyCommands, " && "),
757					"manifest":         a.manifestPbOut.String(),
758					"file_contexts":    fileContexts.String(),
759					"canned_fs_config": cannedFsConfig.String(),
760					"key":              a.privateKeyFile.String(),
761					"opt_flags":        strings.Join(optFlags, " "),
762				},
763			})
764		}
765
766		// TODO(jiyong): make the two rules below as separate functions
767		apexProtoFile := android.PathForModuleOut(ctx, a.Name()+".pb"+suffix)
768		bundleModuleFile := android.PathForModuleOut(ctx, a.Name()+suffix+"-base.zip")
769		a.bundleModuleFile = bundleModuleFile
770
771		ctx.Build(pctx, android.BuildParams{
772			Rule:        apexProtoConvertRule,
773			Input:       unsignedOutputFile,
774			Output:      apexProtoFile,
775			Description: "apex proto convert",
776		})
777
778		implicitInputs = append(implicitInputs, unsignedOutputFile)
779
780		// Run coverage analysis
781		apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.txt")
782		ctx.Build(pctx, android.BuildParams{
783			Rule:        generateAPIsUsedbyApexRule,
784			Implicits:   implicitInputs,
785			Description: "coverage",
786			Output:      apisUsedbyOutputFile,
787			Args: map[string]string{
788				"image_dir": imageDir.String(),
789				"readelf":   "${config.ClangBin}/llvm-readelf",
790			},
791		})
792		a.nativeApisUsedByModuleFile = apisUsedbyOutputFile
793
794		var nativeLibNames []string
795		for _, f := range a.filesInfo {
796			if f.class == nativeSharedLib {
797				nativeLibNames = append(nativeLibNames, f.stem())
798			}
799		}
800		apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt")
801		rule := android.NewRuleBuilder(pctx, ctx)
802		rule.Command().
803			Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")).
804			Output(apisBackedbyOutputFile).
805			Flags(nativeLibNames)
806		rule.Build("ndk_backedby_list", "Generate API libraries backed by Apex")
807		a.nativeApisBackedByModuleFile = apisBackedbyOutputFile
808
809		var javaLibOrApkPath []android.Path
810		for _, f := range a.filesInfo {
811			if f.class == javaSharedLib || f.class == app {
812				javaLibOrApkPath = append(javaLibOrApkPath, f.builtFile)
813			}
814		}
815		javaApiUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.xml")
816		javaUsedByRule := android.NewRuleBuilder(pctx, ctx)
817		javaUsedByRule.Command().
818			Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")).
819			BuiltTool("dexdeps").
820			Output(javaApiUsedbyOutputFile).
821			Inputs(javaLibOrApkPath)
822		javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex")
823		a.javaApisUsedByModuleFile = javaApiUsedbyOutputFile
824
825		bundleConfig := a.buildBundleConfig(ctx)
826
827		var abis []string
828		for _, target := range ctx.MultiTargets() {
829			if len(target.Arch.Abi) > 0 {
830				abis = append(abis, target.Arch.Abi[0])
831			}
832		}
833
834		abis = android.FirstUniqueStrings(abis)
835
836		ctx.Build(pctx, android.BuildParams{
837			Rule:        apexBundleRule,
838			Input:       apexProtoFile,
839			Implicit:    bundleConfig,
840			Output:      a.bundleModuleFile,
841			Description: "apex bundle module",
842			Args: map[string]string{
843				"abi":    strings.Join(abis, "."),
844				"config": bundleConfig.String(),
845			},
846		})
847	} else { // zipApex
848		ctx.Build(pctx, android.BuildParams{
849			Rule:        zipApexRule,
850			Implicits:   implicitInputs,
851			Output:      unsignedOutputFile,
852			Description: "apex (" + apexType.name() + ")",
853			Args: map[string]string{
854				"tool_path":     outHostBinDir + ":" + prebuiltSdkToolsBinDir,
855				"image_dir":     imageDir.String(),
856				"copy_commands": strings.Join(copyCommands, " && "),
857				"manifest":      a.manifestPbOut.String(),
858			},
859		})
860	}
861
862	////////////////////////////////////////////////////////////////////////////////////
863	// Step 4: Sign the APEX using signapk
864	signedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix)
865
866	pem, key := a.getCertificateAndPrivateKey(ctx)
867	rule := java.Signapk
868	args := map[string]string{
869		"certificates": pem.String() + " " + key.String(),
870		"flags":        "-a 4096 --align-file-size", //alignment
871	}
872	implicits := android.Paths{pem, key}
873	if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
874		rule = java.SignapkRE
875		args["implicits"] = strings.Join(implicits.Strings(), ",")
876		args["outCommaList"] = signedOutputFile.String()
877	}
878	var validations android.Paths
879	if suffix == imageApexSuffix {
880		validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile.OutputPath))
881	}
882	ctx.Build(pctx, android.BuildParams{
883		Rule:        rule,
884		Description: "signapk",
885		Output:      signedOutputFile,
886		Input:       unsignedOutputFile,
887		Implicits:   implicits,
888		Args:        args,
889		Validations: validations,
890	})
891	if suffix == imageApexSuffix {
892		a.outputApexFile = signedOutputFile
893	}
894	a.outputFile = signedOutputFile
895
896	if ctx.ModuleDir() != "system/apex/apexd/apexd_testdata" && a.testOnlyShouldForceCompression() {
897		ctx.PropertyErrorf("test_only_force_compression", "not available")
898		return
899	}
900
901	installSuffix := suffix
902	a.setCompression(ctx)
903	if a.isCompressed {
904		unsignedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+imageCapexSuffix+".unsigned")
905
906		compressRule := android.NewRuleBuilder(pctx, ctx)
907		compressRule.Command().
908			Text("rm").
909			FlagWithOutput("-f ", unsignedCompressedOutputFile)
910		compressRule.Command().
911			BuiltTool("apex_compression_tool").
912			Flag("compress").
913			FlagWithArg("--apex_compression_tool ", outHostBinDir+":"+prebuiltSdkToolsBinDir).
914			FlagWithInput("--input ", signedOutputFile).
915			FlagWithOutput("--output ", unsignedCompressedOutputFile)
916		compressRule.Build("compressRule", "Generate unsigned compressed APEX file")
917
918		signedCompressedOutputFile := android.PathForModuleOut(ctx, a.Name()+imageCapexSuffix)
919		if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
920			args["outCommaList"] = signedCompressedOutputFile.String()
921		}
922		ctx.Build(pctx, android.BuildParams{
923			Rule:        rule,
924			Description: "sign compressedApex",
925			Output:      signedCompressedOutputFile,
926			Input:       unsignedCompressedOutputFile,
927			Implicits:   implicits,
928			Args:        args,
929		})
930		a.outputFile = signedCompressedOutputFile
931		installSuffix = imageCapexSuffix
932	}
933
934	if !a.installable() {
935		a.SkipInstall()
936	}
937
938	// Install to $OUT/soong/{target,host}/.../apex.
939	a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile,
940		a.compatSymlinks.Paths()...)
941
942	// installed-files.txt is dist'ed
943	a.installedFilesFile = a.buildInstalledFilesFile(ctx, a.outputFile, imageDir)
944}
945
946// buildFlattenedApex creates rules for a flattened APEX. Flattened APEX actually doesn't have a
947// single output file. It is a phony target for all the files under /system/apex/<name> directory.
948// This function creates the installation rules for the files.
949func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) {
950	bundleName := a.Name()
951	installedSymlinks := append(android.InstallPaths(nil), a.compatSymlinks...)
952	if a.installable() {
953		for _, fi := range a.filesInfo {
954			dir := filepath.Join("apex", bundleName, fi.installDir)
955			installDir := android.PathForModuleInstall(ctx, dir)
956			if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
957				pathOnDevice := filepath.Join("/", fi.partition, fi.path())
958				installedSymlinks = append(installedSymlinks,
959					ctx.InstallAbsoluteSymlink(installDir, fi.stem(), pathOnDevice))
960			} else {
961				if fi.class == appSet {
962					as := fi.module.(*java.AndroidAppSet)
963					ctx.InstallFileWithExtraFilesZip(installDir, as.BaseModuleName()+".apk",
964						as.OutputFile(), as.PackedAdditionalOutputs())
965				} else {
966					target := ctx.InstallFile(installDir, fi.stem(), fi.builtFile)
967					for _, sym := range fi.symlinks {
968						installedSymlinks = append(installedSymlinks,
969							ctx.InstallSymlink(installDir, sym, target))
970					}
971				}
972			}
973		}
974
975		// Create install rules for the files added in GenerateAndroidBuildActions after
976		// buildFlattenedApex is called.  Add the links to system libs (if any) as dependencies
977		// of the apex_manifest.pb file since it is always present.
978		dir := filepath.Join("apex", bundleName)
979		installDir := android.PathForModuleInstall(ctx, dir)
980		ctx.InstallFile(installDir, "apex_manifest.pb", a.manifestPbOut, installedSymlinks.Paths()...)
981		ctx.InstallFile(installDir, "apex_pubkey", a.publicKeyFile)
982	}
983
984	a.fileContexts = a.buildFileContexts(ctx)
985
986	a.outputFile = android.PathForModuleInstall(ctx, "apex", bundleName)
987}
988
989// getCertificateAndPrivateKey retrieves the cert and the private key that will be used to sign
990// the zip container of this APEX. See the description of the 'certificate' property for how
991// the cert and the private key are found.
992func (a *apexBundle) getCertificateAndPrivateKey(ctx android.PathContext) (pem, key android.Path) {
993	if a.containerCertificateFile != nil {
994		return a.containerCertificateFile, a.containerPrivateKeyFile
995	}
996
997	cert := String(a.overridableProperties.Certificate)
998	if cert == "" {
999		return ctx.Config().DefaultAppCertificate(ctx)
1000	}
1001
1002	defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
1003	pem = defaultDir.Join(ctx, cert+".x509.pem")
1004	key = defaultDir.Join(ctx, cert+".pk8")
1005	return pem, key
1006}
1007
1008func (a *apexBundle) getOverrideManifestPackageName(ctx android.ModuleContext) string {
1009	// For VNDK APEXes, check "com.android.vndk" in PRODUCT_MANIFEST_PACKAGE_NAME_OVERRIDES
1010	// to see if it should be overridden because their <apex name> is dynamically generated
1011	// according to its VNDK version.
1012	if a.vndkApex {
1013		overrideName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(vndkApexName)
1014		if overridden {
1015			return overrideName + ".v" + a.vndkVersion(ctx.DeviceConfig())
1016		}
1017		return ""
1018	}
1019	if a.overridableProperties.Package_name != "" {
1020		return a.overridableProperties.Package_name
1021	}
1022	manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName())
1023	if overridden {
1024		return manifestPackageName
1025	}
1026	return ""
1027}
1028
1029func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) {
1030	if !a.primaryApexType {
1031		return
1032	}
1033
1034	if a.properties.IsCoverageVariant {
1035		// Otherwise, we will have duplicated rules for coverage and
1036		// non-coverage variants of the same APEX
1037		return
1038	}
1039
1040	if ctx.Host() {
1041		// No need to generate dependency info for host variant
1042		return
1043	}
1044
1045	depInfos := android.DepNameToDepInfoMap{}
1046	a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
1047		if from.Name() == to.Name() {
1048			// This can happen for cc.reuseObjTag. We are not interested in tracking this.
1049			// As soon as the dependency graph crosses the APEX boundary, don't go further.
1050			return !externalDep
1051		}
1052
1053		// Skip dependencies that are only available to APEXes; they are developed with updatability
1054		// in mind and don't need manual approval.
1055		if to.(android.ApexModule).NotAvailableForPlatform() {
1056			return !externalDep
1057		}
1058
1059		depTag := ctx.OtherModuleDependencyTag(to)
1060		// Check to see if dependency been marked to skip the dependency check
1061		if skipDepCheck, ok := depTag.(android.SkipApexAllowedDependenciesCheck); ok && skipDepCheck.SkipApexAllowedDependenciesCheck() {
1062			return !externalDep
1063		}
1064
1065		if info, exists := depInfos[to.Name()]; exists {
1066			if !android.InList(from.Name(), info.From) {
1067				info.From = append(info.From, from.Name())
1068			}
1069			info.IsExternal = info.IsExternal && externalDep
1070			depInfos[to.Name()] = info
1071		} else {
1072			toMinSdkVersion := "(no version)"
1073			if m, ok := to.(interface {
1074				MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel
1075			}); ok {
1076				if v := m.MinSdkVersion(ctx); !v.IsNone() {
1077					toMinSdkVersion = v.String()
1078				}
1079			} else if m, ok := to.(interface{ MinSdkVersion() string }); ok {
1080				// TODO(b/175678607) eliminate the use of MinSdkVersion returning
1081				// string
1082				if v := m.MinSdkVersion(); v != "" {
1083					toMinSdkVersion = v
1084				}
1085			}
1086			depInfos[to.Name()] = android.ApexModuleDepInfo{
1087				To:            to.Name(),
1088				From:          []string{from.Name()},
1089				IsExternal:    externalDep,
1090				MinSdkVersion: toMinSdkVersion,
1091			}
1092		}
1093
1094		// As soon as the dependency graph crosses the APEX boundary, don't go further.
1095		return !externalDep
1096	})
1097
1098	a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(ctx).String(), depInfos)
1099
1100	ctx.Build(pctx, android.BuildParams{
1101		Rule:   android.Phony,
1102		Output: android.PathForPhony(ctx, a.Name()+"-deps-info"),
1103		Inputs: []android.Path{
1104			a.ApexBundleDepsInfo.FullListPath(),
1105			a.ApexBundleDepsInfo.FlatListPath(),
1106		},
1107	})
1108}
1109
1110func (a *apexBundle) buildLintReports(ctx android.ModuleContext) {
1111	depSetsBuilder := java.NewLintDepSetBuilder()
1112	for _, fi := range a.filesInfo {
1113		depSetsBuilder.Transitive(fi.lintDepSets)
1114	}
1115
1116	a.lintReports = java.BuildModuleLintReportZips(ctx, depSetsBuilder.Build())
1117}
1118
1119func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.OutputPath {
1120	var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"}
1121	var executablePaths []string // this also includes dirs
1122	var appSetDirs []string
1123	appSetFiles := make(map[string]android.Path)
1124	for _, f := range a.filesInfo {
1125		pathInApex := f.path()
1126		if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") {
1127			executablePaths = append(executablePaths, pathInApex)
1128			for _, d := range f.dataPaths {
1129				readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, d.RelativeInstallPath, d.SrcPath.Rel()))
1130			}
1131			for _, s := range f.symlinks {
1132				executablePaths = append(executablePaths, filepath.Join(f.installDir, s))
1133			}
1134		} else if f.class == appSet {
1135			// base APK
1136			readOnlyPaths = append(readOnlyPaths, pathInApex)
1137			// Additional APKs
1138			appSetDirs = append(appSetDirs, f.installDir)
1139			appSetFiles[f.installDir] = f.module.(*java.AndroidAppSet).PackedAdditionalOutputs()
1140		} else {
1141			readOnlyPaths = append(readOnlyPaths, pathInApex)
1142		}
1143		dir := f.installDir
1144		for !android.InList(dir, executablePaths) && dir != "" {
1145			executablePaths = append(executablePaths, dir)
1146			dir, _ = filepath.Split(dir) // move up to the parent
1147			if len(dir) > 0 {
1148				// remove trailing slash
1149				dir = dir[:len(dir)-1]
1150			}
1151		}
1152	}
1153	sort.Strings(readOnlyPaths)
1154	sort.Strings(executablePaths)
1155	sort.Strings(appSetDirs)
1156
1157	cannedFsConfig := android.PathForModuleOut(ctx, "canned_fs_config")
1158	builder := android.NewRuleBuilder(pctx, ctx)
1159	cmd := builder.Command()
1160	cmd.Text("(")
1161	cmd.Text("echo '/ 1000 1000 0755';")
1162	for _, p := range readOnlyPaths {
1163		cmd.Textf("echo '/%s 1000 1000 0644';", p)
1164	}
1165	for _, p := range executablePaths {
1166		cmd.Textf("echo '/%s 0 2000 0755';", p)
1167	}
1168	for _, dir := range appSetDirs {
1169		cmd.Textf("echo '/%s 0 2000 0755';", dir)
1170		file := appSetFiles[dir]
1171		cmd.Text("zipinfo -1").Input(file).Textf(`| sed "s:\(.*\):/%s/\1 1000 1000 0644:";`, dir)
1172	}
1173	// Custom fs_config is "appended" to the last so that entries from the file are preferred
1174	// over default ones set above.
1175	if a.properties.Canned_fs_config != nil {
1176		cmd.Text("cat").Input(android.PathForModuleSrc(ctx, *a.properties.Canned_fs_config))
1177	}
1178	cmd.Text(")").FlagWithOutput("> ", cannedFsConfig)
1179	builder.Build("generateFsConfig", fmt.Sprintf("Generating canned fs config for %s", a.BaseModuleName()))
1180
1181	return cannedFsConfig.OutputPath
1182}
1183
1184// Runs apex_sepolicy_tests
1185//
1186// $ deapexer list -Z {apex_file} > {file_contexts}
1187// $ apex_sepolicy_tests -f {file_contexts}
1188func runApexSepolicyTests(ctx android.ModuleContext, apexFile android.OutputPath) android.Path {
1189	timestamp := android.PathForModuleOut(ctx, "sepolicy_tests.timestamp")
1190	ctx.Build(pctx, android.BuildParams{
1191		Rule:   apexSepolicyTestsRule,
1192		Input:  apexFile,
1193		Output: timestamp,
1194	})
1195	return timestamp
1196}
1197