| // Copyright 2020 Google Inc. All rights reserved. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | package java | 
 |  | 
 | import ( | 
 | 	"fmt" | 
 | 	"reflect" | 
 | 	"strings" | 
 | 	"testing" | 
 |  | 
 | 	"github.com/google/blueprint/proptools" | 
 |  | 
 | 	"android/soong/android" | 
 | ) | 
 |  | 
 | func TestAndroidAppImport(t *testing.T) { | 
 | 	ctx, _ := testJava(t, ` | 
 | 		android_app_import { | 
 | 			name: "foo", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			certificate: "platform", | 
 | 			dex_preopt: { | 
 | 				enabled: true, | 
 | 			}, | 
 | 		} | 
 | 		`) | 
 |  | 
 | 	variant := ctx.ModuleForTests("foo", "android_common") | 
 |  | 
 | 	// Check dexpreopt outputs. | 
 | 	if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil || | 
 | 		variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule == nil { | 
 | 		t.Errorf("can't find dexpreopt outputs") | 
 | 	} | 
 |  | 
 | 	// Check cert signing flag. | 
 | 	signedApk := variant.Output("signed/foo.apk") | 
 | 	signingFlag := signedApk.Args["certificates"] | 
 | 	expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8" | 
 | 	if expected != signingFlag { | 
 | 		t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) | 
 | 	} | 
 | 	rule := variant.Rule("genProvenanceMetaData") | 
 | 	android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String()) | 
 | 	android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) | 
 | 	android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) | 
 | 	android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"]) | 
 | } | 
 |  | 
 | func TestAndroidAppImport_NoDexPreopt(t *testing.T) { | 
 | 	ctx, _ := testJava(t, ` | 
 | 		android_app_import { | 
 | 			name: "foo", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			certificate: "platform", | 
 | 			dex_preopt: { | 
 | 				enabled: false, | 
 | 			}, | 
 | 		} | 
 | 		`) | 
 |  | 
 | 	variant := ctx.ModuleForTests("foo", "android_common") | 
 |  | 
 | 	// Check dexpreopt outputs. They shouldn't exist. | 
 | 	if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule != nil || | 
 | 		variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule != nil { | 
 | 		t.Errorf("dexpreopt shouldn't have run.") | 
 | 	} | 
 |  | 
 | 	rule := variant.Rule("genProvenanceMetaData") | 
 | 	android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String()) | 
 | 	android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) | 
 | 	android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) | 
 | 	android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"]) | 
 | } | 
 |  | 
 | func TestAndroidAppImport_Presigned(t *testing.T) { | 
 | 	ctx, _ := testJava(t, ` | 
 | 		android_app_import { | 
 | 			name: "foo", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			presigned: true, | 
 | 			dex_preopt: { | 
 | 				enabled: true, | 
 | 			}, | 
 | 		} | 
 | 		`) | 
 |  | 
 | 	variant := ctx.ModuleForTests("foo", "android_common") | 
 |  | 
 | 	// Check dexpreopt outputs. | 
 | 	if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil || | 
 | 		variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule == nil { | 
 | 		t.Errorf("can't find dexpreopt outputs") | 
 | 	} | 
 | 	// Make sure signing was skipped and aligning was done. | 
 | 	if variant.MaybeOutput("signed/foo.apk").Rule != nil { | 
 | 		t.Errorf("signing rule shouldn't be included.") | 
 | 	} | 
 | 	if variant.MaybeOutput("zip-aligned/foo.apk").Rule == nil { | 
 | 		t.Errorf("can't find aligning rule") | 
 | 	} | 
 |  | 
 | 	rule := variant.Rule("genProvenanceMetaData") | 
 | 	android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String()) | 
 | 	android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) | 
 | 	android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) | 
 | 	android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"]) | 
 | } | 
 |  | 
 | func TestAndroidAppImport_SigningLineage(t *testing.T) { | 
 | 	ctx, _ := testJava(t, ` | 
 | 	  android_app_import { | 
 | 			name: "foo", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			certificate: "platform", | 
 | 			additional_certificates: [":additional_certificate"], | 
 | 			lineage: "lineage.bin", | 
 | 			rotationMinSdkVersion: "32", | 
 | 		} | 
 |  | 
 | 		android_app_certificate { | 
 | 			name: "additional_certificate", | 
 | 			certificate: "cert/additional_cert", | 
 | 		} | 
 | 	`) | 
 |  | 
 | 	variant := ctx.ModuleForTests("foo", "android_common") | 
 |  | 
 | 	signedApk := variant.Output("signed/foo.apk") | 
 | 	// Check certificates | 
 | 	certificatesFlag := signedApk.Args["certificates"] | 
 | 	expected := "build/make/target/product/security/platform.x509.pem " + | 
 | 		"build/make/target/product/security/platform.pk8 " + | 
 | 		"cert/additional_cert.x509.pem cert/additional_cert.pk8" | 
 | 	if expected != certificatesFlag { | 
 | 		t.Errorf("Incorrect certificates flags, expected: %q, got: %q", expected, certificatesFlag) | 
 | 	} | 
 |  | 
 | 	// Check cert signing flags. | 
 | 	actualCertSigningFlags := signedApk.Args["flags"] | 
 | 	expectedCertSigningFlags := "--lineage lineage.bin --rotation-min-sdk-version 32" | 
 | 	if expectedCertSigningFlags != actualCertSigningFlags { | 
 | 		t.Errorf("Incorrect signing flags, expected: %q, got: %q", expectedCertSigningFlags, actualCertSigningFlags) | 
 | 	} | 
 |  | 
 | 	rule := variant.Rule("genProvenanceMetaData") | 
 | 	android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String()) | 
 | 	android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) | 
 | 	android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) | 
 | 	android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"]) | 
 | } | 
 |  | 
 | func TestAndroidAppImport_SigningLineageFilegroup(t *testing.T) { | 
 | 	ctx, _ := testJava(t, ` | 
 | 	  android_app_import { | 
 | 			name: "foo", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			certificate: "platform", | 
 | 			lineage: ":lineage_bin", | 
 | 		} | 
 |  | 
 | 		filegroup { | 
 | 			name: "lineage_bin", | 
 | 			srcs: ["lineage.bin"], | 
 | 		} | 
 | 	`) | 
 |  | 
 | 	variant := ctx.ModuleForTests("foo", "android_common") | 
 |  | 
 | 	signedApk := variant.Output("signed/foo.apk") | 
 | 	// Check cert signing lineage flag. | 
 | 	signingFlag := signedApk.Args["flags"] | 
 | 	expected := "--lineage lineage.bin" | 
 | 	if expected != signingFlag { | 
 | 		t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) | 
 | 	} | 
 |  | 
 | 	rule := variant.Rule("genProvenanceMetaData") | 
 | 	android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String()) | 
 | 	android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) | 
 | 	android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) | 
 | 	android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"]) | 
 | } | 
 |  | 
 | func TestAndroidAppImport_DefaultDevCert(t *testing.T) { | 
 | 	ctx, _ := testJava(t, ` | 
 | 		android_app_import { | 
 | 			name: "foo", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			default_dev_cert: true, | 
 | 			dex_preopt: { | 
 | 				enabled: true, | 
 | 			}, | 
 | 		} | 
 | 		`) | 
 |  | 
 | 	variant := ctx.ModuleForTests("foo", "android_common") | 
 |  | 
 | 	// Check dexpreopt outputs. | 
 | 	if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil || | 
 | 		variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule == nil { | 
 | 		t.Errorf("can't find dexpreopt outputs") | 
 | 	} | 
 |  | 
 | 	// Check cert signing flag. | 
 | 	signedApk := variant.Output("signed/foo.apk") | 
 | 	signingFlag := signedApk.Args["certificates"] | 
 | 	expected := "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8" | 
 | 	if expected != signingFlag { | 
 | 		t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) | 
 | 	} | 
 |  | 
 | 	rule := variant.Rule("genProvenanceMetaData") | 
 | 	android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String()) | 
 | 	android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) | 
 | 	android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) | 
 | 	android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"]) | 
 | } | 
 |  | 
 | func TestAndroidAppImport_DpiVariants(t *testing.T) { | 
 | 	bp := ` | 
 | 		android_app_import { | 
 | 			name: "foo", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			dpi_variants: { | 
 | 				xhdpi: { | 
 | 					apk: "prebuilts/apk/app_xhdpi.apk", | 
 | 				}, | 
 | 				xxhdpi: { | 
 | 					apk: "prebuilts/apk/app_xxhdpi.apk", | 
 | 				}, | 
 | 			}, | 
 | 			presigned: true, | 
 | 			dex_preopt: { | 
 | 				enabled: true, | 
 | 			}, | 
 | 		} | 
 | 		` | 
 | 	testCases := []struct { | 
 | 		name                                   string | 
 | 		aaptPreferredConfig                    *string | 
 | 		aaptPrebuiltDPI                        []string | 
 | 		expected                               string | 
 | 		expectedProvenanceMetaDataArtifactPath string | 
 | 	}{ | 
 | 		{ | 
 | 			name:                                   "no preferred", | 
 | 			aaptPreferredConfig:                    nil, | 
 | 			aaptPrebuiltDPI:                        []string{}, | 
 | 			expected:                               "verify_uses_libraries/apk/app.apk", | 
 | 			expectedProvenanceMetaDataArtifactPath: "prebuilts/apk/app.apk", | 
 | 		}, | 
 | 		{ | 
 | 			name:                                   "AAPTPreferredConfig matches", | 
 | 			aaptPreferredConfig:                    proptools.StringPtr("xhdpi"), | 
 | 			aaptPrebuiltDPI:                        []string{"xxhdpi", "ldpi"}, | 
 | 			expected:                               "verify_uses_libraries/apk/app_xhdpi.apk", | 
 | 			expectedProvenanceMetaDataArtifactPath: "prebuilts/apk/app_xhdpi.apk", | 
 | 		}, | 
 | 		{ | 
 | 			name:                                   "AAPTPrebuiltDPI matches", | 
 | 			aaptPreferredConfig:                    proptools.StringPtr("mdpi"), | 
 | 			aaptPrebuiltDPI:                        []string{"xxhdpi", "xhdpi"}, | 
 | 			expected:                               "verify_uses_libraries/apk/app_xxhdpi.apk", | 
 | 			expectedProvenanceMetaDataArtifactPath: "prebuilts/apk/app_xxhdpi.apk", | 
 | 		}, | 
 | 		{ | 
 | 			name:                                   "non-first AAPTPrebuiltDPI matches", | 
 | 			aaptPreferredConfig:                    proptools.StringPtr("mdpi"), | 
 | 			aaptPrebuiltDPI:                        []string{"ldpi", "xhdpi"}, | 
 | 			expected:                               "verify_uses_libraries/apk/app_xhdpi.apk", | 
 | 			expectedProvenanceMetaDataArtifactPath: "prebuilts/apk/app_xhdpi.apk", | 
 | 		}, | 
 | 		{ | 
 | 			name:                                   "no matches", | 
 | 			aaptPreferredConfig:                    proptools.StringPtr("mdpi"), | 
 | 			aaptPrebuiltDPI:                        []string{"ldpi", "xxxhdpi"}, | 
 | 			expected:                               "verify_uses_libraries/apk/app.apk", | 
 | 			expectedProvenanceMetaDataArtifactPath: "prebuilts/apk/app.apk", | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	for _, test := range testCases { | 
 | 		result := android.GroupFixturePreparers( | 
 | 			PrepareForTestWithJavaDefaultModules, | 
 | 			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { | 
 | 				variables.AAPTPreferredConfig = test.aaptPreferredConfig | 
 | 				variables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI | 
 | 			}), | 
 | 		).RunTestWithBp(t, bp) | 
 |  | 
 | 		variant := result.ModuleForTests("foo", "android_common") | 
 | 		input := variant.Output("jnis-uncompressed/foo.apk").Input.String() | 
 | 		if strings.HasSuffix(input, test.expected) { | 
 | 			t.Errorf("wrong src apk, expected: %q got: %q", test.expected, input) | 
 | 		} | 
 |  | 
 | 		provenanceMetaDataRule := variant.Rule("genProvenanceMetaData") | 
 | 		android.AssertStringEquals(t, "Invalid input", test.expectedProvenanceMetaDataArtifactPath, provenanceMetaDataRule.Inputs[0].String()) | 
 | 		android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", provenanceMetaDataRule.Output.String()) | 
 | 		android.AssertStringEquals(t, "Invalid args", "foo", provenanceMetaDataRule.Args["module_name"]) | 
 | 		android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", provenanceMetaDataRule.Args["install_path"]) | 
 | 	} | 
 | } | 
 |  | 
 | func TestAndroidAppImport_Filename(t *testing.T) { | 
 | 	ctx, _ := testJava(t, ` | 
 | 		android_app_import { | 
 | 			name: "foo", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			presigned: true, | 
 | 		} | 
 |  | 
 | 		android_app_import { | 
 | 			name: "bar", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			presigned: true, | 
 | 			filename: "bar_sample.apk" | 
 | 		} | 
 | 		`) | 
 |  | 
 | 	testCases := []struct { | 
 | 		name                 string | 
 | 		expected             string | 
 | 		onDevice             string | 
 | 		expectedArtifactPath string | 
 | 		expectedMetaDataPath string | 
 | 	}{ | 
 | 		{ | 
 | 			name:                 "foo", | 
 | 			expected:             "foo.apk", | 
 | 			onDevice:             "/system/app/foo/foo.apk", | 
 | 			expectedArtifactPath: "prebuilts/apk/app.apk", | 
 | 			expectedMetaDataPath: "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", | 
 | 		}, | 
 | 		{ | 
 | 			name:                 "bar", | 
 | 			expected:             "bar_sample.apk", | 
 | 			onDevice:             "/system/app/bar/bar_sample.apk", | 
 | 			expectedArtifactPath: "prebuilts/apk/app.apk", | 
 | 			expectedMetaDataPath: "out/soong/.intermediates/provenance_metadata/bar/provenance_metadata.textproto", | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	for _, test := range testCases { | 
 | 		variant := ctx.ModuleForTests(test.name, "android_common") | 
 | 		if variant.MaybeOutput(test.expected).Rule == nil { | 
 | 			t.Errorf("can't find output named %q - all outputs: %v", test.expected, variant.AllOutputs()) | 
 | 		} | 
 |  | 
 | 		a := variant.Module().(*AndroidAppImport) | 
 | 		expectedValues := []string{test.expected} | 
 | 		entries := android.AndroidMkEntriesForTest(t, ctx, a)[0] | 
 | 		actualValues := entries.EntryMap["LOCAL_INSTALLED_MODULE_STEM"] | 
 | 		if !reflect.DeepEqual(actualValues, expectedValues) { | 
 | 			t.Errorf("Incorrect LOCAL_INSTALLED_MODULE_STEM value '%s', expected '%s'", | 
 | 				actualValues, expectedValues) | 
 | 		} | 
 | 		android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "android_app_import", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0]) | 
 |  | 
 | 		rule := variant.Rule("genProvenanceMetaData") | 
 | 		android.AssertStringEquals(t, "Invalid input", test.expectedArtifactPath, rule.Inputs[0].String()) | 
 | 		android.AssertStringEquals(t, "Invalid output", test.expectedMetaDataPath, rule.Output.String()) | 
 | 		android.AssertStringEquals(t, "Invalid args", test.name, rule.Args["module_name"]) | 
 | 		android.AssertStringEquals(t, "Invalid args", test.onDevice, rule.Args["install_path"]) | 
 | 	} | 
 | } | 
 |  | 
 | func TestAndroidAppImport_ArchVariants(t *testing.T) { | 
 | 	// The test config's target arch is ARM64. | 
 | 	testCases := []struct { | 
 | 		name         string | 
 | 		bp           string | 
 | 		expected     string | 
 | 		artifactPath string | 
 | 		metaDataPath string | 
 | 		installPath  string | 
 | 	}{ | 
 | 		{ | 
 | 			name: "matching arch", | 
 | 			bp: ` | 
 | 				android_app_import { | 
 | 					name: "foo", | 
 | 					apk: "prebuilts/apk/app.apk", | 
 | 					arch: { | 
 | 						arm64: { | 
 | 							apk: "prebuilts/apk/app_arm64.apk", | 
 | 						}, | 
 | 					}, | 
 | 					presigned: true, | 
 | 					dex_preopt: { | 
 | 						enabled: true, | 
 | 					}, | 
 | 				} | 
 | 			`, | 
 | 			expected:     "verify_uses_libraries/apk/app_arm64.apk", | 
 | 			artifactPath: "prebuilts/apk/app_arm64.apk", | 
 | 			installPath:  "/system/app/foo/foo.apk", | 
 | 		}, | 
 | 		{ | 
 | 			name: "matching arch without default", | 
 | 			bp: ` | 
 | 				android_app_import { | 
 | 					name: "foo", | 
 | 					apk: "prebuilts/apk/app.apk", | 
 | 					arch: { | 
 | 						arm64: { | 
 | 							apk: "prebuilts/apk/app_arm64.apk", | 
 | 						}, | 
 | 					}, | 
 | 					presigned: true, | 
 | 					dex_preopt: { | 
 | 						enabled: true, | 
 | 					}, | 
 | 				} | 
 | 			`, | 
 | 			expected:     "verify_uses_libraries/apk/app_arm64.apk", | 
 | 			artifactPath: "prebuilts/apk/app_arm64.apk", | 
 | 			installPath:  "/system/app/foo/foo.apk", | 
 | 		}, | 
 | 		{ | 
 | 			name: "no matching arch", | 
 | 			bp: ` | 
 | 				android_app_import { | 
 | 					name: "foo", | 
 | 					apk: "prebuilts/apk/app.apk", | 
 | 					arch: { | 
 | 						arm: { | 
 | 							apk: "prebuilts/apk/app_arm.apk", | 
 | 						}, | 
 | 					}, | 
 | 					presigned: true, | 
 | 					dex_preopt: { | 
 | 						enabled: true, | 
 | 					}, | 
 | 				} | 
 | 			`, | 
 | 			expected:     "verify_uses_libraries/apk/app.apk", | 
 | 			artifactPath: "prebuilts/apk/app.apk", | 
 | 			installPath:  "/system/app/foo/foo.apk", | 
 | 		}, | 
 | 		{ | 
 | 			name: "no matching arch without default", | 
 | 			bp: ` | 
 | 				android_app_import { | 
 | 					name: "foo", | 
 | 					arch: { | 
 | 						arm: { | 
 | 							apk: "prebuilts/apk/app_arm.apk", | 
 | 						}, | 
 | 					}, | 
 | 					presigned: true, | 
 | 					dex_preopt: { | 
 | 						enabled: true, | 
 | 					}, | 
 | 				} | 
 | 			`, | 
 | 			expected:     "", | 
 | 			artifactPath: "prebuilts/apk/app_arm.apk", | 
 | 			installPath:  "/system/app/foo/foo.apk", | 
 | 		}, | 
 | 		{ | 
 | 			name: "matching arch and dpi_variants", | 
 | 			bp: ` | 
 | 				android_app_import { | 
 | 					name: "foo", | 
 | 					apk: "prebuilts/apk/app.apk", | 
 | 					arch: { | 
 | 						arm64: { | 
 | 							apk: "prebuilts/apk/app_arm64.apk", | 
 | 							dpi_variants: { | 
 | 								mdpi: { | 
 | 									apk: "prebuilts/apk/app_arm64_mdpi.apk", | 
 | 								}, | 
 | 								xhdpi: { | 
 | 									apk: "prebuilts/apk/app_arm64_xhdpi.apk", | 
 | 								}, | 
 | 							}, | 
 | 						}, | 
 | 					}, | 
 | 					presigned: true, | 
 | 					dex_preopt: { | 
 | 						enabled: true, | 
 | 					}, | 
 | 				} | 
 | 			`, | 
 | 			expected:     "verify_uses_libraries/apk/app_arm64_xhdpi.apk", | 
 | 			artifactPath: "prebuilts/apk/app_arm64_xhdpi.apk", | 
 | 			installPath:  "/system/app/foo/foo.apk", | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	for _, test := range testCases { | 
 | 		t.Run(test.name, func(t *testing.T) { | 
 | 			ctx, _ := testJava(t, test.bp) | 
 |  | 
 | 			variant := ctx.ModuleForTests("foo", "android_common") | 
 | 			if test.expected == "" { | 
 | 				if variant.Module().Enabled(android.PanickingConfigAndErrorContext(ctx)) { | 
 | 					t.Error("module should have been disabled, but wasn't") | 
 | 				} | 
 | 				rule := variant.MaybeRule("genProvenanceMetaData") | 
 | 				android.AssertDeepEquals(t, "Provenance metadata is not empty", android.TestingBuildParams{}, rule) | 
 | 				return | 
 | 			} | 
 | 			input := variant.Output("jnis-uncompressed/foo.apk").Input.String() | 
 | 			if strings.HasSuffix(input, test.expected) { | 
 | 				t.Errorf("wrong src apk, expected: %q got: %q", test.expected, input) | 
 | 			} | 
 | 			rule := variant.Rule("genProvenanceMetaData") | 
 | 			android.AssertStringEquals(t, "Invalid input", test.artifactPath, rule.Inputs[0].String()) | 
 | 			android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) | 
 | 			android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) | 
 | 			android.AssertStringEquals(t, "Invalid args", test.installPath, rule.Args["install_path"]) | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | func TestAndroidAppImport_SoongConfigVariables(t *testing.T) { | 
 | 	testCases := []struct { | 
 | 		name         string | 
 | 		bp           string | 
 | 		expected     string | 
 | 		artifactPath string | 
 | 		metaDataPath string | 
 | 		installPath  string | 
 | 	}{ | 
 | 		{ | 
 | 			name: "matching arch", | 
 | 			bp: ` | 
 | 				soong_config_module_type { | 
 | 					name: "my_android_app_import", | 
 | 					module_type: "android_app_import", | 
 | 					config_namespace: "my_namespace", | 
 | 					value_variables: ["my_apk_var"], | 
 | 					properties: ["apk"], | 
 | 				} | 
 | 				soong_config_value_variable { | 
 | 					name: "my_apk_var", | 
 | 				} | 
 | 				my_android_app_import { | 
 | 					name: "foo", | 
 | 					soong_config_variables: { | 
 | 						my_apk_var: { | 
 | 							apk: "prebuilts/apk/%s.apk", | 
 | 						}, | 
 | 					}, | 
 | 					presigned: true, | 
 | 					dex_preopt: { | 
 | 						enabled: true, | 
 | 					}, | 
 | 				} | 
 | 			`, | 
 | 			expected:     "verify_uses_libraries/apk/name_from_soong_config.apk", | 
 | 			artifactPath: "prebuilts/apk/name_from_soong_config.apk", | 
 | 			installPath:  "/system/app/foo/foo.apk", | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	for _, test := range testCases { | 
 | 		t.Run(test.name, func(t *testing.T) { | 
 | 			ctx := android.GroupFixturePreparers( | 
 | 				prepareForJavaTest, | 
 | 				android.PrepareForTestWithSoongConfigModuleBuildComponents, | 
 | 				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { | 
 | 					variables.VendorVars = map[string]map[string]string{ | 
 | 						"my_namespace": { | 
 | 							"my_apk_var": "name_from_soong_config", | 
 | 						}, | 
 | 					} | 
 | 				}), | 
 | 			).RunTestWithBp(t, test.bp).TestContext | 
 |  | 
 | 			variant := ctx.ModuleForTests("foo", "android_common") | 
 | 			if test.expected == "" { | 
 | 				if variant.Module().Enabled(android.PanickingConfigAndErrorContext(ctx)) { | 
 | 					t.Error("module should have been disabled, but wasn't") | 
 | 				} | 
 | 				rule := variant.MaybeRule("genProvenanceMetaData") | 
 | 				android.AssertDeepEquals(t, "Provenance metadata is not empty", android.TestingBuildParams{}, rule) | 
 | 				return | 
 | 			} | 
 | 			input := variant.Output("jnis-uncompressed/foo.apk").Input.String() | 
 | 			if strings.HasSuffix(input, test.expected) { | 
 | 				t.Errorf("wrong src apk, expected: %q got: %q", test.expected, input) | 
 | 			} | 
 | 			rule := variant.Rule("genProvenanceMetaData") | 
 | 			android.AssertStringEquals(t, "Invalid input", test.artifactPath, rule.Inputs[0].String()) | 
 | 			android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) | 
 | 			android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) | 
 | 			android.AssertStringEquals(t, "Invalid args", test.installPath, rule.Args["install_path"]) | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | func TestAndroidAppImport_overridesDisabledAndroidApp(t *testing.T) { | 
 | 	ctx, _ := testJava(t, ` | 
 | 		android_app { | 
 | 			name: "foo", | 
 | 			srcs: ["a.java"], | 
 | 			enabled: false, | 
 | 		} | 
 |  | 
 |  		android_app_import { | 
 | 			name: "foo", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			certificate: "platform", | 
 | 			prefer: true, | 
 | 		} | 
 | 		`) | 
 |  | 
 | 	variant := ctx.ModuleForTests("prebuilt_foo", "android_common") | 
 | 	a := variant.Module().(*AndroidAppImport) | 
 | 	// The prebuilt module should still be enabled and active even if the source-based counterpart | 
 | 	// is disabled. | 
 | 	if !a.prebuilt.UsePrebuilt() { | 
 | 		t.Errorf("prebuilt foo module is not active") | 
 | 	} | 
 | 	if !a.Enabled(android.PanickingConfigAndErrorContext(ctx)) { | 
 | 		t.Errorf("prebuilt foo module is disabled") | 
 | 	} | 
 | } | 
 |  | 
 | func TestAndroidAppImport_relativeInstallPath(t *testing.T) { | 
 | 	bp := ` | 
 | 		android_app_import { | 
 | 			name: "no_relative_install_path", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			presigned: true, | 
 | 		} | 
 |  | 
 | 		android_app_import { | 
 | 			name: "relative_install_path", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			presigned: true, | 
 | 			relative_install_path: "my/path", | 
 | 		} | 
 |  | 
 | 		android_app_import { | 
 | 			name: "privileged_relative_install_path", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			presigned: true, | 
 | 			privileged: true, | 
 | 			relative_install_path: "my/path" | 
 | 		} | 
 | 		` | 
 | 	testCases := []struct { | 
 | 		name                string | 
 | 		expectedInstallPath string | 
 | 		errorMessage        string | 
 | 	}{ | 
 | 		{ | 
 | 			name:                "no_relative_install_path", | 
 | 			expectedInstallPath: "out/soong/target/product/test_device/system/app/no_relative_install_path/no_relative_install_path.apk", | 
 | 			errorMessage:        "Install path is not correct when relative_install_path is missing", | 
 | 		}, | 
 | 		{ | 
 | 			name:                "relative_install_path", | 
 | 			expectedInstallPath: "out/soong/target/product/test_device/system/app/my/path/relative_install_path/relative_install_path.apk", | 
 | 			errorMessage:        "Install path is not correct for app when relative_install_path is present", | 
 | 		}, | 
 | 		{ | 
 | 			name:                "privileged_relative_install_path", | 
 | 			expectedInstallPath: "out/soong/target/product/test_device/system/priv-app/my/path/privileged_relative_install_path/privileged_relative_install_path.apk", | 
 | 			errorMessage:        "Install path is not correct for privileged app when relative_install_path is present", | 
 | 		}, | 
 | 	} | 
 | 	for _, testCase := range testCases { | 
 | 		ctx, _ := testJava(t, bp) | 
 | 		mod := ctx.ModuleForTests(testCase.name, "android_common").Module().(*AndroidAppImport) | 
 | 		android.AssertPathRelativeToTopEquals(t, testCase.errorMessage, testCase.expectedInstallPath, mod.installPath) | 
 | 	} | 
 | } | 
 |  | 
 | func TestAndroidTestImport(t *testing.T) { | 
 | 	ctx, _ := testJava(t, ` | 
 | 		android_test_import { | 
 | 			name: "foo", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			presigned: true, | 
 | 			data: [ | 
 | 				"testdata/data", | 
 | 			], | 
 | 		} | 
 | 		`) | 
 |  | 
 | 	test := ctx.ModuleForTests("foo", "android_common").Module().(*AndroidTestImport) | 
 |  | 
 | 	// Check android mks. | 
 | 	entries := android.AndroidMkEntriesForTest(t, ctx, test)[0] | 
 | 	expected := []string{"tests"} | 
 | 	actual := entries.EntryMap["LOCAL_MODULE_TAGS"] | 
 | 	if !reflect.DeepEqual(expected, actual) { | 
 | 		t.Errorf("Unexpected module tags - expected: %q, actual: %q", expected, actual) | 
 | 	} | 
 | 	expected = []string{"testdata/data:testdata/data"} | 
 | 	actual = entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"] | 
 | 	if !reflect.DeepEqual(expected, actual) { | 
 | 		t.Errorf("Unexpected test data - expected: %q, actual: %q", expected, actual) | 
 | 	} | 
 | } | 
 |  | 
 | func TestAndroidTestImport_NoJinUncompressForPresigned(t *testing.T) { | 
 | 	ctx, _ := testJava(t, ` | 
 | 		android_test_import { | 
 | 			name: "foo", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			certificate: "cert/new_cert", | 
 | 			data: [ | 
 | 				"testdata/data", | 
 | 			], | 
 | 		} | 
 |  | 
 | 		android_test_import { | 
 | 			name: "foo_presigned", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			presigned: true, | 
 | 			data: [ | 
 | 				"testdata/data", | 
 | 			], | 
 | 		} | 
 | 		`) | 
 |  | 
 | 	variant := ctx.ModuleForTests("foo", "android_common") | 
 | 	jniRule := variant.Output("jnis-uncompressed/foo.apk").BuildParams.Rule.String() | 
 | 	if jniRule == android.Cp.String() { | 
 | 		t.Errorf("Unexpected JNI uncompress rule command: " + jniRule) | 
 | 	} | 
 |  | 
 | 	variant = ctx.ModuleForTests("foo_presigned", "android_common") | 
 | 	jniRule = variant.Output("jnis-uncompressed/foo_presigned.apk").BuildParams.Rule.String() | 
 | 	if jniRule != android.Cp.String() { | 
 | 		t.Errorf("Unexpected JNI uncompress rule: " + jniRule) | 
 | 	} | 
 | 	if variant.MaybeOutput("zip-aligned/foo_presigned.apk").Rule == nil { | 
 | 		t.Errorf("Presigned test apk should be aligned") | 
 | 	} | 
 | } | 
 |  | 
 | func TestAndroidTestImport_Preprocessed(t *testing.T) { | 
 | 	ctx, _ := testJava(t, ` | 
 | 		android_test_import { | 
 | 			name: "foo", | 
 | 			apk: "prebuilts/apk/app.apk", | 
 | 			presigned: true, | 
 | 			preprocessed: true, | 
 | 		} | 
 | 		`) | 
 |  | 
 | 	apkName := "foo.apk" | 
 | 	variant := ctx.ModuleForTests("foo", "android_common") | 
 | 	jniRule := variant.Output("jnis-uncompressed/" + apkName).BuildParams.Rule.String() | 
 | 	if jniRule != android.Cp.String() { | 
 | 		t.Errorf("Unexpected JNI uncompress rule: " + jniRule) | 
 | 	} | 
 |  | 
 | 	// Make sure signing and aligning were skipped. | 
 | 	if variant.MaybeOutput("signed/"+apkName).Rule != nil { | 
 | 		t.Errorf("signing rule shouldn't be included for preprocessed.") | 
 | 	} | 
 | 	if variant.MaybeOutput("zip-aligned/"+apkName).Rule != nil { | 
 | 		t.Errorf("aligning rule shouldn't be for preprocessed") | 
 | 	} | 
 | } | 
 |  | 
 | func TestAndroidAppImport_Preprocessed(t *testing.T) { | 
 | 	for _, dontUncompressPrivAppDexs := range []bool{false, true} { | 
 | 		name := fmt.Sprintf("dontUncompressPrivAppDexs:%t", dontUncompressPrivAppDexs) | 
 | 		t.Run(name, func(t *testing.T) { | 
 | 			result := android.GroupFixturePreparers( | 
 | 				PrepareForTestWithJavaDefaultModules, | 
 | 				android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { | 
 | 					variables.UncompressPrivAppDex = proptools.BoolPtr(!dontUncompressPrivAppDexs) | 
 | 				}), | 
 | 			).RunTestWithBp(t, ` | 
 | 				android_app_import { | 
 | 					name: "foo", | 
 | 					apk: "prebuilts/apk/app.apk", | 
 | 					presigned: true, | 
 | 					preprocessed: true, | 
 | 				} | 
 |  | 
 | 				android_app_import { | 
 | 					name: "bar", | 
 | 					apk: "prebuilts/apk/app.apk", | 
 | 					presigned: true, | 
 | 					privileged: true, | 
 | 					preprocessed: true, | 
 | 				} | 
 | 			`) | 
 |  | 
 | 			// non-privileged app | 
 | 			apkName := "foo.apk" | 
 | 			variant := result.ModuleForTests("foo", "android_common") | 
 | 			outputBuildParams := variant.Output(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 outputBuildParams.Validation == nil { | 
 | 				t.Errorf("Expected validation rule, but was not found") | 
 | 			} | 
 |  | 
 | 			validationBuildParams := variant.Output("validated-prebuilt/check.stamp").BuildParams | 
 | 			if validationBuildParams.Rule.String() != checkPresignedApkRule.String() { | 
 | 				t.Errorf("Unexpected validation rule: " + validationBuildParams.Rule.String()) | 
 | 			} | 
 |  | 
 | 			expectedScriptArgs := "--preprocessed" | 
 | 			actualScriptArgs := validationBuildParams.Args["extraArgs"] | 
 | 			android.AssertStringEquals(t, "check script extraArgs", expectedScriptArgs, actualScriptArgs) | 
 |  | 
 | 			// privileged app | 
 | 			apkName = "bar.apk" | 
 | 			variant = result.ModuleForTests("bar", "android_common") | 
 | 			outputBuildParams = variant.Output(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 outputBuildParams.Validation == nil { | 
 | 				t.Errorf("Expected validation rule, but was not found") | 
 | 			} | 
 |  | 
 | 			validationBuildParams = variant.Output("validated-prebuilt/check.stamp").BuildParams | 
 | 			if validationBuildParams.Rule.String() != checkPresignedApkRule.String() { | 
 | 				t.Errorf("Unexpected validation rule: " + validationBuildParams.Rule.String()) | 
 | 			} | 
 |  | 
 | 			expectedScriptArgs = "--privileged" | 
 | 			if !dontUncompressPrivAppDexs { | 
 | 				expectedScriptArgs += " --uncompress-priv-app-dex" | 
 | 			} | 
 | 			expectedScriptArgs += " --preprocessed" | 
 | 			actualScriptArgs = validationBuildParams.Args["extraArgs"] | 
 | 			android.AssertStringEquals(t, "check script extraArgs", expectedScriptArgs, actualScriptArgs) | 
 | 		}) | 
 | 	} | 
 | } | 
 |  | 
 | func TestAndroidTestImport_UncompressDex(t *testing.T) { | 
 | 	testCases := []struct { | 
 | 		name string | 
 | 		bp   string | 
 | 	}{ | 
 | 		{ | 
 | 			name: "normal", | 
 | 			bp: ` | 
 | 				android_app_import { | 
 | 					name: "foo", | 
 | 					presigned: true, | 
 | 					apk: "prebuilts/apk/app.apk", | 
 | 				} | 
 | 			`, | 
 | 		}, | 
 | 		{ | 
 | 			name: "privileged", | 
 | 			bp: ` | 
 | 				android_app_import { | 
 | 					name: "foo", | 
 | 					presigned: true, | 
 | 					privileged: true, | 
 | 					apk: "prebuilts/apk/app.apk", | 
 | 				} | 
 | 			`, | 
 | 		}, | 
 | 	} | 
 |  | 
 | 	test := func(t *testing.T, bp string, unbundled bool, dontUncompressPrivAppDexs bool) { | 
 | 		t.Helper() | 
 |  | 
 | 		result := android.GroupFixturePreparers( | 
 | 			prepareForJavaTest, | 
 | 			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { | 
 | 				if unbundled { | 
 | 					variables.Unbundled_build = proptools.BoolPtr(true) | 
 | 				} | 
 | 				variables.UncompressPrivAppDex = proptools.BoolPtr(!dontUncompressPrivAppDexs) | 
 | 			}), | 
 | 		).RunTestWithBp(t, bp) | 
 |  | 
 | 		foo := result.ModuleForTests("foo", "android_common") | 
 | 		actual := foo.MaybeRule("uncompress-dex").Rule != nil | 
 |  | 
 | 		expect := !unbundled | 
 | 		if strings.Contains(bp, "privileged: true") { | 
 | 			if dontUncompressPrivAppDexs { | 
 | 				expect = false | 
 | 			} else { | 
 | 				// TODO(b/194504107): shouldn't priv-apps be always uncompressed unless | 
 | 				// DONT_UNCOMPRESS_PRIV_APPS_DEXS is true (regardless of unbundling)? | 
 | 				// expect = true | 
 | 			} | 
 | 		} | 
 |  | 
 | 		android.AssertBoolEquals(t, "uncompress dex", expect, actual) | 
 | 	} | 
 |  | 
 | 	for _, unbundled := range []bool{false, true} { | 
 | 		for _, dontUncompressPrivAppDexs := range []bool{false, true} { | 
 | 			for _, tt := range testCases { | 
 | 				name := fmt.Sprintf("%s,unbundled:%t,dontUncompressPrivAppDexs:%t", | 
 | 					tt.name, unbundled, dontUncompressPrivAppDexs) | 
 | 				t.Run(name, func(t *testing.T) { | 
 | 					test(t, tt.bp, unbundled, dontUncompressPrivAppDexs) | 
 | 				}) | 
 | 			} | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func TestAppImportMissingCertificateAllowMissingDependencies(t *testing.T) { | 
 | 	result := android.GroupFixturePreparers( | 
 | 		PrepareForTestWithJavaDefaultModules, | 
 | 		android.PrepareForTestWithAllowMissingDependencies, | 
 | 		android.PrepareForTestWithAndroidMk, | 
 | 	).RunTestWithBp(t, ` | 
 | 		android_app_import { | 
 | 			name: "foo", | 
 | 			apk: "a.apk", | 
 | 			certificate: ":missing_certificate", | 
 | 		}`) | 
 |  | 
 | 	foo := result.ModuleForTests("foo", "android_common") | 
 | 	fooApk := foo.Output("signed/foo.apk") | 
 | 	if fooApk.Rule != android.ErrorRule { | 
 | 		t.Fatalf("expected ErrorRule for foo.apk, got %s", fooApk.Rule.String()) | 
 | 	} | 
 | 	android.AssertStringDoesContain(t, "expected error rule message", fooApk.Args["error"], "missing dependencies: missing_certificate\n") | 
 | } |