Uncompress dex in unbundled privileged apps

Mainline builds privileged apps unbundled and then uses them as
prebuilts, so they need to respect the privileged flag when
deciding whether or not to uncompress the dex.

Bug: 135772877
Test: TestUncompressDex
Change-Id: I91da7116b779ae35c0617ef77dbcb9788902370c
Merged-In: I91da7116b779ae35c0617ef77dbcb9788902370c
(cherry picked from commit 53a87f523b75f86008c3e0971489a06a6450a670)
diff --git a/android/config.go b/android/config.go
index 43eeb97..d1db87b 100644
--- a/android/config.go
+++ b/android/config.go
@@ -208,6 +208,7 @@
 			AAPTPreferredConfig:         stringPtr("xhdpi"),
 			AAPTCharacteristics:         stringPtr("nosdcard"),
 			AAPTPrebuiltDPI:             []string{"xhdpi", "xxhdpi"},
+			UncompressPrivAppDex:        boolPtr(true),
 		},
 
 		buildDir:     buildDir,
diff --git a/java/app.go b/java/app.go
index 8d41b57..ad672ea 100644
--- a/java/app.go
+++ b/java/app.go
@@ -188,17 +188,18 @@
 		return true
 	}
 
-	if ctx.Config().UnbundledBuild() {
-		return false
-	}
-
-	// Uncompress dex in APKs of privileged apps, and modules used by privileged apps.
+	// Uncompress dex in APKs of privileged apps, and modules used by privileged apps
+	// (even for unbundled builds, they may be preinstalled as prebuilts).
 	if ctx.Config().UncompressPrivAppDex() &&
 		(Bool(a.appProperties.Privileged) ||
 			inList(ctx.ModuleName(), ctx.Config().ModulesLoadedByPrivilegedModules())) {
 		return true
 	}
 
+	if ctx.Config().UnbundledBuild() {
+		return false
+	}
+
 	// Uncompress if the dex files is preopted on /system.
 	if !a.dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !odexOnSystemOther(ctx, a.dexpreopter.installPath)) {
 		return true
diff --git a/java/app_test.go b/java/app_test.go
index d268510..2bd44ad 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -24,6 +24,8 @@
 	"sort"
 	"strings"
 	"testing"
+
+	"github.com/google/blueprint/proptools"
 )
 
 var (
@@ -1063,3 +1065,86 @@
 		t.Errorf("mergeNotices shouldn't have run for baz")
 	}
 }
+
+func TestUncompressDex(t *testing.T) {
+	testCases := []struct {
+		name string
+		bp   string
+
+		uncompressedPlatform  bool
+		uncompressedUnbundled bool
+	}{
+		{
+			name: "normal",
+			bp: `
+				android_app {
+					name: "foo",
+					srcs: ["a.java"],
+				}
+			`,
+			uncompressedPlatform:  true,
+			uncompressedUnbundled: false,
+		},
+		{
+			name: "use_embedded_dex",
+			bp: `
+				android_app {
+					name: "foo",
+					use_embedded_dex: true,
+					srcs: ["a.java"],
+				}
+			`,
+			uncompressedPlatform:  true,
+			uncompressedUnbundled: true,
+		},
+		{
+			name: "privileged",
+			bp: `
+				android_app {
+					name: "foo",
+					privileged: true,
+					srcs: ["a.java"],
+				}
+			`,
+			uncompressedPlatform:  true,
+			uncompressedUnbundled: true,
+		},
+	}
+
+	test := func(t *testing.T, bp string, want bool, unbundled bool) {
+		t.Helper()
+
+		config := testConfig(nil)
+		if unbundled {
+			config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
+		}
+
+		ctx := testAppContext(config, bp, nil)
+
+		run(t, ctx, config)
+
+		foo := ctx.ModuleForTests("foo", "android_common")
+		dex := foo.Rule("r8")
+		uncompressedInDexJar := strings.Contains(dex.Args["zipFlags"], "-L 0")
+		aligned := foo.MaybeRule("zipalign").Rule != nil
+
+		if uncompressedInDexJar != want {
+			t.Errorf("want uncompressed in dex %v, got %v", want, uncompressedInDexJar)
+		}
+
+		if aligned != want {
+			t.Errorf("want aligned %v, got %v", want, aligned)
+		}
+	}
+
+	for _, tt := range testCases {
+		t.Run(tt.name, func(t *testing.T) {
+			t.Run("platform", func(t *testing.T) {
+				test(t, tt.bp, tt.uncompressedPlatform, false)
+			})
+			t.Run("unbundled", func(t *testing.T) {
+				test(t, tt.bp, tt.uncompressedUnbundled, true)
+			})
+		})
+	}
+}