summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Cole Faust <colefaust@google.com> 2025-02-14 12:47:51 -0800
committer Cole Faust <colefaust@google.com> 2025-02-14 13:20:23 -0800
commitb052df5062d9c4695d0f48362d8a113571a01bfc (patch)
tree860cd07a5de034ab64c773f39670f843f1cd3abc
parent83cc13dc2ffdb2e1b77cb56e9d7dfb7b251a27ac (diff)
Reapply "Make fsverity files able to be built independently"
The difference from the original cl is an extra mkdir -p before copying the apks to their staging dir path. The parent directories weren't being created before. Right now, fsverity files are built when building the staging directory. This is slow, before this cl it takes over a minute to generate the staging directory, after it's only ~10 seconds. Fsverity files are now generated before the staging directory is built, in independant ninja actions. Bug: 394404628 Test: m aosp_shared_system_image, verified it didn't change before/after Change-Id: Icf48f0859e6d66ba5ce68d77a7254218d271d526
-rw-r--r--android/packaging.go5
-rw-r--r--filesystem/fsverity_metadata.go234
2 files changed, 178 insertions, 61 deletions
diff --git a/android/packaging.go b/android/packaging.go
index 551fd4c3f..4e0c74a12 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -202,6 +202,11 @@ func (p *PackagingSpec) SrcPath() Path {
return p.srcPath
}
+// The symlink target of the PackagingSpec. Do not use, for the soong-only migration.
+func (p *PackagingSpec) SymlinkTarget() string {
+ return p.symlinkTarget
+}
+
type PackageModule interface {
Module
packagingBase() *PackagingBase
diff --git a/filesystem/fsverity_metadata.go b/filesystem/fsverity_metadata.go
index a3a2086ce..89da3182a 100644
--- a/filesystem/fsverity_metadata.go
+++ b/filesystem/fsverity_metadata.go
@@ -21,9 +21,27 @@ import (
"android/soong/android"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
+func init() {
+ pctx.HostBinToolVariable("fsverity_metadata_generator", "fsverity_metadata_generator")
+ pctx.HostBinToolVariable("fsverity_manifest_generator", "fsverity_manifest_generator")
+ pctx.HostBinToolVariable("fsverity", "fsverity")
+}
+
+var (
+ buildFsverityMeta = pctx.AndroidStaticRule("build_fsverity_meta", blueprint.RuleParams{
+ Command: `$fsverity_metadata_generator --fsverity-path $fsverity --signature none --hash-alg sha256 --output $out $in`,
+ CommandDeps: []string{"$fsverity_metadata_generator", "$fsverity"},
+ })
+ buildFsverityManifest = pctx.AndroidStaticRule("build_fsverity_manifest", blueprint.RuleParams{
+ Command: `$fsverity_manifest_generator --fsverity-path $fsverity --output $out @$in`,
+ CommandDeps: []string{"$fsverity_manifest_generator", "$fsverity"},
+ })
+)
+
type fsverityProperties struct {
// Patterns of files for fsverity metadata generation. For each matched file, a .fsv_meta file
// will be generated and included to the filesystem image.
@@ -35,13 +53,57 @@ type fsverityProperties struct {
Libs proptools.Configurable[[]string] `android:"path"`
}
-func (f *filesystem) writeManifestGeneratorListFile(ctx android.ModuleContext, outputPath android.WritablePath, matchedSpecs []android.PackagingSpec, rebasedDir android.OutputPath) {
+// Mapping of a given fsverity file, which may be a real file or a symlink, and the on-device
+// path it should have relative to the filesystem root.
+type fsveritySrcDest struct {
+ src android.Path
+ dest string
+}
+
+func (f *filesystem) writeManifestGeneratorListFile(
+ ctx android.ModuleContext,
+ outputPath android.WritablePath,
+ matchedFiles []fsveritySrcDest,
+ rootDir android.OutputPath,
+ rebasedDir android.OutputPath,
+) []android.Path {
+ prefix, err := filepath.Rel(rootDir.String(), rebasedDir.String())
+ if err != nil {
+ panic("rebasedDir should be relative to rootDir")
+ }
+ if prefix == "." {
+ prefix = ""
+ }
+ if f.PartitionType() == "system_ext" {
+ // Use the equivalent of $PRODUCT_OUT as the base dir.
+ // This ensures that the paths in build_manifest.pb contain on-device paths
+ // e.g. system_ext/framework/javalib.jar
+ // and not framework/javalib.jar.
+ //
+ // Although base-dir is outside the rootdir provided for packaging, this action
+ // is hermetic since it uses `manifestGeneratorListPath` to filter the files to be written to build_manifest.pb
+ prefix = "system_ext"
+ }
+
+ var deps []android.Path
var buf strings.Builder
- for _, spec := range matchedSpecs {
- buf.WriteString(rebasedDir.Join(ctx, spec.RelPathInPackage()).String())
- buf.WriteRune('\n')
+ for _, spec := range matchedFiles {
+ src := spec.src.String()
+ dst := filepath.Join(prefix, spec.dest)
+ if strings.Contains(src, ",") {
+ ctx.ModuleErrorf("Path cannot contain a comma: %s", src)
+ }
+ if strings.Contains(dst, ",") {
+ ctx.ModuleErrorf("Path cannot contain a comma: %s", dst)
+ }
+ buf.WriteString(src)
+ buf.WriteString(",")
+ buf.WriteString(dst)
+ buf.WriteString("\n")
+ deps = append(deps, spec.src)
}
android.WriteFileRuleVerbatim(ctx, outputPath, buf.String())
+ return deps
}
func (f *filesystem) buildFsverityMetadataFiles(
@@ -64,69 +126,98 @@ func (f *filesystem) buildFsverityMetadataFiles(
return false
}
- var matchedSpecs []android.PackagingSpec
+ var matchedFiles []android.PackagingSpec
+ var matchedSymlinks []android.PackagingSpec
for _, relPath := range android.SortedKeys(specs) {
if match(relPath) {
- matchedSpecs = append(matchedSpecs, specs[relPath])
+ spec := specs[relPath]
+ if spec.SrcPath() != nil {
+ matchedFiles = append(matchedFiles, spec)
+ } else if spec.SymlinkTarget() != "" {
+ matchedSymlinks = append(matchedSymlinks, spec)
+ } else {
+ ctx.ModuleErrorf("Expected a file or symlink for fsverity packaging spec")
+ }
}
}
- if len(matchedSpecs) == 0 {
+ if len(matchedFiles) == 0 && len(matchedSymlinks) == 0 {
return
}
- fsverityPath := ctx.Config().HostToolPath(ctx, "fsverity")
-
// STEP 1: generate .fsv_meta
- var sb strings.Builder
- sb.WriteString("set -e\n")
- for _, spec := range matchedSpecs {
+ var fsverityFileSpecs []fsveritySrcDest
+ for _, spec := range matchedFiles {
+ rel := spec.RelPathInPackage() + ".fsv_meta"
+ outPath := android.PathForModuleOut(ctx, "fsverity/meta_files", rel)
+ destPath := rebasedDir.Join(ctx, rel)
// srcPath is copied by CopySpecsToDir()
- srcPath := rebasedDir.Join(ctx, spec.RelPathInPackage())
- destPath := rebasedDir.Join(ctx, spec.RelPathInPackage()+".fsv_meta")
- builder.Command().
- BuiltTool("fsverity_metadata_generator").
- FlagWithInput("--fsverity-path ", fsverityPath).
- FlagWithArg("--signature ", "none").
- FlagWithArg("--hash-alg ", "sha256").
- FlagWithOutput("--output ", destPath).
- Text(srcPath.String())
+ ctx.Build(pctx, android.BuildParams{
+ Rule: buildFsverityMeta,
+ Input: spec.SrcPath(),
+ Output: outPath,
+ })
+ builder.Command().Textf("cp").Input(outPath).Output(destPath)
f.appendToEntry(ctx, destPath)
*fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
SourcePath: destPath,
- FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), spec.RelPathInPackage()+".fsv_meta"),
+ FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), rel),
+ })
+ fsverityFileSpecs = append(fsverityFileSpecs, fsveritySrcDest{
+ src: spec.SrcPath(),
+ dest: spec.RelPathInPackage(),
})
}
-
- fsVerityBaseDir := rootDir.String()
- if f.PartitionType() == "system_ext" {
- // Use the equivalent of $PRODUCT_OUT as the base dir.
- // This ensures that the paths in build_manifest.pb contain on-device paths
- // e.g. system_ext/framework/javalib.jar
- // and not framework/javalib.jar.
- //
- // Although base-dir is outside the rootdir provided for packaging, this action
- // is hermetic since it uses `manifestGeneratorListPath` to filter the files to be written to build_manifest.pb
- fsVerityBaseDir = filepath.Dir(rootDir.String())
+ for _, spec := range matchedSymlinks {
+ rel := spec.RelPathInPackage() + ".fsv_meta"
+ outPath := android.PathForModuleOut(ctx, "fsverity/meta_files", rel)
+ destPath := rebasedDir.Join(ctx, rel)
+ target := spec.SymlinkTarget() + ".fsv_meta"
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Symlink,
+ Output: outPath,
+ Args: map[string]string{
+ "fromPath": target,
+ },
+ })
+ builder.Command().
+ Textf("cp").
+ Flag(ctx.Config().CpPreserveSymlinksFlags()).
+ Input(outPath).
+ Output(destPath)
+ f.appendToEntry(ctx, destPath)
+ *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
+ SymlinkTarget: target,
+ FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), rel),
+ })
+ // The fsverity manifest tool needs to actually look at the symlink. But symlink
+ // packagingSpecs are not actually created on disk, at least until the staging dir is
+ // built for the partition. Create a fake one now so the tool can see it.
+ realizedSymlink := android.PathForModuleOut(ctx, "fsverity/realized_symlinks", spec.RelPathInPackage())
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Symlink,
+ Output: realizedSymlink,
+ Args: map[string]string{
+ "fromPath": spec.SymlinkTarget(),
+ },
+ })
+ fsverityFileSpecs = append(fsverityFileSpecs, fsveritySrcDest{
+ src: realizedSymlink,
+ dest: spec.RelPathInPackage(),
+ })
}
// STEP 2: generate signed BuildManifest.apk
// STEP 2-1: generate build_manifest.pb
- manifestGeneratorListPath := android.PathForModuleOut(ctx, "fsverity_manifest.list")
- f.writeManifestGeneratorListFile(ctx, manifestGeneratorListPath, matchedSpecs, rebasedDir)
- assetsPath := android.PathForModuleOut(ctx, "fsverity_manifest/assets")
- manifestPbPath := assetsPath.Join(ctx, "build_manifest.pb")
- builder.Command().Text("rm -rf " + assetsPath.String())
- builder.Command().Text("mkdir -p " + assetsPath.String())
- builder.Command().
- BuiltTool("fsverity_manifest_generator").
- FlagWithInput("--fsverity-path ", fsverityPath).
- FlagWithArg("--base-dir ", fsVerityBaseDir).
- FlagWithArg("--output ", manifestPbPath.String()).
- FlagWithInput("@", manifestGeneratorListPath)
-
- f.appendToEntry(ctx, manifestPbPath)
- f.appendToEntry(ctx, manifestGeneratorListPath)
+ manifestGeneratorListPath := android.PathForModuleOut(ctx, "fsverity/fsverity_manifest.list")
+ manifestDeps := f.writeManifestGeneratorListFile(ctx, manifestGeneratorListPath, fsverityFileSpecs, rootDir, rebasedDir)
+ manifestPbPath := android.PathForModuleOut(ctx, "fsverity/build_manifest.pb")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: buildFsverityManifest,
+ Input: manifestGeneratorListPath,
+ Implicits: manifestDeps,
+ Output: manifestPbPath,
+ })
// STEP 2-2: generate BuildManifest.apk (unsigned)
apkNameSuffix := ""
@@ -134,8 +225,8 @@ func (f *filesystem) buildFsverityMetadataFiles(
//https://source.corp.google.com/h/googleplex-android/platform/build/+/e392d2b486c2d4187b20a72b1c67cc737ecbcca5:core/Makefile;l=3410;drc=ea8f34bc1d6e63656b4ec32f2391e9d54b3ebb6b;bpv=1;bpt=0
apkNameSuffix = "SystemExt"
}
- apkPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", fmt.Sprintf("BuildManifest%s.apk", apkNameSuffix))
- idsigPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", fmt.Sprintf("BuildManifest%s.apk.idsig", apkNameSuffix))
+ apkPath := android.PathForModuleOut(ctx, "fsverity", fmt.Sprintf("BuildManifest%s.apk", apkNameSuffix))
+ idsigPath := android.PathForModuleOut(ctx, "fsverity", fmt.Sprintf("BuildManifest%s.apk.idsig", apkNameSuffix))
manifestTemplatePath := android.PathForSource(ctx, "system/security/fsverity/AndroidManifest.xml")
libs := android.PathsForModuleSrc(ctx, f.properties.Fsverity.Libs.GetOrDefault(ctx, nil))
@@ -144,12 +235,23 @@ func (f *filesystem) buildFsverityMetadataFiles(
minSdkVersion = ctx.Config().PlatformSdkVersion().String()
}
- unsignedApkCommand := builder.Command().
- Textf("mkdir -p %s && ", filepath.Dir(apkPath.String())).
+ apkBuilder := android.NewRuleBuilder(pctx, ctx)
+
+ // aapt2 doesn't support adding individual asset files. Create a temp directory to hold asset
+ // files and pass it to aapt2.
+ tmpAssetDir := android.PathForModuleOut(ctx, "fsverity/tmp_asset_dir")
+ stagedManifestPbPath := tmpAssetDir.Join(ctx, "build_manifest.pb")
+ apkBuilder.Command().
+ Text("rm -rf").Text(tmpAssetDir.String()).
+ Text("&&").
+ Text("mkdir -p").Text(tmpAssetDir.String())
+ apkBuilder.Command().Text("cp").Input(manifestPbPath).Output(stagedManifestPbPath)
+
+ unsignedApkCommand := apkBuilder.Command().
BuiltTool("aapt2").
Text("link").
FlagWithOutput("-o ", apkPath).
- FlagWithArg("-A ", assetsPath.String())
+ FlagWithArg("-A ", tmpAssetDir.String()).Implicit(stagedManifestPbPath)
for _, lib := range libs {
unsignedApkCommand.FlagWithInput("-I ", lib)
}
@@ -159,26 +261,36 @@ func (f *filesystem) buildFsverityMetadataFiles(
FlagWithArg("--version-name ", ctx.Config().AppsDefaultVersionName()).
FlagWithInput("--manifest ", manifestTemplatePath).
Text(" --rename-manifest-package com.android.security.fsverity_metadata." + f.partitionName())
- *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
- SourcePath: apkPath,
- FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), fmt.Sprintf("etc/security/fsverity/BuildManifest%s.apk", apkNameSuffix)),
- })
-
- f.appendToEntry(ctx, apkPath)
// STEP 2-3: sign BuildManifest.apk
pemPath, keyPath := ctx.Config().DefaultAppCertificate(ctx)
- builder.Command().
+ apkBuilder.Command().
BuiltTool("apksigner").
Text("sign").
FlagWithArg("--in ", apkPath.String()).
FlagWithInput("--cert ", pemPath).
FlagWithInput("--key ", keyPath).
ImplicitOutput(idsigPath)
+ apkBuilder.Build(fmt.Sprintf("%s_fsverity_apk", ctx.ModuleName()), "build fsverity apk")
+
+ // STEP 2-4: Install the apk into the staging directory
+ installedApkPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", fmt.Sprintf("BuildManifest%s.apk", apkNameSuffix))
+ installedIdsigPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", fmt.Sprintf("BuildManifest%s.apk.idsig", apkNameSuffix))
+ builder.Command().Text("mkdir -p").Text(filepath.Dir(installedApkPath.String()))
+ builder.Command().Text("cp").Input(apkPath).Text(installedApkPath.String())
+ builder.Command().Text("cp").Input(idsigPath).Text(installedIdsigPath.String())
+
+ *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
+ SourcePath: apkPath,
+ FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), fmt.Sprintf("etc/security/fsverity/BuildManifest%s.apk", apkNameSuffix)),
+ })
+
+ f.appendToEntry(ctx, installedApkPath)
+
*fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{
SourcePath: idsigPath,
FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), fmt.Sprintf("etc/security/fsverity/BuildManifest%s.apk.idsig", apkNameSuffix)),
})
- f.appendToEntry(ctx, idsigPath)
+ f.appendToEntry(ctx, installedIdsigPath)
}