diff options
Diffstat (limited to 'apex/builder.go')
| -rw-r--r-- | apex/builder.go | 732 |
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 +} |