From b81b99032d2e3a0bef421735913caaafb7308257 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Tue, 24 Nov 2020 19:51:18 +0900 Subject: [PATCH] Documenting apex/builer.go Mostly documentation changes, but includes a few refactorings like changing the variable names, reordering functions, reordering statements in logical order, etc. Bug: 173472337 Test: m Change-Id: Iefdc8e463bcda60187b98e8c90661e220e8cdf40 --- apex/apex.go | 22 +++- apex/builder.go | 287 +++++++++++++++++++++++++++--------------------- apex/key.go | 5 +- 3 files changed, 186 insertions(+), 128 deletions(-) diff --git a/apex/apex.go b/apex/apex.go index a645b06d0..d0e015663 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -1786,14 +1786,11 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.linkToSystemLib = false } - a.setCertificateAndPrivateKey(ctx) - a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx) //////////////////////////////////////////////////////////////////////////////////////////// // 4) generate the build rules to create the APEX. This is done in builder.go. a.buildManifest(ctx, provideNativeLibs, requireNativeLibs) - a.buildFileContexts(ctx) if a.properties.ApexType == flattenedApex { a.buildFlattenedApex(ctx) } else { @@ -1802,6 +1799,25 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.buildApexDependencyInfo(ctx) a.buildLintReports(ctx) a.distFiles = a.GenerateTaggedDistFiles(ctx) + + // Append meta-files to the filesInfo list so that they are reflected in Android.mk as well. + if a.installable() { + // For flattened APEX, make sure that APEX manifest and apex_pubkey are also copied + // along with other ordinary files. (Note that this is done by apexer for + // non-flattened APEXes) + a.filesInfo = append(a.filesInfo, newApexFile(ctx, a.manifestPbOut, "apex_manifest.pb", ".", etc, nil)) + + // Place the public key as apex_pubkey. This is also done by apexer for + // non-flattened APEXes case. + // TODO(jiyong): Why do we need this CP rule? + copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey") + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: a.public_key_file, + Output: copiedPubkey, + }) + a.filesInfo = append(a.filesInfo, newApexFile(ctx, copiedPubkey, "apex_pubkey", ".", etc, nil)) + } } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/apex/builder.go b/apex/builder.go index 6f27dd179..b85813587 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -40,7 +40,7 @@ func init() { pctx.Import("android/soong/java") pctx.HostBinToolVariable("apexer", "apexer") // ART minimal builds (using the master-art manifest) do not have the "frameworks/base" - // projects, and hence cannot built 'aapt2'. Use the SDK prebuilt instead. + // projects, and hence cannot build 'aapt2'. Use the SDK prebuilt instead. hostBinToolVariableWithPrebuilt := func(name, prebuiltDir, tool string) { pctx.VariableFunc(name, func(ctx android.PackageVarContext) string { if !ctx.Config().FrameworksBaseDirExists(ctx) { @@ -175,24 +175,29 @@ var ( `exit 1); touch ${out}`, Description: "Diff ${image_content_file} and ${allowed_files_file}", }, "image_content_file", "allowed_files_file", "apex_module_name") + + // Don't add more rules here. Consider using android.NewRuleBuilder instead. ) +// buildManifest creates buile rules to modify the input apex_manifest.json to add information +// gathered by the build system such as provided/required native libraries. Two output files having +// different formats are generated. a.manifestJsonOut is JSON format for Q devices, and +// a.manifest.PbOut is protobuf format for R+ devices. +// TODO(jiyong): make this to return paths instead of directly storing the paths to apexBundle func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, requireNativeLibs []string) { - manifestSrc := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json")) + src := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json")) - manifestJsonFullOut := android.PathForModuleOut(ctx, "apex_manifest_full.json") - - // put dependency({provide|require}NativeLibs) in apex_manifest.json + // Put dependency({provide|require}NativeLibs) in apex_manifest.json provideNativeLibs = android.SortedUniqueStrings(provideNativeLibs) requireNativeLibs = android.SortedUniqueStrings(android.RemoveListFromList(requireNativeLibs, provideNativeLibs)) - // apex name can be overridden + // APEX name can be overridden optCommands := []string{} if a.properties.Apex_name != nil { optCommands = append(optCommands, "-v name "+*a.properties.Apex_name) } - // collect jniLibs. Notice that a.filesInfo is already sorted + // Collect jniLibs. Notice that a.filesInfo is already sorted var jniLibs []string for _, fi := range a.filesInfo { if fi.isJniLib && !android.InList(fi.stem(), jniLibs) { @@ -203,9 +208,10 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, optCommands = append(optCommands, "-a jniLibs "+strings.Join(jniLibs, " ")) } + manifestJsonFullOut := android.PathForModuleOut(ctx, "apex_manifest_full.json") ctx.Build(pctx, android.BuildParams{ Rule: apexManifestRule, - Input: manifestSrc, + Input: src, Output: manifestJsonFullOut, Args: map[string]string{ "provideNativeLibs": strings.Join(provideNativeLibs, " "), @@ -214,10 +220,10 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, }, }) + // b/143654022 Q apexd can't understand newly added keys in apex_manifest.json prepare + // stripped-down version so that APEX modules built from R+ can be installed to Q minSdkVersion := a.minSdkVersion(ctx) if minSdkVersion.EqualTo(android.SdkVersion_Android10) { - // b/143654022 Q apexd can't understand newly added keys in apex_manifest.json - // prepare stripped-down version so that APEX modules built from R+ can be installed to Q a.manifestJsonOut = android.PathForModuleOut(ctx, "apex_manifest.json") ctx.Build(pctx, android.BuildParams{ Rule: stripApexManifestRule, @@ -226,7 +232,7 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, }) } - // from R+, protobuf binary format (.pb) is the standard format for apex_manifest + // From R+, protobuf binary format (.pb) is the standard format for apex_manifest a.manifestPbOut = android.PathForModuleOut(ctx, "apex_manifest.pb") ctx.Build(pctx, android.BuildParams{ Rule: pbApexManifestRule, @@ -235,10 +241,11 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, }) } -func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) { - if a.properties.ApexType == zipApex { - return - } +// buildFileContexts create build rules to append an entry for apex_manifest.pb to the file_contexts +// file for this APEX which is either from /systme/sepolicy/apex/-file_contexts or from +// the file_contexts property of this APEX. This is to make sure that the manifest file is correctly +// labeled as system_file. +func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.OutputPath { var fileContexts android.Path if a.properties.File_contexts == nil { fileContexts = android.PathForSource(ctx, "system/sepolicy/apex", ctx.ModuleName()+"-file_contexts") @@ -248,18 +255,17 @@ func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) { if a.Platform() { if matched, err := path.Match("system/sepolicy/**/*", fileContexts.String()); err != nil || !matched { ctx.PropertyErrorf("file_contexts", "should be under system/sepolicy, but %q", fileContexts) - return } } if !android.ExistentPathForSource(ctx, fileContexts.String()).Valid() { - ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", a.fileContexts) - return + ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", fileContexts.String()) } output := android.PathForModuleOut(ctx, "file_contexts") rule := android.NewRuleBuilder() - if a.properties.ApexType == imageApex { + switch a.properties.ApexType { + case imageApex: // remove old file rule.Command().Text("rm").FlagWithOutput("-f ", output) // copy file_contexts @@ -269,7 +275,7 @@ func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) { // force-label /apex_manifest.pb and / as system_file so that apexd can read them rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output) rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output) - } else { + case flattenedApex: // For flattened apexes, install path should be prepended. // File_contexts file should be emiited to make via LOCAL_FILE_CONTEXTS // so that it can be merged into file_contexts.bin @@ -284,13 +290,16 @@ func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) { // force-label /apex_manifest.pb and / as system_file so that apexd can read them rule.Command().Text("echo").Flag(apexPath + `/apex_manifest\\.pb u:object_r:system_file:s0`).Text(">>").Output(output) rule.Command().Text("echo").Flag(apexPath + "/ u:object_r:system_file:s0").Text(">>").Output(output) + default: + panic(fmt.Errorf("unsupported type %v", a.properties.ApexType)) } rule.Build(pctx, ctx, "file_contexts."+a.Name(), "Generate file_contexts") - - a.fileContexts = output.OutputPath + return output.OutputPath } +// buildNoticeFiles creates a buile rule for aggregating notice files from the modules that +// contributes to this APEX. The notice files are merged into a big notice file. func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName string) android.NoticeOutputs { var noticeFiles android.Paths @@ -299,13 +308,11 @@ func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName st // As soon as the dependency graph crosses the APEX boundary, don't go further. return false } - - notices := to.NoticeFiles() - noticeFiles = append(noticeFiles, notices...) - + noticeFiles = append(noticeFiles, to.NoticeFiles()...) return true }) + // TODO(jiyong): why do we need this? WalkPayloadDeps should have already covered this. for _, fi := range a.filesInfo { noticeFiles = append(noticeFiles, fi.noticeFiles...) } @@ -317,6 +324,9 @@ func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName st return android.BuildNoticeOutput(ctx, a.installDir, apexFileName, android.SortedUniquePaths(noticeFiles)) } +// buildInstalledFilesFile creates a build rule for the installed-files.txt file where the list of +// files included in this APEX is shown. The text file is dist'ed so that people can see what's +// included in the APEX without actually downloading and extracting it. func (a *apexBundle) buildInstalledFilesFile(ctx android.ModuleContext, builtApex android.Path, imageDir android.Path) android.OutputPath { output := android.PathForModuleOut(ctx, "installed-files.txt") rule := android.NewRuleBuilder() @@ -330,6 +340,8 @@ func (a *apexBundle) buildInstalledFilesFile(ctx android.ModuleContext, builtApe return output.OutputPath } +// buildBundleConfig creates a build rule for the bundle config file that will control the bundle +// creation process. func (a *apexBundle) buildBundleConfig(ctx android.ModuleContext) android.OutputPath { output := android.PathForModuleOut(ctx, "bundle_config.json") @@ -351,8 +363,8 @@ func (a *apexBundle) buildBundleConfig(ctx android.ModuleContext) android.Output "apex_manifest.*", } - // collect the manifest names and paths of android apps - // if their manifest names are overridden + // Collect the manifest names and paths of android apps if their manifest names are + // overridden. for _, fi := range a.filesInfo { if fi.class != app && fi.class != appSet { continue @@ -378,30 +390,31 @@ func (a *apexBundle) buildBundleConfig(ctx android.ModuleContext) android.Output return output.OutputPath } +// buildUnflattendApex creates build rules to build an APEX using apexer. func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { - var abis []string - for _, target := range ctx.MultiTargets() { - if len(target.Arch.Abi) > 0 { - abis = append(abis, target.Arch.Abi[0]) - } - } - - abis = android.FirstUniqueStrings(abis) - apexType := a.properties.ApexType suffix := apexType.suffix() - var implicitInputs []android.Path - unsignedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix+".unsigned") - // TODO(jiyong): construct the copy rules using RuleBuilder + //////////////////////////////////////////////////////////////////////////////////////////// + // Step 1: copy built files to appropriate directories under the image directory + + imageDir := android.PathForModuleOut(ctx, "image"+suffix) + + // TODO(jiyong): use the RuleBuilder var copyCommands []string + var implicitInputs []android.Path for _, fi := range a.filesInfo { - destPath := android.PathForModuleOut(ctx, "image"+suffix, fi.path()).String() + destPath := imageDir.Join(ctx, fi.path()).String() + + // Prepare the destination path destPathDir := filepath.Dir(destPath) if fi.class == appSet { copyCommands = append(copyCommands, "rm -rf "+destPathDir) } copyCommands = append(copyCommands, "mkdir -p "+destPathDir) + + // Copy the built file to the directory. But if the symlink optimization is turned + // on, place a symlink to the corresponding file in /system partition instead. if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() { // TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here pathOnDevice := filepath.Join("/system", fi.path()) @@ -415,11 +428,15 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { } implicitInputs = append(implicitInputs, fi.builtFile) } - // create additional symlinks pointing the file inside the APEX + + // Create additional symlinks pointing the file inside the APEX (if any). Note that + // this is independent from the symlink optimization. for _, symlinkPath := range fi.symlinkPaths() { - symlinkDest := android.PathForModuleOut(ctx, "image"+suffix, symlinkPath).String() + symlinkDest := imageDir.Join(ctx, symlinkPath).String() copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest) } + + // Copy the test files (if any) for _, d := range fi.dataPaths { // TODO(eakammer): This is now the third repetition of ~this logic for test paths, refactoring should be possible relPath := d.SrcPath.Rel() @@ -428,28 +445,37 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { panic(fmt.Errorf("path %q does not end with %q", dataPath, relPath)) } - dataDest := android.PathForModuleOut(ctx, "image"+suffix, fi.apexRelativePath(relPath), d.RelativeInstallPath).String() + dataDest := imageDir.Join(ctx, fi.apexRelativePath(relPath), d.RelativeInstallPath).String() copyCommands = append(copyCommands, "cp -f "+d.SrcPath.String()+" "+dataDest) implicitInputs = append(implicitInputs, d.SrcPath) } } - - // TODO(jiyong): use RuleBuilder - var emitCommands []string - imageContentFile := android.PathForModuleOut(ctx, "content.txt") - emitCommands = append(emitCommands, "echo ./apex_manifest.pb >> "+imageContentFile.String()) - minSdkVersion := a.minSdkVersion(ctx) - if minSdkVersion.EqualTo(android.SdkVersion_Android10) { - emitCommands = append(emitCommands, "echo ./apex_manifest.json >> "+imageContentFile.String()) - } - for _, fi := range a.filesInfo { - emitCommands = append(emitCommands, "echo './"+fi.path()+"' >> "+imageContentFile.String()) - } - emitCommands = append(emitCommands, "sort -o "+imageContentFile.String()+" "+imageContentFile.String()) implicitInputs = append(implicitInputs, a.manifestPbOut) + //////////////////////////////////////////////////////////////////////////////////////////// + // Step 1.a: Write the list of files in this APEX to a txt file and compare it against + // the allowed list given via the allowed_files property. Build fails when the two lists + // differ. + // + // TODO(jiyong): consider removing this. Nobody other than com.android.apex.cts.shim.* seems + // to be using this at this moment. Furthermore, this looks very similar to what + // buildInstalledFilesFile does. At least, move this to somewhere else so that this doesn't + // hurt readability. + // TODO(jiyong): use RuleBuilder if a.overridableProperties.Allowed_files != nil { + // Build content.txt + var emitCommands []string + imageContentFile := android.PathForModuleOut(ctx, "content.txt") + emitCommands = append(emitCommands, "echo ./apex_manifest.pb >> "+imageContentFile.String()) + minSdkVersion := a.minSdkVersion(ctx) + if minSdkVersion.EqualTo(android.SdkVersion_Android10) { + emitCommands = append(emitCommands, "echo ./apex_manifest.json >> "+imageContentFile.String()) + } + for _, fi := range a.filesInfo { + emitCommands = append(emitCommands, "echo './"+fi.path()+"' >> "+imageContentFile.String()) + } + emitCommands = append(emitCommands, "sort -o "+imageContentFile.String()+" "+imageContentFile.String()) ctx.Build(pctx, android.BuildParams{ Rule: emitApexContentRule, Implicits: implicitInputs, @@ -460,8 +486,9 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { }, }) implicitInputs = append(implicitInputs, imageContentFile) - allowedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.overridableProperties.Allowed_files)) + // Compare content.txt against allowed_files. + allowedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.overridableProperties.Allowed_files)) phonyOutput := android.PathForModuleOut(ctx, a.Name()+"-diff-phony-output") ctx.Build(pctx, android.BuildParams{ Rule: diffApexContentRule, @@ -474,16 +501,19 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { "apex_module_name": a.Name(), }, }) - implicitInputs = append(implicitInputs, phonyOutput) } + unsignedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix+".unsigned") outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String() prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin") - imageDir := android.PathForModuleOut(ctx, "image"+suffix) if apexType == imageApex { - // files and dirs that will be created in APEX + //////////////////////////////////////////////////////////////////////////////////// + // Step 2: create canned_fs_config which encodes filemode,uid,gid of each files + // in this APEX. The file will be used by apexer in later steps. + // TODO(jiyong): make this as a function + // TODO(jiyong): use the RuleBuilder var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"} var executablePaths []string // this also includes dirs var extractedAppSetPaths android.Paths @@ -528,11 +558,17 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { "apk_paths": strings.Join(extractedAppSetDirs, " "), }, }) + implicitInputs = append(implicitInputs, cannedFsConfig) + //////////////////////////////////////////////////////////////////////////////////// + // Step 3: Prepare option flags for apexer and invoke it to create an unsigned APEX. + // TODO(jiyong): use the RuleBuilder optFlags := []string{} - // Additional implicit inputs. - implicitInputs = append(implicitInputs, cannedFsConfig, a.fileContexts, a.private_key_file, a.public_key_file) + fileContexts := a.buildFileContexts(ctx) + implicitInputs = append(implicitInputs, fileContexts) + + implicitInputs = append(implicitInputs, a.private_key_file, a.public_key_file) optFlags = append(optFlags, "--pubkey "+a.public_key_file.String()) manifestPackageName := a.getOverrideManifestPackageName(ctx) @@ -546,15 +582,18 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String()) } + // Determine target/min sdk version from the context + // TODO(jiyong): make this as a function moduleMinSdkVersion := a.minSdkVersion(ctx) minSdkVersion := moduleMinSdkVersion.String() - // bundletool doesn't understand what "current" is. We need to transform it to codename + // bundletool doesn't understand what "current" is. We need to transform it to + // codename if moduleMinSdkVersion.IsCurrent() { minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String() } - // apex module doesn't have a concept of target_sdk_version, hence for the time being - // targetSdkVersion == default targetSdkVersion of the branch. + // apex module doesn't have a concept of target_sdk_version, hence for the time + // being targetSdkVersion == default targetSdkVersion of the branch. targetSdkVersion := strconv.Itoa(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt()) if java.UseApiFingerprint(ctx) { @@ -595,8 +634,8 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { } if a.properties.Apex_name != nil { - // If apex_name is set, apexer can skip checking if key name matches with apex name. - // Note that apex_manifest is also mended. + // If apex_name is set, apexer can skip checking if key name matches with + // apex name. Note that apex_manifest is also mended. optFlags = append(optFlags, "--do_not_check_keyname") } @@ -617,13 +656,14 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { "image_dir": imageDir.String(), "copy_commands": strings.Join(copyCommands, " && "), "manifest": a.manifestPbOut.String(), - "file_contexts": a.fileContexts.String(), + "file_contexts": fileContexts.String(), "canned_fs_config": cannedFsConfig.String(), "key": a.private_key_file.String(), "opt_flags": strings.Join(optFlags, " "), }, }) + // TODO(jiyong): make the two rules below as separate functions apexProtoFile := android.PathForModuleOut(ctx, a.Name()+".pb"+suffix) bundleModuleFile := android.PathForModuleOut(ctx, a.Name()+suffix+"-base.zip") a.bundleModuleFile = bundleModuleFile @@ -637,6 +677,15 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { bundleConfig := a.buildBundleConfig(ctx) + var abis []string + for _, target := range ctx.MultiTargets() { + if len(target.Arch.Abi) > 0 { + abis = append(abis, target.Arch.Abi[0]) + } + } + + abis = android.FirstUniqueStrings(abis) + ctx.Build(pctx, android.BuildParams{ Rule: apexBundleRule, Input: apexProtoFile, @@ -648,7 +697,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { "config": bundleConfig.String(), }, }) - } else { + } else { // zipApex ctx.Build(pctx, android.BuildParams{ Rule: zipApexRule, Implicits: implicitInputs, @@ -663,16 +712,17 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { }) } + //////////////////////////////////////////////////////////////////////////////////// + // Step 4: Sign the APEX using signapk a.outputFile = android.PathForModuleOut(ctx, a.Name()+suffix) + + pem, key := a.getCertificateAndPrivateKey(ctx) rule := java.Signapk args := map[string]string{ - "certificates": a.container_certificate_file.String() + " " + a.container_private_key_file.String(), + "certificates": pem.String() + " " + key.String(), "flags": "-a 4096", //alignment } - implicits := android.Paths{ - a.container_certificate_file, - a.container_private_key_file, - } + implicits := android.Paths{pem, key} if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_SIGNAPK") { rule = java.SignapkRE args["implicits"] = strings.Join(implicits.Strings(), ",") @@ -691,7 +741,6 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { if a.installable() { ctx.InstallFile(a.installDir, a.Name()+suffix, a.outputFile) } - a.buildFilesInfo(ctx) // installed-files.txt is dist'ed a.installedFilesFile = a.buildInstalledFilesFile(ctx, a.outputFile, imageDir) @@ -706,58 +755,50 @@ func (c *flattenedApexContext) InstallBypassMake() bool { return true } +// buildFlattenedApex creates rules for a flattened APEX. Flattened APEX actually doesn't have a +// single output file. It is a phony target for all the files under /system/apex/ directory. +// This function creates the installation rules for the files. func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) { - // Temporarily wrap the original `ctx` into a `flattenedApexContext` to have it - // reply true to `InstallBypassMake()` (thus making the call - // `android.PathForModuleInstall` below use `android.pathForInstallInMakeDir` - // instead of `android.PathForOutput`) to return the correct path to the flattened - // APEX (as its contents is installed by Make, not Soong). - factx := flattenedApexContext{ctx} - a.outputFile = android.PathForModuleInstall(&factx, "apex", a.Name()) - a.buildFilesInfo(ctx) -} - -func (a *apexBundle) setCertificateAndPrivateKey(ctx android.ModuleContext) { - if a.container_certificate_file == nil { - cert := String(a.properties.Certificate) - if cert == "" { - pem, key := ctx.Config().DefaultAppCertificate(ctx) - a.container_certificate_file = pem - a.container_private_key_file = key - } else { - defaultDir := ctx.Config().DefaultAppCertificateDir(ctx) - a.container_certificate_file = defaultDir.Join(ctx, cert+".x509.pem") - a.container_private_key_file = defaultDir.Join(ctx, cert+".pk8") - } - } -} - -func (a *apexBundle) buildFilesInfo(ctx android.ModuleContext) { + bundleName := a.Name() if a.installable() { - // For flattened APEX, do nothing but make sure that APEX manifest and apex_pubkey are also copied along - // with other ordinary files. - a.filesInfo = append(a.filesInfo, newApexFile(ctx, a.manifestPbOut, "apex_manifest.pb", ".", etc, nil)) - - // rename to apex_pubkey - copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey") - ctx.Build(pctx, android.BuildParams{ - Rule: android.Cp, - Input: a.public_key_file, - Output: copiedPubkey, - }) - a.filesInfo = append(a.filesInfo, newApexFile(ctx, copiedPubkey, "apex_pubkey", ".", etc, nil)) - - if a.properties.ApexType == flattenedApex { - apexBundleName := a.Name() - for _, fi := range a.filesInfo { - dir := filepath.Join("apex", apexBundleName, fi.installDir) - target := ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.stem(), fi.builtFile) - for _, sym := range fi.symlinks { - ctx.InstallSymlink(android.PathForModuleInstall(ctx, dir), sym, target) - } + for _, fi := range a.filesInfo { + dir := filepath.Join("apex", bundleName, fi.installDir) + target := ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.stem(), fi.builtFile) + for _, sym := range fi.symlinks { + ctx.InstallSymlink(android.PathForModuleInstall(ctx, dir), sym, target) } } } + + a.fileContexts = a.buildFileContexts(ctx) + + // Temporarily wrap the original `ctx` into a `flattenedApexContext` to have it reply true + // to `InstallBypassMake()` (thus making the call `android.PathForModuleInstall` below use + // `android.pathForInstallInMakeDir` instead of `android.PathForOutput`) to return the + // correct path to the flattened APEX (as its contents is installed by Make, not Soong). + // TODO(jiyong): Why do we need to set outputFile for flattened APEX? We don't seem to use + // it and it actually points to a path that can never be built. Remove this. + factx := flattenedApexContext{ctx} + a.outputFile = android.PathForModuleInstall(&factx, "apex", bundleName) +} + +// getCertificateAndPrivateKey retrieves the cert and the private key that will be used to sign +// the zip container of this APEX. See the description of the 'certificate' property for how +// the cert and the private key are found. +func (a *apexBundle) getCertificateAndPrivateKey(ctx android.PathContext) (pem, key android.Path) { + if a.container_certificate_file != nil { + return a.container_certificate_file, a.container_private_key_file + } + + cert := String(a.properties.Certificate) + if cert == "" { + return ctx.Config().DefaultAppCertificate(ctx) + } + + defaultDir := ctx.Config().DefaultAppCertificateDir(ctx) + pem = defaultDir.Join(ctx, cert+".x509.pem") + key = defaultDir.Join(ctx, cert+".pk8") + return pem, key } func (a *apexBundle) getOverrideManifestPackageName(ctx android.ModuleContext) string { diff --git a/apex/key.go b/apex/key.go index 43764da59..d9e3c1051 100644 --- a/apex/key.go +++ b/apex/key.go @@ -127,13 +127,14 @@ func (s *apexKeysText) GenerateBuildActions(ctx android.SingletonContext) { apexKeyMap := make(map[string]apexKeyEntry) ctx.VisitAllModules(func(module android.Module) { if m, ok := module.(*apexBundle); ok && m.Enabled() && m.installable() { + pem, key := m.getCertificateAndPrivateKey(ctx) apexKeyMap[m.Name()] = apexKeyEntry{ name: m.Name() + ".apex", presigned: false, public_key: m.public_key_file.String(), private_key: m.private_key_file.String(), - container_certificate: m.container_certificate_file.String(), - container_private_key: m.container_private_key_file.String(), + container_certificate: pem.String(), + container_private_key: key.String(), partition: m.PartitionTag(ctx.DeviceConfig()), } }