f923333a93
* changes: Enforce updatable=true on apps of updatable apexes Update sdk_version check for jni_libs of updatable apps
2983 lines
79 KiB
Go
2983 lines
79 KiB
Go
// 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")
|
|
expectedLinkImplicits = append(expectedLinkImplicits,
|
|
frameworkRes.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("partialLd").Output
|
|
expectedCrtEnd := ctx.ModuleForTests("crtend_so",
|
|
"android_arm64_armv8-a_sdk_29").Rule("partialLd").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 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,
|
|
PrepareForTestWithOverlayBuildComponents,
|
|
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"],
|
|
}
|
|
|
|
android_library {
|
|
name: "lib4",
|
|
sdk_version: "current",
|
|
asset_dirs: ["assets_b"],
|
|
}
|
|
`
|
|
|
|
testCases := []struct {
|
|
name string
|
|
assetFlag string
|
|
assetPackages []string
|
|
}{
|
|
{
|
|
name: "foo",
|
|
// lib1 has its own asset. lib3 doesn't have any, but provides lib4's transitively.
|
|
assetPackages: []string{
|
|
"out/soong/.intermediates/foo/android_common/aapt2/package-res.apk",
|
|
"out/soong/.intermediates/lib1/android_common/assets.zip",
|
|
"out/soong/.intermediates/lib3/android_common/assets.zip",
|
|
},
|
|
},
|
|
{
|
|
name: "lib1",
|
|
assetFlag: "-A assets_a",
|
|
},
|
|
{
|
|
name: "lib2",
|
|
},
|
|
{
|
|
name: "lib3",
|
|
assetPackages: []string{
|
|
"out/soong/.intermediates/lib3/android_common/aapt2/package-res.apk",
|
|
"out/soong/.intermediates/lib4/android_common/assets.zip",
|
|
},
|
|
},
|
|
{
|
|
name: "lib4",
|
|
assetFlag: "-A assets_b",
|
|
},
|
|
}
|
|
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)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
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 TestAndroidResources(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,
|
|
PrepareForTestWithOverlayBuildComponents,
|
|
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).ExportedRRODirs() {
|
|
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
|
|
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"},
|
|
},
|
|
}
|
|
|
|
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,"
|
|
}
|
|
bp := fmt.Sprintf(`%s {
|
|
name: "foo",
|
|
srcs: ["a.java"],
|
|
sdk_version: "%s",
|
|
%s
|
|
}`, moduleType, test.sdkVersion, platformApiProp)
|
|
|
|
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_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
|
|
certificateOverride string
|
|
expectedLineage string
|
|
expectedCertificate string
|
|
}{
|
|
{
|
|
name: "default",
|
|
bp: `
|
|
android_app {
|
|
name: "foo",
|
|
srcs: ["a.java"],
|
|
sdk_version: "current",
|
|
}
|
|
`,
|
|
certificateOverride: "",
|
|
expectedLineage: "",
|
|
expectedCertificate: "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8",
|
|
},
|
|
{
|
|
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: "",
|
|
expectedLineage: "",
|
|
expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
|
|
},
|
|
{
|
|
name: "path certificate property",
|
|
bp: `
|
|
android_app {
|
|
name: "foo",
|
|
srcs: ["a.java"],
|
|
certificate: "expiredkey",
|
|
sdk_version: "current",
|
|
}
|
|
`,
|
|
certificateOverride: "",
|
|
expectedLineage: "",
|
|
expectedCertificate: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
|
|
},
|
|
{
|
|
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",
|
|
expectedLineage: "",
|
|
expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
|
|
},
|
|
{
|
|
name: "certificate lineage",
|
|
bp: `
|
|
android_app {
|
|
name: "foo",
|
|
srcs: ["a.java"],
|
|
certificate: ":new_certificate",
|
|
lineage: "lineage.bin",
|
|
sdk_version: "current",
|
|
}
|
|
|
|
android_app_certificate {
|
|
name: "new_certificate",
|
|
certificate: "cert/new_cert",
|
|
}
|
|
`,
|
|
certificateOverride: "",
|
|
expectedLineage: "--lineage lineage.bin",
|
|
expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
|
|
},
|
|
{
|
|
name: "lineage from filegroup",
|
|
bp: `
|
|
android_app {
|
|
name: "foo",
|
|
srcs: ["a.java"],
|
|
certificate: ":new_certificate",
|
|
lineage: ":lineage_bin",
|
|
sdk_version: "current",
|
|
}
|
|
|
|
android_app_certificate {
|
|
name: "new_certificate",
|
|
certificate: "cert/new_cert",
|
|
}
|
|
|
|
filegroup {
|
|
name: "lineage_bin",
|
|
srcs: ["lineage.bin"],
|
|
}
|
|
`,
|
|
certificateOverride: "",
|
|
expectedLineage: "--lineage lineage.bin",
|
|
expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8",
|
|
},
|
|
}
|
|
|
|
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}
|
|
}
|
|
}),
|
|
).RunTestWithBp(t, test.bp)
|
|
|
|
foo := result.ModuleForTests("foo", "android_common")
|
|
|
|
signapk := foo.Output("foo.apk")
|
|
signCertificateFlags := signapk.Args["certificates"]
|
|
android.AssertStringEquals(t, "certificates flags", test.expectedCertificate, signCertificateFlags)
|
|
|
|
signFlags := signapk.Args["flags"]
|
|
android.AssertStringEquals(t, "signing flags", test.expectedLineage, signFlags)
|
|
})
|
|
}
|
|
}
|
|
|
|
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",
|
|
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
|
|
lineageFlag 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",
|
|
lineageFlag: "",
|
|
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",
|
|
lineageFlag: "--lineage lineage.bin",
|
|
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",
|
|
lineageFlag: "",
|
|
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",
|
|
lineageFlag: "",
|
|
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",
|
|
lineageFlag: "",
|
|
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",
|
|
lineageFlag: "",
|
|
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 lineage flags
|
|
lineageFlag := signapk.Args["flags"]
|
|
android.AssertStringEquals(t, "signing flags", expected.lineageFlag, lineageFlag)
|
|
|
|
// Check if the overrides field values are correctly aggregated.
|
|
mod := variant.Module().(*AndroidApp)
|
|
android.AssertDeepEquals(t, "overrides property", expected.overrides, mod.appProperties.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 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.appProperties.Overrides) {
|
|
t.Errorf("Incorrect overrides property value, expected: %q, got: %q",
|
|
expected.overrides, mod.appProperties.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",
|
|
}
|
|
|
|
override_android_test {
|
|
name: "baz_test",
|
|
base: "foo_test",
|
|
package_name: "com.android.baz.test",
|
|
}
|
|
`)
|
|
|
|
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",
|
|
},
|
|
},
|
|
{
|
|
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",
|
|
},
|
|
},
|
|
}
|
|
|
|
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"],
|
|
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",
|
|
"baz",
|
|
],
|
|
}
|
|
|
|
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",
|
|
"baz",
|
|
],
|
|
}
|
|
`
|
|
|
|
result := android.GroupFixturePreparers(
|
|
prepareForJavaTest,
|
|
PrepareForTestWithJavaSdkLibraryFiles,
|
|
FixtureWithLastReleaseApis("runtime-library", "foo", "quuz", "qux", "bar", "fred"),
|
|
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
|
|
variables.MissingUsesLibraries = []string{"baz"}
|
|
}),
|
|
).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 qux ` +
|
|
`--uses-library quuz ` +
|
|
`--uses-library foo ` +
|
|
`--uses-library com.non.sdk.lib ` +
|
|
`--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 baz ` +
|
|
`--optional-uses-library runtime-optional-x ` +
|
|
`--optional-uses-library runtime-optional-y `
|
|
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 ` +
|
|
`--optional-uses-library baz `
|
|
android.AssertStringDoesContain(t, "verify apk cmd args", verifyApkCmd, verifyApkArgs)
|
|
|
|
// Test that all present libraries are preopted, including implicit SDK dependencies, possibly stubs
|
|
cmd := app.Rule("dexpreopt").RuleParams.Command
|
|
w := `--target-context-for-sdk any ` +
|
|
`PCL[/system/framework/qux.jar]#` +
|
|
`PCL[/system/framework/quuz.jar]#` +
|
|
`PCL[/system/framework/foo.jar]#` +
|
|
`PCL[/system/framework/non-sdk-lib.jar]#` +
|
|
`PCL[/system/framework/bar.jar]#` +
|
|
`PCL[/system/framework/runtime-library.jar]#` +
|
|
`PCL[/system/framework/runtime-required-x.jar]#` +
|
|
`PCL[/system/framework/runtime-optional-x.jar]#` +
|
|
`PCL[/system/framework/runtime-required-y.jar]#` +
|
|
`PCL[/system/framework/runtime-optional-y.jar] `
|
|
android.AssertStringDoesContain(t, "dexpreopt app cmd args", cmd, w)
|
|
|
|
// Test conditional context for target SDK version 28.
|
|
android.AssertStringDoesContain(t, "dexpreopt app cmd 28", cmd,
|
|
`--target-context-for-sdk 28`+
|
|
` PCL[/system/framework/org.apache.http.legacy.jar] `)
|
|
|
|
// Test conditional context for target SDK version 29.
|
|
android.AssertStringDoesContain(t, "dexpreopt app cmd 29", cmd,
|
|
`--target-context-for-sdk 29`+
|
|
` PCL[/system/framework/android.hidl.manager-V1.0-java.jar]`+
|
|
`#PCL[/system/framework/android.hidl.base-V1.0-java.jar] `)
|
|
|
|
// Test conditional context for target SDK version 30.
|
|
// "android.test.mock" is absent because "android.test.runner" is not used.
|
|
android.AssertStringDoesContain(t, "dexpreopt app cmd 30", cmd,
|
|
`--target-context-for-sdk 30`+
|
|
` PCL[/system/framework/android.test.base.jar] `)
|
|
|
|
cmd = prebuilt.Rule("dexpreopt").RuleParams.Command
|
|
android.AssertStringDoesContain(t, "dexpreopt prebuilt cmd", cmd,
|
|
`--target-context-for-sdk any`+
|
|
` PCL[/system/framework/foo.jar]`+
|
|
`#PCL[/system/framework/non-sdk-lib.jar]`+
|
|
`#PCL[/system/framework/android.test.runner.jar]`+
|
|
`#PCL[/system/framework/bar.jar] `)
|
|
|
|
// Test conditional context for target SDK version 30.
|
|
// "android.test.mock" is present because "android.test.runner" is used.
|
|
android.AssertStringDoesContain(t, "dexpreopt prebuilt cmd 30", cmd,
|
|
`--target-context-for-sdk 30`+
|
|
` PCL[/system/framework/android.test.base.jar]`+
|
|
`#PCL[/system/framework/android.test.mock.jar] `)
|
|
}
|
|
|
|
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"],
|
|
}
|
|
|
|
android_library {
|
|
name: "lib1",
|
|
sdk_version: "current",
|
|
optimize: {
|
|
proguard_flags_files: ["lib1proguard.cfg"],
|
|
}
|
|
}
|
|
`)
|
|
|
|
m := ctx.ModuleForTests("foo", "android_common")
|
|
hasLib1Proguard := false
|
|
for _, s := range m.Rule("java.r8").Implicits.Strings() {
|
|
if s == "lib1proguard.cfg" {
|
|
hasLib1Proguard = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !hasLib1Proguard {
|
|
t.Errorf("App does not use library proguard config")
|
|
}
|
|
}
|
|
|
|
func TestTargetSdkVersionManifestFixer(t *testing.T) {
|
|
platform_sdk_codename := "Tiramisu"
|
|
testCases := []struct {
|
|
name string
|
|
targetSdkVersionInBp string
|
|
targetSdkVersionExpected string
|
|
unbundledBuild 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,
|
|
},
|
|
}
|
|
for _, testCase := range testCases {
|
|
bp := fmt.Sprintf(`
|
|
android_app {
|
|
name: "foo",
|
|
sdk_version: "current",
|
|
target_sdk_version: "%v",
|
|
}
|
|
`, testCase.targetSdkVersionInBp)
|
|
fixture := android.GroupFixturePreparers(
|
|
prepareForJavaTest,
|
|
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
|
|
// explicitly set platform_sdk_codename to make the test deterministic
|
|
variables.Platform_sdk_codename = &platform_sdk_codename
|
|
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 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",
|
|
}`)
|
|
|
|
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")
|
|
}
|