Expand preprocessed flag to work on android_app_imports
Setting the preprocessed flag will now also verify that the apk is
zip-aligned and does not have compressed JNI libs or dex files.
Bug: 185811447
Test: m nothing
Change-Id: I01b7c25f390345b14385f6f9e1640f48a5d9dc93
diff --git a/java/app.go b/java/app.go
index 03e2330..7bb8cdb 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1461,10 +1461,8 @@
// verifyUsesLibrariesAPK checks the <uses-library> tags in the manifest of an APK against the build
// system and returns the path to a copy of the APK.
-func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) android.Path {
+func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) {
u.verifyUsesLibraries(ctx, apk, nil) // for APKs manifest_check does not write output file
- outputFile := android.PathForModuleOut(ctx, "verify_uses_libraries", apk.Base())
- return outputFile
}
// For Bazel / bp2build
diff --git a/java/app_import.go b/java/app_import.go
index 85b35eb..bfd6767 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -49,6 +49,17 @@
CommandDeps: []string{"${config.Zip2ZipCmd}"},
Description: "Uncompress dex files",
})
+
+ checkJniAndDexLibsAreUncompressedRule = pctx.AndroidStaticRule("check-jni-and-dex-libs-are-uncompressed", blueprint.RuleParams{
+ // grep -v ' stor ' will search for lines that don't have ' stor '. stor means the file is stored uncompressed
+ Command: "if (zipinfo $in 'lib/*.so' '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then " +
+ "echo $in: Contains compressed JNI libraries and/or dex files >&2;" +
+ "exit 1; " +
+ "else " +
+ "touch $out; " +
+ "fi",
+ Description: "Check for compressed JNI libs or dex files",
+ })
)
func RegisterAppImportBuildComponents(ctx android.RegistrationContext) {
@@ -73,8 +84,6 @@
usesLibrary usesLibrary
- preprocessed bool
-
installPath android.InstallPath
hideApexVariantFromMake bool
@@ -128,6 +137,13 @@
// Optional. Install to a subdirectory of the default install path for the module
Relative_install_path *string
+
+ // Whether the prebuilt apk can be installed without additional processing. Default is false.
+ Preprocessed *bool
+
+ // Whether or not to skip checking the preprocessed apk for proper alignment and uncompressed
+ // JNI libs and dex files. Default is false
+ Skip_preprocessed_apk_checks *bool
}
func (a *AndroidAppImport) IsInstallable() bool {
@@ -201,7 +217,7 @@
ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
// Test apps don't need their JNI libraries stored uncompressed. As a matter of fact, messing
// with them may invalidate pre-existing signature data.
- if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || a.preprocessed) {
+ if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || Bool(a.properties.Preprocessed)) {
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
Output: outputPath,
@@ -219,7 +235,7 @@
// Returns whether this module should have the dex file stored uncompressed in the APK.
func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
- if ctx.Config().UnbundledBuild() || a.preprocessed {
+ if ctx.Config().UnbundledBuild() || proptools.Bool(a.properties.Preprocessed) {
return false
}
@@ -297,7 +313,7 @@
a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx)
if a.usesLibrary.enforceUsesLibraries() {
- srcApk = a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
+ a.usesLibrary.verifyUsesLibrariesAPK(ctx, srcApk)
}
a.dexpreopter.dexpreopt(ctx, jnisUncompressed)
@@ -317,8 +333,15 @@
// Sign or align the package if package has not been preprocessed
- if a.preprocessed {
- a.outputFile = srcApk
+ if proptools.Bool(a.properties.Preprocessed) {
+ output := srcApk
+ // TODO(b/185811447) Uncomment this after all existing failing apks set skip_preprocessed_apk_checks: true
+ //if !proptools.Bool(a.properties.Skip_preprocessed_apk_checks) {
+ // writableOutput := android.PathForModuleOut(ctx, "validated-prebuilt", apkFilename)
+ // a.validatePreprocessedApk(ctx, srcApk, writableOutput)
+ // output = writableOutput
+ //}
+ a.outputFile = output
a.certificate = PresignedCertificate
} else if !Bool(a.properties.Presigned) {
// If the certificate property is empty at this point, default_dev_cert must be set to true.
@@ -352,6 +375,30 @@
// TODO: androidmk converter jni libs
}
+func (a *AndroidAppImport) validatePreprocessedApk(ctx android.ModuleContext, srcApk android.Path, dstApk android.WritablePath) {
+ alignmentStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "alignment.stamp")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: checkZipAlignment,
+ Input: srcApk,
+ Output: alignmentStamp,
+ })
+ compressionStamp := android.PathForModuleOut(ctx, "validated-prebuilt", "compression.stamp")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: checkJniAndDexLibsAreUncompressedRule,
+ Input: srcApk,
+ Output: compressionStamp,
+ })
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: srcApk,
+ Output: dstApk,
+ Validations: []android.Path{
+ alignmentStamp,
+ compressionStamp,
+ },
+ })
+}
+
func (a *AndroidAppImport) Prebuilt() *android.Prebuilt {
return &a.prebuilt
}
@@ -487,11 +534,6 @@
return module
}
-type androidTestImportProperties struct {
- // Whether the prebuilt apk can be installed without additional processing. Default is false.
- Preprocessed *bool
-}
-
type AndroidTestImport struct {
AndroidAppImport
@@ -508,14 +550,10 @@
Per_testcase_directory *bool
}
- testImportProperties androidTestImportProperties
-
data android.Paths
}
func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- a.preprocessed = Bool(a.testImportProperties.Preprocessed)
-
a.generateAndroidBuildActions(ctx)
a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
@@ -532,7 +570,6 @@
module.AddProperties(&module.properties)
module.AddProperties(&module.dexpreoptProperties)
module.AddProperties(&module.testProperties)
- module.AddProperties(&module.testImportProperties)
module.populateAllVariantStructs()
android.AddLoadHook(module, func(ctx android.LoadHookContext) {
module.processVariants(ctx)
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 8093024..845a962 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -657,6 +657,30 @@
}
}
+// TODO(b/185811447) Uncomment this after all existing failing apks set skip_preprocessed_apk_checks: true
+//func TestAndroidAppImport_Preprocessed(t *testing.T) {
+// ctx, _ := testJava(t, `
+// android_app_import {
+// name: "foo",
+// apk: "prebuilts/apk/app.apk",
+// presigned: true,
+// preprocessed: true,
+// }
+// `)
+//
+// apkName := "foo.apk"
+// variant := ctx.ModuleForTests("foo", "android_common")
+// outputBuildParams := variant.Output("validated-prebuilt/" + apkName).BuildParams
+// if outputBuildParams.Rule.String() != android.Cp.String() {
+// t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String())
+// }
+//
+// // Make sure compression and aligning were validated.
+// if len(outputBuildParams.Validations) != 2 {
+// t.Errorf("Expected compression/alignment validation rules, found %d validations", len(outputBuildParams.Validations))
+// }
+//}
+
func TestAndroidTestImport_UncompressDex(t *testing.T) {
testCases := []struct {
name string
diff --git a/java/builder.go b/java/builder.go
index 4626267..0c57738 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -246,6 +246,19 @@
CommandDeps: []string{"${config.ZipAlign}"},
},
)
+
+ checkZipAlignment = pctx.AndroidStaticRule("checkzipalign",
+ blueprint.RuleParams{
+ Command: "if ! ${config.ZipAlign} -c -p 4 $in > /dev/null; then " +
+ "echo $in: Improper package alignment >&2; " +
+ "exit 1; " +
+ "else " +
+ "touch $out; " +
+ "fi",
+ CommandDeps: []string{"${config.ZipAlign}"},
+ Description: "Check zip alignment",
+ },
+ )
)
func init() {