summaryrefslogtreecommitdiff
path: root/apex/builder.go
diff options
context:
space:
mode:
Diffstat (limited to 'apex/builder.go')
-rw-r--r--apex/builder.go732
1 files changed, 391 insertions, 341 deletions
diff --git a/apex/builder.go b/apex/builder.go
index 3c7671b00..763ce4d20 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -17,12 +17,14 @@ package apex
import (
"encoding/json"
"fmt"
+ "path"
"path/filepath"
"runtime"
"sort"
"strconv"
"strings"
+ "android/soong/aconfig"
"android/soong/android"
"android/soong/java"
@@ -35,6 +37,7 @@ var (
)
func init() {
+ pctx.Import("android/soong/aconfig")
pctx.Import("android/soong/android")
pctx.Import("android/soong/cc/config")
pctx.Import("android/soong/java")
@@ -74,7 +77,24 @@ func init() {
pctx.HostBinToolVariable("apex_sepolicy_tests", "apex_sepolicy_tests")
pctx.HostBinToolVariable("deapexer", "deapexer")
pctx.HostBinToolVariable("debugfs_static", "debugfs_static")
+ pctx.HostBinToolVariable("fsck_erofs", "fsck.erofs")
pctx.SourcePathVariable("genNdkUsedbyApexPath", "build/soong/scripts/gen_ndk_usedby_apex.sh")
+ pctx.HostBinToolVariable("conv_linker_config", "conv_linker_config")
+ pctx.HostBinToolVariable("assemble_vintf", "assemble_vintf")
+ pctx.HostBinToolVariable("apex_elf_checker", "apex_elf_checker")
+ pctx.HostBinToolVariable("aconfig", "aconfig")
+}
+
+type createStorageStruct struct {
+ Output_file string
+ Desc string
+ File_type string
+}
+
+var createStorageInfo = []createStorageStruct{
+ {"package.map", "create_aconfig_package_map_file", "package_map"},
+ {"flag.map", "create_aconfig_flag_map_file", "flag_map"},
+ {"flag.val", "create_aconfig_flag_val_file", "flag_val"},
}
var (
@@ -179,19 +199,6 @@ var (
}, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key",
"opt_flags", "manifest", "libs_to_trim")
- zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
- Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
- `(. ${out}.copy_commands) && ` +
- `APEXER_TOOL_PATH=${tool_path} ` +
- `${apexer} --force --manifest ${manifest} ` +
- `--payload_type zip ` +
- `${image_dir} ${out} `,
- CommandDeps: []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
- Rspfile: "${out}.copy_commands",
- RspfileContent: "${copy_commands}",
- Description: "ZipAPEX ${image_dir} => ${out}",
- }, "tool_path", "image_dir", "copy_commands", "manifest")
-
apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule",
blueprint.RuleParams{
Command: `${aapt2} convert --output-format proto $in -o $out`,
@@ -231,10 +238,28 @@ var (
apexSepolicyTestsRule = pctx.StaticRule("apexSepolicyTestsRule", blueprint.RuleParams{
Command: `${deapexer} --debugfs_path ${debugfs_static} list -Z ${in} > ${out}.fc` +
- `&& ${apex_sepolicy_tests} -f ${out}.fc && touch ${out}`,
+ ` && ${apex_sepolicy_tests} -f ${out}.fc && touch ${out}`,
CommandDeps: []string{"${apex_sepolicy_tests}", "${deapexer}", "${debugfs_static}"},
Description: "run apex_sepolicy_tests",
})
+
+ apexLinkerconfigValidationRule = pctx.StaticRule("apexLinkerconfigValidationRule", blueprint.RuleParams{
+ Command: `${conv_linker_config} validate --type apex ${image_dir} && touch ${out}`,
+ CommandDeps: []string{"${conv_linker_config}"},
+ Description: "run apex_linkerconfig_validation",
+ }, "image_dir")
+
+ assembleVintfRule = pctx.StaticRule("assembleVintfRule", blueprint.RuleParams{
+ Command: `rm -f $out && VINTF_IGNORE_TARGET_FCM_VERSION=true ${assemble_vintf} -i $in -o $out`,
+ CommandDeps: []string{"${assemble_vintf}"},
+ Description: "run assemble_vintf",
+ })
+
+ apexElfCheckerUnwantedRule = pctx.StaticRule("apexElfCheckerUnwantedRule", blueprint.RuleParams{
+ Command: `${apex_elf_checker} --tool_path ${tool_path} --unwanted ${unwanted} ${in} && touch ${out}`,
+ CommandDeps: []string{"${apex_elf_checker}", "${deapexer}", "${debugfs_static}", "${fsck_erofs}", "${config.ClangBin}/llvm-readelf"},
+ Description: "run apex_elf_checker --unwanted",
+ }, "tool_path", "unwanted")
)
// buildManifest creates buile rules to modify the input apex_manifest.json to add information
@@ -252,7 +277,7 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs,
// VNDK APEX name is determined at runtime, so update "name" in apex_manifest
optCommands := []string{}
if a.vndkApex {
- apexName := vndkApexNamePrefix + a.vndkVersion(ctx.DeviceConfig())
+ apexName := vndkApexNamePrefix + a.vndkVersion()
optCommands = append(optCommands, "-v name "+apexName)
}
@@ -268,13 +293,29 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs,
}
if android.InList(":vndk", requireNativeLibs) {
- if _, vndkVersion := a.getImageVariationPair(ctx.DeviceConfig()); vndkVersion != "" {
+ if _, vndkVersion := a.getImageVariationPair(); vndkVersion != "" {
optCommands = append(optCommands, "-v vndkVersion "+vndkVersion)
}
}
manifestJsonFullOut := android.PathForModuleOut(ctx, "apex_manifest_full.json")
defaultVersion := android.DefaultUpdatableModuleVersion
+ if a.properties.Variant_version != nil {
+ defaultVersionInt, err := strconv.Atoi(defaultVersion)
+ if err != nil {
+ ctx.ModuleErrorf("expected DefaultUpdatableModuleVersion to be an int, but got %s", defaultVersion)
+ }
+ if defaultVersionInt%10 != 0 {
+ ctx.ModuleErrorf("expected DefaultUpdatableModuleVersion to end in a zero, but got %s", defaultVersion)
+ }
+ variantVersion := []rune(*a.properties.Variant_version)
+ if len(variantVersion) != 1 || variantVersion[0] < '0' || variantVersion[0] > '9' {
+ ctx.PropertyErrorf("variant_version", "expected an integer between 0-9; got %s", *a.properties.Variant_version)
+ }
+ defaultVersionRunes := []rune(defaultVersion)
+ defaultVersionRunes[len(defaultVersion)-1] = []rune(variantVersion)[0]
+ defaultVersion = string(defaultVersionRunes)
+ }
if override := ctx.Config().Getenv("OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION"); override != "" {
defaultVersion = override
}
@@ -314,14 +355,16 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs,
// 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/<apexname>-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.
+// labeled as system_file or vendor_apex_metadata_file.
func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.OutputPath {
var fileContexts android.Path
var fileContextsDir string
+ isFileContextsModule := false
if a.properties.File_contexts == nil {
fileContexts = android.PathForSource(ctx, "system/sepolicy/apex", ctx.ModuleName()+"-file_contexts")
} else {
if m, t := android.SrcIsModuleWithTag(*a.properties.File_contexts); m != "" {
+ isFileContextsModule = true
otherModule := android.GetModuleFromPathDep(ctx, m, t)
fileContextsDir = ctx.OtherModuleDir(otherModule)
}
@@ -337,7 +380,7 @@ func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.Output
ctx.PropertyErrorf("file_contexts", "should be under system/sepolicy, but found in %q", fileContextsDir)
}
}
- if !android.ExistentPathForSource(ctx, fileContexts.String()).Valid() {
+ if !isFileContextsModule && !android.ExistentPathForSource(ctx, fileContexts.String()).Valid() {
ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", fileContexts.String())
}
@@ -346,38 +389,23 @@ func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.Output
output := android.PathForModuleOut(ctx, "file_contexts")
rule := android.NewRuleBuilder(pctx, ctx)
- switch a.properties.ApexType {
- case imageApex:
- // remove old file
- rule.Command().Text("rm").FlagWithOutput("-f ", output)
- // copy file_contexts
- rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
- // new line
- rule.Command().Text("echo").Text(">>").Output(output)
- if !useFileContextsAsIs {
- // 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)
- }
- 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
- apexPath := android.InstallPathToOnDevicePath(ctx, a.installDir.Join(ctx, a.Name()))
- apexPath = strings.ReplaceAll(apexPath, ".", `\\.`)
- // remove old file
- rule.Command().Text("rm").FlagWithOutput("-f ", output)
- // copy file_contexts
- rule.Command().Text("awk").Text(`'/object_r/{printf("` + apexPath + `%s\n", $0)}'`).Input(fileContexts).Text(">").Output(output)
- // new line
- rule.Command().Text("echo").Text(">>").Output(output)
- if !useFileContextsAsIs {
- // 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))
+ labelForRoot := "u:object_r:system_file:s0"
+ labelForManifest := "u:object_r:system_file:s0"
+ if a.SocSpecific() && !a.vndkApex {
+ // APEX on /vendor should label ./ and ./apex_manifest.pb as vendor file.
+ labelForRoot = "u:object_r:vendor_file:s0"
+ labelForManifest = "u:object_r:vendor_apex_metadata_file:s0"
+ }
+ // remove old file
+ rule.Command().Text("rm").FlagWithOutput("-f ", output)
+ // copy file_contexts
+ rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
+ // new line
+ rule.Command().Text("echo").Text(">>").Output(output)
+ if !useFileContextsAsIs {
+ // force-label /apex_manifest.pb and /
+ rule.Command().Text("echo").Text("/apex_manifest\\\\.pb").Text(labelForManifest).Text(">>").Output(output)
+ rule.Command().Text("echo").Text("/").Text(labelForRoot).Text(">>").Output(output)
}
rule.Build("file_contexts."+a.Name(), "Generate file_contexts")
@@ -456,10 +484,25 @@ func markManifestTestOnly(ctx android.ModuleContext, androidManifestFile android
})
}
-// buildUnflattendApex creates build rules to build an APEX using apexer.
-func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
- apexType := a.properties.ApexType
- suffix := apexType.suffix()
+func isVintfFragment(fi apexFile) bool {
+ isVintfFragment, _ := path.Match("etc/vintf/*", fi.path())
+ return isVintfFragment
+}
+
+func runAssembleVintf(ctx android.ModuleContext, vintfFragment android.Path) android.Path {
+ processed := android.PathForModuleOut(ctx, "vintf", vintfFragment.Base())
+ ctx.Build(pctx, android.BuildParams{
+ Rule: assembleVintfRule,
+ Input: vintfFragment,
+ Output: processed,
+ Description: "run assemble_vintf for VINTF in APEX",
+ })
+ return processed
+}
+
+// buildApex creates build rules to build an APEX using apexer.
+func (a *apexBundle) buildApex(ctx android.ModuleContext) {
+ suffix := imageApexSuffix
apexName := a.BaseModuleName()
////////////////////////////////////////////////////////////////////////////////////////////
@@ -468,10 +511,6 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
imageDir := android.PathForModuleOut(ctx, "image"+suffix)
installSymbolFiles := (!ctx.Config().KatiEnabled() || a.ExportedToMake()) && a.installable()
- // We can't install symbol files when prebuilt is used.
- if a.IsReplacedByPrebuilt() {
- installSymbolFiles = false
- }
// set of dependency module:location mappings
installMapSet := make(map[string]bool)
@@ -498,7 +537,15 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath)
} else {
// Copy the file into APEX
- copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
+ if !a.testApex && isVintfFragment(fi) {
+ // copy the output of assemble_vintf instead of the original
+ vintfFragment := runAssembleVintf(ctx, fi.builtFile)
+ copyCommands = append(copyCommands, "cp -f "+vintfFragment.String()+" "+destPath)
+ implicitInputs = append(implicitInputs, vintfFragment)
+ } else {
+ copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
+ implicitInputs = append(implicitInputs, fi.builtFile)
+ }
var installedPath android.InstallPath
if fi.class == appSet {
@@ -516,7 +563,6 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
installedPath = ctx.InstallFile(apexDir.Join(ctx, fi.installDir), fi.stem(), fi.builtFile)
}
}
- implicitInputs = append(implicitInputs, fi.builtFile)
// Create additional symlinks pointing the file inside the APEX (if any). Note that
// this is independent from the symlink optimization.
@@ -534,13 +580,8 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
// 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()
- dataPath := d.SrcPath.String()
- if !strings.HasSuffix(dataPath, relPath) {
- panic(fmt.Errorf("path %q does not end with %q", dataPath, relPath))
- }
-
- dataDest := imageDir.Join(ctx, fi.apexRelativePath(relPath), d.RelativeInstallPath).String()
+ relPath := d.ToRelativeInstallPath()
+ dataDest := imageDir.Join(ctx, fi.apexRelativePath(relPath)).String()
copyCommands = append(copyCommands, "cp -f "+d.SrcPath.String()+" "+dataDest)
implicitInputs = append(implicitInputs, d.SrcPath)
@@ -548,6 +589,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
installMapSet[installMapPath.String()+":"+fi.installDir+"/"+fi.builtFile.Base()] = true
}
+
implicitInputs = append(implicitInputs, a.manifestPbOut)
if len(installMapSet) > 0 {
@@ -602,263 +644,287 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
outHostBinDir := ctx.Config().HostToolPath(ctx, "").String()
prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
- if apexType == imageApex {
-
- ////////////////////////////////////////////////////////////////////////////////////
- // 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.
- cannedFsConfig := a.buildCannedFsConfig(ctx)
- 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{}
+ defaultReadOnlyFiles := []string{"apex_manifest.json", "apex_manifest.pb"}
+ aconfigDest := imageDir.Join(ctx, "etc").String()
+ if len(a.aconfigFiles) > 0 {
+ apexAconfigFile := android.PathForModuleOut(ctx, "aconfig_flags.pb")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: aconfig.AllDeclarationsRule,
+ Inputs: a.aconfigFiles,
+ Output: apexAconfigFile,
+ Description: "combine_aconfig_declarations",
+ Args: map[string]string{
+ "cache_files": android.JoinPathsWithPrefix(a.aconfigFiles, "--cache "),
+ },
+ })
- fileContexts := a.buildFileContexts(ctx)
- implicitInputs = append(implicitInputs, fileContexts)
+ copyCommands = append(copyCommands, "cp -f "+apexAconfigFile.String()+" "+aconfigDest)
+ implicitInputs = append(implicitInputs, apexAconfigFile)
+ defaultReadOnlyFiles = append(defaultReadOnlyFiles, "etc/"+apexAconfigFile.Base())
- implicitInputs = append(implicitInputs, a.privateKeyFile, a.publicKeyFile)
- optFlags = append(optFlags, "--pubkey "+a.publicKeyFile.String())
+ for _, info := range createStorageInfo {
+ outputFile := android.PathForModuleOut(ctx, info.Output_file)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: aconfig.CreateStorageRule,
+ Inputs: a.aconfigFiles,
+ Output: outputFile,
+ Description: info.Desc,
+ Args: map[string]string{
+ "container": ctx.ModuleName(),
+ "file_type": info.File_type,
+ "cache_files": android.JoinPathsWithPrefix(a.aconfigFiles, "--cache "),
+ },
+ })
- manifestPackageName := a.getOverrideManifestPackageName(ctx)
- if manifestPackageName != "" {
- optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName)
+ copyCommands = append(copyCommands, "cp -f "+outputFile.String()+" "+aconfigDest)
+ implicitInputs = append(implicitInputs, outputFile)
+ defaultReadOnlyFiles = append(defaultReadOnlyFiles, "etc/"+outputFile.Base())
}
+ }
- if a.properties.AndroidManifest != nil {
- androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))
+ ////////////////////////////////////////////////////////////////////////////////////
+ // 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.
+ cannedFsConfig := a.buildCannedFsConfig(ctx, defaultReadOnlyFiles)
+ implicitInputs = append(implicitInputs, cannedFsConfig)
- if a.testApex {
- androidManifestFile = markManifestTestOnly(ctx, androidManifestFile)
- }
+ ////////////////////////////////////////////////////////////////////////////////////
+ // Step 3: Prepare option flags for apexer and invoke it to create an unsigned APEX.
+ // TODO(jiyong): use the RuleBuilder
+ optFlags := []string{}
- implicitInputs = append(implicitInputs, androidManifestFile)
- optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
- } else if a.testApex {
- optFlags = append(optFlags, "--test_only")
- }
+ fileContexts := a.buildFileContexts(ctx)
+ implicitInputs = append(implicitInputs, fileContexts)
- // Determine target/min sdk version from the context
- // TODO(jiyong): make this as a function
- moduleMinSdkVersion := a.minSdkVersion(ctx)
- minSdkVersion := moduleMinSdkVersion.String()
+ implicitInputs = append(implicitInputs, a.privateKeyFile, a.publicKeyFile)
+ optFlags = append(optFlags, "--pubkey "+a.publicKeyFile.String())
- // bundletool doesn't understand what "current" is. We need to transform it to
- // codename
- if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() {
- minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
+ manifestPackageName := a.getOverrideManifestPackageName(ctx)
+ if manifestPackageName != "" {
+ optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName)
+ }
- if java.UseApiFingerprint(ctx) {
- minSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
- implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
- }
- }
- // 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 a.properties.AndroidManifest != nil {
+ androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))
- if java.UseApiFingerprint(ctx) {
- targetSdkVersion = ctx.Config().PlatformSdkCodename() + fmt.Sprintf(".$$(cat %s)", java.ApiFingerprintPath(ctx).String())
- implicitInputs = append(implicitInputs, java.ApiFingerprintPath(ctx))
+ if a.testApex {
+ androidManifestFile = markManifestTestOnly(ctx, androidManifestFile)
}
- optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
- optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion)
- if a.overridableProperties.Logging_parent != "" {
- optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent)
- }
+ implicitInputs = append(implicitInputs, androidManifestFile)
+ optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
+ } else if a.testApex {
+ optFlags = append(optFlags, "--test_only")
+ }
- // Create a NOTICE file, and embed it as an asset file in the APEX.
- htmlGzNotice := android.PathForModuleOut(ctx, "NOTICE.html.gz")
- android.BuildNoticeHtmlOutputFromLicenseMetadata(
- ctx, htmlGzNotice, "", "",
- []string{
- android.PathForModuleInstall(ctx).String() + "/",
- android.PathForModuleInPartitionInstall(ctx, "apex").String() + "/",
- })
- noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
- builder := android.NewRuleBuilder(pctx, ctx)
- builder.Command().Text("cp").
- Input(htmlGzNotice).
- Output(noticeAssetPath)
- builder.Build("notice_dir", "Building notice dir")
- implicitInputs = append(implicitInputs, noticeAssetPath)
- optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String()))
-
- // Apexes which are supposed to be installed in builtin dirs(/system, etc)
- // don't need hashtree for activation. Therefore, by removing hashtree from
- // apex bundle (filesystem image in it, to be specific), we can save storage.
- needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) ||
- a.shouldGenerateHashtree()
- if ctx.Config().ApexCompressionEnabled() && a.isCompressable() {
- needHashTree = true
- }
- if !needHashTree {
- optFlags = append(optFlags, "--no_hashtree")
- }
+ // Determine target/min sdk version from the context
+ // TODO(jiyong): make this as a function
+ moduleMinSdkVersion := a.minSdkVersion(ctx)
+ minSdkVersion := moduleMinSdkVersion.String()
- if a.testOnlyShouldSkipPayloadSign() {
- optFlags = append(optFlags, "--unsigned_payload")
- }
+ // bundletool doesn't understand what "current" is. We need to transform it to
+ // codename
+ if moduleMinSdkVersion.IsCurrent() || moduleMinSdkVersion.IsNone() {
+ minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
- if moduleMinSdkVersion == android.SdkVersion_Android10 {
- implicitInputs = append(implicitInputs, a.manifestJsonOut)
- optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String())
+ if useApiFingerprint, fingerprintMinSdkVersion, fingerprintDeps :=
+ java.UseApiFingerprint(ctx); useApiFingerprint {
+ minSdkVersion = fingerprintMinSdkVersion
+ implicitInputs = append(implicitInputs, fingerprintDeps)
}
+ }
+ // 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 useApiFingerprint, fingerprintTargetSdkVersion, fingerprintDeps :=
+ java.UseApiFingerprint(ctx); useApiFingerprint {
+ targetSdkVersion = fingerprintTargetSdkVersion
+ implicitInputs = append(implicitInputs, fingerprintDeps)
+ }
+ optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
+ optFlags = append(optFlags, "--min_sdk_version "+minSdkVersion)
- optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string())
+ if a.overridableProperties.Logging_parent != "" {
+ optFlags = append(optFlags, "--logging_parent ", a.overridableProperties.Logging_parent)
+ }
- if a.dynamic_common_lib_apex() {
- ctx.Build(pctx, android.BuildParams{
- Rule: DCLAApexRule,
- Implicits: implicitInputs,
- Output: unsignedOutputFile,
- Description: "apex (" + apexType.name() + ")",
- Args: map[string]string{
- "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
- "image_dir": imageDir.String(),
- "copy_commands": strings.Join(copyCommands, " && "),
- "manifest": a.manifestPbOut.String(),
- "file_contexts": fileContexts.String(),
- "canned_fs_config": cannedFsConfig.String(),
- "key": a.privateKeyFile.String(),
- "opt_flags": strings.Join(optFlags, " "),
- },
- })
- } else if ctx.Config().ApexTrimEnabled() && len(a.libs_to_trim(ctx)) > 0 {
- ctx.Build(pctx, android.BuildParams{
- Rule: TrimmedApexRule,
- Implicits: implicitInputs,
- Output: unsignedOutputFile,
- Description: "apex (" + apexType.name() + ")",
- Args: map[string]string{
- "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
- "image_dir": imageDir.String(),
- "copy_commands": strings.Join(copyCommands, " && "),
- "manifest": a.manifestPbOut.String(),
- "file_contexts": fileContexts.String(),
- "canned_fs_config": cannedFsConfig.String(),
- "key": a.privateKeyFile.String(),
- "opt_flags": strings.Join(optFlags, " "),
- "libs_to_trim": strings.Join(a.libs_to_trim(ctx), ","),
- },
- })
- } else {
- ctx.Build(pctx, android.BuildParams{
- Rule: apexRule,
- Implicits: implicitInputs,
- Output: unsignedOutputFile,
- Description: "apex (" + apexType.name() + ")",
- Args: map[string]string{
- "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
- "image_dir": imageDir.String(),
- "copy_commands": strings.Join(copyCommands, " && "),
- "manifest": a.manifestPbOut.String(),
- "file_contexts": fileContexts.String(),
- "canned_fs_config": cannedFsConfig.String(),
- "key": a.privateKeyFile.String(),
- "opt_flags": strings.Join(optFlags, " "),
- },
- })
- }
+ // Create a NOTICE file, and embed it as an asset file in the APEX.
+ htmlGzNotice := android.PathForModuleOut(ctx, "NOTICE.html.gz")
+ android.BuildNoticeHtmlOutputFromLicenseMetadata(
+ ctx, htmlGzNotice, "", "",
+ []string{
+ android.PathForModuleInstall(ctx).String() + "/",
+ android.PathForModuleInPartitionInstall(ctx, "apex").String() + "/",
+ })
+ noticeAssetPath := android.PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
+ builder := android.NewRuleBuilder(pctx, ctx)
+ builder.Command().Text("cp").
+ Input(htmlGzNotice).
+ Output(noticeAssetPath)
+ builder.Build("notice_dir", "Building notice dir")
+ implicitInputs = append(implicitInputs, noticeAssetPath)
+ optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String()))
+
+ // Apexes which are supposed to be installed in builtin dirs(/system, etc)
+ // don't need hashtree for activation. Therefore, by removing hashtree from
+ // apex bundle (filesystem image in it, to be specific), we can save storage.
+ needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) ||
+ a.shouldGenerateHashtree()
+ if ctx.Config().ApexCompressionEnabled() && a.isCompressable() {
+ needHashTree = true
+ }
+ if !needHashTree {
+ optFlags = append(optFlags, "--no_hashtree")
+ }
- // 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
+ if a.testOnlyShouldSkipPayloadSign() {
+ optFlags = append(optFlags, "--unsigned_payload")
+ }
- ctx.Build(pctx, android.BuildParams{
- Rule: apexProtoConvertRule,
- Input: unsignedOutputFile,
- Output: apexProtoFile,
- Description: "apex proto convert",
- })
+ if moduleMinSdkVersion == android.SdkVersion_Android10 {
+ implicitInputs = append(implicitInputs, a.manifestJsonOut)
+ optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String())
+ }
- implicitInputs = append(implicitInputs, unsignedOutputFile)
+ optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string())
- // Run coverage analysis
- apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.txt")
+ if a.dynamic_common_lib_apex() {
ctx.Build(pctx, android.BuildParams{
- Rule: generateAPIsUsedbyApexRule,
+ Rule: DCLAApexRule,
Implicits: implicitInputs,
- Description: "coverage",
- Output: apisUsedbyOutputFile,
+ Output: unsignedOutputFile,
+ Description: "apex",
Args: map[string]string{
- "image_dir": imageDir.String(),
- "readelf": "${config.ClangBin}/llvm-readelf",
+ "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
+ "image_dir": imageDir.String(),
+ "copy_commands": strings.Join(copyCommands, " && "),
+ "manifest": a.manifestPbOut.String(),
+ "file_contexts": fileContexts.String(),
+ "canned_fs_config": cannedFsConfig.String(),
+ "key": a.privateKeyFile.String(),
+ "opt_flags": strings.Join(optFlags, " "),
},
})
- a.nativeApisUsedByModuleFile = apisUsedbyOutputFile
-
- var nativeLibNames []string
- for _, f := range a.filesInfo {
- if f.class == nativeSharedLib {
- nativeLibNames = append(nativeLibNames, f.stem())
- }
- }
- apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt")
- rule := android.NewRuleBuilder(pctx, ctx)
- rule.Command().
- Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")).
- Output(apisBackedbyOutputFile).
- Flags(nativeLibNames)
- rule.Build("ndk_backedby_list", "Generate API libraries backed by Apex")
- a.nativeApisBackedByModuleFile = apisBackedbyOutputFile
-
- var javaLibOrApkPath []android.Path
- for _, f := range a.filesInfo {
- if f.class == javaSharedLib || f.class == app {
- javaLibOrApkPath = append(javaLibOrApkPath, f.builtFile)
- }
- }
- javaApiUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.xml")
- javaUsedByRule := android.NewRuleBuilder(pctx, ctx)
- javaUsedByRule.Command().
- Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")).
- BuiltTool("dexdeps").
- Output(javaApiUsedbyOutputFile).
- Inputs(javaLibOrApkPath)
- javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex")
- a.javaApisUsedByModuleFile = javaApiUsedbyOutputFile
-
- 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)
-
+ } else if ctx.Config().ApexTrimEnabled() && len(a.libs_to_trim(ctx)) > 0 {
ctx.Build(pctx, android.BuildParams{
- Rule: apexBundleRule,
- Input: apexProtoFile,
- Implicit: bundleConfig,
- Output: a.bundleModuleFile,
- Description: "apex bundle module",
+ Rule: TrimmedApexRule,
+ Implicits: implicitInputs,
+ Output: unsignedOutputFile,
+ Description: "apex",
Args: map[string]string{
- "abi": strings.Join(abis, "."),
- "config": bundleConfig.String(),
+ "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
+ "image_dir": imageDir.String(),
+ "copy_commands": strings.Join(copyCommands, " && "),
+ "manifest": a.manifestPbOut.String(),
+ "file_contexts": fileContexts.String(),
+ "canned_fs_config": cannedFsConfig.String(),
+ "key": a.privateKeyFile.String(),
+ "opt_flags": strings.Join(optFlags, " "),
+ "libs_to_trim": strings.Join(a.libs_to_trim(ctx), ","),
},
})
- } else { // zipApex
+ } else {
ctx.Build(pctx, android.BuildParams{
- Rule: zipApexRule,
+ Rule: apexRule,
Implicits: implicitInputs,
Output: unsignedOutputFile,
- Description: "apex (" + apexType.name() + ")",
+ Description: "apex",
Args: map[string]string{
- "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
- "image_dir": imageDir.String(),
- "copy_commands": strings.Join(copyCommands, " && "),
- "manifest": a.manifestPbOut.String(),
+ "tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
+ "image_dir": imageDir.String(),
+ "copy_commands": strings.Join(copyCommands, " && "),
+ "manifest": a.manifestPbOut.String(),
+ "file_contexts": fileContexts.String(),
+ "canned_fs_config": cannedFsConfig.String(),
+ "key": a.privateKeyFile.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
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: apexProtoConvertRule,
+ Input: unsignedOutputFile,
+ Output: apexProtoFile,
+ Description: "apex proto convert",
+ })
+
+ implicitInputs = append(implicitInputs, unsignedOutputFile)
+
+ // Run coverage analysis
+ apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.txt")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: generateAPIsUsedbyApexRule,
+ Implicits: implicitInputs,
+ Description: "coverage",
+ Output: apisUsedbyOutputFile,
+ Args: map[string]string{
+ "image_dir": imageDir.String(),
+ "readelf": "${config.ClangBin}/llvm-readelf",
+ },
+ })
+ a.nativeApisUsedByModuleFile = apisUsedbyOutputFile
+
+ var nativeLibNames []string
+ for _, f := range a.filesInfo {
+ if f.class == nativeSharedLib {
+ nativeLibNames = append(nativeLibNames, f.stem())
+ }
+ }
+ apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt")
+ rb := android.NewRuleBuilder(pctx, ctx)
+ rb.Command().
+ Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")).
+ Output(apisBackedbyOutputFile).
+ Flags(nativeLibNames)
+ rb.Build("ndk_backedby_list", "Generate API libraries backed by Apex")
+ a.nativeApisBackedByModuleFile = apisBackedbyOutputFile
+
+ var javaLibOrApkPath []android.Path
+ for _, f := range a.filesInfo {
+ if f.class == javaSharedLib || f.class == app {
+ javaLibOrApkPath = append(javaLibOrApkPath, f.builtFile)
+ }
+ }
+ javaApiUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_using.xml")
+ javaUsedByRule := android.NewRuleBuilder(pctx, ctx)
+ javaUsedByRule.Command().
+ Tool(android.PathForSource(ctx, "build/soong/scripts/gen_java_usedby_apex.sh")).
+ BuiltTool("dexdeps").
+ Output(javaApiUsedbyOutputFile).
+ Inputs(javaLibOrApkPath)
+ javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex")
+ a.javaApisUsedByModuleFile = javaApiUsedbyOutputFile
+
+ 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,
+ Implicit: bundleConfig,
+ Output: a.bundleModuleFile,
+ Description: "apex bundle module",
+ Args: map[string]string{
+ "abi": strings.Join(abis, "."),
+ "config": bundleConfig.String(),
+ },
+ })
+
////////////////////////////////////////////////////////////////////////////////////
// Step 4: Sign the APEX using signapk
signedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix)
@@ -876,9 +942,15 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
args["outCommaList"] = signedOutputFile.String()
}
var validations android.Paths
- if suffix == imageApexSuffix {
+ validations = append(validations, runApexLinkerconfigValidation(ctx, unsignedOutputFile.OutputPath, imageDir.OutputPath))
+ // TODO(b/279688635) deapexer supports [ext4]
+ if !a.testApex && suffix == imageApexSuffix && ext4 == a.payloadFsType {
validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile.OutputPath))
}
+ if !a.testApex && len(a.properties.Unwanted_transitive_deps) > 0 {
+ validations = append(validations,
+ runApexElfCheckerUnwanted(ctx, unsignedOutputFile.OutputPath, a.properties.Unwanted_transitive_deps))
+ }
ctx.Build(pctx, android.BuildParams{
Rule: rule,
Description: "signapk",
@@ -937,53 +1009,12 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) {
// Install to $OUT/soong/{target,host}/.../apex.
a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile,
- a.compatSymlinks.Paths()...)
+ a.compatSymlinks...)
// installed-files.txt is dist'ed
a.installedFilesFile = a.buildInstalledFilesFile(ctx, a.outputFile, imageDir)
-}
-
-// 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/<name> directory.
-// This function creates the installation rules for the files.
-func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) {
- bundleName := a.Name()
- installedSymlinks := append(android.InstallPaths(nil), a.compatSymlinks...)
- if a.installable() {
- for _, fi := range a.filesInfo {
- dir := filepath.Join("apex", bundleName, fi.installDir)
- installDir := android.PathForModuleInstall(ctx, dir)
- if a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() {
- pathOnDevice := filepath.Join("/", fi.partition, fi.path())
- installedSymlinks = append(installedSymlinks,
- ctx.InstallAbsoluteSymlink(installDir, fi.stem(), pathOnDevice))
- } else {
- if fi.class == appSet {
- as := fi.module.(*java.AndroidAppSet)
- ctx.InstallFileWithExtraFilesZip(installDir, as.BaseModuleName()+".apk",
- as.OutputFile(), as.PackedAdditionalOutputs())
- } else {
- target := ctx.InstallFile(installDir, fi.stem(), fi.builtFile)
- for _, sym := range fi.symlinks {
- installedSymlinks = append(installedSymlinks,
- ctx.InstallSymlink(installDir, sym, target))
- }
- }
- }
- }
-
- // Create install rules for the files added in GenerateAndroidBuildActions after
- // buildFlattenedApex is called. Add the links to system libs (if any) as dependencies
- // of the apex_manifest.pb file since it is always present.
- dir := filepath.Join("apex", bundleName)
- installDir := android.PathForModuleInstall(ctx, dir)
- ctx.InstallFile(installDir, "apex_manifest.pb", a.manifestPbOut, installedSymlinks.Paths()...)
- ctx.InstallFile(installDir, "apex_pubkey", a.publicKeyFile)
- }
-
- a.fileContexts = a.buildFileContexts(ctx)
- a.outputFile = android.PathForModuleInstall(ctx, "apex", bundleName)
+ a.apexKeysPath = writeApexKeys(ctx, a)
}
// getCertificateAndPrivateKey retrieves the cert and the private key that will be used to sign
@@ -1012,7 +1043,7 @@ func (a *apexBundle) getOverrideManifestPackageName(ctx android.ModuleContext) s
if a.vndkApex {
overrideName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(vndkApexName)
if overridden {
- return overrideName + ".v" + a.vndkVersion(ctx.DeviceConfig())
+ return overrideName + ".v" + a.vndkVersion()
}
return ""
}
@@ -1027,21 +1058,12 @@ func (a *apexBundle) getOverrideManifestPackageName(ctx android.ModuleContext) s
}
func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) {
- if !a.primaryApexType {
- return
- }
-
if a.properties.IsCoverageVariant {
// Otherwise, we will have duplicated rules for coverage and
// non-coverage variants of the same APEX
return
}
- if ctx.Host() {
- // No need to generate dependency info for host variant
- return
- }
-
depInfos := android.DepNameToDepInfoMap{}
a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
if from.Name() == to.Name() {
@@ -1116,8 +1138,8 @@ func (a *apexBundle) buildLintReports(ctx android.ModuleContext) {
a.lintReports = java.BuildModuleLintReportZips(ctx, depSetsBuilder.Build())
}
-func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.OutputPath {
- var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"}
+func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext, defaultReadOnlyFiles []string) android.OutputPath {
+ var readOnlyPaths = defaultReadOnlyFiles
var executablePaths []string // this also includes dirs
var appSetDirs []string
appSetFiles := make(map[string]android.Path)
@@ -1126,7 +1148,8 @@ func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.Outp
if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") {
executablePaths = append(executablePaths, pathInApex)
for _, d := range f.dataPaths {
- readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, d.RelativeInstallPath, d.SrcPath.Rel()))
+ rel := d.ToRelativeInstallPath()
+ readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, rel))
}
for _, s := range f.symlinks {
executablePaths = append(executablePaths, filepath.Join(f.installDir, s))
@@ -1181,6 +1204,19 @@ func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.Outp
return cannedFsConfig.OutputPath
}
+func runApexLinkerconfigValidation(ctx android.ModuleContext, apexFile android.OutputPath, imageDir android.OutputPath) android.Path {
+ timestamp := android.PathForModuleOut(ctx, "apex_linkerconfig_validation.timestamp")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: apexLinkerconfigValidationRule,
+ Input: apexFile,
+ Output: timestamp,
+ Args: map[string]string{
+ "image_dir": imageDir.String(),
+ },
+ })
+ return timestamp
+}
+
// Runs apex_sepolicy_tests
//
// $ deapexer list -Z {apex_file} > {file_contexts}
@@ -1194,3 +1230,17 @@ func runApexSepolicyTests(ctx android.ModuleContext, apexFile android.OutputPath
})
return timestamp
}
+
+func runApexElfCheckerUnwanted(ctx android.ModuleContext, apexFile android.OutputPath, unwanted []string) android.Path {
+ timestamp := android.PathForModuleOut(ctx, "apex_elf_unwanted.timestamp")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: apexElfCheckerUnwantedRule,
+ Input: apexFile,
+ Output: timestamp,
+ Args: map[string]string{
+ "unwanted": android.JoinWithSuffixAndSeparator(unwanted, ".so", ":"),
+ "tool_path": ctx.Config().HostToolPath(ctx, "").String() + ":${config.ClangBin}",
+ },
+ })
+ return timestamp
+}