| // Copyright 2017 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" |
| "path/filepath" |
| "reflect" |
| "sort" |
| "strings" |
| "testing" |
| |
| "github.com/google/blueprint/proptools" |
| |
| "android/soong/android" |
| "android/soong/cc" |
| "android/soong/dexpreopt" |
| ) |
| |
| // testApp runs tests using the prepareForJavaTest |
| // |
| // See testJava for an explanation as to how to stop using this deprecated method. |
| // |
| // deprecated |
| func testApp(t *testing.T, bp string) *android.TestContext { |
| t.Helper() |
| result := prepareForJavaTest.RunTestWithBp(t, bp) |
| return result.TestContext |
| } |
| |
| func TestApp(t *testing.T) { |
| resourceFiles := []string{ |
| "res/layout/layout.xml", |
| "res/values/strings.xml", |
| "res/values-en-rUS/strings.xml", |
| } |
| |
| compiledResourceFiles := []string{ |
| "aapt2/res/layout_layout.xml.flat", |
| "aapt2/res/values_strings.arsc.flat", |
| "aapt2/res/values-en-rUS_strings.arsc.flat", |
| } |
| |
| for _, moduleType := range []string{"android_app", "android_library"} { |
| t.Run(moduleType, func(t *testing.T) { |
| result := android.GroupFixturePreparers( |
| prepareForJavaTest, |
| android.FixtureModifyMockFS(func(fs android.MockFS) { |
| for _, file := range resourceFiles { |
| fs[file] = nil |
| } |
| }), |
| ).RunTestWithBp(t, moduleType+` { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current" |
| } |
| `) |
| |
| foo := result.ModuleForTests("foo", "android_common") |
| |
| var expectedLinkImplicits []string |
| |
| manifestFixer := foo.Output("manifest_fixer/AndroidManifest.xml") |
| expectedLinkImplicits = append(expectedLinkImplicits, manifestFixer.Output.String()) |
| |
| frameworkRes := result.ModuleForTests("framework-res", "android_common") |
| lineageRes := result.ModuleForTests("org.lineageos.platform-res", "android_common") |
| expectedLinkImplicits = append(expectedLinkImplicits, |
| frameworkRes.Output("package-res.apk").Output.String()) |
| expectedLinkImplicits = append(expectedLinkImplicits, |
| lineageRes.Output("package-res.apk").Output.String()) |
| |
| // Test the mapping from input files to compiled output file names |
| compile := foo.Output(compiledResourceFiles[0]) |
| android.AssertDeepEquals(t, "aapt2 compile inputs", resourceFiles, compile.Inputs.Strings()) |
| |
| compiledResourceOutputs := compile.Outputs.Strings() |
| sort.Strings(compiledResourceOutputs) |
| |
| expectedLinkImplicits = append(expectedLinkImplicits, compiledResourceOutputs...) |
| |
| list := foo.Output("aapt2/res.list") |
| expectedLinkImplicits = append(expectedLinkImplicits, list.Output.String()) |
| |
| // Check that the link rule uses |
| res := result.ModuleForTests("foo", "android_common").Output("package-res.apk") |
| android.AssertDeepEquals(t, "aapt2 link implicits", expectedLinkImplicits, res.Implicits.Strings()) |
| }) |
| } |
| } |
| |
| func TestAppSplits(t *testing.T) { |
| ctx := testApp(t, ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| package_splits: ["v4", "v7,hdpi"], |
| sdk_version: "current" |
| }`) |
| |
| foo := ctx.ModuleForTests("foo", "android_common") |
| |
| expectedOutputs := []string{ |
| "out/soong/.intermediates/foo/android_common/foo.apk", |
| "out/soong/.intermediates/foo/android_common/foo_v4.apk", |
| "out/soong/.intermediates/foo/android_common/foo_v7_hdpi.apk", |
| } |
| for _, expectedOutput := range expectedOutputs { |
| foo.Output(expectedOutput) |
| } |
| |
| outputFiles, err := foo.Module().(*AndroidApp).OutputFiles("") |
| if err != nil { |
| t.Fatal(err) |
| } |
| android.AssertPathsRelativeToTopEquals(t, `OutputFiles("")`, expectedOutputs, outputFiles) |
| } |
| |
| func TestPlatformAPIs(t *testing.T) { |
| testJava(t, ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| platform_apis: true, |
| } |
| `) |
| |
| testJava(t, ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| } |
| `) |
| |
| testJavaError(t, "This module has conflicting settings. sdk_version is empty, which means that this module is build against platform APIs. However platform_apis is not set to true", ` |
| android_app { |
| name: "bar", |
| srcs: ["b.java"], |
| } |
| `) |
| |
| testJavaError(t, "This module has conflicting settings. sdk_version is not empty, which means this module cannot use platform APIs. However platform_apis is set to true.", ` |
| android_app { |
| name: "bar", |
| srcs: ["b.java"], |
| sdk_version: "system_current", |
| platform_apis: true, |
| } |
| `) |
| } |
| |
| func TestAndroidAppLinkType(t *testing.T) { |
| testJava(t, ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| libs: ["bar"], |
| static_libs: ["baz"], |
| platform_apis: true, |
| } |
| |
| java_library { |
| name: "bar", |
| sdk_version: "current", |
| srcs: ["b.java"], |
| } |
| |
| android_library { |
| name: "baz", |
| sdk_version: "system_current", |
| srcs: ["c.java"], |
| } |
| `) |
| |
| testJavaError(t, "consider adjusting sdk_version: OR platform_apis:", ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| libs: ["bar"], |
| sdk_version: "current", |
| static_libs: ["baz"], |
| } |
| |
| java_library { |
| name: "bar", |
| sdk_version: "current", |
| srcs: ["b.java"], |
| } |
| |
| android_library { |
| name: "baz", |
| sdk_version: "system_current", |
| srcs: ["c.java"], |
| } |
| `) |
| |
| testJava(t, ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| libs: ["bar"], |
| sdk_version: "system_current", |
| static_libs: ["baz"], |
| } |
| |
| java_library { |
| name: "bar", |
| sdk_version: "current", |
| srcs: ["b.java"], |
| } |
| |
| android_library { |
| name: "baz", |
| sdk_version: "system_current", |
| srcs: ["c.java"], |
| } |
| `) |
| |
| testJavaError(t, "consider adjusting sdk_version: OR platform_apis:", ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| libs: ["bar"], |
| sdk_version: "system_current", |
| static_libs: ["baz"], |
| } |
| |
| java_library { |
| name: "bar", |
| sdk_version: "current", |
| srcs: ["b.java"], |
| } |
| |
| android_library { |
| name: "baz", |
| srcs: ["c.java"], |
| } |
| `) |
| } |
| |
| func TestUpdatableApps(t *testing.T) { |
| testCases := []struct { |
| name string |
| bp string |
| expectedError string |
| }{ |
| { |
| name: "Stable public SDK", |
| bp: `android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "29", |
| min_sdk_version: "29", |
| updatable: true, |
| }`, |
| }, |
| { |
| name: "Stable system SDK", |
| bp: `android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "system_29", |
| min_sdk_version: "29", |
| updatable: true, |
| }`, |
| }, |
| { |
| name: "Current public SDK", |
| bp: `android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| min_sdk_version: "29", |
| updatable: true, |
| }`, |
| }, |
| { |
| name: "Current system SDK", |
| bp: `android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "system_current", |
| min_sdk_version: "29", |
| updatable: true, |
| }`, |
| }, |
| { |
| name: "Current module SDK", |
| bp: `android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "module_current", |
| min_sdk_version: "29", |
| updatable: true, |
| }`, |
| }, |
| { |
| name: "Current core SDK", |
| bp: `android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "core_current", |
| min_sdk_version: "29", |
| updatable: true, |
| }`, |
| }, |
| { |
| name: "No Platform APIs", |
| bp: `android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| platform_apis: true, |
| min_sdk_version: "29", |
| updatable: true, |
| }`, |
| expectedError: "Updatable apps must use stable SDKs", |
| }, |
| { |
| name: "No Core Platform APIs", |
| bp: `android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "core_platform", |
| min_sdk_version: "29", |
| updatable: true, |
| }`, |
| expectedError: "Updatable apps must use stable SDKs", |
| }, |
| { |
| name: "No unspecified APIs", |
| bp: `android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| updatable: true, |
| min_sdk_version: "29", |
| }`, |
| expectedError: "Updatable apps must use stable SDK", |
| }, |
| { |
| name: "Must specify min_sdk_version", |
| bp: `android_app { |
| name: "app_without_min_sdk_version", |
| srcs: ["a.java"], |
| sdk_version: "29", |
| updatable: true, |
| }`, |
| expectedError: "updatable apps must set min_sdk_version.", |
| }, |
| } |
| |
| for _, test := range testCases { |
| t.Run(test.name, func(t *testing.T) { |
| errorHandler := android.FixtureExpectsNoErrors |
| if test.expectedError != "" { |
| errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(test.expectedError) |
| } |
| android.GroupFixturePreparers( |
| prepareForJavaTest, FixtureWithPrebuiltApis(map[string][]string{ |
| "29": {"foo"}, |
| })). |
| ExtendWithErrorHandler(errorHandler).RunTestWithBp(t, test.bp) |
| }) |
| } |
| } |
| |
| func TestUpdatableApps_TransitiveDepsShouldSetMinSdkVersion(t *testing.T) { |
| testJavaError(t, `module "bar".*: should support min_sdk_version\(29\)`, cc.GatherRequiredDepsForTest(android.Android)+` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| updatable: true, |
| sdk_version: "current", |
| min_sdk_version: "29", |
| static_libs: ["bar"], |
| } |
| |
| java_library { |
| name: "bar", |
| sdk_version: "current", |
| } |
| `) |
| } |
| |
| func TestUpdatableApps_JniLibsShouldShouldSupportMinSdkVersion(t *testing.T) { |
| testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| updatable: true, |
| sdk_version: "current", |
| min_sdk_version: "current", |
| jni_libs: ["libjni"], |
| } |
| |
| cc_library { |
| name: "libjni", |
| stl: "none", |
| system_shared_libs: [], |
| sdk_version: "current", |
| } |
| `) |
| } |
| |
| func TestUpdatableApps_JniLibShouldBeBuiltAgainstMinSdkVersion(t *testing.T) { |
| bp := cc.GatherRequiredDepsForTest(android.Android) + ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| updatable: true, |
| sdk_version: "current", |
| min_sdk_version: "29", |
| jni_libs: ["libjni"], |
| } |
| |
| cc_library { |
| name: "libjni", |
| stl: "none", |
| system_shared_libs: [], |
| sdk_version: "current", |
| min_sdk_version: "29", |
| } |
| ` |
| fs := map[string][]byte{ |
| "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtbegin_so.o": nil, |
| "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtend_so.o": nil, |
| "prebuilts/ndk/current/platforms/android-29/arch-arm/usr/lib/crtbegin_so.o": nil, |
| "prebuilts/ndk/current/platforms/android-29/arch-arm/usr/lib/crtend_so.o": nil, |
| } |
| |
| ctx, _ := testJavaWithFS(t, bp, fs) |
| |
| inputs := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared").Description("link").Implicits |
| var crtbeginFound, crtendFound bool |
| expectedCrtBegin := ctx.ModuleForTests("crtbegin_so", |
| "android_arm64_armv8-a_sdk_29").Rule("noAddrSig").Output |
| expectedCrtEnd := ctx.ModuleForTests("crtend_so", |
| "android_arm64_armv8-a_sdk_29").Rule("noAddrSig").Output |
| implicits := []string{} |
| for _, input := range inputs { |
| implicits = append(implicits, input.String()) |
| if strings.HasSuffix(input.String(), expectedCrtBegin.String()) { |
| crtbeginFound = true |
| } else if strings.HasSuffix(input.String(), expectedCrtEnd.String()) { |
| crtendFound = true |
| } |
| } |
| if !crtbeginFound { |
| t.Error(fmt.Sprintf( |
| "expected implicit with suffix %q, have the following implicits:\n%s", |
| expectedCrtBegin, strings.Join(implicits, "\n"))) |
| } |
| if !crtendFound { |
| t.Error(fmt.Sprintf( |
| "expected implicit with suffix %q, have the following implicits:\n%s", |
| expectedCrtEnd, strings.Join(implicits, "\n"))) |
| } |
| } |
| |
| func TestUpdatableApps_ErrorIfJniLibDoesntSupportMinSdkVersion(t *testing.T) { |
| bp := cc.GatherRequiredDepsForTest(android.Android) + ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| updatable: true, |
| sdk_version: "current", |
| min_sdk_version: "29", // this APK should support 29 |
| jni_libs: ["libjni"], |
| } |
| |
| cc_library { |
| name: "libjni", |
| stl: "none", |
| sdk_version: "current", |
| min_sdk_version: "current", |
| } |
| ` |
| testJavaError(t, `"libjni" .*: min_sdk_version\(current\) is higher than min_sdk_version\(29\)`, bp) |
| } |
| |
| func TestUpdatableApps_ErrorIfDepMinSdkVersionIsHigher(t *testing.T) { |
| bp := cc.GatherRequiredDepsForTest(android.Android) + ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| updatable: true, |
| sdk_version: "current", |
| min_sdk_version: "29", // this APK should support 29 |
| jni_libs: ["libjni"], |
| } |
| |
| cc_library { |
| name: "libjni", |
| stl: "none", |
| shared_libs: ["libbar"], |
| system_shared_libs: [], |
| sdk_version: "27", |
| min_sdk_version: "27", |
| } |
| |
| cc_library { |
| name: "libbar", |
| stl: "none", |
| system_shared_libs: [], |
| sdk_version: "current", |
| min_sdk_version: "current", |
| } |
| ` |
| testJavaError(t, `"libjni" .*: links "libbar" built against newer API version "current"`, bp) |
| } |
| |
| func TestUpdatableApps_ApplyDefaultUpdatableModuleVersion(t *testing.T) { |
| result := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| ).RunTestWithBp(t, ` |
| android_app { |
| name: "com.android.foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| min_sdk_version: "31", |
| updatable: true, |
| } |
| `) |
| foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer") |
| android.AssertStringDoesContain(t, |
| "com.android.foo: expected manifest fixer to set override-placeholder-version to android.DefaultUpdatableModuleVersion", |
| foo.BuildParams.Args["args"], |
| fmt.Sprintf("--override-placeholder-version %s", android.DefaultUpdatableModuleVersion), |
| ) |
| } |
| |
| func TestUpdatableApps_ApplyOverrideApexManifestDefaultVersion(t *testing.T) { |
| result := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| android.FixtureMergeEnv(map[string]string{ |
| "OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION": "1234", |
| }), |
| ).RunTestWithBp(t, ` |
| android_app { |
| name: "com.android.foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| min_sdk_version: "31", |
| updatable: true, |
| } |
| `) |
| foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer") |
| android.AssertStringDoesContain(t, |
| "com.android.foo: expected manifest fixer to set override-placeholder-version to 1234", |
| foo.BuildParams.Args["args"], |
| "--override-placeholder-version 1234", |
| ) |
| } |
| |
| func TestResourceDirs(t *testing.T) { |
| testCases := []struct { |
| name string |
| prop string |
| resources []string |
| }{ |
| { |
| name: "no resource_dirs", |
| prop: "", |
| resources: []string{"res/res/values/strings.xml"}, |
| }, |
| { |
| name: "resource_dirs", |
| prop: `resource_dirs: ["res"]`, |
| resources: []string{"res/res/values/strings.xml"}, |
| }, |
| { |
| name: "empty resource_dirs", |
| prop: `resource_dirs: []`, |
| resources: nil, |
| }, |
| } |
| |
| fs := android.MockFS{ |
| "res/res/values/strings.xml": nil, |
| } |
| |
| bp := ` |
| android_app { |
| name: "foo", |
| sdk_version: "current", |
| %s |
| } |
| ` |
| |
| for _, testCase := range testCases { |
| t.Run(testCase.name, func(t *testing.T) { |
| result := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| fs.AddToFixture(), |
| ).RunTestWithBp(t, fmt.Sprintf(bp, testCase.prop)) |
| |
| module := result.ModuleForTests("foo", "android_common") |
| resourceList := module.MaybeOutput("aapt2/res.list") |
| |
| var resources []string |
| if resourceList.Rule != nil { |
| for _, compiledResource := range resourceList.Inputs.Strings() { |
| resources = append(resources, module.Output(compiledResource).Inputs.Strings()...) |
| } |
| } |
| |
| android.AssertDeepEquals(t, "resource files", testCase.resources, resources) |
| }) |
| } |
| } |
| |
| func TestLibraryAssets(t *testing.T) { |
| bp := ` |
| android_app { |
| name: "foo", |
| sdk_version: "current", |
| static_libs: ["lib1", "lib2", "lib3"], |
| } |
| |
| android_library { |
| name: "lib1", |
| sdk_version: "current", |
| asset_dirs: ["assets_a"], |
| } |
| |
| android_library { |
| name: "lib2", |
| sdk_version: "current", |
| } |
| |
| android_library { |
| name: "lib3", |
| sdk_version: "current", |
| static_libs: ["lib4", "import"], |
| } |
| |
| android_library { |
| name: "lib4", |
| sdk_version: "current", |
| asset_dirs: ["assets_b"], |
| } |
| |
| android_library { |
| name: "lib5", |
| sdk_version: "current", |
| assets: [ |
| "path/to/asset_file_1", |
| "path/to/asset_file_2", |
| ], |
| } |
| |
| android_library_import { |
| name: "import", |
| sdk_version: "current", |
| aars: ["import.aar"], |
| } |
| ` |
| |
| testCases := []struct { |
| name string |
| assetFlag string |
| assetPackages []string |
| tmpAssetDirInputs []string |
| tmpAssetDirOutputs []string |
| }{ |
| { |
| name: "foo", |
| // lib1 has its own assets. lib3 doesn't have any, but lib4 and import have assets. |
| assetPackages: []string{ |
| "out/soong/.intermediates/foo/android_common/aapt2/package-res.apk", |
| "out/soong/.intermediates/lib1/android_common/assets.zip", |
| "out/soong/.intermediates/lib4/android_common/assets.zip", |
| "out/soong/.intermediates/import/android_common/assets.zip", |
| }, |
| }, |
| { |
| name: "lib1", |
| assetFlag: "-A assets_a", |
| }, |
| { |
| name: "lib2", |
| }, |
| { |
| name: "lib3", |
| }, |
| { |
| name: "lib4", |
| assetFlag: "-A assets_b", |
| }, |
| { |
| name: "lib5", |
| assetFlag: "-A out/soong/.intermediates/lib5/android_common/tmp_asset_dir", |
| tmpAssetDirInputs: []string{ |
| "path/to/asset_file_1", |
| "path/to/asset_file_2", |
| }, |
| tmpAssetDirOutputs: []string{ |
| "out/soong/.intermediates/lib5/android_common/tmp_asset_dir/path/to/asset_file_1", |
| "out/soong/.intermediates/lib5/android_common/tmp_asset_dir/path/to/asset_file_2", |
| }, |
| }, |
| } |
| ctx := testApp(t, bp) |
| |
| for _, test := range testCases { |
| t.Run(test.name, func(t *testing.T) { |
| m := ctx.ModuleForTests(test.name, "android_common") |
| |
| // Check asset flag in aapt2 link flags |
| var aapt2link android.TestingBuildParams |
| if len(test.assetPackages) > 0 { |
| aapt2link = m.Output("aapt2/package-res.apk") |
| } else { |
| aapt2link = m.Output("package-res.apk") |
| } |
| aapt2link = aapt2link |
| aapt2Flags := aapt2link.Args["flags"] |
| if test.assetFlag != "" { |
| android.AssertStringDoesContain(t, "asset flag", aapt2Flags, test.assetFlag) |
| } else { |
| android.AssertStringDoesNotContain(t, "aapt2 link flags", aapt2Flags, " -A ") |
| } |
| |
| // Check asset merge rule. |
| if len(test.assetPackages) > 0 { |
| mergeAssets := m.Output("package-res.apk") |
| android.AssertPathsRelativeToTopEquals(t, "mergeAssets inputs", test.assetPackages, mergeAssets.Inputs) |
| } |
| |
| if len(test.tmpAssetDirInputs) > 0 { |
| rule := m.Rule("tmp_asset_dir") |
| inputs := rule.Implicits |
| outputs := append(android.WritablePaths{rule.Output}, rule.ImplicitOutputs...).Paths() |
| android.AssertPathsRelativeToTopEquals(t, "tmp_asset_dir inputs", test.tmpAssetDirInputs, inputs) |
| android.AssertPathsRelativeToTopEquals(t, "tmp_asset_dir outputs", test.tmpAssetDirOutputs, outputs) |
| } |
| }) |
| } |
| } |
| |
| func TestAppJavaResources(t *testing.T) { |
| bp := ` |
| android_app { |
| name: "foo", |
| sdk_version: "current", |
| java_resources: ["resources/a"], |
| srcs: ["a.java"], |
| } |
| |
| android_app { |
| name: "bar", |
| sdk_version: "current", |
| java_resources: ["resources/a"], |
| } |
| ` |
| |
| ctx := testApp(t, bp) |
| |
| foo := ctx.ModuleForTests("foo", "android_common") |
| fooResources := foo.Output("res/foo.jar") |
| fooDexJar := foo.Output("dex-withres/foo.jar") |
| fooDexJarAligned := foo.Output("dex-withres-aligned/foo.jar") |
| fooApk := foo.Rule("combineApk") |
| |
| if g, w := fooDexJar.Inputs.Strings(), fooResources.Output.String(); !android.InList(w, g) { |
| t.Errorf("expected resource jar %q in foo dex jar inputs %q", w, g) |
| } |
| |
| if g, w := fooDexJarAligned.Input.String(), fooDexJar.Output.String(); g != w { |
| t.Errorf("expected dex jar %q in foo aligned dex jar inputs %q", w, g) |
| } |
| |
| if g, w := fooApk.Inputs.Strings(), fooDexJarAligned.Output.String(); !android.InList(w, g) { |
| t.Errorf("expected aligned dex jar %q in foo apk inputs %q", w, g) |
| } |
| |
| bar := ctx.ModuleForTests("bar", "android_common") |
| barResources := bar.Output("res/bar.jar") |
| barApk := bar.Rule("combineApk") |
| |
| if g, w := barApk.Inputs.Strings(), barResources.Output.String(); !android.InList(w, g) { |
| t.Errorf("expected resources jar %q in bar apk inputs %q", w, g) |
| } |
| } |
| |
| func TestAndroidResourceProcessor(t *testing.T) { |
| testCases := []struct { |
| name string |
| appUsesRP bool |
| directLibUsesRP bool |
| transitiveLibUsesRP bool |
| sharedLibUsesRP bool |
| sharedTransitiveStaticLibUsesRP bool |
| sharedTransitiveSharedLibUsesRP bool |
| |
| dontVerifyApp bool |
| appResources []string |
| appOverlays []string |
| appImports []string |
| appSrcJars []string |
| appClasspath []string |
| appCombined []string |
| |
| dontVerifyDirect bool |
| directResources []string |
| directOverlays []string |
| directImports []string |
| directSrcJars []string |
| directClasspath []string |
| directCombined []string |
| |
| dontVerifyTransitive bool |
| transitiveResources []string |
| transitiveOverlays []string |
| transitiveImports []string |
| transitiveSrcJars []string |
| transitiveClasspath []string |
| transitiveCombined []string |
| |
| dontVerifyDirectImport bool |
| directImportResources []string |
| directImportOverlays []string |
| directImportImports []string |
| |
| dontVerifyTransitiveImport bool |
| transitiveImportResources []string |
| transitiveImportOverlays []string |
| transitiveImportImports []string |
| |
| dontVerifyShared bool |
| sharedResources []string |
| sharedOverlays []string |
| sharedImports []string |
| sharedSrcJars []string |
| sharedClasspath []string |
| sharedCombined []string |
| }{ |
| { |
| // Test with all modules set to use_resource_processor: false (except android_library_import modules, |
| // which always use resource processor). |
| name: "legacy", |
| appUsesRP: false, |
| directLibUsesRP: false, |
| transitiveLibUsesRP: false, |
| |
| appResources: nil, |
| appOverlays: []string{ |
| "out/soong/.intermediates/transitive/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import/android_common/package-res.apk", |
| "out/soong/.intermediates/direct/android_common/package-res.apk", |
| "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk", |
| "out/soong/.intermediates/direct_import/android_common/package-res.apk", |
| "out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat", |
| }, |
| appImports: []string{ |
| "out/soong/.intermediates/shared/android_common/package-res.apk", |
| "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", |
| }, |
| appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"}, |
| appClasspath: []string{ |
| "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", |
| "out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar", |
| "out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar", |
| "out/soong/.intermediates/direct_import/android_common/turbine-combined/direct_import.jar", |
| }, |
| appCombined: []string{ |
| "out/soong/.intermediates/app/android_common/javac/app.jar", |
| "out/soong/.intermediates/direct/android_common/combined/direct.jar", |
| "out/soong/.intermediates/direct_import/android_common/combined/direct_import.jar", |
| }, |
| |
| directResources: nil, |
| directOverlays: []string{ |
| "out/soong/.intermediates/transitive/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import/android_common/package-res.apk", |
| "out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat", |
| }, |
| directImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"}, |
| directSrcJars: []string{"out/soong/.intermediates/direct/android_common/gen/android/R.srcjar"}, |
| directClasspath: []string{ |
| "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", |
| "out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar", |
| "out/soong/.intermediates/transitive_import/android_common/turbine-combined/transitive_import.jar", |
| }, |
| directCombined: []string{ |
| "out/soong/.intermediates/direct/android_common/javac/direct.jar", |
| "out/soong/.intermediates/transitive/android_common/javac/transitive.jar", |
| "out/soong/.intermediates/transitive_import/android_common/combined/transitive_import.jar", |
| }, |
| |
| transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"}, |
| transitiveOverlays: nil, |
| transitiveImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"}, |
| transitiveSrcJars: []string{"out/soong/.intermediates/transitive/android_common/gen/android/R.srcjar"}, |
| transitiveClasspath: []string{"out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar"}, |
| transitiveCombined: nil, |
| |
| sharedResources: nil, |
| sharedOverlays: []string{ |
| "out/soong/.intermediates/shared_transitive_static/android_common/package-res.apk", |
| "out/soong/.intermediates/shared/android_common/aapt2/shared/res/values_strings.arsc.flat", |
| }, |
| sharedImports: []string{ |
| "out/soong/.intermediates/shared_transitive_shared/android_common/package-res.apk", |
| "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", |
| }, |
| sharedSrcJars: []string{"out/soong/.intermediates/shared/android_common/gen/android/R.srcjar"}, |
| sharedClasspath: []string{ |
| "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", |
| "out/soong/.intermediates/shared_transitive_shared/android_common/turbine-combined/shared_transitive_shared.jar", |
| "out/soong/.intermediates/shared_transitive_static/android_common/turbine-combined/shared_transitive_static.jar", |
| }, |
| sharedCombined: []string{ |
| "out/soong/.intermediates/shared/android_common/javac/shared.jar", |
| "out/soong/.intermediates/shared_transitive_static/android_common/javac/shared_transitive_static.jar", |
| }, |
| |
| directImportResources: nil, |
| directImportOverlays: []string{"out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata"}, |
| directImportImports: []string{ |
| "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", |
| "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk", |
| }, |
| |
| transitiveImportResources: nil, |
| transitiveImportOverlays: []string{"out/soong/.intermediates/transitive_import/android_common/flat-res/gen_res.flata"}, |
| transitiveImportImports: []string{ |
| "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", |
| }, |
| }, |
| { |
| // Test with all modules set to use_resource_processor: true. |
| name: "resource_processor", |
| appUsesRP: true, |
| directLibUsesRP: true, |
| transitiveLibUsesRP: true, |
| sharedLibUsesRP: true, |
| sharedTransitiveSharedLibUsesRP: true, |
| sharedTransitiveStaticLibUsesRP: true, |
| |
| appResources: nil, |
| appOverlays: []string{ |
| "out/soong/.intermediates/transitive/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import/android_common/package-res.apk", |
| "out/soong/.intermediates/direct/android_common/package-res.apk", |
| "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk", |
| "out/soong/.intermediates/direct_import/android_common/package-res.apk", |
| "out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat", |
| }, |
| appImports: []string{ |
| "out/soong/.intermediates/shared/android_common/package-res.apk", |
| "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", |
| }, |
| appSrcJars: nil, |
| appClasspath: []string{ |
| "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", |
| "out/soong/.intermediates/app/android_common/busybox/R.jar", |
| "out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar", |
| "out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar", |
| "out/soong/.intermediates/direct_import/android_common/turbine-combined/direct_import.jar", |
| }, |
| appCombined: []string{ |
| "out/soong/.intermediates/app/android_common/javac/app.jar", |
| "out/soong/.intermediates/app/android_common/busybox/R.jar", |
| "out/soong/.intermediates/direct/android_common/combined/direct.jar", |
| "out/soong/.intermediates/direct_import/android_common/combined/direct_import.jar", |
| }, |
| |
| directResources: nil, |
| directOverlays: []string{"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat"}, |
| directImports: []string{ |
| "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive/android_common/package-res.apk", |
| }, |
| directSrcJars: nil, |
| directClasspath: []string{ |
| "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", |
| "out/soong/.intermediates/direct/android_common/busybox/R.jar", |
| "out/soong/.intermediates/transitive/android_common/busybox/R.jar", |
| "out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar", |
| "out/soong/.intermediates/transitive_import/android_common/busybox/R.jar", |
| "out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar", |
| "out/soong/.intermediates/transitive_import/android_common/turbine-combined/transitive_import.jar", |
| }, |
| directCombined: []string{ |
| "out/soong/.intermediates/direct/android_common/javac/direct.jar", |
| "out/soong/.intermediates/transitive/android_common/javac/transitive.jar", |
| "out/soong/.intermediates/transitive_import/android_common/combined/transitive_import.jar", |
| }, |
| |
| transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"}, |
| transitiveOverlays: nil, |
| transitiveImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"}, |
| transitiveSrcJars: nil, |
| transitiveClasspath: []string{ |
| "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", |
| "out/soong/.intermediates/transitive/android_common/busybox/R.jar", |
| }, |
| transitiveCombined: nil, |
| |
| sharedResources: nil, |
| sharedOverlays: []string{"out/soong/.intermediates/shared/android_common/aapt2/shared/res/values_strings.arsc.flat"}, |
| sharedImports: []string{ |
| "out/soong/.intermediates/shared_transitive_shared/android_common/package-res.apk", |
| "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", |
| "out/soong/.intermediates/shared_transitive_static/android_common/package-res.apk", |
| }, |
| sharedSrcJars: nil, |
| sharedClasspath: []string{ |
| "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", |
| "out/soong/.intermediates/shared/android_common/busybox/R.jar", |
| "out/soong/.intermediates/shared_transitive_static/android_common/busybox/R.jar", |
| "out/soong/.intermediates/shared_transitive_shared/android_common/busybox/R.jar", |
| "out/soong/.intermediates/shared_transitive_shared/android_common/turbine-combined/shared_transitive_shared.jar", |
| "out/soong/.intermediates/shared_transitive_static/android_common/turbine-combined/shared_transitive_static.jar", |
| }, |
| sharedCombined: []string{ |
| "out/soong/.intermediates/shared/android_common/javac/shared.jar", |
| "out/soong/.intermediates/shared_transitive_static/android_common/javac/shared_transitive_static.jar", |
| }, |
| |
| directImportResources: nil, |
| directImportOverlays: []string{"out/soong/.intermediates/direct_import/android_common/flat-res/gen_res.flata"}, |
| directImportImports: []string{ |
| "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", |
| "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk", |
| }, |
| |
| transitiveImportResources: nil, |
| transitiveImportOverlays: []string{"out/soong/.intermediates/transitive_import/android_common/flat-res/gen_res.flata"}, |
| transitiveImportImports: []string{ |
| "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", |
| }, |
| }, { |
| // Test an app building with resource processor enabled but with dependencies built without |
| // resource processor. |
| name: "app_resource_processor", |
| appUsesRP: true, |
| directLibUsesRP: false, |
| transitiveLibUsesRP: false, |
| |
| appResources: nil, |
| appOverlays: []string{ |
| "out/soong/.intermediates/transitive/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import/android_common/package-res.apk", |
| "out/soong/.intermediates/direct/android_common/package-res.apk", |
| "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk", |
| "out/soong/.intermediates/direct_import/android_common/package-res.apk", |
| "out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat", |
| }, |
| appImports: []string{ |
| "out/soong/.intermediates/shared/android_common/package-res.apk", |
| "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", |
| }, |
| appSrcJars: nil, |
| appClasspath: []string{ |
| "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", |
| // R.jar has to come before direct.jar |
| "out/soong/.intermediates/app/android_common/busybox/R.jar", |
| "out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar", |
| "out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar", |
| "out/soong/.intermediates/direct_import/android_common/turbine-combined/direct_import.jar", |
| }, |
| appCombined: []string{ |
| "out/soong/.intermediates/app/android_common/javac/app.jar", |
| "out/soong/.intermediates/app/android_common/busybox/R.jar", |
| "out/soong/.intermediates/direct/android_common/combined/direct.jar", |
| "out/soong/.intermediates/direct_import/android_common/combined/direct_import.jar", |
| }, |
| |
| dontVerifyDirect: true, |
| dontVerifyTransitive: true, |
| dontVerifyShared: true, |
| dontVerifyDirectImport: true, |
| dontVerifyTransitiveImport: true, |
| }, |
| { |
| // Test an app building without resource processor enabled but with a dependency built with |
| // resource processor. |
| name: "app_dependency_lib_resource_processor", |
| appUsesRP: false, |
| directLibUsesRP: true, |
| transitiveLibUsesRP: false, |
| |
| appOverlays: []string{ |
| "out/soong/.intermediates/transitive/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import/android_common/package-res.apk", |
| "out/soong/.intermediates/direct/android_common/package-res.apk", |
| "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk", |
| "out/soong/.intermediates/direct_import/android_common/package-res.apk", |
| "out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat", |
| }, |
| appImports: []string{ |
| "out/soong/.intermediates/shared/android_common/package-res.apk", |
| "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", |
| }, |
| appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"}, |
| appClasspath: []string{ |
| "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", |
| "out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar", |
| "out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar", |
| "out/soong/.intermediates/direct_import/android_common/turbine-combined/direct_import.jar", |
| }, |
| appCombined: []string{ |
| "out/soong/.intermediates/app/android_common/javac/app.jar", |
| "out/soong/.intermediates/direct/android_common/combined/direct.jar", |
| "out/soong/.intermediates/direct_import/android_common/combined/direct_import.jar", |
| }, |
| |
| directResources: nil, |
| directOverlays: []string{"out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat"}, |
| directImports: []string{ |
| "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive/android_common/package-res.apk", |
| }, |
| directSrcJars: nil, |
| directClasspath: []string{ |
| "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", |
| "out/soong/.intermediates/direct/android_common/busybox/R.jar", |
| "out/soong/.intermediates/transitive_import_dep/android_common/busybox/R.jar", |
| "out/soong/.intermediates/transitive_import/android_common/busybox/R.jar", |
| "out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar", |
| "out/soong/.intermediates/transitive_import/android_common/turbine-combined/transitive_import.jar", |
| }, |
| directCombined: []string{ |
| "out/soong/.intermediates/direct/android_common/javac/direct.jar", |
| "out/soong/.intermediates/transitive/android_common/javac/transitive.jar", |
| "out/soong/.intermediates/transitive_import/android_common/combined/transitive_import.jar", |
| }, |
| |
| dontVerifyTransitive: true, |
| dontVerifyShared: true, |
| dontVerifyDirectImport: true, |
| dontVerifyTransitiveImport: true, |
| }, |
| { |
| // Test a library building without resource processor enabled but with a dependency built with |
| // resource processor. |
| name: "lib_dependency_lib_resource_processor", |
| appUsesRP: false, |
| directLibUsesRP: false, |
| transitiveLibUsesRP: true, |
| |
| appOverlays: []string{ |
| "out/soong/.intermediates/transitive/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import/android_common/package-res.apk", |
| "out/soong/.intermediates/direct/android_common/package-res.apk", |
| "out/soong/.intermediates/direct_import_dep/android_common/package-res.apk", |
| "out/soong/.intermediates/direct_import/android_common/package-res.apk", |
| "out/soong/.intermediates/app/android_common/aapt2/app/res/values_strings.arsc.flat", |
| }, |
| appImports: []string{ |
| "out/soong/.intermediates/shared/android_common/package-res.apk", |
| "out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk", |
| }, |
| appSrcJars: []string{"out/soong/.intermediates/app/android_common/gen/android/R.srcjar"}, |
| appClasspath: []string{ |
| "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", |
| "out/soong/.intermediates/shared/android_common/turbine-combined/shared.jar", |
| "out/soong/.intermediates/direct/android_common/turbine-combined/direct.jar", |
| "out/soong/.intermediates/direct_import/android_common/turbine-combined/direct_import.jar", |
| }, |
| appCombined: []string{ |
| "out/soong/.intermediates/app/android_common/javac/app.jar", |
| "out/soong/.intermediates/direct/android_common/combined/direct.jar", |
| "out/soong/.intermediates/direct_import/android_common/combined/direct_import.jar", |
| }, |
| |
| directResources: nil, |
| directOverlays: []string{ |
| "out/soong/.intermediates/transitive/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import_dep/android_common/package-res.apk", |
| "out/soong/.intermediates/transitive_import/android_common/package-res.apk", |
| "out/soong/.intermediates/direct/android_common/aapt2/direct/res/values_strings.arsc.flat", |
| }, |
| directImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"}, |
| directSrcJars: []string{"out/soong/.intermediates/direct/android_common/gen/android/R.srcjar"}, |
| directClasspath: []string{ |
| "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", |
| "out/soong/.intermediates/transitive/android_common/turbine-combined/transitive.jar", |
| "out/soong/.intermediates/transitive_import/android_common/turbine-combined/transitive_import.jar", |
| }, |
| directCombined: []string{ |
| "out/soong/.intermediates/direct/android_common/javac/direct.jar", |
| "out/soong/.intermediates/transitive/android_common/javac/transitive.jar", |
| "out/soong/.intermediates/transitive_import/android_common/combined/transitive_import.jar", |
| }, |
| |
| transitiveResources: []string{"out/soong/.intermediates/transitive/android_common/aapt2/transitive/res/values_strings.arsc.flat"}, |
| transitiveOverlays: nil, |
| transitiveImports: []string{"out/soong/.intermediates/default/java/framework-res/android_common/package-res.apk"}, |
| transitiveSrcJars: nil, |
| transitiveClasspath: []string{ |
| "out/soong/.intermediates/default/java/android_stubs_current/android_common/turbine-combined/android_stubs_current.jar", |
| "out/soong/.intermediates/transitive/android_common/busybox/R.jar", |
| }, |
| transitiveCombined: nil, |
| |
| dontVerifyShared: true, |
| dontVerifyDirectImport: true, |
| dontVerifyTransitiveImport: true, |
| }, |
| } |
| |
| for _, testCase := range testCases { |
| t.Run(testCase.name, func(t *testing.T) { |
| bp := fmt.Sprintf(` |
| android_app { |
| name: "app", |
| sdk_version: "current", |
| srcs: ["app/app.java"], |
| resource_dirs: ["app/res"], |
| manifest: "app/AndroidManifest.xml", |
| libs: ["shared"], |
| static_libs: ["direct", "direct_import"], |
| use_resource_processor: %v, |
| } |
| |
| android_library { |
| name: "direct", |
| sdk_version: "current", |
| srcs: ["direct/direct.java"], |
| resource_dirs: ["direct/res"], |
| manifest: "direct/AndroidManifest.xml", |
| static_libs: ["transitive", "transitive_import"], |
| use_resource_processor: %v, |
| } |
| |
| android_library { |
| name: "transitive", |
| sdk_version: "current", |
| srcs: ["transitive/transitive.java"], |
| resource_dirs: ["transitive/res"], |
| manifest: "transitive/AndroidManifest.xml", |
| use_resource_processor: %v, |
| } |
| |
| android_library { |
| name: "shared", |
| sdk_version: "current", |
| srcs: ["shared/shared.java"], |
| resource_dirs: ["shared/res"], |
| manifest: "shared/AndroidManifest.xml", |
| use_resource_processor: %v, |
| libs: ["shared_transitive_shared"], |
| static_libs: ["shared_transitive_static"], |
| } |
| |
| android_library { |
| name: "shared_transitive_shared", |
| sdk_version: "current", |
| srcs: ["shared_transitive_shared/shared_transitive_shared.java"], |
| resource_dirs: ["shared_transitive_shared/res"], |
| manifest: "shared_transitive_shared/AndroidManifest.xml", |
| use_resource_processor: %v, |
| } |
| |
| android_library { |
| name: "shared_transitive_static", |
| sdk_version: "current", |
| srcs: ["shared_transitive_static/shared.java"], |
| resource_dirs: ["shared_transitive_static/res"], |
| manifest: "shared_transitive_static/AndroidManifest.xml", |
| use_resource_processor: %v, |
| } |
| |
| android_library_import { |
| name: "direct_import", |
| sdk_version: "current", |
| aars: ["direct_import.aar"], |
| static_libs: ["direct_import_dep"], |
| } |
| |
| android_library_import { |
| name: "direct_import_dep", |
| sdk_version: "current", |
| aars: ["direct_import_dep.aar"], |
| } |
| |
| android_library_import { |
| name: "transitive_import", |
| sdk_version: "current", |
| aars: ["transitive_import.aar"], |
| static_libs: ["transitive_import_dep"], |
| } |
| |
| android_library_import { |
| name: "transitive_import_dep", |
| sdk_version: "current", |
| aars: ["transitive_import_dep.aar"], |
| } |
| `, testCase.appUsesRP, testCase.directLibUsesRP, testCase.transitiveLibUsesRP, |
| testCase.sharedLibUsesRP, testCase.sharedTransitiveSharedLibUsesRP, testCase.sharedTransitiveStaticLibUsesRP) |
| |
| fs := android.MockFS{ |
| "app/res/values/strings.xml": nil, |
| "direct/res/values/strings.xml": nil, |
| "transitive/res/values/strings.xml": nil, |
| "shared/res/values/strings.xml": nil, |
| "shared_transitive_static/res/values/strings.xml": nil, |
| "shared_transitive_shared/res/values/strings.xml": nil, |
| } |
| |
| result := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| fs.AddToFixture(), |
| ).RunTestWithBp(t, bp) |
| |
| type aaptInfo struct { |
| resources, overlays, imports, srcJars, classpath, combined android.Paths |
| } |
| |
| getAaptInfo := func(moduleName string) (aaptInfo aaptInfo) { |
| mod := result.ModuleForTests(moduleName, "android_common") |
| resourceListRule := mod.MaybeOutput("aapt2/res.list") |
| overlayListRule := mod.MaybeOutput("aapt2/overlay.list") |
| aaptRule := mod.Rule("aapt2Link") |
| javacRule := mod.MaybeRule("javac") |
| combinedRule := mod.MaybeOutput("combined/" + moduleName + ".jar") |
| |
| aaptInfo.resources = resourceListRule.Inputs |
| aaptInfo.overlays = overlayListRule.Inputs |
| |
| aaptFlags := strings.Split(aaptRule.Args["flags"], " ") |
| for i, flag := range aaptFlags { |
| if flag == "-I" && i+1 < len(aaptFlags) { |
| aaptInfo.imports = append(aaptInfo.imports, android.PathForTesting(aaptFlags[i+1])) |
| } |
| } |
| |
| if len(javacRule.Args["srcJars"]) > 0 { |
| aaptInfo.srcJars = android.PathsForTesting(strings.Split(javacRule.Args["srcJars"], " ")...) |
| } |
| |
| if len(javacRule.Args["classpath"]) > 0 { |
| classpathArg := strings.TrimPrefix(javacRule.Args["classpath"], "-classpath ") |
| aaptInfo.classpath = android.PathsForTesting(strings.Split(classpathArg, ":")...) |
| } |
| |
| aaptInfo.combined = combinedRule.Inputs |
| return |
| } |
| |
| app := getAaptInfo("app") |
| direct := getAaptInfo("direct") |
| transitive := getAaptInfo("transitive") |
| shared := getAaptInfo("shared") |
| directImport := getAaptInfo("direct_import") |
| transitiveImport := getAaptInfo("transitive_import") |
| |
| if !testCase.dontVerifyApp { |
| android.AssertPathsRelativeToTopEquals(t, "app resources", testCase.appResources, app.resources) |
| android.AssertPathsRelativeToTopEquals(t, "app overlays", testCase.appOverlays, app.overlays) |
| android.AssertPathsRelativeToTopEquals(t, "app imports", testCase.appImports, app.imports) |
| android.AssertPathsRelativeToTopEquals(t, "app srcjars", testCase.appSrcJars, app.srcJars) |
| android.AssertPathsRelativeToTopEquals(t, "app classpath", testCase.appClasspath, app.classpath) |
| android.AssertPathsRelativeToTopEquals(t, "app combined", testCase.appCombined, app.combined) |
| } |
| |
| if !testCase.dontVerifyDirect { |
| android.AssertPathsRelativeToTopEquals(t, "direct resources", testCase.directResources, direct.resources) |
| android.AssertPathsRelativeToTopEquals(t, "direct overlays", testCase.directOverlays, direct.overlays) |
| android.AssertPathsRelativeToTopEquals(t, "direct imports", testCase.directImports, direct.imports) |
| android.AssertPathsRelativeToTopEquals(t, "direct srcjars", testCase.directSrcJars, direct.srcJars) |
| android.AssertPathsRelativeToTopEquals(t, "direct classpath", testCase.directClasspath, direct.classpath) |
| android.AssertPathsRelativeToTopEquals(t, "direct combined", testCase.directCombined, direct.combined) |
| } |
| |
| if !testCase.dontVerifyTransitive { |
| android.AssertPathsRelativeToTopEquals(t, "transitive resources", testCase.transitiveResources, transitive.resources) |
| android.AssertPathsRelativeToTopEquals(t, "transitive overlays", testCase.transitiveOverlays, transitive.overlays) |
| android.AssertPathsRelativeToTopEquals(t, "transitive imports", testCase.transitiveImports, transitive.imports) |
| android.AssertPathsRelativeToTopEquals(t, "transitive srcjars", testCase.transitiveSrcJars, transitive.srcJars) |
| android.AssertPathsRelativeToTopEquals(t, "transitive classpath", testCase.transitiveClasspath, transitive.classpath) |
| android.AssertPathsRelativeToTopEquals(t, "transitive combined", testCase.transitiveCombined, transitive.combined) |
| } |
| |
| if !testCase.dontVerifyShared { |
| android.AssertPathsRelativeToTopEquals(t, "shared resources", testCase.sharedResources, shared.resources) |
| android.AssertPathsRelativeToTopEquals(t, "shared overlays", testCase.sharedOverlays, shared.overlays) |
| android.AssertPathsRelativeToTopEquals(t, "shared imports", testCase.sharedImports, shared.imports) |
| android.AssertPathsRelativeToTopEquals(t, "shared srcjars", testCase.sharedSrcJars, shared.srcJars) |
| android.AssertPathsRelativeToTopEquals(t, "shared classpath", testCase.sharedClasspath, shared.classpath) |
| android.AssertPathsRelativeToTopEquals(t, "shared combined", testCase.sharedCombined, shared.combined) |
| } |
| |
| if !testCase.dontVerifyDirectImport { |
| android.AssertPathsRelativeToTopEquals(t, "direct_import resources", testCase.directImportResources, directImport.resources) |
| android.AssertPathsRelativeToTopEquals(t, "direct_import overlays", testCase.directImportOverlays, directImport.overlays) |
| android.AssertPathsRelativeToTopEquals(t, "direct_import imports", testCase.directImportImports, directImport.imports) |
| } |
| |
| if !testCase.dontVerifyTransitiveImport { |
| android.AssertPathsRelativeToTopEquals(t, "transitive_import resources", testCase.transitiveImportResources, transitiveImport.resources) |
| android.AssertPathsRelativeToTopEquals(t, "transitive_import overlays", testCase.transitiveImportOverlays, transitiveImport.overlays) |
| android.AssertPathsRelativeToTopEquals(t, "transitive_import imports", testCase.transitiveImportImports, transitiveImport.imports) |
| } |
| }) |
| } |
| } |
| |
| func TestAndroidResourceOverlays(t *testing.T) { |
| testCases := []struct { |
| name string |
| enforceRROTargets []string |
| enforceRROExcludedOverlays []string |
| resourceFiles map[string][]string |
| overlayFiles map[string][]string |
| rroDirs map[string][]string |
| }{ |
| { |
| name: "no RRO", |
| enforceRROTargets: nil, |
| enforceRROExcludedOverlays: nil, |
| resourceFiles: map[string][]string{ |
| "foo": nil, |
| "bar": {"bar/res/res/values/strings.xml"}, |
| "lib": nil, |
| "lib2": {"lib2/res/res/values/strings.xml"}, |
| }, |
| overlayFiles: map[string][]string{ |
| "foo": { |
| "out/soong/.intermediates/lib2/android_common/package-res.apk", |
| "out/soong/.intermediates/lib/android_common/package-res.apk", |
| "out/soong/.intermediates/lib3/android_common/package-res.apk", |
| "foo/res/res/values/strings.xml", |
| "device/vendor/blah/static_overlay/foo/res/values/strings.xml", |
| "device/vendor/blah/overlay/foo/res/values/strings.xml", |
| "product/vendor/blah/overlay/foo/res/values/strings.xml", |
| }, |
| "bar": { |
| "device/vendor/blah/static_overlay/bar/res/values/strings.xml", |
| "device/vendor/blah/overlay/bar/res/values/strings.xml", |
| }, |
| "lib": { |
| "out/soong/.intermediates/lib2/android_common/package-res.apk", |
| "lib/res/res/values/strings.xml", |
| "device/vendor/blah/overlay/lib/res/values/strings.xml", |
| }, |
| }, |
| rroDirs: map[string][]string{ |
| "foo": nil, |
| "bar": nil, |
| }, |
| }, |
| { |
| name: "enforce RRO on foo", |
| enforceRROTargets: []string{"foo"}, |
| enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"}, |
| resourceFiles: map[string][]string{ |
| "foo": nil, |
| "bar": {"bar/res/res/values/strings.xml"}, |
| "lib": nil, |
| "lib2": {"lib2/res/res/values/strings.xml"}, |
| }, |
| overlayFiles: map[string][]string{ |
| "foo": { |
| "out/soong/.intermediates/lib2/android_common/package-res.apk", |
| "out/soong/.intermediates/lib/android_common/package-res.apk", |
| "out/soong/.intermediates/lib3/android_common/package-res.apk", |
| "foo/res/res/values/strings.xml", |
| "device/vendor/blah/static_overlay/foo/res/values/strings.xml", |
| }, |
| "bar": { |
| "device/vendor/blah/static_overlay/bar/res/values/strings.xml", |
| "device/vendor/blah/overlay/bar/res/values/strings.xml", |
| }, |
| "lib": { |
| "out/soong/.intermediates/lib2/android_common/package-res.apk", |
| "lib/res/res/values/strings.xml", |
| }, |
| }, |
| |
| rroDirs: map[string][]string{ |
| "foo": { |
| "device:device/vendor/blah/overlay/foo/res", |
| "product:product/vendor/blah/overlay/foo/res", |
| "device:device/vendor/blah/overlay/lib/res", |
| }, |
| "bar": nil, |
| "lib": {"device:device/vendor/blah/overlay/lib/res"}, |
| }, |
| }, |
| { |
| name: "enforce RRO on all", |
| enforceRROTargets: []string{"*"}, |
| enforceRROExcludedOverlays: []string{ |
| // Excluding specific apps/res directories also allowed. |
| "device/vendor/blah/static_overlay/foo", |
| "device/vendor/blah/static_overlay/bar/res", |
| }, |
| resourceFiles: map[string][]string{ |
| "foo": nil, |
| "bar": {"bar/res/res/values/strings.xml"}, |
| "lib": nil, |
| "lib2": {"lib2/res/res/values/strings.xml"}, |
| }, |
| overlayFiles: map[string][]string{ |
| "foo": { |
| "out/soong/.intermediates/lib2/android_common/package-res.apk", |
| "out/soong/.intermediates/lib/android_common/package-res.apk", |
| "out/soong/.intermediates/lib3/android_common/package-res.apk", |
| "foo/res/res/values/strings.xml", |
| "device/vendor/blah/static_overlay/foo/res/values/strings.xml", |
| }, |
| "bar": {"device/vendor/blah/static_overlay/bar/res/values/strings.xml"}, |
| "lib": { |
| "out/soong/.intermediates/lib2/android_common/package-res.apk", |
| "lib/res/res/values/strings.xml", |
| }, |
| }, |
| rroDirs: map[string][]string{ |
| "foo": { |
| "device:device/vendor/blah/overlay/foo/res", |
| "product:product/vendor/blah/overlay/foo/res", |
| // Lib dep comes after the direct deps |
| "device:device/vendor/blah/overlay/lib/res", |
| }, |
| "bar": {"device:device/vendor/blah/overlay/bar/res"}, |
| "lib": {"device:device/vendor/blah/overlay/lib/res"}, |
| }, |
| }, |
| } |
| |
| deviceResourceOverlays := []string{ |
| "device/vendor/blah/overlay", |
| "device/vendor/blah/overlay2", |
| "device/vendor/blah/static_overlay", |
| } |
| |
| productResourceOverlays := []string{ |
| "product/vendor/blah/overlay", |
| } |
| |
| fs := android.MockFS{ |
| "foo/res/res/values/strings.xml": nil, |
| "bar/res/res/values/strings.xml": nil, |
| "lib/res/res/values/strings.xml": nil, |
| "lib2/res/res/values/strings.xml": nil, |
| "device/vendor/blah/overlay/foo/res/values/strings.xml": nil, |
| "device/vendor/blah/overlay/bar/res/values/strings.xml": nil, |
| "device/vendor/blah/overlay/lib/res/values/strings.xml": nil, |
| "device/vendor/blah/static_overlay/foo/res/values/strings.xml": nil, |
| "device/vendor/blah/static_overlay/bar/res/values/strings.xml": nil, |
| "device/vendor/blah/overlay2/res/values/strings.xml": nil, |
| "product/vendor/blah/overlay/foo/res/values/strings.xml": nil, |
| } |
| |
| bp := ` |
| android_app { |
| name: "foo", |
| sdk_version: "current", |
| resource_dirs: ["foo/res"], |
| static_libs: ["lib", "lib3"], |
| } |
| |
| android_app { |
| name: "bar", |
| sdk_version: "current", |
| resource_dirs: ["bar/res"], |
| } |
| |
| android_library { |
| name: "lib", |
| sdk_version: "current", |
| resource_dirs: ["lib/res"], |
| static_libs: ["lib2"], |
| } |
| |
| android_library { |
| name: "lib2", |
| sdk_version: "current", |
| resource_dirs: ["lib2/res"], |
| } |
| |
| // This library has the same resources as lib (should not lead to dupe RROs) |
| android_library { |
| name: "lib3", |
| sdk_version: "current", |
| resource_dirs: ["lib/res"] |
| } |
| ` |
| |
| for _, testCase := range testCases { |
| t.Run(testCase.name, func(t *testing.T) { |
| result := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| fs.AddToFixture(), |
| android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { |
| variables.DeviceResourceOverlays = deviceResourceOverlays |
| variables.ProductResourceOverlays = productResourceOverlays |
| if testCase.enforceRROTargets != nil { |
| variables.EnforceRROTargets = testCase.enforceRROTargets |
| } |
| if testCase.enforceRROExcludedOverlays != nil { |
| variables.EnforceRROExcludedOverlays = testCase.enforceRROExcludedOverlays |
| } |
| }), |
| ).RunTestWithBp(t, bp) |
| |
| resourceListToFiles := func(module android.TestingModule, list []string) (files []string) { |
| for _, o := range list { |
| res := module.MaybeOutput(o) |
| if res.Rule != nil { |
| // If the overlay is compiled as part of this module (i.e. a .arsc.flat file), |
| // verify the inputs to the .arsc.flat rule. |
| files = append(files, res.Inputs.Strings()...) |
| } else { |
| // Otherwise, verify the full path to the output of the other module |
| files = append(files, o) |
| } |
| } |
| return files |
| } |
| |
| getResources := func(moduleName string) (resourceFiles, overlayFiles, rroDirs []string) { |
| module := result.ModuleForTests(moduleName, "android_common") |
| resourceList := module.MaybeOutput("aapt2/res.list") |
| if resourceList.Rule != nil { |
| resourceFiles = resourceListToFiles(module, android.PathsRelativeToTop(resourceList.Inputs)) |
| } |
| overlayList := module.MaybeOutput("aapt2/overlay.list") |
| if overlayList.Rule != nil { |
| overlayFiles = resourceListToFiles(module, android.PathsRelativeToTop(overlayList.Inputs)) |
| } |
| |
| for _, d := range module.Module().(AndroidLibraryDependency).RRODirsDepSet().ToList() { |
| var prefix string |
| if d.overlayType == device { |
| prefix = "device:" |
| } else if d.overlayType == product { |
| prefix = "product:" |
| } else { |
| t.Fatalf("Unexpected overlayType %d", d.overlayType) |
| } |
| rroDirs = append(rroDirs, prefix+android.PathRelativeToTop(d.path)) |
| } |
| |
| return resourceFiles, overlayFiles, rroDirs |
| } |
| |
| modules := []string{"foo", "bar", "lib", "lib2"} |
| for _, module := range modules { |
| resourceFiles, overlayFiles, rroDirs := getResources(module) |
| |
| if !reflect.DeepEqual(resourceFiles, testCase.resourceFiles[module]) { |
| t.Errorf("expected %s resource files:\n %#v\n got:\n %#v", |
| module, testCase.resourceFiles[module], resourceFiles) |
| } |
| if !reflect.DeepEqual(overlayFiles, testCase.overlayFiles[module]) { |
| t.Errorf("expected %s overlay files:\n %#v\n got:\n %#v", |
| module, testCase.overlayFiles[module], overlayFiles) |
| } |
| if !reflect.DeepEqual(rroDirs, testCase.rroDirs[module]) { |
| t.Errorf("expected %s rroDirs: %#v\n got:\n %#v", |
| module, testCase.rroDirs[module], rroDirs) |
| } |
| } |
| }) |
| } |
| } |
| |
| func checkSdkVersion(t *testing.T, result *android.TestResult, expectedSdkVersion string) { |
| foo := result.ModuleForTests("foo", "android_common") |
| link := foo.Output("package-res.apk") |
| linkFlags := strings.Split(link.Args["flags"], " ") |
| min := android.IndexList("--min-sdk-version", linkFlags) |
| target := android.IndexList("--target-sdk-version", linkFlags) |
| |
| if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 { |
| t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags) |
| } |
| |
| gotMinSdkVersion := linkFlags[min+1] |
| gotTargetSdkVersion := linkFlags[target+1] |
| |
| android.AssertStringEquals(t, "incorrect --min-sdk-version", expectedSdkVersion, gotMinSdkVersion) |
| |
| android.AssertStringEquals(t, "incorrect --target-sdk-version", expectedSdkVersion, gotTargetSdkVersion) |
| } |
| |
| func TestAppSdkVersion(t *testing.T) { |
| testCases := []struct { |
| name string |
| sdkVersion string |
| platformSdkInt int |
| platformSdkCodename string |
| platformSdkFinal bool |
| minSdkVersionBp string |
| expectedMinSdkVersion string |
| platformApis bool |
| activeCodenames []string |
| }{ |
| { |
| name: "current final SDK", |
| sdkVersion: "current", |
| platformSdkInt: 27, |
| platformSdkCodename: "REL", |
| platformSdkFinal: true, |
| expectedMinSdkVersion: "27", |
| }, |
| { |
| name: "current non-final SDK", |
| sdkVersion: "current", |
| platformSdkInt: 27, |
| platformSdkCodename: "OMR1", |
| platformSdkFinal: false, |
| expectedMinSdkVersion: "OMR1", |
| activeCodenames: []string{"OMR1"}, |
| }, |
| { |
| name: "default final SDK", |
| sdkVersion: "", |
| platformApis: true, |
| platformSdkInt: 27, |
| platformSdkCodename: "REL", |
| platformSdkFinal: true, |
| expectedMinSdkVersion: "27", |
| }, |
| { |
| name: "default non-final SDK", |
| sdkVersion: "", |
| platformApis: true, |
| platformSdkInt: 27, |
| platformSdkCodename: "OMR1", |
| platformSdkFinal: false, |
| expectedMinSdkVersion: "OMR1", |
| activeCodenames: []string{"OMR1"}, |
| }, |
| { |
| name: "14", |
| sdkVersion: "14", |
| expectedMinSdkVersion: "14", |
| platformSdkCodename: "S", |
| activeCodenames: []string{"S"}, |
| }, |
| { |
| name: "two active SDKs", |
| sdkVersion: "module_current", |
| minSdkVersionBp: "UpsideDownCake", |
| expectedMinSdkVersion: "UpsideDownCake", // And not VanillaIceCream |
| platformSdkCodename: "VanillaIceCream", |
| activeCodenames: []string{"UpsideDownCake", "VanillaIceCream"}, |
| }, |
| } |
| |
| for _, moduleType := range []string{"android_app", "android_library"} { |
| for _, test := range testCases { |
| t.Run(moduleType+" "+test.name, func(t *testing.T) { |
| platformApiProp := "" |
| if test.platformApis { |
| platformApiProp = "platform_apis: true," |
| } |
| minSdkVersionProp := "" |
| if test.minSdkVersionBp != "" { |
| minSdkVersionProp = fmt.Sprintf(` min_sdk_version: "%s",`, test.minSdkVersionBp) |
| } |
| bp := fmt.Sprintf(`%s { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "%s", |
| %s |
| %s |
| }`, moduleType, test.sdkVersion, platformApiProp, minSdkVersionProp) |
| |
| result := android.GroupFixturePreparers( |
| prepareForJavaTest, |
| android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { |
| variables.Platform_sdk_version = &test.platformSdkInt |
| variables.Platform_sdk_codename = &test.platformSdkCodename |
| variables.Platform_version_active_codenames = test.activeCodenames |
| variables.Platform_sdk_final = &test.platformSdkFinal |
| }), |
| FixtureWithPrebuiltApis(map[string][]string{ |
| "14": {"foo"}, |
| }), |
| ).RunTestWithBp(t, bp) |
| |
| checkSdkVersion(t, result, test.expectedMinSdkVersion) |
| }) |
| } |
| } |
| } |
| |
| func TestVendorAppSdkVersion(t *testing.T) { |
| testCases := []struct { |
| name string |
| sdkVersion string |
| platformSdkInt int |
| platformSdkCodename string |
| platformSdkFinal bool |
| deviceCurrentApiLevelForVendorModules string |
| expectedMinSdkVersion string |
| }{ |
| { |
| name: "current final SDK", |
| sdkVersion: "current", |
| platformSdkInt: 29, |
| platformSdkCodename: "REL", |
| platformSdkFinal: true, |
| deviceCurrentApiLevelForVendorModules: "29", |
| expectedMinSdkVersion: "29", |
| }, |
| { |
| name: "current final SDK", |
| sdkVersion: "current", |
| platformSdkInt: 29, |
| platformSdkCodename: "REL", |
| platformSdkFinal: true, |
| deviceCurrentApiLevelForVendorModules: "28", |
| expectedMinSdkVersion: "28", |
| }, |
| { |
| name: "current final SDK", |
| sdkVersion: "current", |
| platformSdkInt: 29, |
| platformSdkCodename: "Q", |
| platformSdkFinal: false, |
| deviceCurrentApiLevelForVendorModules: "28", |
| expectedMinSdkVersion: "28", |
| }, |
| } |
| |
| for _, moduleType := range []string{"android_app", "android_library"} { |
| for _, sdkKind := range []string{"", "system_"} { |
| for _, test := range testCases { |
| t.Run(moduleType+" "+test.name, func(t *testing.T) { |
| bp := fmt.Sprintf(`%s { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "%s%s", |
| vendor: true, |
| }`, moduleType, sdkKind, test.sdkVersion) |
| |
| result := android.GroupFixturePreparers( |
| prepareForJavaTest, |
| android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { |
| variables.Platform_sdk_version = &test.platformSdkInt |
| variables.Platform_sdk_codename = &test.platformSdkCodename |
| variables.Platform_sdk_final = &test.platformSdkFinal |
| variables.DeviceCurrentApiLevelForVendorModules = &test.deviceCurrentApiLevelForVendorModules |
| variables.DeviceSystemSdkVersions = []string{"28", "29"} |
| }), |
| FixtureWithPrebuiltApis(map[string][]string{ |
| "28": {"foo"}, |
| "29": {"foo"}, |
| "current": {"foo"}, |
| }), |
| ).RunTestWithBp(t, bp) |
| |
| checkSdkVersion(t, result, test.expectedMinSdkVersion) |
| }) |
| } |
| } |
| } |
| } |
| |
| func TestJNIABI(t *testing.T) { |
| ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` |
| cc_library { |
| name: "libjni", |
| system_shared_libs: [], |
| sdk_version: "current", |
| stl: "none", |
| } |
| |
| android_test { |
| name: "test", |
| sdk_version: "core_platform", |
| jni_libs: ["libjni"], |
| } |
| |
| android_test { |
| name: "test_first", |
| sdk_version: "core_platform", |
| compile_multilib: "first", |
| jni_libs: ["libjni"], |
| } |
| |
| android_test { |
| name: "test_both", |
| sdk_version: "core_platform", |
| compile_multilib: "both", |
| jni_libs: ["libjni"], |
| } |
| |
| android_test { |
| name: "test_32", |
| sdk_version: "core_platform", |
| compile_multilib: "32", |
| jni_libs: ["libjni"], |
| } |
| |
| android_test { |
| name: "test_64", |
| sdk_version: "core_platform", |
| compile_multilib: "64", |
| jni_libs: ["libjni"], |
| } |
| `) |
| |
| testCases := []struct { |
| name string |
| abis []string |
| }{ |
| {"test", []string{"arm64-v8a"}}, |
| {"test_first", []string{"arm64-v8a"}}, |
| {"test_both", []string{"arm64-v8a", "armeabi-v7a"}}, |
| {"test_32", []string{"armeabi-v7a"}}, |
| {"test_64", []string{"arm64-v8a"}}, |
| } |
| |
| for _, test := range testCases { |
| t.Run(test.name, func(t *testing.T) { |
| app := ctx.ModuleForTests(test.name, "android_common") |
| jniLibZip := app.Output("jnilibs.zip") |
| var abis []string |
| args := strings.Fields(jniLibZip.Args["jarArgs"]) |
| for i := 0; i < len(args); i++ { |
| if args[i] == "-P" { |
| abis = append(abis, filepath.Base(args[i+1])) |
| i++ |
| } |
| } |
| if !reflect.DeepEqual(abis, test.abis) { |
| t.Errorf("want abis %v, got %v", test.abis, abis) |
| } |
| }) |
| } |
| } |
| |
| func TestAppSdkVersionByPartition(t *testing.T) { |
| testJavaError(t, "sdk_version must have a value when the module is located at vendor or product", ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| vendor: true, |
| platform_apis: true, |
| } |
| `) |
| |
| testJava(t, ` |
| android_app { |
| name: "bar", |
| srcs: ["b.java"], |
| platform_apis: true, |
| } |
| `) |
| |
| for _, enforce := range []bool{true, false} { |
| bp := ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| product_specific: true, |
| platform_apis: true, |
| } |
| ` |
| |
| errorHandler := android.FixtureExpectsNoErrors |
| if enforce { |
| errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern("sdk_version must have a value when the module is located at vendor or product") |
| } |
| |
| android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { |
| variables.EnforceProductPartitionInterface = proptools.BoolPtr(enforce) |
| }), |
| ). |
| ExtendWithErrorHandler(errorHandler). |
| RunTestWithBp(t, bp) |
| } |
| } |
| |
| func TestJNIPackaging(t *testing.T) { |
| ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` |
| cc_library { |
| name: "libjni", |
| system_shared_libs: [], |
| stl: "none", |
| sdk_version: "current", |
| } |
| |
| android_app { |
| name: "app", |
| jni_libs: ["libjni"], |
| sdk_version: "current", |
| } |
| |
| android_app { |
| name: "app_noembed", |
| jni_libs: ["libjni"], |
| use_embedded_native_libs: false, |
| sdk_version: "current", |
| } |
| |
| android_app { |
| name: "app_embed", |
| jni_libs: ["libjni"], |
| use_embedded_native_libs: true, |
| sdk_version: "current", |
| } |
| |
| android_test { |
| name: "test", |
| sdk_version: "current", |
| jni_libs: ["libjni"], |
| } |
| |
| android_test { |
| name: "test_noembed", |
| sdk_version: "current", |
| jni_libs: ["libjni"], |
| use_embedded_native_libs: false, |
| } |
| |
| android_test_helper_app { |
| name: "test_helper", |
| sdk_version: "current", |
| jni_libs: ["libjni"], |
| } |
| |
| android_test_helper_app { |
| name: "test_helper_noembed", |
| sdk_version: "current", |
| jni_libs: ["libjni"], |
| use_embedded_native_libs: false, |
| } |
| `) |
| |
| testCases := []struct { |
| name string |
| packaged bool |
| compressed bool |
| }{ |
| {"app", false, false}, |
| {"app_noembed", false, false}, |
| {"app_embed", true, false}, |
| {"test", true, false}, |
| {"test_noembed", true, true}, |
| {"test_helper", true, false}, |
| {"test_helper_noembed", true, true}, |
| } |
| |
| for _, test := range testCases { |
| t.Run(test.name, func(t *testing.T) { |
| app := ctx.ModuleForTests(test.name, "android_common") |
| jniLibZip := app.MaybeOutput("jnilibs.zip") |
| if g, w := (jniLibZip.Rule != nil), test.packaged; g != w { |
| t.Errorf("expected jni packaged %v, got %v", w, g) |
| } |
| |
| if jniLibZip.Rule != nil { |
| if g, w := !strings.Contains(jniLibZip.Args["jarArgs"], "-L 0"), test.compressed; g != w { |
| t.Errorf("expected jni compressed %v, got %v", w, g) |
| } |
| |
| if !strings.Contains(jniLibZip.Implicits[0].String(), "_sdk_") { |
| t.Errorf("expected input %q to use sdk variant", jniLibZip.Implicits[0].String()) |
| } |
| } |
| }) |
| } |
| } |
| |
| func TestJNISDK(t *testing.T) { |
| ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` |
| cc_library { |
| name: "libjni", |
| system_shared_libs: [], |
| stl: "none", |
| sdk_version: "current", |
| } |
| |
| android_test { |
| name: "app_platform", |
| jni_libs: ["libjni"], |
| platform_apis: true, |
| } |
| |
| android_test { |
| name: "app_sdk", |
| jni_libs: ["libjni"], |
| sdk_version: "current", |
| } |
| |
| android_test { |
| name: "app_force_platform", |
| jni_libs: ["libjni"], |
| sdk_version: "current", |
| jni_uses_platform_apis: true, |
| } |
| |
| android_test { |
| name: "app_force_sdk", |
| jni_libs: ["libjni"], |
| platform_apis: true, |
| jni_uses_sdk_apis: true, |
| } |
| |
| cc_library { |
| name: "libvendorjni", |
| system_shared_libs: [], |
| stl: "none", |
| vendor: true, |
| } |
| |
| android_test { |
| name: "app_vendor", |
| jni_libs: ["libvendorjni"], |
| sdk_version: "current", |
| vendor: true, |
| } |
| `) |
| |
| testCases := []struct { |
| name string |
| sdkJNI bool |
| vendorJNI bool |
| }{ |
| {name: "app_platform"}, |
| {name: "app_sdk", sdkJNI: true}, |
| {name: "app_force_platform"}, |
| {name: "app_force_sdk", sdkJNI: true}, |
| {name: "app_vendor", vendorJNI: true}, |
| } |
| |
| platformJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_shared"). |
| Output("libjni.so").Output.String() |
| sdkJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared"). |
| Output("libjni.so").Output.String() |
| vendorJNI := ctx.ModuleForTests("libvendorjni", "android_vendor_arm64_armv8-a_shared"). |
| Output("libvendorjni.so").Output.String() |
| |
| for _, test := range testCases { |
| t.Run(test.name, func(t *testing.T) { |
| app := ctx.ModuleForTests(test.name, "android_common") |
| |
| jniLibZip := app.MaybeOutput("jnilibs.zip") |
| if len(jniLibZip.Implicits) != 1 { |
| t.Fatalf("expected exactly one jni library, got %q", jniLibZip.Implicits.Strings()) |
| } |
| gotJNI := jniLibZip.Implicits[0].String() |
| |
| if test.sdkJNI { |
| if gotJNI != sdkJNI { |
| t.Errorf("expected SDK JNI library %q, got %q", sdkJNI, gotJNI) |
| } |
| } else if test.vendorJNI { |
| if gotJNI != vendorJNI { |
| t.Errorf("expected platform JNI library %q, got %q", vendorJNI, gotJNI) |
| } |
| } else { |
| if gotJNI != platformJNI { |
| t.Errorf("expected platform JNI library %q, got %q", platformJNI, gotJNI) |
| } |
| } |
| }) |
| } |
| |
| t.Run("jni_uses_platform_apis_error", func(t *testing.T) { |
| testJavaError(t, `jni_uses_platform_apis: can only be set for modules that set sdk_version`, ` |
| android_test { |
| name: "app_platform", |
| platform_apis: true, |
| jni_uses_platform_apis: true, |
| } |
| `) |
| }) |
| |
| t.Run("jni_uses_sdk_apis_error", func(t *testing.T) { |
| testJavaError(t, `jni_uses_sdk_apis: can only be set for modules that do not set sdk_version`, ` |
| android_test { |
| name: "app_sdk", |
| sdk_version: "current", |
| jni_uses_sdk_apis: true, |
| } |
| `) |
| }) |
| |
| } |
| |
| func TestCertificates(t *testing.T) { |
| testCases := []struct { |
| name string |
| bp string |
| allowMissingDependencies bool |
| certificateOverride string |
| expectedCertSigningFlags string |
| expectedCertificate string |
| }{ |
| { |
| name: "default", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| } |
| `, |
| certificateOverride: "", |
| expectedCertSigningFlags: "", |
| expectedCertificate: "build/make/target/product/security/testkey", |
| }, |
| { |
| name: "module certificate property", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| certificate: ":new_certificate", |
| sdk_version: "current", |
| } |
| |
| android_app_certificate { |
| name: "new_certificate", |
| certificate: "cert/new_cert", |
| } |
| `, |
| certificateOverride: "", |
| expectedCertSigningFlags: "", |
| expectedCertificate: "cert/new_cert", |
| }, |
| { |
| name: "path certificate property", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| certificate: "expiredkey", |
| sdk_version: "current", |
| } |
| `, |
| certificateOverride: "", |
| expectedCertSigningFlags: "", |
| expectedCertificate: "build/make/target/product/security/expiredkey", |
| }, |
| { |
| name: "certificate overrides", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| certificate: "expiredkey", |
| sdk_version: "current", |
| } |
| |
| android_app_certificate { |
| name: "new_certificate", |
| certificate: "cert/new_cert", |
| } |
| `, |
| certificateOverride: "foo:new_certificate", |
| expectedCertSigningFlags: "", |
| expectedCertificate: "cert/new_cert", |
| }, |
| { |
| name: "certificate signing flags", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| certificate: ":new_certificate", |
| lineage: "lineage.bin", |
| rotationMinSdkVersion: "32", |
| sdk_version: "current", |
| } |
| |
| android_app_certificate { |
| name: "new_certificate", |
| certificate: "cert/new_cert", |
| } |
| `, |
| certificateOverride: "", |
| expectedCertSigningFlags: "--lineage lineage.bin --rotation-min-sdk-version 32", |
| expectedCertificate: "cert/new_cert", |
| }, |
| { |
| name: "cert signing flags from filegroup", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| certificate: ":new_certificate", |
| lineage: ":lineage_bin", |
| rotationMinSdkVersion: "32", |
| sdk_version: "current", |
| } |
| |
| android_app_certificate { |
| name: "new_certificate", |
| certificate: "cert/new_cert", |
| } |
| |
| filegroup { |
| name: "lineage_bin", |
| srcs: ["lineage.bin"], |
| } |
| `, |
| certificateOverride: "", |
| expectedCertSigningFlags: "--lineage lineage.bin --rotation-min-sdk-version 32", |
| expectedCertificate: "cert/new_cert", |
| }, |
| { |
| name: "missing with AllowMissingDependencies", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| certificate: ":new_certificate", |
| sdk_version: "current", |
| } |
| `, |
| expectedCertificate: "out/soong/.intermediates/foo/android_common/missing", |
| allowMissingDependencies: true, |
| }, |
| } |
| |
| for _, test := range testCases { |
| t.Run(test.name, func(t *testing.T) { |
| result := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { |
| if test.certificateOverride != "" { |
| variables.CertificateOverrides = []string{test.certificateOverride} |
| } |
| if test.allowMissingDependencies { |
| variables.Allow_missing_dependencies = proptools.BoolPtr(true) |
| } |
| }), |
| android.FixtureModifyContext(func(ctx *android.TestContext) { |
| ctx.SetAllowMissingDependencies(test.allowMissingDependencies) |
| }), |
| ).RunTestWithBp(t, test.bp) |
| |
| foo := result.ModuleForTests("foo", "android_common") |
| |
| certificate := foo.Module().(*AndroidApp).certificate |
| android.AssertPathRelativeToTopEquals(t, "certificates key", test.expectedCertificate+".pk8", certificate.Key) |
| // The sign_target_files_apks and check_target_files_signatures |
| // tools require that certificates have a .x509.pem extension. |
| android.AssertPathRelativeToTopEquals(t, "certificates pem", test.expectedCertificate+".x509.pem", certificate.Pem) |
| |
| signapk := foo.Output("foo.apk") |
| if signapk.Rule != android.ErrorRule { |
| signCertificateFlags := signapk.Args["certificates"] |
| expectedFlags := certificate.Pem.String() + " " + certificate.Key.String() |
| android.AssertStringEquals(t, "certificates flags", expectedFlags, signCertificateFlags) |
| |
| certSigningFlags := signapk.Args["flags"] |
| android.AssertStringEquals(t, "cert signing flags", test.expectedCertSigningFlags, certSigningFlags) |
| } |
| }) |
| } |
| } |
| |
| func TestRequestV4SigningFlag(t *testing.T) { |
| testCases := []struct { |
| name string |
| bp string |
| expected string |
| }{ |
| { |
| name: "default", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| } |
| `, |
| expected: "", |
| }, |
| { |
| name: "default", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| v4_signature: false, |
| } |
| `, |
| expected: "", |
| }, |
| { |
| name: "module certificate property", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| v4_signature: true, |
| } |
| `, |
| expected: "--enable-v4", |
| }, |
| } |
| |
| for _, test := range testCases { |
| t.Run(test.name, func(t *testing.T) { |
| result := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| ).RunTestWithBp(t, test.bp) |
| |
| foo := result.ModuleForTests("foo", "android_common") |
| |
| signapk := foo.Output("foo.apk") |
| signFlags := signapk.Args["flags"] |
| android.AssertStringEquals(t, "signing flags", test.expected, signFlags) |
| }) |
| } |
| } |
| |
| func TestPackageNameOverride(t *testing.T) { |
| testCases := []struct { |
| name string |
| bp string |
| packageNameOverride string |
| expected []string |
| }{ |
| { |
| name: "default", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| } |
| `, |
| packageNameOverride: "", |
| expected: []string{ |
| "out/soong/.intermediates/foo/android_common/foo.apk", |
| "out/soong/target/product/test_device/system/app/foo/foo.apk", |
| }, |
| }, |
| { |
| name: "overridden via PRODUCT_PACKAGE_NAME_OVERRIDES", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| } |
| `, |
| packageNameOverride: "foo:bar", |
| expected: []string{ |
| // The package apk should be still be the original name for test dependencies. |
| "out/soong/.intermediates/foo/android_common/bar.apk", |
| "out/soong/target/product/test_device/system/app/bar/bar.apk", |
| }, |
| }, |
| { |
| name: "overridden via stem", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| stem: "bar", |
| } |
| `, |
| packageNameOverride: "", |
| expected: []string{ |
| "out/soong/.intermediates/foo/android_common/bar.apk", |
| "out/soong/target/product/test_device/system/app/bar/bar.apk", |
| }, |
| }, |
| } |
| |
| for _, test := range testCases { |
| t.Run(test.name, func(t *testing.T) { |
| result := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { |
| if test.packageNameOverride != "" { |
| variables.PackageNameOverrides = []string{test.packageNameOverride} |
| } |
| }), |
| ).RunTestWithBp(t, test.bp) |
| |
| foo := result.ModuleForTests("foo", "android_common") |
| |
| outSoongDir := result.Config.SoongOutDir() |
| |
| outputs := foo.AllOutputs() |
| outputMap := make(map[string]bool) |
| for _, o := range outputs { |
| outputMap[android.StringPathRelativeToTop(outSoongDir, o)] = true |
| } |
| for _, e := range test.expected { |
| if _, exist := outputMap[e]; !exist { |
| t.Errorf("Can't find %q in output files.\nAll outputs:%v", e, outputs) |
| } |
| } |
| }) |
| } |
| } |
| |
| func TestInstrumentationTargetOverridden(t *testing.T) { |
| bp := ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| } |
| |
| android_test { |
| name: "bar", |
| instrumentation_for: "foo", |
| sdk_version: "current", |
| } |
| ` |
| |
| result := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { |
| variables.ManifestPackageNameOverrides = []string{"foo:org.dandroid.bp"} |
| }), |
| ).RunTestWithBp(t, bp) |
| |
| bar := result.ModuleForTests("bar", "android_common") |
| res := bar.Output("package-res.apk") |
| aapt2Flags := res.Args["flags"] |
| e := "--rename-instrumentation-target-package org.dandroid.bp" |
| if !strings.Contains(aapt2Flags, e) { |
| t.Errorf("target package renaming flag, %q is missing in aapt2 link flags, %q", e, aapt2Flags) |
| } |
| } |
| |
| func TestOverrideAndroidApp(t *testing.T) { |
| result := PrepareForTestWithJavaDefaultModules.RunTestWithBp( |
| t, ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| certificate: "expiredkey", |
| overrides: ["qux"], |
| sdk_version: "current", |
| } |
| |
| override_android_app { |
| name: "bar", |
| base: "foo", |
| certificate: ":new_certificate", |
| lineage: "lineage.bin", |
| rotationMinSdkVersion: "32", |
| logging_parent: "bah", |
| } |
| |
| android_app_certificate { |
| name: "new_certificate", |
| certificate: "cert/new_cert", |
| } |
| |
| override_android_app { |
| name: "baz", |
| base: "foo", |
| package_name: "org.dandroid.bp", |
| } |
| |
| override_android_app { |
| name: "baz_no_rename_resources", |
| base: "foo", |
| package_name: "org.dandroid.bp", |
| rename_resources_package: false, |
| } |
| |
| android_app { |
| name: "foo_no_rename_resources", |
| srcs: ["a.java"], |
| certificate: "expiredkey", |
| overrides: ["qux"], |
| rename_resources_package: false, |
| sdk_version: "current", |
| } |
| |
| override_android_app { |
| name: "baz_base_no_rename_resources", |
| base: "foo_no_rename_resources", |
| package_name: "org.dandroid.bp", |
| } |
| |
| override_android_app { |
| name: "baz_override_base_rename_resources", |
| base: "foo_no_rename_resources", |
| package_name: "org.dandroid.bp", |
| rename_resources_package: true, |
| } |
| `) |
| |
| expectedVariants := []struct { |
| name string |
| moduleName string |
| variantName string |
| apkName string |
| apkPath string |
| certFlag string |
| certSigningFlags string |
| overrides []string |
| packageFlag string |
| renameResources bool |
| logging_parent string |
| }{ |
| { |
| name: "foo", |
| moduleName: "foo", |
| variantName: "android_common", |
| apkPath: "out/soong/target/product/test_device/system/app/foo/foo.apk", |
| certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", |
| certSigningFlags: "", |
| overrides: []string{"qux"}, |
| packageFlag: "", |
| renameResources: false, |
| logging_parent: "", |
| }, |
| { |
| name: "foo", |
| moduleName: "bar", |
| variantName: "android_common_bar", |
| apkPath: "out/soong/target/product/test_device/system/app/bar/bar.apk", |
| certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8", |
| certSigningFlags: "--lineage lineage.bin --rotation-min-sdk-version 32", |
| overrides: []string{"qux", "foo"}, |
| packageFlag: "", |
| renameResources: false, |
| logging_parent: "bah", |
| }, |
| { |
| name: "foo", |
| moduleName: "baz", |
| variantName: "android_common_baz", |
| apkPath: "out/soong/target/product/test_device/system/app/baz/baz.apk", |
| certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", |
| certSigningFlags: "", |
| overrides: []string{"qux", "foo"}, |
| packageFlag: "org.dandroid.bp", |
| renameResources: true, |
| logging_parent: "", |
| }, |
| { |
| name: "foo", |
| moduleName: "baz_no_rename_resources", |
| variantName: "android_common_baz_no_rename_resources", |
| apkPath: "out/soong/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk", |
| certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", |
| certSigningFlags: "", |
| overrides: []string{"qux", "foo"}, |
| packageFlag: "org.dandroid.bp", |
| renameResources: false, |
| logging_parent: "", |
| }, |
| { |
| name: "foo_no_rename_resources", |
| moduleName: "baz_base_no_rename_resources", |
| variantName: "android_common_baz_base_no_rename_resources", |
| apkPath: "out/soong/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk", |
| certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", |
| certSigningFlags: "", |
| overrides: []string{"qux", "foo_no_rename_resources"}, |
| packageFlag: "org.dandroid.bp", |
| renameResources: false, |
| logging_parent: "", |
| }, |
| { |
| name: "foo_no_rename_resources", |
| moduleName: "baz_override_base_rename_resources", |
| variantName: "android_common_baz_override_base_rename_resources", |
| apkPath: "out/soong/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk", |
| certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", |
| certSigningFlags: "", |
| overrides: []string{"qux", "foo_no_rename_resources"}, |
| packageFlag: "org.dandroid.bp", |
| renameResources: true, |
| logging_parent: "", |
| }, |
| } |
| for _, expected := range expectedVariants { |
| variant := result.ModuleForTests(expected.name, expected.variantName) |
| |
| // Check the final apk name |
| variant.Output(expected.apkPath) |
| |
| // Check the certificate paths |
| signapk := variant.Output(expected.moduleName + ".apk") |
| certFlag := signapk.Args["certificates"] |
| android.AssertStringEquals(t, "certificates flags", expected.certFlag, certFlag) |
| |
| // Check the cert signing flags |
| certSigningFlags := signapk.Args["flags"] |
| android.AssertStringEquals(t, "cert signing flags", expected.certSigningFlags, certSigningFlags) |
| |
| // Check if the overrides field values are correctly aggregated. |
| mod := variant.Module().(*AndroidApp) |
| android.AssertDeepEquals(t, "overrides property", expected.overrides, mod.overridableAppProperties.Overrides) |
| |
| // Test Overridable property: Logging_parent |
| logging_parent := mod.aapt.LoggingParent |
| android.AssertStringEquals(t, "overrides property value for logging parent", expected.logging_parent, logging_parent) |
| |
| // Check the package renaming flag, if exists. |
| res := variant.Output("package-res.apk") |
| aapt2Flags := res.Args["flags"] |
| checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag) |
| expectedPackage := expected.packageFlag |
| if !expected.renameResources { |
| expectedPackage = "" |
| } |
| checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", expectedPackage) |
| } |
| } |
| |
| func TestOverrideAndroidAppOverrides(t *testing.T) { |
| ctx, _ := testJava( |
| t, ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| overrides: ["qux"] |
| } |
| |
| android_app { |
| name: "bar", |
| srcs: ["b.java"], |
| sdk_version: "current", |
| overrides: ["foo"] |
| } |
| |
| override_android_app { |
| name: "foo_override", |
| base: "foo", |
| overrides: ["bar"] |
| } |
| `) |
| |
| expectedVariants := []struct { |
| name string |
| moduleName string |
| variantName string |
| overrides []string |
| }{ |
| { |
| name: "foo", |
| moduleName: "foo", |
| variantName: "android_common", |
| overrides: []string{"qux"}, |
| }, |
| { |
| name: "bar", |
| moduleName: "bar", |
| variantName: "android_common", |
| overrides: []string{"foo"}, |
| }, |
| { |
| name: "foo", |
| moduleName: "foo_override", |
| variantName: "android_common_foo_override", |
| overrides: []string{"bar", "foo"}, |
| }, |
| } |
| for _, expected := range expectedVariants { |
| variant := ctx.ModuleForTests(expected.name, expected.variantName) |
| |
| // Check if the overrides field values are correctly aggregated. |
| mod := variant.Module().(*AndroidApp) |
| android.AssertDeepEquals(t, "overrides property", expected.overrides, mod.overridableAppProperties.Overrides) |
| } |
| } |
| |
| func TestOverrideAndroidAppWithPrebuilt(t *testing.T) { |
| result := PrepareForTestWithJavaDefaultModules.RunTestWithBp( |
| t, ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| } |
| |
| override_android_app { |
| name: "bar", |
| base: "foo", |
| } |
| |
| android_app_import { |
| name: "bar", |
| prefer: true, |
| apk: "bar.apk", |
| presigned: true, |
| } |
| `) |
| |
| // An app that has an override that also has a prebuilt should not be hidden. |
| foo := result.ModuleForTests("foo", "android_common") |
| if foo.Module().IsHideFromMake() { |
| t.Errorf("expected foo to have HideFromMake false") |
| } |
| |
| // An override that also has a prebuilt should be hidden. |
| barOverride := result.ModuleForTests("foo", "android_common_bar") |
| if !barOverride.Module().IsHideFromMake() { |
| t.Errorf("expected bar override variant of foo to have HideFromMake true") |
| } |
| } |
| |
| func TestOverrideAndroidAppStem(t *testing.T) { |
| ctx, _ := testJava(t, ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| } |
| override_android_app { |
| name: "bar", |
| base: "foo", |
| } |
| override_android_app { |
| name: "baz", |
| base: "foo", |
| stem: "baz_stem", |
| } |
| android_app { |
| name: "foo2", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| stem: "foo2_stem", |
| } |
| override_android_app { |
| name: "bar2", |
| base: "foo2", |
| } |
| override_android_app { |
| name: "baz2", |
| base: "foo2", |
| stem: "baz2_stem", |
| } |
| `) |
| for _, expected := range []struct { |
| moduleName string |
| variantName string |
| apkPath string |
| }{ |
| { |
| moduleName: "foo", |
| variantName: "android_common", |
| apkPath: "out/soong/target/product/test_device/system/app/foo/foo.apk", |
| }, |
| { |
| moduleName: "foo", |
| variantName: "android_common_bar", |
| apkPath: "out/soong/target/product/test_device/system/app/bar/bar.apk", |
| }, |
| { |
| moduleName: "foo", |
| variantName: "android_common_baz", |
| apkPath: "out/soong/target/product/test_device/system/app/baz_stem/baz_stem.apk", |
| }, |
| { |
| moduleName: "foo2", |
| variantName: "android_common", |
| apkPath: "out/soong/target/product/test_device/system/app/foo2_stem/foo2_stem.apk", |
| }, |
| { |
| moduleName: "foo2", |
| variantName: "android_common_bar2", |
| // Note that this may cause the duplicate output error. |
| apkPath: "out/soong/target/product/test_device/system/app/foo2_stem/foo2_stem.apk", |
| }, |
| { |
| moduleName: "foo2", |
| variantName: "android_common_baz2", |
| apkPath: "out/soong/target/product/test_device/system/app/baz2_stem/baz2_stem.apk", |
| }, |
| } { |
| variant := ctx.ModuleForTests(expected.moduleName, expected.variantName) |
| variant.Output(expected.apkPath) |
| } |
| } |
| |
| func TestOverrideAndroidAppDependency(t *testing.T) { |
| ctx, _ := testJava(t, ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| } |
| |
| override_android_app { |
| name: "bar", |
| base: "foo", |
| package_name: "org.dandroid.bp", |
| } |
| |
| android_test { |
| name: "baz", |
| srcs: ["b.java"], |
| instrumentation_for: "foo", |
| } |
| |
| android_test { |
| name: "qux", |
| srcs: ["b.java"], |
| instrumentation_for: "bar", |
| } |
| `) |
| |
| // Verify baz, which depends on the overridden module foo, has the correct classpath javac arg. |
| javac := ctx.ModuleForTests("baz", "android_common").Rule("javac") |
| fooTurbine := "out/soong/.intermediates/foo/android_common/turbine-combined/foo.jar" |
| if !strings.Contains(javac.Args["classpath"], fooTurbine) { |
| t.Errorf("baz classpath %v does not contain %q", javac.Args["classpath"], fooTurbine) |
| } |
| |
| // Verify qux, which depends on the overriding module bar, has the correct classpath javac arg. |
| javac = ctx.ModuleForTests("qux", "android_common").Rule("javac") |
| barTurbine := "out/soong/.intermediates/foo/android_common_bar/turbine-combined/foo.jar" |
| if !strings.Contains(javac.Args["classpath"], barTurbine) { |
| t.Errorf("qux classpath %v does not contain %q", javac.Args["classpath"], barTurbine) |
| } |
| } |
| |
| func TestOverrideAndroidTest(t *testing.T) { |
| ctx, _ := testJava(t, ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| package_name: "com.android.foo", |
| sdk_version: "current", |
| } |
| |
| override_android_app { |
| name: "bar", |
| base: "foo", |
| package_name: "com.android.bar", |
| } |
| |
| android_test { |
| name: "foo_test", |
| srcs: ["b.java"], |
| instrumentation_for: "foo", |
| } |
| |
| override_android_test { |
| name: "bar_test", |
| base: "foo_test", |
| package_name: "com.android.bar.test", |
| instrumentation_for: "bar", |
| instrumentation_target_package: "com.android.bar", |
| } |
| `) |
| |
| expectedVariants := []struct { |
| moduleName string |
| variantName string |
| apkPath string |
| overrides []string |
| targetVariant string |
| packageFlag string |
| targetPackageFlag string |
| }{ |
| { |
| variantName: "android_common", |
| apkPath: "/target/product/test_device/testcases/foo_test/arm64/foo_test.apk", |
| overrides: nil, |
| targetVariant: "android_common", |
| packageFlag: "", |
| targetPackageFlag: "", |
| }, |
| { |
| variantName: "android_common_bar_test", |
| apkPath: "/target/product/test_device/testcases/bar_test/arm64/bar_test.apk", |
| overrides: []string{"foo_test"}, |
| targetVariant: "android_common_bar", |
| packageFlag: "com.android.bar.test", |
| targetPackageFlag: "com.android.bar", |
| }, |
| } |
| for _, expected := range expectedVariants { |
| variant := ctx.ModuleForTests("foo_test", expected.variantName) |
| |
| // Check the final apk name |
| variant.Output("out/soong" + expected.apkPath) |
| |
| // Check if the overrides field values are correctly aggregated. |
| mod := variant.Module().(*AndroidTest) |
| if !reflect.DeepEqual(expected.overrides, mod.overridableAppProperties.Overrides) { |
| t.Errorf("Incorrect overrides property value, expected: %q, got: %q", |
| expected.overrides, mod.overridableAppProperties.Overrides) |
| } |
| |
| // Check if javac classpath has the correct jar file path. This checks instrumentation_for overrides. |
| javac := variant.Rule("javac") |
| turbine := filepath.Join("out", "soong", ".intermediates", "foo", expected.targetVariant, "turbine-combined", "foo.jar") |
| if !strings.Contains(javac.Args["classpath"], turbine) { |
| t.Errorf("classpath %q does not contain %q", javac.Args["classpath"], turbine) |
| } |
| |
| // Check aapt2 flags. |
| res := variant.Output("package-res.apk") |
| aapt2Flags := res.Args["flags"] |
| checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag) |
| checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", expected.packageFlag) |
| checkAapt2LinkFlag(t, aapt2Flags, "rename-instrumentation-target-package", expected.targetPackageFlag) |
| } |
| } |
| |
| func TestAndroidTest_FixTestConfig(t *testing.T) { |
| ctx, _ := testJava(t, ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| package_name: "com.android.foo", |
| sdk_version: "current", |
| } |
| |
| android_test { |
| name: "foo_test", |
| srcs: ["b.java"], |
| instrumentation_for: "foo", |
| } |
| |
| android_test { |
| name: "bar_test", |
| srcs: ["b.java"], |
| package_name: "com.android.bar.test", |
| instrumentation_for: "foo", |
| mainline_package_name: "com.android.bar", |
| } |
| |
| override_android_test { |
| name: "baz_test", |
| base: "foo_test", |
| package_name: "com.android.baz.test", |
| mainline_package_name: "com.android.baz", |
| } |
| `) |
| |
| testCases := []struct { |
| moduleName string |
| variantName string |
| expectedFlags []string |
| }{ |
| { |
| moduleName: "foo_test", |
| variantName: "android_common", |
| }, |
| { |
| moduleName: "bar_test", |
| variantName: "android_common", |
| expectedFlags: []string{ |
| "--manifest out/soong/.intermediates/bar_test/android_common/manifest_fixer/AndroidManifest.xml", |
| "--package-name com.android.bar.test", |
| "--mainline-package-name com.android.bar", |
| }, |
| }, |
| { |
| moduleName: "foo_test", |
| variantName: "android_common_baz_test", |
| expectedFlags: []string{ |
| "--manifest out/soong/.intermediates/foo_test/android_common_baz_test/manifest_fixer/AndroidManifest.xml", |
| "--package-name com.android.baz.test", |
| "--test-file-name baz_test.apk", |
| "out/soong/.intermediates/foo_test/android_common_baz_test/test_config_fixer/AndroidTest.xml", |
| "--mainline-package-name com.android.baz", |
| }, |
| }, |
| } |
| |
| for _, test := range testCases { |
| variant := ctx.ModuleForTests(test.moduleName, test.variantName) |
| params := variant.MaybeOutput("test_config_fixer/AndroidTest.xml") |
| |
| if len(test.expectedFlags) > 0 { |
| if params.Rule == nil { |
| t.Errorf("test_config_fixer was expected to run, but didn't") |
| } else { |
| for _, flag := range test.expectedFlags { |
| if !strings.Contains(params.RuleParams.Command, flag) { |
| t.Errorf("Flag %q was not found in command: %q", flag, params.RuleParams.Command) |
| } |
| } |
| } |
| } else { |
| if params.Rule != nil { |
| t.Errorf("test_config_fixer was not expected to run, but did: %q", params.RuleParams.Command) |
| } |
| } |
| } |
| } |
| |
| func TestInstrumentationTargetPrebuilt(t *testing.T) { |
| bp := ` |
| android_app_import { |
| name: "foo", |
| apk: "foo.apk", |
| presigned: true, |
| } |
| |
| android_test { |
| name: "bar", |
| srcs: ["a.java"], |
| instrumentation_for: "foo", |
| sdk_version: "current", |
| } |
| ` |
| |
| android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| ).ExtendWithErrorHandler( |
| android.FixtureExpectsAtLeastOneErrorMatchingPattern( |
| "instrumentation_for: dependency \"foo\" of type \"android_app_import\" does not provide JavaInfo so is unsuitable for use with this property")). |
| RunTestWithBp(t, bp) |
| } |
| |
| func TestStl(t *testing.T) { |
| ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` |
| cc_library { |
| name: "libjni", |
| sdk_version: "current", |
| stl: "c++_shared", |
| } |
| |
| android_test { |
| name: "stl", |
| jni_libs: ["libjni"], |
| compile_multilib: "both", |
| sdk_version: "current", |
| stl: "c++_shared", |
| } |
| |
| android_test { |
| name: "system", |
| jni_libs: ["libjni"], |
| compile_multilib: "both", |
| sdk_version: "current", |
| } |
| `) |
| |
| testCases := []struct { |
| name string |
| jnis []string |
| }{ |
| {"stl", |
| []string{ |
| "libjni.so", |
| "libc++_shared.so", |
| }, |
| }, |
| {"system", |
| []string{ |
| "libjni.so", |
| }, |
| }, |
| } |
| |
| for _, test := range testCases { |
| t.Run(test.name, func(t *testing.T) { |
| app := ctx.ModuleForTests(test.name, "android_common") |
| jniLibZip := app.Output("jnilibs.zip") |
| var jnis []string |
| args := strings.Fields(jniLibZip.Args["jarArgs"]) |
| for i := 0; i < len(args); i++ { |
| if args[i] == "-f" { |
| jnis = append(jnis, args[i+1]) |
| i += 1 |
| } |
| } |
| jnisJoined := strings.Join(jnis, " ") |
| for _, jni := range test.jnis { |
| if !strings.Contains(jnisJoined, jni) { |
| t.Errorf("missing jni %q in %q", jni, jnis) |
| } |
| } |
| }) |
| } |
| } |
| |
| func TestUsesLibraries(t *testing.T) { |
| bp := ` |
| java_sdk_library { |
| name: "foo", |
| srcs: ["a.java"], |
| api_packages: ["foo"], |
| sdk_version: "current", |
| } |
| |
| java_sdk_library { |
| name: "qux", |
| srcs: ["a.java"], |
| api_packages: ["qux"], |
| sdk_version: "current", |
| } |
| |
| java_sdk_library { |
| name: "quuz", |
| srcs: ["a.java"], |
| api_packages: ["quuz"], |
| sdk_version: "current", |
| } |
| |
| java_sdk_library { |
| name: "fred", |
| srcs: ["a.java"], |
| api_packages: ["fred"], |
| sdk_version: "current", |
| } |
| |
| java_sdk_library { |
| name: "bar", |
| srcs: ["a.java"], |
| api_packages: ["bar"], |
| sdk_version: "current", |
| } |
| |
| java_sdk_library { |
| name: "runtime-library", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| } |
| |
| java_library { |
| name: "static-runtime-helper", |
| srcs: ["a.java"], |
| libs: ["runtime-library"], |
| sdk_version: "current", |
| } |
| |
| java_library { |
| name: "runtime-required-x", |
| srcs: ["a.java"], |
| installable: true, |
| sdk_version: "current", |
| } |
| |
| java_library { |
| name: "runtime-optional-x", |
| srcs: ["a.java"], |
| installable: true, |
| sdk_version: "current", |
| } |
| |
| android_library { |
| name: "static-x", |
| uses_libs: ["runtime-required-x"], |
| optional_uses_libs: ["runtime-optional-x"], |
| sdk_version: "current", |
| } |
| |
| java_library { |
| name: "runtime-required-y", |
| srcs: ["a.java"], |
| installable: true, |
| sdk_version: "current", |
| } |
| |
| java_library { |
| name: "runtime-optional-y", |
| srcs: ["a.java"], |
| installable: true, |
| sdk_version: "current", |
| } |
| |
| java_library { |
| name: "static-y", |
| srcs: ["a.java"], |
| uses_libs: ["runtime-required-y"], |
| optional_uses_libs: [ |
| "runtime-optional-y", |
| "missing-lib-a", |
| ], |
| sdk_version: "current", |
| } |
| |
| // A library that has to use "provides_uses_lib", because: |
| // - it is not an SDK library |
| // - its library name is different from its module name |
| java_library { |
| name: "non-sdk-lib", |
| provides_uses_lib: "com.non.sdk.lib", |
| installable: true, |
| srcs: ["a.java"], |
| } |
| |
| android_app { |
| name: "app", |
| srcs: ["a.java"], |
| libs: [ |
| "qux", |
| "quuz.stubs" |
| ], |
| static_libs: [ |
| "static-runtime-helper", |
| // statically linked component libraries should not pull their SDK libraries, |
| // so "fred" should not be added to class loader context |
| "fred.stubs", |
| "static-x", |
| "static-y", |
| ], |
| uses_libs: [ |
| "foo", |
| "non-sdk-lib" |
| ], |
| sdk_version: "current", |
| optional_uses_libs: [ |
| "bar", |
| "missing-lib-b", |
| ], |
| } |
| |
| android_app_import { |
| name: "prebuilt", |
| apk: "prebuilts/apk/app.apk", |
| certificate: "platform", |
| uses_libs: [ |
| "foo", |
| "non-sdk-lib", |
| "android.test.runner" |
| ], |
| optional_uses_libs: [ |
| "bar", |
| "missing-lib-b", |
| ], |
| } |
| ` |
| |
| result := android.GroupFixturePreparers( |
| prepareForJavaTest, |
| PrepareForTestWithJavaSdkLibraryFiles, |
| FixtureWithLastReleaseApis("runtime-library", "foo", "quuz", "qux", "bar", "fred"), |
| android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { |
| variables.BuildWarningBadOptionalUsesLibsAllowlist = []string{"app", "prebuilt"} |
| }), |
| ).RunTestWithBp(t, bp) |
| |
| app := result.ModuleForTests("app", "android_common") |
| prebuilt := result.ModuleForTests("prebuilt", "android_common") |
| |
| // Test that implicit dependencies on java_sdk_library instances are passed to the manifest. |
| // These also include explicit `uses_libs`/`optional_uses_libs` entries, as they may be |
| // propagated from dependencies. |
| actualManifestFixerArgs := app.Output("manifest_fixer/AndroidManifest.xml").Args["args"] |
| expectManifestFixerArgs := `--extract-native-libs=true ` + |
| `--uses-library foo ` + |
| `--uses-library com.non.sdk.lib ` + |
| `--uses-library qux ` + |
| `--uses-library quuz ` + |
| `--uses-library runtime-library ` + |
| `--uses-library runtime-required-x ` + |
| `--uses-library runtime-required-y ` + |
| `--optional-uses-library bar ` + |
| `--optional-uses-library runtime-optional-x ` + |
| `--optional-uses-library runtime-optional-y` |
| android.AssertStringDoesContain(t, "manifest_fixer args", actualManifestFixerArgs, expectManifestFixerArgs) |
| |
| // Test that all libraries are verified (library order matters). |
| verifyCmd := app.Rule("verify_uses_libraries").RuleParams.Command |
| verifyArgs := `--uses-library foo ` + |
| `--uses-library com.non.sdk.lib ` + |
| `--uses-library qux ` + |
| `--uses-library quuz ` + |
| `--uses-library runtime-library ` + |
| `--uses-library runtime-required-x ` + |
| `--uses-library runtime-required-y ` + |
| `--optional-uses-library bar ` + |
| `--optional-uses-library runtime-optional-x ` + |
| `--optional-uses-library runtime-optional-y ` + |
| `--missing-optional-uses-library missing-lib-b ` + |
| `--missing-optional-uses-library missing-lib-a` |
| android.AssertStringDoesContain(t, "verify cmd args", verifyCmd, verifyArgs) |
| |
| // Test that all libraries are verified for an APK (library order matters). |
| verifyApkCmd := prebuilt.Rule("verify_uses_libraries").RuleParams.Command |
| verifyApkArgs := `--uses-library foo ` + |
| `--uses-library com.non.sdk.lib ` + |
| `--uses-library android.test.runner ` + |
| `--optional-uses-library bar ` + |
| `--missing-optional-uses-library missing-lib-b ` |
| android.AssertStringDoesContain(t, "verify apk cmd args", verifyApkCmd, verifyApkArgs) |
| |
| // Test that necessary args are passed for constructing CLC in Ninja phase. |
| cmd := app.Rule("dexpreopt").RuleParams.Command |
| android.AssertStringDoesContain(t, "dexpreopt app cmd context", cmd, "--context-json=") |
| android.AssertStringDoesContain(t, "dexpreopt app cmd product_packages", cmd, |
| "--product-packages=out/soong/.intermediates/app/android_common/dexpreopt/app/product_packages.txt") |
| } |
| |
| func TestDexpreoptBcp(t *testing.T) { |
| bp := ` |
| java_sdk_library { |
| name: "foo", |
| srcs: ["a.java"], |
| api_packages: ["foo"], |
| sdk_version: "current", |
| } |
| |
| java_sdk_library { |
| name: "bar", |
| srcs: ["a.java"], |
| api_packages: ["bar"], |
| permitted_packages: ["bar"], |
| sdk_version: "current", |
| } |
| |
| android_app { |
| name: "app", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| } |
| ` |
| |
| testCases := []struct { |
| name string |
| with bool |
| expect string |
| }{ |
| { |
| name: "with updatable bcp", |
| with: true, |
| expect: "/system/framework/foo.jar:/system/framework/bar.jar", |
| }, |
| { |
| name: "without updatable bcp", |
| with: false, |
| expect: "/system/framework/foo.jar", |
| }, |
| } |
| |
| for _, test := range testCases { |
| t.Run(test.name, func(t *testing.T) { |
| result := android.GroupFixturePreparers( |
| prepareForJavaTest, |
| PrepareForTestWithJavaSdkLibraryFiles, |
| FixtureWithLastReleaseApis("runtime-library", "foo", "bar"), |
| dexpreopt.FixtureSetBootJars("platform:foo"), |
| dexpreopt.FixtureSetApexBootJars("platform:bar"), |
| dexpreopt.FixtureSetPreoptWithUpdatableBcp(test.with), |
| ).RunTestWithBp(t, bp) |
| |
| app := result.ModuleForTests("app", "android_common") |
| cmd := app.Rule("dexpreopt").RuleParams.Command |
| bcp := " -Xbootclasspath-locations:" + test.expect + " " // space at the end matters |
| android.AssertStringDoesContain(t, "dexpreopt app bcp", cmd, bcp) |
| }) |
| } |
| } |
| |
| func TestCodelessApp(t *testing.T) { |
| testCases := []struct { |
| name string |
| bp string |
| noCode bool |
| }{ |
| { |
| name: "normal", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| } |
| `, |
| noCode: false, |
| }, |
| { |
| name: "app without sources", |
| bp: ` |
| android_app { |
| name: "foo", |
| sdk_version: "current", |
| } |
| `, |
| noCode: true, |
| }, |
| { |
| name: "app with libraries", |
| bp: ` |
| android_app { |
| name: "foo", |
| static_libs: ["lib"], |
| sdk_version: "current", |
| } |
| |
| java_library { |
| name: "lib", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| } |
| `, |
| noCode: false, |
| }, |
| { |
| name: "app with sourceless libraries", |
| bp: ` |
| android_app { |
| name: "foo", |
| static_libs: ["lib"], |
| sdk_version: "current", |
| } |
| |
| java_library { |
| name: "lib", |
| sdk_version: "current", |
| } |
| `, |
| // TODO(jungjw): this should probably be true |
| noCode: false, |
| }, |
| } |
| |
| for _, test := range testCases { |
| t.Run(test.name, func(t *testing.T) { |
| ctx := testApp(t, test.bp) |
| |
| foo := ctx.ModuleForTests("foo", "android_common") |
| manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] |
| if strings.Contains(manifestFixerArgs, "--has-no-code") != test.noCode { |
| t.Errorf("unexpected manifest_fixer args: %q", manifestFixerArgs) |
| } |
| }) |
| } |
| } |
| |
| 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"], |
| sdk_version: "current", |
| } |
| `, |
| uncompressedPlatform: true, |
| uncompressedUnbundled: false, |
| }, |
| { |
| name: "use_embedded_dex", |
| bp: ` |
| android_app { |
| name: "foo", |
| use_embedded_dex: true, |
| srcs: ["a.java"], |
| sdk_version: "current", |
| } |
| `, |
| uncompressedPlatform: true, |
| uncompressedUnbundled: true, |
| }, |
| { |
| name: "privileged", |
| bp: ` |
| android_app { |
| name: "foo", |
| privileged: true, |
| srcs: ["a.java"], |
| sdk_version: "current", |
| } |
| `, |
| uncompressedPlatform: true, |
| uncompressedUnbundled: true, |
| }, |
| { |
| name: "normal_uncompress_dex_true", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| uncompress_dex: true, |
| } |
| `, |
| uncompressedPlatform: true, |
| uncompressedUnbundled: true, |
| }, |
| { |
| name: "normal_uncompress_dex_false", |
| bp: ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| uncompress_dex: false, |
| } |
| `, |
| uncompressedPlatform: false, |
| uncompressedUnbundled: false, |
| }, |
| } |
| |
| test := func(t *testing.T, bp string, want bool, unbundled bool) { |
| t.Helper() |
| |
| result := android.GroupFixturePreparers( |
| prepareForJavaTest, |
| PrepareForTestWithPrebuiltsOfCurrentApi, |
| android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { |
| if unbundled { |
| variables.Unbundled_build = proptools.BoolPtr(true) |
| variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true) |
| } |
| }), |
| ).RunTestWithBp(t, bp) |
| |
| foo := result.ModuleForTests("foo", "android_common") |
| dex := foo.Rule("r8") |
| uncompressedInDexJar := strings.Contains(dex.Args["zipFlags"], "-L 0") |
| aligned := foo.MaybeRule("zipalign").Rule != nil |
| |
| android.AssertBoolEquals(t, "uncompressed in dex", want, uncompressedInDexJar) |
| |
| android.AssertBoolEquals(t, "aligne", 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) |
| }) |
| }) |
| } |
| } |
| |
| func checkAapt2LinkFlag(t *testing.T, aapt2Flags, flagName, expectedValue string) { |
| if expectedValue != "" { |
| expectedFlag := "--" + flagName + " " + expectedValue |
| if !strings.Contains(aapt2Flags, expectedFlag) { |
| t.Errorf("%q is missing in aapt2 link flags, %q", expectedFlag, aapt2Flags) |
| } |
| } else { |
| unexpectedFlag := "--" + flagName |
| if strings.Contains(aapt2Flags, unexpectedFlag) { |
| t.Errorf("unexpected flag, %q is found in aapt2 link flags, %q", unexpectedFlag, aapt2Flags) |
| } |
| } |
| } |
| |
| func TestExportedProguardFlagFiles(t *testing.T) { |
| ctx, _ := testJava(t, ` |
| android_app { |
| name: "foo", |
| sdk_version: "current", |
| static_libs: [ |
| "lib1", |
| "lib3", |
| ], |
| } |
| |
| android_library { |
| name: "lib1", |
| sdk_version: "current", |
| optimize: { |
| proguard_flags_files: ["lib1proguard.cfg"], |
| }, |
| static_libs: ["lib2"], |
| } |
| |
| android_library { |
| name: "lib2", |
| sdk_version: "current", |
| optimize: { |
| proguard_flags_files: ["lib2proguard.cfg"], |
| } |
| } |
| |
| android_library_import { |
| name: "lib3", |
| sdk_version: "current", |
| aars: ["lib3.aar"], |
| static_libs: ["lib4"], |
| } |
| |
| android_library { |
| name: "lib4", |
| sdk_version: "current", |
| optimize: { |
| proguard_flags_files: ["lib4proguard.cfg"], |
| } |
| } |
| |
| |
| `) |
| |
| m := ctx.ModuleForTests("foo", "android_common") |
| r8 := m.Rule("java.r8") |
| implicits := r8.Implicits.RelativeToTop().Strings() |
| android.AssertStringListContains(t, "r8 implicits", implicits, "lib1proguard.cfg") |
| android.AssertStringListContains(t, "r8 implicits", implicits, "lib2proguard.cfg") |
| android.AssertStringListContains(t, "r8 implicits", implicits, "lib4proguard.cfg") |
| android.AssertStringListContains(t, "r8 implicits", implicits, "out/soong/.intermediates/lib3/android_common/aar/proguard.txt") |
| |
| flags := r8.Args["r8Flags"] |
| android.AssertStringDoesContain(t, "r8 flags", flags, "-include lib1proguard.cfg") |
| android.AssertStringDoesContain(t, "r8 flags", flags, "-include lib2proguard.cfg") |
| android.AssertStringDoesContain(t, "r8 flags", flags, "-include lib4proguard.cfg") |
| android.AssertStringDoesContain(t, "r8 flags", flags, "-include out/soong/.intermediates/lib3/android_common/aar/proguard.txt") |
| } |
| |
| func TestTargetSdkVersionManifestFixer(t *testing.T) { |
| platform_sdk_codename := "Tiramisu" |
| platform_sdk_version := 33 |
| testCases := []struct { |
| name string |
| targetSdkVersionInBp string |
| targetSdkVersionExpected string |
| unbundledBuild bool |
| platformSdkFinal bool |
| }{ |
| { |
| name: "Non-Unbundled build: Android.bp has targetSdkVersion", |
| targetSdkVersionInBp: "30", |
| targetSdkVersionExpected: "30", |
| unbundledBuild: false, |
| }, |
| { |
| name: "Unbundled build: Android.bp has targetSdkVersion", |
| targetSdkVersionInBp: "30", |
| targetSdkVersionExpected: "30", |
| unbundledBuild: true, |
| }, |
| { |
| name: "Non-Unbundled build: Android.bp has targetSdkVersion equal to platform_sdk_codename", |
| targetSdkVersionInBp: platform_sdk_codename, |
| targetSdkVersionExpected: platform_sdk_codename, |
| unbundledBuild: false, |
| }, |
| { |
| name: "Unbundled build: Android.bp has targetSdkVersion equal to platform_sdk_codename", |
| targetSdkVersionInBp: platform_sdk_codename, |
| targetSdkVersionExpected: "10000", |
| unbundledBuild: true, |
| }, |
| |
| { |
| name: "Non-Unbundled build: Android.bp has no targetSdkVersion", |
| targetSdkVersionExpected: platform_sdk_codename, |
| unbundledBuild: false, |
| }, |
| { |
| name: "Unbundled build: Android.bp has no targetSdkVersion", |
| targetSdkVersionExpected: "10000", |
| unbundledBuild: true, |
| }, |
| { |
| name: "Bundled build in REL branches", |
| targetSdkVersionExpected: "33", |
| unbundledBuild: false, |
| platformSdkFinal: true, |
| }, |
| } |
| for _, testCase := range testCases { |
| targetSdkVersionTemplate := "" |
| if testCase.targetSdkVersionInBp != "" { |
| targetSdkVersionTemplate = fmt.Sprintf(`target_sdk_version: "%s",`, testCase.targetSdkVersionInBp) |
| } |
| bp := fmt.Sprintf(` |
| android_app { |
| name: "foo", |
| sdk_version: "current", |
| %s |
| } |
| `, targetSdkVersionTemplate) |
| fixture := android.GroupFixturePreparers( |
| prepareForJavaTest, |
| android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { |
| if testCase.platformSdkFinal { |
| variables.Platform_sdk_final = proptools.BoolPtr(true) |
| } |
| // explicitly set platform_sdk_codename to make the test deterministic |
| variables.Platform_sdk_codename = &platform_sdk_codename |
| variables.Platform_sdk_version = &platform_sdk_version |
| variables.Platform_version_active_codenames = []string{platform_sdk_codename} |
| // create a non-empty list if unbundledBuild==true |
| if testCase.unbundledBuild { |
| variables.Unbundled_build_apps = []string{"apex_a", "apex_b"} |
| } |
| }), |
| ) |
| |
| result := fixture.RunTestWithBp(t, bp) |
| foo := result.ModuleForTests("foo", "android_common") |
| |
| manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] |
| android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected) |
| } |
| } |
| |
| func TestDefaultAppTargetSdkVersionForUpdatableModules(t *testing.T) { |
| platform_sdk_codename := "Tiramisu" |
| platform_sdk_version := 33 |
| testCases := []struct { |
| name string |
| platform_sdk_final bool |
| targetSdkVersionInBp *string |
| targetSdkVersionExpected *string |
| updatable bool |
| }{ |
| { |
| name: "Non-Updatable Module: Android.bp has older targetSdkVersion", |
| targetSdkVersionInBp: proptools.StringPtr("29"), |
| targetSdkVersionExpected: proptools.StringPtr("29"), |
| updatable: false, |
| }, |
| { |
| name: "Updatable Module: Android.bp has older targetSdkVersion", |
| targetSdkVersionInBp: proptools.StringPtr("30"), |
| targetSdkVersionExpected: proptools.StringPtr("30"), |
| updatable: true, |
| }, |
| { |
| name: "Updatable Module: Android.bp has no targetSdkVersion", |
| targetSdkVersionExpected: proptools.StringPtr("10000"), |
| updatable: true, |
| }, |
| { |
| name: "[SDK finalised] Non-Updatable Module: Android.bp has older targetSdkVersion", |
| platform_sdk_final: true, |
| targetSdkVersionInBp: proptools.StringPtr("30"), |
| targetSdkVersionExpected: proptools.StringPtr("30"), |
| updatable: false, |
| }, |
| { |
| name: "[SDK finalised] Updatable Module: Android.bp has older targetSdkVersion", |
| platform_sdk_final: true, |
| targetSdkVersionInBp: proptools.StringPtr("30"), |
| targetSdkVersionExpected: proptools.StringPtr("30"), |
| updatable: true, |
| }, |
| { |
| name: "[SDK finalised] Updatable Module: Android.bp has targetSdkVersion as platform sdk codename", |
| platform_sdk_final: true, |
| targetSdkVersionInBp: proptools.StringPtr(platform_sdk_codename), |
| targetSdkVersionExpected: proptools.StringPtr("33"), |
| updatable: true, |
| }, |
| { |
| name: "[SDK finalised] Updatable Module: Android.bp has no targetSdkVersion", |
| platform_sdk_final: true, |
| targetSdkVersionExpected: proptools.StringPtr("33"), |
| updatable: true, |
| }, |
| } |
| for _, testCase := range testCases { |
| targetSdkVersionTemplate := "" |
| if testCase.targetSdkVersionInBp != nil { |
| targetSdkVersionTemplate = fmt.Sprintf(`target_sdk_version: "%s",`, *testCase.targetSdkVersionInBp) |
| } |
| bp := fmt.Sprintf(` |
| android_app { |
| name: "foo", |
| sdk_version: "current", |
| min_sdk_version: "29", |
| %s |
| updatable: %t, |
| enforce_default_target_sdk_version: %t |
| } |
| `, targetSdkVersionTemplate, testCase.updatable, testCase.updatable) // enforce default target sdk version if app is updatable |
| |
| fixture := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| android.PrepareForTestWithAllowMissingDependencies, |
| android.PrepareForTestWithAndroidMk, |
| android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { |
| // explicitly set following platform variables to make the test deterministic |
| variables.Platform_sdk_final = &testCase.platform_sdk_final |
| variables.Platform_sdk_version = &platform_sdk_version |
| variables.Platform_sdk_codename = &platform_sdk_codename |
| variables.Platform_version_active_codenames = []string{platform_sdk_codename} |
| variables.Unbundled_build = proptools.BoolPtr(true) |
| variables.Unbundled_build_apps = []string{"sampleModule"} |
| }), |
| ) |
| |
| result := fixture.RunTestWithBp(t, bp) |
| foo := result.ModuleForTests("foo", "android_common") |
| |
| manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] |
| android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+*testCase.targetSdkVersionExpected) |
| } |
| } |
| |
| func TestEnforceDefaultAppTargetSdkVersionFlag(t *testing.T) { |
| platform_sdk_codename := "Tiramisu" |
| platform_sdk_version := 33 |
| testCases := []struct { |
| name string |
| enforceDefaultTargetSdkVersion bool |
| expectedError string |
| platform_sdk_final bool |
| targetSdkVersionInBp string |
| targetSdkVersionExpected string |
| updatable bool |
| }{ |
| { |
| name: "Not enforcing Target SDK Version: Android.bp has older targetSdkVersion", |
| enforceDefaultTargetSdkVersion: false, |
| targetSdkVersionInBp: "29", |
| targetSdkVersionExpected: "29", |
| updatable: false, |
| }, |
| { |
| name: "[SDK finalised] Enforce Target SDK Version: Android.bp has current targetSdkVersion", |
| enforceDefaultTargetSdkVersion: true, |
| platform_sdk_final: true, |
| targetSdkVersionInBp: "current", |
| targetSdkVersionExpected: "33", |
| updatable: true, |
| }, |
| { |
| name: "Enforce Target SDK Version: Android.bp has current targetSdkVersion", |
| enforceDefaultTargetSdkVersion: true, |
| platform_sdk_final: false, |
| targetSdkVersionInBp: "current", |
| targetSdkVersionExpected: "10000", |
| updatable: false, |
| }, |
| { |
| name: "Not enforcing Target SDK Version for Updatable app", |
| enforceDefaultTargetSdkVersion: false, |
| expectedError: "Updatable apps must enforce default target sdk version", |
| targetSdkVersionInBp: "29", |
| targetSdkVersionExpected: "29", |
| updatable: true, |
| }, |
| } |
| for _, testCase := range testCases { |
| errExpected := testCase.expectedError != "" |
| bp := fmt.Sprintf(` |
| android_app { |
| name: "foo", |
| enforce_default_target_sdk_version: %t, |
| sdk_version: "current", |
| min_sdk_version: "29", |
| target_sdk_version: "%v", |
| updatable: %t |
| } |
| `, testCase.enforceDefaultTargetSdkVersion, testCase.targetSdkVersionInBp, testCase.updatable) |
| |
| fixture := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| android.PrepareForTestWithAllowMissingDependencies, |
| android.PrepareForTestWithAndroidMk, |
| android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { |
| // explicitly set following platform variables to make the test deterministic |
| variables.Platform_sdk_final = &testCase.platform_sdk_final |
| variables.Platform_sdk_version = &platform_sdk_version |
| variables.Platform_sdk_codename = &platform_sdk_codename |
| variables.Unbundled_build = proptools.BoolPtr(true) |
| variables.Unbundled_build_apps = []string{"sampleModule"} |
| }), |
| ) |
| |
| errorHandler := android.FixtureExpectsNoErrors |
| if errExpected { |
| errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.expectedError) |
| } |
| result := fixture.ExtendWithErrorHandler(errorHandler).RunTestWithBp(t, bp) |
| |
| if !errExpected { |
| foo := result.ModuleForTests("foo", "android_common") |
| manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] |
| android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected) |
| } |
| } |
| } |
| |
| func TestEnforceDefaultAppTargetSdkVersionFlagForTests(t *testing.T) { |
| platform_sdk_codename := "Tiramisu" |
| platform_sdk_version := 33 |
| testCases := []struct { |
| name string |
| enforceDefaultTargetSdkVersion bool |
| expectedError string |
| platform_sdk_final bool |
| targetSdkVersionInBp string |
| targetSdkVersionExpected string |
| }{ |
| { |
| name: "Not enforcing Target SDK Version: Android.bp has older targetSdkVersion", |
| enforceDefaultTargetSdkVersion: false, |
| targetSdkVersionInBp: "29", |
| targetSdkVersionExpected: "29", |
| }, |
| { |
| name: "[SDK finalised] Enforce Target SDK Version: Android.bp has current targetSdkVersion", |
| enforceDefaultTargetSdkVersion: true, |
| platform_sdk_final: true, |
| targetSdkVersionInBp: "current", |
| targetSdkVersionExpected: "33", |
| }, |
| { |
| name: "Enforce Target SDK Version: Android.bp has current targetSdkVersion", |
| enforceDefaultTargetSdkVersion: true, |
| platform_sdk_final: false, |
| targetSdkVersionInBp: "current", |
| targetSdkVersionExpected: "10000", |
| }, |
| } |
| for _, testCase := range testCases { |
| errExpected := testCase.expectedError != "" |
| bp := fmt.Sprintf(` |
| android_test { |
| name: "foo", |
| enforce_default_target_sdk_version: %t, |
| min_sdk_version: "29", |
| target_sdk_version: "%v", |
| } |
| `, testCase.enforceDefaultTargetSdkVersion, testCase.targetSdkVersionInBp) |
| |
| fixture := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| android.PrepareForTestWithAllowMissingDependencies, |
| android.PrepareForTestWithAndroidMk, |
| android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { |
| // explicitly set following platform variables to make the test deterministic |
| variables.Platform_sdk_final = &testCase.platform_sdk_final |
| variables.Platform_sdk_version = &platform_sdk_version |
| variables.Platform_sdk_codename = &platform_sdk_codename |
| variables.Unbundled_build = proptools.BoolPtr(true) |
| variables.Unbundled_build_apps = []string{"sampleModule"} |
| }), |
| ) |
| |
| errorHandler := android.FixtureExpectsNoErrors |
| if errExpected { |
| errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.expectedError) |
| } |
| result := fixture.ExtendWithErrorHandler(errorHandler).RunTestWithBp(t, bp) |
| |
| if !errExpected { |
| foo := result.ModuleForTests("foo", "android_common") |
| manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] |
| android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected) |
| } |
| } |
| } |
| |
| func TestAppMissingCertificateAllowMissingDependencies(t *testing.T) { |
| result := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| android.PrepareForTestWithAllowMissingDependencies, |
| android.PrepareForTestWithAndroidMk, |
| ).RunTestWithBp(t, ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| certificate: ":missing_certificate", |
| sdk_version: "current", |
| } |
| |
| android_app { |
| name: "bar", |
| srcs: ["a.java"], |
| certificate: ":missing_certificate", |
| product_specific: true, |
| sdk_version: "current", |
| }`) |
| |
| foo := result.ModuleForTests("foo", "android_common") |
| fooApk := foo.Output("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") |
| } |
| |
| func TestAppIncludesJniPackages(t *testing.T) { |
| ctx := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| ).RunTestWithBp(t, ` |
| android_library_import { |
| name: "aary-nodeps", |
| aars: ["aary.aar"], |
| extract_jni: true, |
| } |
| |
| android_library { |
| name: "aary-lib", |
| sdk_version: "current", |
| min_sdk_version: "21", |
| static_libs: ["aary-nodeps"], |
| } |
| |
| android_app { |
| name: "aary-lib-dep", |
| sdk_version: "current", |
| min_sdk_version: "21", |
| manifest: "AndroidManifest.xml", |
| static_libs: ["aary-lib"], |
| use_embedded_native_libs: true, |
| } |
| |
| android_app { |
| name: "aary-import-dep", |
| sdk_version: "current", |
| min_sdk_version: "21", |
| manifest: "AndroidManifest.xml", |
| static_libs: ["aary-nodeps"], |
| use_embedded_native_libs: true, |
| } |
| |
| android_app { |
| name: "aary-no-use-embedded", |
| sdk_version: "current", |
| min_sdk_version: "21", |
| manifest: "AndroidManifest.xml", |
| static_libs: ["aary-nodeps"], |
| }`) |
| |
| testCases := []struct { |
| name string |
| hasPackage bool |
| }{ |
| { |
| name: "aary-import-dep", |
| hasPackage: true, |
| }, |
| { |
| name: "aary-lib-dep", |
| hasPackage: true, |
| }, |
| { |
| name: "aary-no-use-embedded", |
| hasPackage: false, |
| }, |
| } |
| |
| for _, tc := range testCases { |
| t.Run(tc.name, func(t *testing.T) { |
| app := ctx.ModuleForTests(tc.name, "android_common") |
| |
| outputFile := "jnilibs.zip" |
| jniOutputLibZip := app.MaybeOutput(outputFile) |
| if jniOutputLibZip.Rule == nil && !tc.hasPackage { |
| return |
| } |
| |
| jniPackage := "arm64-v8a_jni.zip" |
| inputs := jniOutputLibZip.Inputs |
| foundPackage := false |
| for i := 0; i < len(inputs); i++ { |
| if strings.Contains(inputs[i].String(), jniPackage) { |
| foundPackage = true |
| } |
| } |
| if foundPackage != tc.hasPackage { |
| t.Errorf("expected to find %v in %v inputs; inputs = %v", jniPackage, outputFile, inputs) |
| } |
| }) |
| } |
| } |
| |
| func TestTargetSdkVersionMtsTests(t *testing.T) { |
| platformSdkCodename := "Tiramisu" |
| android_test := "android_test" |
| android_test_helper_app := "android_test_helper_app" |
| bpTemplate := ` |
| %v { |
| name: "mytest", |
| target_sdk_version: "%v", |
| test_suites: ["othersuite", "%v"], |
| } |
| ` |
| testCases := []struct { |
| desc string |
| moduleType string |
| targetSdkVersionInBp string |
| targetSdkVersionExpected string |
| testSuites string |
| }{ |
| { |
| desc: "Non-MTS android_test_apps targeting current should not be upgraded to 10000", |
| moduleType: android_test, |
| targetSdkVersionInBp: "current", |
| targetSdkVersionExpected: platformSdkCodename, |
| testSuites: "non-mts-suite", |
| }, |
| { |
| desc: "MTS android_test_apps targeting released sdks should not be upgraded to 10000", |
| moduleType: android_test, |
| targetSdkVersionInBp: "29", |
| targetSdkVersionExpected: "29", |
| testSuites: "mts-suite", |
| }, |
| { |
| desc: "MTS android_test_apps targeting current should be upgraded to 10000", |
| moduleType: android_test, |
| targetSdkVersionInBp: "current", |
| targetSdkVersionExpected: "10000", |
| testSuites: "mts-suite", |
| }, |
| { |
| desc: "MTS android_test_helper_apps targeting current should be upgraded to 10000", |
| moduleType: android_test_helper_app, |
| targetSdkVersionInBp: "current", |
| targetSdkVersionExpected: "10000", |
| testSuites: "mts-suite", |
| }, |
| } |
| fixture := android.GroupFixturePreparers( |
| prepareForJavaTest, |
| android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { |
| variables.Platform_sdk_codename = &platformSdkCodename |
| variables.Platform_version_active_codenames = []string{platformSdkCodename} |
| }), |
| ) |
| for _, testCase := range testCases { |
| result := fixture.RunTestWithBp(t, fmt.Sprintf(bpTemplate, testCase.moduleType, testCase.targetSdkVersionInBp, testCase.testSuites)) |
| mytest := result.ModuleForTests("mytest", "android_common") |
| manifestFixerArgs := mytest.Output("manifest_fixer/AndroidManifest.xml").Args["args"] |
| android.AssertStringDoesContain(t, testCase.desc, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected) |
| } |
| } |
| |
| func TestPrivappAllowlist(t *testing.T) { |
| testJavaError(t, "privileged must be set in order to use privapp_allowlist", ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| privapp_allowlist: "perms.xml", |
| } |
| `) |
| |
| result := PrepareForTestWithJavaDefaultModules.RunTestWithBp( |
| t, |
| ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| privapp_allowlist: "privapp_allowlist_com.android.foo.xml", |
| privileged: true, |
| sdk_version: "current", |
| } |
| override_android_app { |
| name: "bar", |
| base: "foo", |
| package_name: "com.google.android.foo", |
| } |
| `, |
| ) |
| app := result.ModuleForTests("foo", "android_common") |
| overrideApp := result.ModuleForTests("foo", "android_common_bar") |
| |
| // verify that privapp allowlist is created for override apps |
| overrideApp.Output("out/soong/.intermediates/foo/android_common_bar/privapp_allowlist_com.google.android.foo.xml") |
| expectedAllowlistInput := "privapp_allowlist_com.android.foo.xml" |
| overrideActualAllowlistInput := overrideApp.Rule("modifyAllowlist").Input.String() |
| if expectedAllowlistInput != overrideActualAllowlistInput { |
| t.Errorf("expected override allowlist to be %q; got %q", expectedAllowlistInput, overrideActualAllowlistInput) |
| } |
| |
| // verify that permissions are copied to device |
| app.Output("out/soong/target/product/test_device/system/etc/permissions/foo.xml") |
| overrideApp.Output("out/soong/target/product/test_device/system/etc/permissions/bar.xml") |
| } |
| |
| func TestPrivappAllowlistAndroidMk(t *testing.T) { |
| result := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| android.PrepareForTestWithAndroidMk, |
| ).RunTestWithBp( |
| t, |
| ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| privapp_allowlist: "privapp_allowlist_com.android.foo.xml", |
| privileged: true, |
| sdk_version: "current", |
| } |
| override_android_app { |
| name: "bar", |
| base: "foo", |
| package_name: "com.google.android.foo", |
| } |
| `, |
| ) |
| baseApp := result.ModuleForTests("foo", "android_common") |
| overrideApp := result.ModuleForTests("foo", "android_common_bar") |
| |
| baseAndroidApp := baseApp.Module().(*AndroidApp) |
| baseEntries := android.AndroidMkEntriesForTest(t, result.TestContext, baseAndroidApp)[0] |
| android.AssertStringMatches( |
| t, |
| "androidmk has incorrect LOCAL_SOONG_INSTALLED_MODULE; expected to find foo.apk", |
| baseEntries.EntryMap["LOCAL_SOONG_INSTALLED_MODULE"][0], |
| "\\S+foo.apk", |
| ) |
| android.AssertStringMatches( |
| t, |
| "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include foo.apk", |
| baseEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0], |
| "\\S+foo.apk", |
| ) |
| android.AssertStringMatches( |
| t, |
| "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include app", |
| baseEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0], |
| "\\S+foo.apk:\\S+/target/product/test_device/system/priv-app/foo/foo.apk", |
| ) |
| android.AssertStringMatches( |
| t, |
| "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include privapp_allowlist", |
| baseEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0], |
| "privapp_allowlist_com.android.foo.xml:\\S+/target/product/test_device/system/etc/permissions/foo.xml", |
| ) |
| |
| overrideAndroidApp := overrideApp.Module().(*AndroidApp) |
| overrideEntries := android.AndroidMkEntriesForTest(t, result.TestContext, overrideAndroidApp)[0] |
| android.AssertStringMatches( |
| t, |
| "androidmk has incorrect LOCAL_SOONG_INSTALLED_MODULE; expected to find bar.apk", |
| overrideEntries.EntryMap["LOCAL_SOONG_INSTALLED_MODULE"][0], |
| "\\S+bar.apk", |
| ) |
| android.AssertStringMatches( |
| t, |
| "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include bar.apk", |
| overrideEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0], |
| "\\S+bar.apk", |
| ) |
| android.AssertStringMatches( |
| t, |
| "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include app", |
| overrideEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0], |
| "\\S+bar.apk:\\S+/target/product/test_device/system/priv-app/bar/bar.apk", |
| ) |
| android.AssertStringMatches( |
| t, |
| "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include privapp_allowlist", |
| overrideEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0], |
| "\\S+soong/.intermediates/foo/android_common_bar/privapp_allowlist_com.google.android.foo.xml:\\S+/target/product/test_device/system/etc/permissions/bar.xml", |
| ) |
| } |
| |
| func TestAppFlagsPackages(t *testing.T) { |
| ctx := testApp(t, ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| flags_packages: [ |
| "bar", |
| "baz", |
| ], |
| } |
| aconfig_declarations { |
| name: "bar", |
| package: "com.example.package.bar", |
| container: "com.android.foo", |
| srcs: [ |
| "bar.aconfig", |
| ], |
| } |
| aconfig_declarations { |
| name: "baz", |
| package: "com.example.package.baz", |
| container: "com.android.foo", |
| srcs: [ |
| "baz.aconfig", |
| ], |
| } |
| `) |
| |
| foo := ctx.ModuleForTests("foo", "android_common") |
| |
| // android_app module depends on aconfig_declarations listed in flags_packages |
| android.AssertBoolEquals(t, "foo expected to depend on bar", true, |
| CheckModuleHasDependency(t, ctx, "foo", "android_common", "bar")) |
| |
| android.AssertBoolEquals(t, "foo expected to depend on baz", true, |
| CheckModuleHasDependency(t, ctx, "foo", "android_common", "baz")) |
| |
| aapt2LinkRule := foo.Rule("android/soong/java.aapt2Link") |
| linkInFlags := aapt2LinkRule.Args["inFlags"] |
| android.AssertStringDoesContain(t, |
| "aapt2 link command expected to pass feature flags arguments", |
| linkInFlags, |
| "--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt", |
| ) |
| } |
| |
| // Test that dexpreopt is disabled if an optional_uses_libs exists, but does not provide an implementation. |
| func TestNoDexpreoptOptionalUsesLibDoesNotHaveImpl(t *testing.T) { |
| bp := ` |
| java_sdk_library_import { |
| name: "sdklib_noimpl", |
| public: { |
| jars: ["stub.jar"], |
| }, |
| } |
| android_app { |
| name: "app", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| optional_uses_libs: [ |
| "sdklib_noimpl", |
| ], |
| } |
| ` |
| result := prepareForJavaTest.RunTestWithBp(t, bp) |
| dexpreopt := result.ModuleForTests("app", "android_common").MaybeRule("dexpreopt").Rule |
| android.AssertBoolEquals(t, "dexpreopt should be disabled if optional_uses_libs does not have an implementation", true, dexpreopt == nil) |
| } |
| |
| func TestTestOnlyApp(t *testing.T) { |
| t.Parallel() |
| ctx := android.GroupFixturePreparers( |
| prepareForJavaTest, |
| ).RunTestWithBp(t, ` |
| // These should be test-only |
| android_test { |
| name: "android-test", |
| } |
| android_test_helper_app { |
| name: "helper-app", |
| } |
| override_android_test { |
| name: "override-test", |
| base: "android-app", |
| } |
| // And these should not be |
| android_app { |
| name: "android-app", |
| srcs: ["b.java"], |
| sdk_version: "current", |
| } |
| `) |
| |
| expectedTestOnly := []string{ |
| "android-test", |
| "helper-app", |
| "override-test", |
| } |
| |
| expectedTopLevel := []string{ |
| "android-test", |
| "override-test", |
| } |
| |
| assertTestOnlyAndTopLevel(t, ctx, expectedTestOnly, expectedTopLevel) |
| } |
| |
| func TestAppStem(t *testing.T) { |
| ctx := testApp(t, ` |
| android_app { |
| name: "foo", |
| srcs: ["a.java"], |
| stem: "foo-new", |
| sdk_version: "current", |
| }`) |
| |
| foo := ctx.ModuleForTests("foo", "android_common") |
| |
| outputs := fmt.Sprint(foo.AllOutputs()) |
| if !strings.Contains(outputs, "foo-new.apk") { |
| t.Errorf("Module output does not contain expected apk %s", "foo-new.apk") |
| } |
| } |
| |
| func TestAppMinSdkVersionOverride(t *testing.T) { |
| result := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| ).RunTestWithBp(t, ` |
| android_app { |
| name: "com.android.foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| min_sdk_version: "31", |
| updatable: true, |
| } |
| override_android_app { |
| name: "com.android.go.foo", |
| base: "com.android.foo", |
| min_sdk_version: "33", |
| } |
| `) |
| foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer") |
| fooOverride := result.ModuleForTests("com.android.foo", "android_common_com.android.go.foo").Rule("manifestFixer") |
| |
| android.AssertStringDoesContain(t, |
| "com.android.foo: expected manifest fixer to set minSdkVersion to T", |
| foo.BuildParams.Args["args"], |
| "--minSdkVersion 31", |
| ) |
| android.AssertStringDoesContain(t, |
| "com.android.go.foo: expected manifest fixer to set minSdkVersion to T", |
| fooOverride.BuildParams.Args["args"], |
| "--minSdkVersion 33", |
| ) |
| |
| } |
| |
| func TestNotApplyDefaultUpdatableModuleVersion(t *testing.T) { |
| result := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| ).RunTestWithBp(t, ` |
| android_app { |
| name: "com.android.foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| min_sdk_version: "31", |
| } |
| `) |
| foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer") |
| android.AssertStringDoesNotContain(t, |
| "com.android.foo: expected manifest fixer to not set override-placeholder-version", |
| foo.BuildParams.Args["args"], |
| "--override-placeholder-version", |
| ) |
| } |
| |
| func TestNotApplyOverrideApexManifestDefaultVersion(t *testing.T) { |
| result := android.GroupFixturePreparers( |
| PrepareForTestWithJavaDefaultModules, |
| android.FixtureMergeEnv(map[string]string{ |
| "OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION": "1234", |
| }), |
| ).RunTestWithBp(t, ` |
| android_app { |
| name: "com.android.foo", |
| srcs: ["a.java"], |
| sdk_version: "current", |
| min_sdk_version: "31", |
| } |
| `) |
| foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer") |
| android.AssertStringDoesNotContain(t, |
| "com.android.foo: expected manifest fixer to not set override-placeholder-version", |
| foo.BuildParams.Args["args"], |
| "--override-placeholder-version", |
| ) |
| } |