// Copyright 2018 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" "runtime" "strings" "testing" "android/soong/android" "android/soong/cc" "android/soong/dexpreopt" ) func init() { RegisterFakeRuntimeApexMutator() } func TestDexpreoptEnabled(t *testing.T) { tests := []struct { name string bp string moduleName string apexVariant bool enabled bool }{ { name: "app", bp: ` android_app { name: "foo", srcs: ["a.java"], sdk_version: "current", }`, enabled: true, }, { name: "installable java library", bp: ` java_library { name: "foo", installable: true, srcs: ["a.java"], }`, enabled: true, }, { name: "java binary", bp: ` java_binary { name: "foo", srcs: ["a.java"], main_class: "foo.bar.jb", }`, enabled: true, }, { name: "app without sources", bp: ` android_app { name: "foo", sdk_version: "current", }`, enabled: false, }, { 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", }`, enabled: true, }, { name: "installable java library without sources", bp: ` java_library { name: "foo", installable: true, }`, enabled: false, }, { name: "static java library", bp: ` java_library { name: "foo", srcs: ["a.java"], }`, enabled: false, }, { name: "java test", bp: ` java_test { name: "foo", srcs: ["a.java"], }`, enabled: false, }, { name: "android test", bp: ` android_test { name: "foo", srcs: ["a.java"], }`, enabled: false, }, { name: "android test helper app", bp: ` android_test_helper_app { name: "foo", srcs: ["a.java"], }`, enabled: false, }, { name: "compile_dex", bp: ` java_library { name: "foo", srcs: ["a.java"], compile_dex: true, }`, enabled: false, }, { name: "dex_import", bp: ` dex_import { name: "foo", jars: ["a.jar"], }`, enabled: true, }, { name: "apex variant", bp: ` java_library { name: "foo", installable: true, srcs: ["a.java"], apex_available: ["com.android.apex1"], }`, apexVariant: true, enabled: false, }, { name: "apex variant of apex system server jar", bp: ` java_library { name: "service-foo", installable: true, srcs: ["a.java"], apex_available: ["com.android.apex1"], }`, moduleName: "service-foo", apexVariant: true, enabled: true, }, { name: "apex variant of prebuilt apex system server jar", bp: ` java_library { name: "prebuilt_service-foo", installable: true, srcs: ["a.java"], apex_available: ["com.android.apex1"], }`, moduleName: "prebuilt_service-foo", apexVariant: true, enabled: true, }, { name: "platform variant of apex system server jar", bp: ` java_library { name: "service-foo", installable: true, srcs: ["a.java"], apex_available: ["com.android.apex1"], }`, moduleName: "service-foo", apexVariant: false, enabled: false, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { preparers := android.GroupFixturePreparers( PrepareForTestWithDexpreopt, PrepareForTestWithFakeApexMutator, dexpreopt.FixtureSetApexSystemServerJars("com.android.apex1:service-foo"), ) result := preparers.RunTestWithBp(t, test.bp) ctx := result.TestContext moduleName := "foo" if test.moduleName != "" { moduleName = test.moduleName } variant := "android_common" if test.apexVariant { variant += "_apex1000" } dexpreopt := ctx.ModuleForTests(moduleName, variant).MaybeRule("dexpreopt") enabled := dexpreopt.Rule != nil if enabled != test.enabled { t.Fatalf("want dexpreopt %s, got %s", enabledString(test.enabled), enabledString(enabled)) } }) } } func enabledString(enabled bool) string { if enabled { return "enabled" } else { return "disabled" } } func TestDex2oatToolDeps(t *testing.T) { if runtime.GOOS != "linux" { // The host binary paths checked below are build OS dependent. t.Skipf("Unsupported build OS %s", runtime.GOOS) } preparers := android.GroupFixturePreparers( cc.PrepareForTestWithCcDefaultModules, PrepareForTestWithDexpreoptWithoutFakeDex2oatd, dexpreopt.PrepareForTestByEnablingDexpreopt) testDex2oatToolDep := func(sourceEnabled, prebuiltEnabled, prebuiltPreferred bool, expectedDex2oatPath string) { name := fmt.Sprintf("sourceEnabled:%t,prebuiltEnabled:%t,prebuiltPreferred:%t", sourceEnabled, prebuiltEnabled, prebuiltPreferred) t.Run(name, func(t *testing.T) { result := preparers.RunTestWithBp(t, fmt.Sprintf(` cc_binary { name: "dex2oatd", enabled: %t, host_supported: true, } cc_prebuilt_binary { name: "dex2oatd", enabled: %t, prefer: %t, host_supported: true, srcs: ["x86_64/bin/dex2oatd"], } java_library { name: "myjavalib", } `, sourceEnabled, prebuiltEnabled, prebuiltPreferred)) pathContext := android.PathContextForTesting(result.Config) dex2oatPath := dexpreopt.GetCachedGlobalSoongConfig(pathContext).Dex2oat android.AssertStringEquals(t, "Testing "+name, expectedDex2oatPath, android.NormalizePathForTesting(dex2oatPath)) }) } sourceDex2oatPath := "host/linux-x86/bin/dex2oatd" prebuiltDex2oatPath := ".intermediates/prebuilt_dex2oatd/linux_glibc_x86_64/dex2oatd" testDex2oatToolDep(true, false, false, sourceDex2oatPath) testDex2oatToolDep(true, true, false, sourceDex2oatPath) testDex2oatToolDep(true, true, true, prebuiltDex2oatPath) testDex2oatToolDep(false, true, false, prebuiltDex2oatPath) } func TestDexpreoptBuiltInstalledForApex(t *testing.T) { preparers := android.GroupFixturePreparers( PrepareForTestWithDexpreopt, PrepareForTestWithFakeApexMutator, dexpreopt.FixtureSetApexSystemServerJars("com.android.apex1:service-foo"), ) // An APEX system server jar. result := preparers.RunTestWithBp(t, ` java_library { name: "service-foo", installable: true, srcs: ["a.java"], apex_available: ["com.android.apex1"], }`) ctx := result.TestContext module := ctx.ModuleForTests("service-foo", "android_common_apex1000") library := module.Module().(*Library) installs := library.dexpreopter.DexpreoptBuiltInstalledForApex() android.AssertIntEquals(t, "install count", 2, len(installs)) android.AssertStringEquals(t, "installs[0] FullModuleName", "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex", installs[0].FullModuleName()) android.AssertStringEquals(t, "installs[0] SubModuleName", "-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex", installs[0].SubModuleName()) android.AssertStringEquals(t, "installs[1] FullModuleName", "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex", installs[1].FullModuleName()) android.AssertStringEquals(t, "installs[1] SubModuleName", "-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex", installs[1].SubModuleName()) // Not an APEX system server jar. result = preparers.RunTestWithBp(t, ` java_library { name: "foo", installable: true, srcs: ["a.java"], }`) ctx = result.TestContext module = ctx.ModuleForTests("foo", "android_common") library = module.Module().(*Library) installs = library.dexpreopter.DexpreoptBuiltInstalledForApex() android.AssertIntEquals(t, "install count", 0, len(installs)) } func filterDexpreoptEntriesList(entriesList []android.AndroidMkEntries) []android.AndroidMkEntries { var results []android.AndroidMkEntries for _, entries := range entriesList { if strings.Contains(entries.EntryMap["LOCAL_MODULE"][0], "-dexpreopt-") { results = append(results, entries) } } return results } func verifyEntries(t *testing.T, message string, expectedModule string, expectedPrebuiltModuleFile string, expectedModulePath string, expectedInstalledModuleStem string, entries android.AndroidMkEntries) { android.AssertStringEquals(t, message+" LOCAL_MODULE", expectedModule, entries.EntryMap["LOCAL_MODULE"][0]) android.AssertStringEquals(t, message+" LOCAL_MODULE_CLASS", "ETC", entries.EntryMap["LOCAL_MODULE_CLASS"][0]) android.AssertStringDoesContain(t, message+" LOCAL_PREBUILT_MODULE_FILE", entries.EntryMap["LOCAL_PREBUILT_MODULE_FILE"][0], expectedPrebuiltModuleFile) android.AssertStringDoesContain(t, message+" LOCAL_MODULE_PATH", entries.EntryMap["LOCAL_MODULE_PATH"][0], expectedModulePath) android.AssertStringEquals(t, message+" LOCAL_INSTALLED_MODULE_STEM", expectedInstalledModuleStem, entries.EntryMap["LOCAL_INSTALLED_MODULE_STEM"][0]) android.AssertStringEquals(t, message+" LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false", entries.EntryMap["LOCAL_NOT_AVAILABLE_FOR_PLATFORM"][0]) } func TestAndroidMkEntriesForApex(t *testing.T) { preparers := android.GroupFixturePreparers( PrepareForTestWithDexpreopt, PrepareForTestWithFakeApexMutator, dexpreopt.FixtureSetApexSystemServerJars("com.android.apex1:service-foo"), ) // An APEX system server jar. result := preparers.RunTestWithBp(t, ` java_library { name: "service-foo", installable: true, srcs: ["a.java"], apex_available: ["com.android.apex1"], }`) ctx := result.TestContext module := ctx.ModuleForTests("service-foo", "android_common_apex1000") entriesList := android.AndroidMkEntriesForTest(t, ctx, module.Module()) entriesList = filterDexpreoptEntriesList(entriesList) android.AssertIntEquals(t, "entries count", 2, len(entriesList)) verifyEntries(t, "entriesList[0]", "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex", "/dexpreopt/oat/arm64/javalib.odex", "/system/framework/oat/arm64", "apex@com.android.apex1@javalib@service-foo.jar@classes.odex", entriesList[0]) verifyEntries(t, "entriesList[1]", "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex", "/dexpreopt/oat/arm64/javalib.vdex", "/system/framework/oat/arm64", "apex@com.android.apex1@javalib@service-foo.jar@classes.vdex", entriesList[1]) // Not an APEX system server jar. result = preparers.RunTestWithBp(t, ` java_library { name: "foo", installable: true, srcs: ["a.java"], }`) ctx = result.TestContext module = ctx.ModuleForTests("foo", "android_common") entriesList = android.AndroidMkEntriesForTest(t, ctx, module.Module()) entriesList = filterDexpreoptEntriesList(entriesList) android.AssertIntEquals(t, "entries count", 0, len(entriesList)) } func TestGenerateProfileEvenIfDexpreoptIsDisabled(t *testing.T) { preparers := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, PrepareForTestWithFakeApexMutator, dexpreopt.FixtureDisableDexpreopt(true), ) result := preparers.RunTestWithBp(t, ` java_library { name: "foo", installable: true, dex_preopt: { profile: "art-profile", }, srcs: ["a.java"], }`) ctx := result.TestContext dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeRule("dexpreopt") expected := []string{"out/soong/.intermediates/foo/android_common/dexpreopt/profile.prof"} android.AssertArrayString(t, "outputs", expected, dexpreopt.AllOutputs()) }