Merge "bp2build: split as, c, and cpp srcs for cc_library"
diff --git a/android/bazel.go b/android/bazel.go
index 4967b12..8c68055 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -220,8 +220,7 @@
// Per-module denylist to opt modules out of mixed builds. Such modules will
// still be generated via bp2build.
mixedBuildsDisabledList = []string{
- "libc_common_shared", // cparsons@ cc_library_static, breaks module `libc`.
- "libc_nomalloc", // cparsons@ cc_library_static, breaks module `linker`
+ // Currently empty, though should remain present to facilitate granular bp2build migration.
}
// Used for quicker lookups
diff --git a/java/java_test.go b/java/java_test.go
index 1b8aec2..bd373c1 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -19,7 +19,6 @@
"os"
"path/filepath"
"reflect"
- "regexp"
"runtime"
"strconv"
"strings"
@@ -655,306 +654,6 @@
})
}
-func TestJavaSdkLibraryImport(t *testing.T) {
- result := prepareForJavaTest.RunTestWithBp(t, `
- java_library {
- name: "foo",
- srcs: ["a.java"],
- libs: ["sdklib"],
- sdk_version: "current",
- }
-
- java_library {
- name: "foo.system",
- srcs: ["a.java"],
- libs: ["sdklib"],
- sdk_version: "system_current",
- }
-
- java_library {
- name: "foo.test",
- srcs: ["a.java"],
- libs: ["sdklib"],
- sdk_version: "test_current",
- }
-
- java_sdk_library_import {
- name: "sdklib",
- public: {
- jars: ["a.jar"],
- },
- system: {
- jars: ["b.jar"],
- },
- test: {
- jars: ["c.jar"],
- stub_srcs: ["c.java"],
- },
- }
- `)
-
- for _, scope := range []string{"", ".system", ".test"} {
- fooModule := result.ModuleForTests("foo"+scope, "android_common")
- javac := fooModule.Rule("javac")
-
- sdklibStubsJar := result.ModuleForTests("sdklib.stubs"+scope, "android_common").Rule("combineJar").Output
- android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], sdklibStubsJar.String())
- }
-
- CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
- `prebuilt_sdklib.stubs`,
- `prebuilt_sdklib.stubs.source.test`,
- `prebuilt_sdklib.stubs.system`,
- `prebuilt_sdklib.stubs.test`,
- })
-}
-
-func TestJavaSdkLibraryImport_WithSource(t *testing.T) {
- result := android.GroupFixturePreparers(
- prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("sdklib"),
- ).RunTestWithBp(t, `
- java_sdk_library {
- name: "sdklib",
- srcs: ["a.java"],
- sdk_version: "none",
- system_modules: "none",
- public: {
- enabled: true,
- },
- }
-
- java_sdk_library_import {
- name: "sdklib",
- public: {
- jars: ["a.jar"],
- },
- }
- `)
-
- CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
- `dex2oatd`,
- `prebuilt_sdklib`,
- `sdklib.impl`,
- `sdklib.stubs`,
- `sdklib.stubs.source`,
- `sdklib.xml`,
- })
-
- CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{
- `prebuilt_sdklib.stubs`,
- `sdklib.impl`,
- // This should be prebuilt_sdklib.stubs but is set to sdklib.stubs because the
- // dependency is added after prebuilts may have been renamed and so has to use
- // the renamed name.
- `sdklib.xml`,
- })
-}
-
-func TestJavaSdkLibraryImport_Preferred(t *testing.T) {
- result := android.GroupFixturePreparers(
- prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("sdklib"),
- ).RunTestWithBp(t, `
- java_sdk_library {
- name: "sdklib",
- srcs: ["a.java"],
- sdk_version: "none",
- system_modules: "none",
- public: {
- enabled: true,
- },
- }
-
- java_sdk_library_import {
- name: "sdklib",
- prefer: true,
- public: {
- jars: ["a.jar"],
- },
- }
- `)
-
- CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
- `dex2oatd`,
- `prebuilt_sdklib`,
- `sdklib.impl`,
- `sdklib.stubs`,
- `sdklib.stubs.source`,
- `sdklib.xml`,
- })
-
- CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{
- `prebuilt_sdklib.stubs`,
- `sdklib.impl`,
- `sdklib.xml`,
- })
-}
-
-func TestJavaSdkLibraryEnforce(t *testing.T) {
- partitionToBpOption := func(partition string) string {
- switch partition {
- case "system":
- return ""
- case "vendor":
- return "soc_specific: true,"
- case "product":
- return "product_specific: true,"
- default:
- panic("Invalid partition group name: " + partition)
- }
- }
-
- type testConfigInfo struct {
- libraryType string
- fromPartition string
- toPartition string
- enforceVendorInterface bool
- enforceProductInterface bool
- enforceJavaSdkLibraryCheck bool
- allowList []string
- }
-
- createPreparer := func(info testConfigInfo) android.FixturePreparer {
- bpFileTemplate := `
- java_library {
- name: "foo",
- srcs: ["foo.java"],
- libs: ["bar"],
- sdk_version: "current",
- %s
- }
-
- %s {
- name: "bar",
- srcs: ["bar.java"],
- sdk_version: "current",
- %s
- }
- `
-
- bpFile := fmt.Sprintf(bpFileTemplate,
- partitionToBpOption(info.fromPartition),
- info.libraryType,
- partitionToBpOption(info.toPartition))
-
- return android.GroupFixturePreparers(
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("bar"),
- android.FixtureWithRootAndroidBp(bpFile),
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.EnforceProductPartitionInterface = proptools.BoolPtr(info.enforceProductInterface)
- if info.enforceVendorInterface {
- variables.DeviceVndkVersion = proptools.StringPtr("current")
- }
- variables.EnforceInterPartitionJavaSdkLibrary = proptools.BoolPtr(info.enforceJavaSdkLibraryCheck)
- variables.InterPartitionJavaLibraryAllowList = info.allowList
- }),
- )
- }
-
- runTest := func(t *testing.T, info testConfigInfo, expectedErrorPattern string) {
- t.Run(fmt.Sprintf("%v", info), func(t *testing.T) {
- errorHandler := android.FixtureExpectsNoErrors
- if expectedErrorPattern != "" {
- errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorPattern)
- }
- android.GroupFixturePreparers(
- prepareForJavaTest,
- createPreparer(info),
- ).
- ExtendWithErrorHandler(errorHandler).
- RunTest(t)
- })
- }
-
- errorMessage := "is not allowed across the partitions"
-
- runTest(t, testConfigInfo{
- libraryType: "java_library",
- fromPartition: "product",
- toPartition: "system",
- enforceVendorInterface: true,
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: false,
- }, "")
-
- runTest(t, testConfigInfo{
- libraryType: "java_library",
- fromPartition: "product",
- toPartition: "system",
- enforceVendorInterface: true,
- enforceProductInterface: false,
- enforceJavaSdkLibraryCheck: true,
- }, "")
-
- runTest(t, testConfigInfo{
- libraryType: "java_library",
- fromPartition: "product",
- toPartition: "system",
- enforceVendorInterface: true,
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: true,
- }, errorMessage)
-
- runTest(t, testConfigInfo{
- libraryType: "java_library",
- fromPartition: "vendor",
- toPartition: "system",
- enforceVendorInterface: true,
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: true,
- }, errorMessage)
-
- runTest(t, testConfigInfo{
- libraryType: "java_library",
- fromPartition: "vendor",
- toPartition: "system",
- enforceVendorInterface: true,
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: true,
- allowList: []string{"bar"},
- }, "")
-
- runTest(t, testConfigInfo{
- libraryType: "java_library",
- fromPartition: "vendor",
- toPartition: "product",
- enforceVendorInterface: true,
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: true,
- }, errorMessage)
-
- runTest(t, testConfigInfo{
- libraryType: "java_sdk_library",
- fromPartition: "product",
- toPartition: "system",
- enforceVendorInterface: true,
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: true,
- }, "")
-
- runTest(t, testConfigInfo{
- libraryType: "java_sdk_library",
- fromPartition: "vendor",
- toPartition: "system",
- enforceVendorInterface: true,
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: true,
- }, "")
-
- runTest(t, testConfigInfo{
- libraryType: "java_sdk_library",
- fromPartition: "vendor",
- toPartition: "product",
- enforceVendorInterface: true,
- enforceProductInterface: true,
- enforceJavaSdkLibraryCheck: true,
- }, "")
-}
-
func TestDefaults(t *testing.T) {
ctx, _ := testJava(t, `
java_defaults {
@@ -1411,521 +1110,6 @@
})
}
-func TestJavaSdkLibrary(t *testing.T) {
- result := android.GroupFixturePreparers(
- prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithPrebuiltApis(map[string][]string{
- "28": {"foo"},
- "29": {"foo"},
- "30": {"bar", "barney", "baz", "betty", "foo", "fred", "quuz", "wilma"},
- }),
- ).RunTestWithBp(t, `
- droiddoc_exported_dir {
- name: "droiddoc-templates-sdk",
- path: ".",
- }
- java_sdk_library {
- name: "foo",
- srcs: ["a.java", "b.java"],
- api_packages: ["foo"],
- }
- java_sdk_library {
- name: "bar",
- srcs: ["a.java", "b.java"],
- api_packages: ["bar"],
- }
- java_library {
- name: "baz",
- srcs: ["c.java"],
- libs: ["foo", "bar.stubs"],
- sdk_version: "system_current",
- }
- java_sdk_library {
- name: "barney",
- srcs: ["c.java"],
- api_only: true,
- }
- java_sdk_library {
- name: "betty",
- srcs: ["c.java"],
- shared_library: false,
- }
- java_sdk_library_import {
- name: "quuz",
- public: {
- jars: ["c.jar"],
- },
- }
- java_sdk_library_import {
- name: "fred",
- public: {
- jars: ["b.jar"],
- },
- }
- java_sdk_library_import {
- name: "wilma",
- public: {
- jars: ["b.jar"],
- },
- shared_library: false,
- }
- java_library {
- name: "qux",
- srcs: ["c.java"],
- libs: ["baz", "fred", "quuz.stubs", "wilma", "barney", "betty"],
- sdk_version: "system_current",
- }
- java_library {
- name: "baz-test",
- srcs: ["c.java"],
- libs: ["foo"],
- sdk_version: "test_current",
- }
- java_library {
- name: "baz-29",
- srcs: ["c.java"],
- libs: ["foo"],
- sdk_version: "system_29",
- }
- java_library {
- name: "baz-module-30",
- srcs: ["c.java"],
- libs: ["foo"],
- sdk_version: "module_30",
- }
- `)
-
- // check the existence of the internal modules
- result.ModuleForTests("foo", "android_common")
- result.ModuleForTests(apiScopePublic.stubsLibraryModuleName("foo"), "android_common")
- result.ModuleForTests(apiScopeSystem.stubsLibraryModuleName("foo"), "android_common")
- result.ModuleForTests(apiScopeTest.stubsLibraryModuleName("foo"), "android_common")
- result.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo"), "android_common")
- result.ModuleForTests(apiScopeSystem.stubsSourceModuleName("foo"), "android_common")
- result.ModuleForTests(apiScopeTest.stubsSourceModuleName("foo"), "android_common")
- result.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
- result.ModuleForTests("foo.api.public.28", "")
- result.ModuleForTests("foo.api.system.28", "")
- result.ModuleForTests("foo.api.test.28", "")
-
- bazJavac := result.ModuleForTests("baz", "android_common").Rule("javac")
- // tests if baz is actually linked to the stubs lib
- android.AssertStringDoesContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.system.jar")
- // ... and not to the impl lib
- android.AssertStringDoesNotContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.jar")
- // test if baz is not linked to the system variant of foo
- android.AssertStringDoesNotContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.jar")
-
- bazTestJavac := result.ModuleForTests("baz-test", "android_common").Rule("javac")
- // tests if baz-test is actually linked to the test stubs lib
- android.AssertStringDoesContain(t, "baz-test javac classpath", bazTestJavac.Args["classpath"], "foo.stubs.test.jar")
-
- baz29Javac := result.ModuleForTests("baz-29", "android_common").Rule("javac")
- // tests if baz-29 is actually linked to the system 29 stubs lib
- android.AssertStringDoesContain(t, "baz-29 javac classpath", baz29Javac.Args["classpath"], "prebuilts/sdk/29/system/foo.jar")
-
- bazModule30Javac := result.ModuleForTests("baz-module-30", "android_common").Rule("javac")
- // tests if "baz-module-30" is actually linked to the module 30 stubs lib
- android.AssertStringDoesContain(t, "baz-module-30 javac classpath", bazModule30Javac.Args["classpath"], "prebuilts/sdk/30/module-lib/foo.jar")
-
- // test if baz has exported SDK lib names foo and bar to qux
- qux := result.ModuleForTests("qux", "android_common")
- if quxLib, ok := qux.Module().(*Library); ok {
- sdkLibs := quxLib.ClassLoaderContexts().UsesLibs()
- android.AssertDeepEquals(t, "qux exports", []string{"foo", "bar", "fred", "quuz"}, sdkLibs)
- }
-}
-
-func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) {
- result := android.GroupFixturePreparers(
- prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("sdklib"),
- ).RunTestWithBp(t, `
- java_sdk_library {
- name: "sdklib",
- srcs: ["a.java"],
- libs: ["lib"],
- static_libs: ["static-lib"],
- impl_only_libs: ["impl-only-lib"],
- stub_only_libs: ["stub-only-lib"],
- stub_only_static_libs: ["stub-only-static-lib"],
- }
- java_defaults {
- name: "defaults",
- srcs: ["a.java"],
- sdk_version: "current",
- }
- java_library { name: "lib", defaults: ["defaults"] }
- java_library { name: "static-lib", defaults: ["defaults"] }
- java_library { name: "impl-only-lib", defaults: ["defaults"] }
- java_library { name: "stub-only-lib", defaults: ["defaults"] }
- java_library { name: "stub-only-static-lib", defaults: ["defaults"] }
- `)
- var expectations = []struct {
- lib string
- on_impl_classpath bool
- on_stub_classpath bool
- in_impl_combined bool
- in_stub_combined bool
- }{
- {lib: "lib", on_impl_classpath: true},
- {lib: "static-lib", in_impl_combined: true},
- {lib: "impl-only-lib", on_impl_classpath: true},
- {lib: "stub-only-lib", on_stub_classpath: true},
- {lib: "stub-only-static-lib", in_stub_combined: true},
- }
- verify := func(sdklib, dep string, cp, combined bool) {
- sdklibCp := result.ModuleForTests(sdklib, "android_common").Rule("javac").Args["classpath"]
- expected := cp || combined // Every combined jar is also on the classpath.
- android.AssertStringContainsEquals(t, "bad classpath for "+sdklib, sdklibCp, "/"+dep+".jar", expected)
-
- combineJarInputs := result.ModuleForTests(sdklib, "android_common").Rule("combineJar").Inputs.Strings()
- depPath := filepath.Join("out", "soong", ".intermediates", dep, "android_common", "turbine-combined", dep+".jar")
- android.AssertStringListContainsEquals(t, "bad combined inputs for "+sdklib, combineJarInputs, depPath, combined)
- }
- for _, expectation := range expectations {
- verify("sdklib", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined)
- verify("sdklib.impl", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined)
-
- stubName := apiScopePublic.stubsLibraryModuleName("sdklib")
- verify(stubName, expectation.lib, expectation.on_stub_classpath, expectation.in_stub_combined)
- }
-}
-
-func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) {
- result := android.GroupFixturePreparers(
- prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("foo"),
- ).RunTestWithBp(t, `
- java_sdk_library {
- name: "foo",
- srcs: ["a.java"],
- api_only: true,
- public: {
- enabled: true,
- },
- }
-
- java_library {
- name: "bar",
- srcs: ["b.java"],
- libs: ["foo"],
- }
- `)
-
- // The bar library should depend on the stubs jar.
- barLibrary := result.ModuleForTests("bar", "android_common").Rule("javac")
- if expected, actual := `^-classpath .*:out/soong/[^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
- t.Errorf("expected %q, found %#q", expected, actual)
- }
-}
-
-func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) {
- android.GroupFixturePreparers(
- prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("foo"),
- ).RunTestWithBp(t, `
- java_sdk_library {
- name: "foo",
- srcs: ["a.java"],
- api_packages: ["foo"],
- public: {
- enabled: true,
- },
- }
-
- java_library {
- name: "bar",
- srcs: ["b.java", ":foo{.public.stubs.source}"],
- }
- `)
-}
-
-func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) {
- android.GroupFixturePreparers(
- prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("foo"),
- ).
- ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`"foo" does not provide api scope system`)).
- RunTestWithBp(t, `
- java_sdk_library {
- name: "foo",
- srcs: ["a.java"],
- api_packages: ["foo"],
- public: {
- enabled: true,
- },
- }
-
- java_library {
- name: "bar",
- srcs: ["b.java", ":foo{.system.stubs.source}"],
- }
- `)
-}
-
-func TestJavaSdkLibrary_Deps(t *testing.T) {
- result := android.GroupFixturePreparers(
- prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("sdklib"),
- ).RunTestWithBp(t, `
- java_sdk_library {
- name: "sdklib",
- srcs: ["a.java"],
- sdk_version: "none",
- system_modules: "none",
- public: {
- enabled: true,
- },
- }
- `)
-
- CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
- `dex2oatd`,
- `sdklib.impl`,
- `sdklib.stubs`,
- `sdklib.stubs.source`,
- `sdklib.xml`,
- })
-}
-
-func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) {
- prepareForJavaTest.RunTestWithBp(t, `
- java_sdk_library_import {
- name: "foo",
- public: {
- jars: ["a.jar"],
- stub_srcs: ["a.java"],
- current_api: "api/current.txt",
- removed_api: "api/removed.txt",
- },
- }
-
- java_library {
- name: "bar",
- srcs: [":foo{.public.stubs.source}"],
- java_resources: [
- ":foo{.public.api.txt}",
- ":foo{.public.removed-api.txt}",
- ],
- }
- `)
-}
-
-func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) {
- bp := `
- java_sdk_library_import {
- name: "foo",
- public: {
- jars: ["a.jar"],
- },
- }
- `
-
- t.Run("stubs.source", func(t *testing.T) {
- prepareForJavaTest.
- ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`stubs.source not available for api scope public`)).
- RunTestWithBp(t, bp+`
- java_library {
- name: "bar",
- srcs: [":foo{.public.stubs.source}"],
- java_resources: [
- ":foo{.public.api.txt}",
- ":foo{.public.removed-api.txt}",
- ],
- }
- `)
- })
-
- t.Run("api.txt", func(t *testing.T) {
- prepareForJavaTest.
- ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`api.txt not available for api scope public`)).
- RunTestWithBp(t, bp+`
- java_library {
- name: "bar",
- srcs: ["a.java"],
- java_resources: [
- ":foo{.public.api.txt}",
- ],
- }
- `)
- })
-
- t.Run("removed-api.txt", func(t *testing.T) {
- prepareForJavaTest.
- ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`removed-api.txt not available for api scope public`)).
- RunTestWithBp(t, bp+`
- java_library {
- name: "bar",
- srcs: ["a.java"],
- java_resources: [
- ":foo{.public.removed-api.txt}",
- ],
- }
- `)
- })
-}
-
-func TestJavaSdkLibrary_InvalidScopes(t *testing.T) {
- prepareForJavaTest.
- ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo": enabled api scope "system" depends on disabled scope "public"`)).
- RunTestWithBp(t, `
- java_sdk_library {
- name: "foo",
- srcs: ["a.java", "b.java"],
- api_packages: ["foo"],
- // Explicitly disable public to test the check that ensures the set of enabled
- // scopes is consistent.
- public: {
- enabled: false,
- },
- system: {
- enabled: true,
- },
- }
- `)
-}
-
-func TestJavaSdkLibrary_SdkVersion_ForScope(t *testing.T) {
- android.GroupFixturePreparers(
- prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("foo"),
- ).RunTestWithBp(t, `
- java_sdk_library {
- name: "foo",
- srcs: ["a.java", "b.java"],
- api_packages: ["foo"],
- system: {
- enabled: true,
- sdk_version: "module_current",
- },
- }
- `)
-}
-
-func TestJavaSdkLibrary_ModuleLib(t *testing.T) {
- android.GroupFixturePreparers(
- prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("foo"),
- ).RunTestWithBp(t, `
- java_sdk_library {
- name: "foo",
- srcs: ["a.java", "b.java"],
- api_packages: ["foo"],
- system: {
- enabled: true,
- },
- module_lib: {
- enabled: true,
- },
- }
- `)
-}
-
-func TestJavaSdkLibrary_SystemServer(t *testing.T) {
- android.GroupFixturePreparers(
- prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("foo"),
- ).RunTestWithBp(t, `
- java_sdk_library {
- name: "foo",
- srcs: ["a.java", "b.java"],
- api_packages: ["foo"],
- system: {
- enabled: true,
- },
- system_server: {
- enabled: true,
- },
- }
- `)
-}
-
-func TestJavaSdkLibrary_MissingScope(t *testing.T) {
- prepareForJavaTest.
- ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`requires api scope module-lib from foo but it only has \[\] available`)).
- RunTestWithBp(t, `
- java_sdk_library {
- name: "foo",
- srcs: ["a.java"],
- public: {
- enabled: false,
- },
- }
-
- java_library {
- name: "baz",
- srcs: ["a.java"],
- libs: ["foo"],
- sdk_version: "module_current",
- }
- `)
-}
-
-func TestJavaSdkLibrary_FallbackScope(t *testing.T) {
- android.GroupFixturePreparers(
- prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("foo"),
- ).RunTestWithBp(t, `
- java_sdk_library {
- name: "foo",
- srcs: ["a.java"],
- system: {
- enabled: true,
- },
- }
-
- java_library {
- name: "baz",
- srcs: ["a.java"],
- libs: ["foo"],
- // foo does not have module-lib scope so it should fallback to system
- sdk_version: "module_current",
- }
- `)
-}
-
-func TestJavaSdkLibrary_DefaultToStubs(t *testing.T) {
- result := android.GroupFixturePreparers(
- prepareForJavaTest,
- PrepareForTestWithJavaSdkLibraryFiles,
- FixtureWithLastReleaseApis("foo"),
- ).RunTestWithBp(t, `
- java_sdk_library {
- name: "foo",
- srcs: ["a.java"],
- system: {
- enabled: true,
- },
- default_to_stubs: true,
- }
-
- java_library {
- name: "baz",
- srcs: ["a.java"],
- libs: ["foo"],
- // does not have sdk_version set, should fallback to module,
- // which will then fallback to system because the module scope
- // is not enabled.
- }
- `)
- // The baz library should depend on the system stubs jar.
- bazLibrary := result.ModuleForTests("baz", "android_common").Rule("javac")
- if expected, actual := `^-classpath .*:out/soong/[^:]*/turbine-combined/foo\.stubs.system\.jar$`, bazLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
- t.Errorf("expected %q, found %#q", expected, actual)
- }
-}
-
var compilerFlagsTestCases = []struct {
in string
out bool
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 8f36758..ecf2b1a 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -457,6 +457,11 @@
// * API incompatibilities baseline filegroup -> <dist-stem>-incompatibilities.api.<scope>.latest
Dist_stem *string
+ // The subdirectory for the artifacts that are copied to the dist directory. If not specified
+ // then defaults to "android". Should be set to "android" for anything that should be published
+ // in the public Android SDK.
+ Dist_group *string
+
// A compatibility mode that allows historical API-tracking files to not exist.
// Do not use.
Unsafe_ignore_missing_latest_api bool
@@ -1198,12 +1203,10 @@
// The dist path of the stub artifacts
func (module *SdkLibrary) apiDistPath(apiScope *apiScope) string {
- if module.ModuleBase.Owner() != "" {
- return path.Join("apistubs", module.ModuleBase.Owner(), apiScope.name)
- } else if Bool(module.sdkLibraryProperties.Core_lib) {
+ if Bool(module.sdkLibraryProperties.Core_lib) {
return path.Join("apistubs", "core", apiScope.name)
} else {
- return path.Join("apistubs", "android", apiScope.name)
+ return path.Join("apistubs", module.distGroup(), apiScope.name)
}
}
@@ -1228,6 +1231,19 @@
return proptools.StringDefault(module.sdkLibraryProperties.Dist_stem, module.BaseModuleName())
}
+// distGroup returns the subdirectory of the dist path of the stub artifacts.
+func (module *SdkLibrary) distGroup() string {
+ if group := proptools.String(module.sdkLibraryProperties.Dist_group); group != "" {
+ return group
+ }
+ // TODO(b/186723288): Remove this once everything uses dist_group.
+ if owner := module.ModuleBase.Owner(); owner != "" {
+ return owner
+ }
+ // TODO(b/186723288): Make this "unknown".
+ return "android"
+}
+
func (module *SdkLibrary) latestApiFilegroupName(apiScope *apiScope) string {
return ":" + module.distStem() + ".api." + apiScope.name + ".latest"
}
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
new file mode 100644
index 0000000..0fe6e72
--- /dev/null
+++ b/java/sdk_library_test.go
@@ -0,0 +1,931 @@
+// Copyright 2021 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 (
+ "android/soong/android"
+ "fmt"
+ "path/filepath"
+ "regexp"
+ "testing"
+
+ "github.com/google/blueprint/proptools"
+)
+
+func TestJavaSdkLibrary(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithPrebuiltApis(map[string][]string{
+ "28": {"foo"},
+ "29": {"foo"},
+ "30": {"bar", "barney", "baz", "betty", "foo", "fred", "quuz", "wilma"},
+ }),
+ ).RunTestWithBp(t, `
+ droiddoc_exported_dir {
+ name: "droiddoc-templates-sdk",
+ path: ".",
+ }
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ }
+ java_sdk_library {
+ name: "bar",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["bar"],
+ }
+ java_library {
+ name: "baz",
+ srcs: ["c.java"],
+ libs: ["foo", "bar.stubs"],
+ sdk_version: "system_current",
+ }
+ java_sdk_library {
+ name: "barney",
+ srcs: ["c.java"],
+ api_only: true,
+ }
+ java_sdk_library {
+ name: "betty",
+ srcs: ["c.java"],
+ shared_library: false,
+ }
+ java_sdk_library_import {
+ name: "quuz",
+ public: {
+ jars: ["c.jar"],
+ },
+ }
+ java_sdk_library_import {
+ name: "fred",
+ public: {
+ jars: ["b.jar"],
+ },
+ }
+ java_sdk_library_import {
+ name: "wilma",
+ public: {
+ jars: ["b.jar"],
+ },
+ shared_library: false,
+ }
+ java_library {
+ name: "qux",
+ srcs: ["c.java"],
+ libs: ["baz", "fred", "quuz.stubs", "wilma", "barney", "betty"],
+ sdk_version: "system_current",
+ }
+ java_library {
+ name: "baz-test",
+ srcs: ["c.java"],
+ libs: ["foo"],
+ sdk_version: "test_current",
+ }
+ java_library {
+ name: "baz-29",
+ srcs: ["c.java"],
+ libs: ["foo"],
+ sdk_version: "system_29",
+ }
+ java_library {
+ name: "baz-module-30",
+ srcs: ["c.java"],
+ libs: ["foo"],
+ sdk_version: "module_30",
+ }
+ `)
+
+ // check the existence of the internal modules
+ result.ModuleForTests("foo", "android_common")
+ result.ModuleForTests(apiScopePublic.stubsLibraryModuleName("foo"), "android_common")
+ result.ModuleForTests(apiScopeSystem.stubsLibraryModuleName("foo"), "android_common")
+ result.ModuleForTests(apiScopeTest.stubsLibraryModuleName("foo"), "android_common")
+ result.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo"), "android_common")
+ result.ModuleForTests(apiScopeSystem.stubsSourceModuleName("foo"), "android_common")
+ result.ModuleForTests(apiScopeTest.stubsSourceModuleName("foo"), "android_common")
+ result.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
+ result.ModuleForTests("foo.api.public.28", "")
+ result.ModuleForTests("foo.api.system.28", "")
+ result.ModuleForTests("foo.api.test.28", "")
+
+ bazJavac := result.ModuleForTests("baz", "android_common").Rule("javac")
+ // tests if baz is actually linked to the stubs lib
+ android.AssertStringDoesContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.system.jar")
+ // ... and not to the impl lib
+ android.AssertStringDoesNotContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.jar")
+ // test if baz is not linked to the system variant of foo
+ android.AssertStringDoesNotContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.jar")
+
+ bazTestJavac := result.ModuleForTests("baz-test", "android_common").Rule("javac")
+ // tests if baz-test is actually linked to the test stubs lib
+ android.AssertStringDoesContain(t, "baz-test javac classpath", bazTestJavac.Args["classpath"], "foo.stubs.test.jar")
+
+ baz29Javac := result.ModuleForTests("baz-29", "android_common").Rule("javac")
+ // tests if baz-29 is actually linked to the system 29 stubs lib
+ android.AssertStringDoesContain(t, "baz-29 javac classpath", baz29Javac.Args["classpath"], "prebuilts/sdk/29/system/foo.jar")
+
+ bazModule30Javac := result.ModuleForTests("baz-module-30", "android_common").Rule("javac")
+ // tests if "baz-module-30" is actually linked to the module 30 stubs lib
+ android.AssertStringDoesContain(t, "baz-module-30 javac classpath", bazModule30Javac.Args["classpath"], "prebuilts/sdk/30/module-lib/foo.jar")
+
+ // test if baz has exported SDK lib names foo and bar to qux
+ qux := result.ModuleForTests("qux", "android_common")
+ if quxLib, ok := qux.Module().(*Library); ok {
+ sdkLibs := quxLib.ClassLoaderContexts().UsesLibs()
+ android.AssertDeepEquals(t, "qux exports", []string{"foo", "bar", "fred", "quuz"}, sdkLibs)
+ }
+}
+
+func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("sdklib"),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ libs: ["lib"],
+ static_libs: ["static-lib"],
+ impl_only_libs: ["impl-only-lib"],
+ stub_only_libs: ["stub-only-lib"],
+ stub_only_static_libs: ["stub-only-static-lib"],
+ }
+ java_defaults {
+ name: "defaults",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ }
+ java_library { name: "lib", defaults: ["defaults"] }
+ java_library { name: "static-lib", defaults: ["defaults"] }
+ java_library { name: "impl-only-lib", defaults: ["defaults"] }
+ java_library { name: "stub-only-lib", defaults: ["defaults"] }
+ java_library { name: "stub-only-static-lib", defaults: ["defaults"] }
+ `)
+ var expectations = []struct {
+ lib string
+ on_impl_classpath bool
+ on_stub_classpath bool
+ in_impl_combined bool
+ in_stub_combined bool
+ }{
+ {lib: "lib", on_impl_classpath: true},
+ {lib: "static-lib", in_impl_combined: true},
+ {lib: "impl-only-lib", on_impl_classpath: true},
+ {lib: "stub-only-lib", on_stub_classpath: true},
+ {lib: "stub-only-static-lib", in_stub_combined: true},
+ }
+ verify := func(sdklib, dep string, cp, combined bool) {
+ sdklibCp := result.ModuleForTests(sdklib, "android_common").Rule("javac").Args["classpath"]
+ expected := cp || combined // Every combined jar is also on the classpath.
+ android.AssertStringContainsEquals(t, "bad classpath for "+sdklib, sdklibCp, "/"+dep+".jar", expected)
+
+ combineJarInputs := result.ModuleForTests(sdklib, "android_common").Rule("combineJar").Inputs.Strings()
+ depPath := filepath.Join("out", "soong", ".intermediates", dep, "android_common", "turbine-combined", dep+".jar")
+ android.AssertStringListContainsEquals(t, "bad combined inputs for "+sdklib, combineJarInputs, depPath, combined)
+ }
+ for _, expectation := range expectations {
+ verify("sdklib", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined)
+ verify("sdklib.impl", expectation.lib, expectation.on_impl_classpath, expectation.in_impl_combined)
+
+ stubName := apiScopePublic.stubsLibraryModuleName("sdklib")
+ verify(stubName, expectation.lib, expectation.on_stub_classpath, expectation.in_stub_combined)
+ }
+}
+
+func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ api_only: true,
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ libs: ["foo"],
+ }
+ `)
+
+ // The bar library should depend on the stubs jar.
+ barLibrary := result.ModuleForTests("bar", "android_common").Rule("javac")
+ if expected, actual := `^-classpath .*:out/soong/[^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
+ t.Errorf("expected %q, found %#q", expected, actual)
+ }
+}
+
+func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ api_packages: ["foo"],
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java", ":foo{.public.stubs.source}"],
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`"foo" does not provide api scope system`)).
+ RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ api_packages: ["foo"],
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java", ":foo{.system.stubs.source}"],
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_Deps(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("sdklib"),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ public: {
+ enabled: true,
+ },
+ }
+ `)
+
+ CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
+ `dex2oatd`,
+ `sdklib.impl`,
+ `sdklib.stubs`,
+ `sdklib.stubs.source`,
+ `sdklib.xml`,
+ })
+}
+
+func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) {
+ prepareForJavaTest.RunTestWithBp(t, `
+ java_sdk_library_import {
+ name: "foo",
+ public: {
+ jars: ["a.jar"],
+ stub_srcs: ["a.java"],
+ current_api: "api/current.txt",
+ removed_api: "api/removed.txt",
+ },
+ }
+
+ java_library {
+ name: "bar",
+ srcs: [":foo{.public.stubs.source}"],
+ java_resources: [
+ ":foo{.public.api.txt}",
+ ":foo{.public.removed-api.txt}",
+ ],
+ }
+ `)
+}
+
+func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) {
+ bp := `
+ java_sdk_library_import {
+ name: "foo",
+ public: {
+ jars: ["a.jar"],
+ },
+ }
+ `
+
+ t.Run("stubs.source", func(t *testing.T) {
+ prepareForJavaTest.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`stubs.source not available for api scope public`)).
+ RunTestWithBp(t, bp+`
+ java_library {
+ name: "bar",
+ srcs: [":foo{.public.stubs.source}"],
+ java_resources: [
+ ":foo{.public.api.txt}",
+ ":foo{.public.removed-api.txt}",
+ ],
+ }
+ `)
+ })
+
+ t.Run("api.txt", func(t *testing.T) {
+ prepareForJavaTest.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`api.txt not available for api scope public`)).
+ RunTestWithBp(t, bp+`
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ java_resources: [
+ ":foo{.public.api.txt}",
+ ],
+ }
+ `)
+ })
+
+ t.Run("removed-api.txt", func(t *testing.T) {
+ prepareForJavaTest.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`removed-api.txt not available for api scope public`)).
+ RunTestWithBp(t, bp+`
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ java_resources: [
+ ":foo{.public.removed-api.txt}",
+ ],
+ }
+ `)
+ })
+}
+
+func TestJavaSdkLibrary_InvalidScopes(t *testing.T) {
+ prepareForJavaTest.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo": enabled api scope "system" depends on disabled scope "public"`)).
+ RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ // Explicitly disable public to test the check that ensures the set of enabled
+ // scopes is consistent.
+ public: {
+ enabled: false,
+ },
+ system: {
+ enabled: true,
+ },
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_SdkVersion_ForScope(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ system: {
+ enabled: true,
+ sdk_version: "module_current",
+ },
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_ModuleLib(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ system: {
+ enabled: true,
+ },
+ module_lib: {
+ enabled: true,
+ },
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_SystemServer(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ system: {
+ enabled: true,
+ },
+ system_server: {
+ enabled: true,
+ },
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_MissingScope(t *testing.T) {
+ prepareForJavaTest.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`requires api scope module-lib from foo but it only has \[\] available`)).
+ RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ public: {
+ enabled: false,
+ },
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["a.java"],
+ libs: ["foo"],
+ sdk_version: "module_current",
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_FallbackScope(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ system: {
+ enabled: true,
+ },
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["a.java"],
+ libs: ["foo"],
+ // foo does not have module-lib scope so it should fallback to system
+ sdk_version: "module_current",
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_DefaultToStubs(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ system: {
+ enabled: true,
+ },
+ default_to_stubs: true,
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["a.java"],
+ libs: ["foo"],
+ // does not have sdk_version set, should fallback to module,
+ // which will then fallback to system because the module scope
+ // is not enabled.
+ }
+ `)
+ // The baz library should depend on the system stubs jar.
+ bazLibrary := result.ModuleForTests("baz", "android_common").Rule("javac")
+ if expected, actual := `^-classpath .*:out/soong/[^:]*/turbine-combined/foo\.stubs.system\.jar$`, bazLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
+ t.Errorf("expected %q, found %#q", expected, actual)
+ }
+}
+
+func TestJavaSdkLibraryImport(t *testing.T) {
+ result := prepareForJavaTest.RunTestWithBp(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ libs: ["sdklib"],
+ sdk_version: "current",
+ }
+
+ java_library {
+ name: "foo.system",
+ srcs: ["a.java"],
+ libs: ["sdklib"],
+ sdk_version: "system_current",
+ }
+
+ java_library {
+ name: "foo.test",
+ srcs: ["a.java"],
+ libs: ["sdklib"],
+ sdk_version: "test_current",
+ }
+
+ java_sdk_library_import {
+ name: "sdklib",
+ public: {
+ jars: ["a.jar"],
+ },
+ system: {
+ jars: ["b.jar"],
+ },
+ test: {
+ jars: ["c.jar"],
+ stub_srcs: ["c.java"],
+ },
+ }
+ `)
+
+ for _, scope := range []string{"", ".system", ".test"} {
+ fooModule := result.ModuleForTests("foo"+scope, "android_common")
+ javac := fooModule.Rule("javac")
+
+ sdklibStubsJar := result.ModuleForTests("sdklib.stubs"+scope, "android_common").Rule("combineJar").Output
+ android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], sdklibStubsJar.String())
+ }
+
+ CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
+ `prebuilt_sdklib.stubs`,
+ `prebuilt_sdklib.stubs.source.test`,
+ `prebuilt_sdklib.stubs.system`,
+ `prebuilt_sdklib.stubs.test`,
+ })
+}
+
+func TestJavaSdkLibraryImport_WithSource(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("sdklib"),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_sdk_library_import {
+ name: "sdklib",
+ public: {
+ jars: ["a.jar"],
+ },
+ }
+ `)
+
+ CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
+ `dex2oatd`,
+ `prebuilt_sdklib`,
+ `sdklib.impl`,
+ `sdklib.stubs`,
+ `sdklib.stubs.source`,
+ `sdklib.xml`,
+ })
+
+ CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{
+ `prebuilt_sdklib.stubs`,
+ `sdklib.impl`,
+ // This should be prebuilt_sdklib.stubs but is set to sdklib.stubs because the
+ // dependency is added after prebuilts may have been renamed and so has to use
+ // the renamed name.
+ `sdklib.xml`,
+ })
+}
+
+func TestJavaSdkLibraryImport_Preferred(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForJavaTest,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("sdklib"),
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_sdk_library_import {
+ name: "sdklib",
+ prefer: true,
+ public: {
+ jars: ["a.jar"],
+ },
+ }
+ `)
+
+ CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
+ `dex2oatd`,
+ `prebuilt_sdklib`,
+ `sdklib.impl`,
+ `sdklib.stubs`,
+ `sdklib.stubs.source`,
+ `sdklib.xml`,
+ })
+
+ CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{
+ `prebuilt_sdklib.stubs`,
+ `sdklib.impl`,
+ `sdklib.xml`,
+ })
+}
+
+func TestJavaSdkLibraryEnforce(t *testing.T) {
+ partitionToBpOption := func(partition string) string {
+ switch partition {
+ case "system":
+ return ""
+ case "vendor":
+ return "soc_specific: true,"
+ case "product":
+ return "product_specific: true,"
+ default:
+ panic("Invalid partition group name: " + partition)
+ }
+ }
+
+ type testConfigInfo struct {
+ libraryType string
+ fromPartition string
+ toPartition string
+ enforceVendorInterface bool
+ enforceProductInterface bool
+ enforceJavaSdkLibraryCheck bool
+ allowList []string
+ }
+
+ createPreparer := func(info testConfigInfo) android.FixturePreparer {
+ bpFileTemplate := `
+ java_library {
+ name: "foo",
+ srcs: ["foo.java"],
+ libs: ["bar"],
+ sdk_version: "current",
+ %s
+ }
+
+ %s {
+ name: "bar",
+ srcs: ["bar.java"],
+ sdk_version: "current",
+ %s
+ }
+ `
+
+ bpFile := fmt.Sprintf(bpFileTemplate,
+ partitionToBpOption(info.fromPartition),
+ info.libraryType,
+ partitionToBpOption(info.toPartition))
+
+ return android.GroupFixturePreparers(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("bar"),
+ android.FixtureWithRootAndroidBp(bpFile),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.EnforceProductPartitionInterface = proptools.BoolPtr(info.enforceProductInterface)
+ if info.enforceVendorInterface {
+ variables.DeviceVndkVersion = proptools.StringPtr("current")
+ }
+ variables.EnforceInterPartitionJavaSdkLibrary = proptools.BoolPtr(info.enforceJavaSdkLibraryCheck)
+ variables.InterPartitionJavaLibraryAllowList = info.allowList
+ }),
+ )
+ }
+
+ runTest := func(t *testing.T, info testConfigInfo, expectedErrorPattern string) {
+ t.Run(fmt.Sprintf("%v", info), func(t *testing.T) {
+ errorHandler := android.FixtureExpectsNoErrors
+ if expectedErrorPattern != "" {
+ errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorPattern)
+ }
+ android.GroupFixturePreparers(
+ prepareForJavaTest,
+ createPreparer(info),
+ ).
+ ExtendWithErrorHandler(errorHandler).
+ RunTest(t)
+ })
+ }
+
+ errorMessage := "is not allowed across the partitions"
+
+ runTest(t, testConfigInfo{
+ libraryType: "java_library",
+ fromPartition: "product",
+ toPartition: "system",
+ enforceVendorInterface: true,
+ enforceProductInterface: true,
+ enforceJavaSdkLibraryCheck: false,
+ }, "")
+
+ runTest(t, testConfigInfo{
+ libraryType: "java_library",
+ fromPartition: "product",
+ toPartition: "system",
+ enforceVendorInterface: true,
+ enforceProductInterface: false,
+ enforceJavaSdkLibraryCheck: true,
+ }, "")
+
+ runTest(t, testConfigInfo{
+ libraryType: "java_library",
+ fromPartition: "product",
+ toPartition: "system",
+ enforceVendorInterface: true,
+ enforceProductInterface: true,
+ enforceJavaSdkLibraryCheck: true,
+ }, errorMessage)
+
+ runTest(t, testConfigInfo{
+ libraryType: "java_library",
+ fromPartition: "vendor",
+ toPartition: "system",
+ enforceVendorInterface: true,
+ enforceProductInterface: true,
+ enforceJavaSdkLibraryCheck: true,
+ }, errorMessage)
+
+ runTest(t, testConfigInfo{
+ libraryType: "java_library",
+ fromPartition: "vendor",
+ toPartition: "system",
+ enforceVendorInterface: true,
+ enforceProductInterface: true,
+ enforceJavaSdkLibraryCheck: true,
+ allowList: []string{"bar"},
+ }, "")
+
+ runTest(t, testConfigInfo{
+ libraryType: "java_library",
+ fromPartition: "vendor",
+ toPartition: "product",
+ enforceVendorInterface: true,
+ enforceProductInterface: true,
+ enforceJavaSdkLibraryCheck: true,
+ }, errorMessage)
+
+ runTest(t, testConfigInfo{
+ libraryType: "java_sdk_library",
+ fromPartition: "product",
+ toPartition: "system",
+ enforceVendorInterface: true,
+ enforceProductInterface: true,
+ enforceJavaSdkLibraryCheck: true,
+ }, "")
+
+ runTest(t, testConfigInfo{
+ libraryType: "java_sdk_library",
+ fromPartition: "vendor",
+ toPartition: "system",
+ enforceVendorInterface: true,
+ enforceProductInterface: true,
+ enforceJavaSdkLibraryCheck: true,
+ }, "")
+
+ runTest(t, testConfigInfo{
+ libraryType: "java_sdk_library",
+ fromPartition: "vendor",
+ toPartition: "product",
+ enforceVendorInterface: true,
+ enforceProductInterface: true,
+ enforceJavaSdkLibraryCheck: true,
+ }, "")
+}
+
+func TestJavaSdkLibraryDist(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithJavaBuildComponents,
+ PrepareForTestWithJavaDefaultModules,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ ).RunTestWithBp(t, `
+ java_sdk_library {
+ name: "sdklib_no_owner",
+ unsafe_ignore_missing_latest_api: true,
+ srcs: ["foo.java"],
+ }
+
+ java_sdk_library {
+ name: "sdklib_group_foo",
+ unsafe_ignore_missing_latest_api: true,
+ srcs: ["foo.java"],
+ dist_group: "foo",
+ }
+
+ java_sdk_library {
+ name: "sdklib_owner_foo",
+ unsafe_ignore_missing_latest_api: true,
+ srcs: ["foo.java"],
+ owner: "foo",
+ }
+
+ java_sdk_library {
+ name: "sdklib_stem_foo",
+ unsafe_ignore_missing_latest_api: true,
+ srcs: ["foo.java"],
+ dist_stem: "foo",
+ }
+
+ java_sdk_library {
+ name: "sdklib_core_lib",
+ unsafe_ignore_missing_latest_api: true,
+ srcs: ["foo.java"],
+ core_lib: true,
+ }
+ `)
+
+ type testCase struct {
+ module string
+ distDir string
+ distStem string
+ }
+ testCases := []testCase{
+ {
+ module: "sdklib_no_owner",
+ distDir: "apistubs/android/public",
+ distStem: "sdklib_no_owner.jar",
+ },
+ {
+ module: "sdklib_group_foo",
+ distDir: "apistubs/foo/public",
+ distStem: "sdklib_group_foo.jar",
+ },
+ {
+ module: "sdklib_owner_foo",
+ distDir: "apistubs/foo/public",
+ distStem: "sdklib_owner_foo.jar",
+ },
+ {
+ module: "sdklib_stem_foo",
+ distDir: "apistubs/android/public",
+ distStem: "foo.jar",
+ },
+ {
+ module: "sdklib_core_lib",
+ distDir: "apistubs/core/public",
+ distStem: "sdklib_core_lib.jar",
+ },
+ }
+
+ for _, tt := range testCases {
+ t.Run(tt.module, func(t *testing.T) {
+ m := result.ModuleForTests(tt.module+".stubs", "android_common").Module().(*Library)
+ dists := m.Dists()
+ if len(dists) != 1 {
+ t.Fatalf("expected exactly 1 dist entry, got %d", len(dists))
+ }
+ if g, w := String(dists[0].Dir), tt.distDir; g != w {
+ t.Errorf("expected dist dir %q, got %q", w, g)
+ }
+ if g, w := String(dists[0].Dest), tt.distStem; g != w {
+ t.Errorf("expected dist stem %q, got %q", w, g)
+ }
+ })
+ }
+}
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
index 30cb937..39c8fba 100755
--- a/scripts/build-mainline-modules.sh
+++ b/scripts/build-mainline-modules.sh
@@ -68,6 +68,9 @@
# Make sure this build builds from source, regardless of the default.
export SOONG_CONFIG_art_module_source_build=true
+# This script does not intend to handle compressed APEX
+export OVERRIDE_PRODUCT_COMPRESSED_APEX=false
+
OUT_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var OUT_DIR)
DIST_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var DIST_DIR)
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index d17b464..37940ba 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -60,6 +60,7 @@
"path.go",
"proc_sync.go",
"rbe.go",
+ "sandbox_config.go",
"signal.go",
"soong.go",
"test_build.go",
@@ -86,5 +87,8 @@
"config_linux.go",
"sandbox_linux.go",
],
+ testSrcs: [
+ "sandbox_linux_test.go",
+ ],
},
}
diff --git a/ui/build/config.go b/ui/build/config.go
index 3ebde0d..f1f5989 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -57,6 +57,7 @@
katiSuffix string
targetDevice string
targetDeviceDir string
+ sandboxConfig *SandboxConfig
// Autodetected
totalRAM uint64
@@ -123,7 +124,8 @@
func NewConfig(ctx Context, args ...string) Config {
ret := &configImpl{
- environ: OsEnvironment(),
+ environ: OsEnvironment(),
+ sandboxConfig: &SandboxConfig{},
}
// Default matching ninja
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 54aeda0..83c8865 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -225,6 +225,10 @@
// Extra environment variables to be exported to ninja
"BUILD_BROKEN_NINJA_USES_ENV_VARS",
+ // Used to restrict write access to source tree
+ "BUILD_BROKEN_SRC_DIR_IS_WRITABLE",
+ "BUILD_BROKEN_SRC_DIR_RW_ALLOWLIST",
+
// Not used, but useful to be in the soong.log
"BOARD_VNDK_VERSION",
@@ -280,6 +284,8 @@
config.SetNinjaArgs(strings.Fields(makeVars["NINJA_GOALS"]))
config.SetTargetDevice(makeVars["TARGET_DEVICE"])
config.SetTargetDeviceDir(makeVars["TARGET_DEVICE_DIR"])
+ config.sandboxConfig.SetSrcDirIsRO(makeVars["BUILD_BROKEN_SRC_DIR_IS_WRITABLE"] == "false")
+ config.sandboxConfig.SetSrcDirRWAllowlist(strings.Fields(makeVars["BUILD_BROKEN_SRC_DIR_RW_ALLOWLIST"]))
config.SetBuildBrokenDupRules(makeVars["BUILD_BROKEN_DUP_RULES"] == "true")
config.SetBuildBrokenUsesNetwork(makeVars["BUILD_BROKEN_USES_NETWORK"] == "true")
diff --git a/ui/build/sandbox_config.go b/ui/build/sandbox_config.go
new file mode 100644
index 0000000..1b46459
--- /dev/null
+++ b/ui/build/sandbox_config.go
@@ -0,0 +1,36 @@
+// Copyright 2021 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 build
+
+type SandboxConfig struct {
+ srcDirIsRO bool
+ srcDirRWAllowlist []string
+}
+
+func (sc *SandboxConfig) SetSrcDirIsRO(ro bool) {
+ sc.srcDirIsRO = ro
+}
+
+func (sc *SandboxConfig) SrcDirIsRO() bool {
+ return sc.srcDirIsRO
+}
+
+func (sc *SandboxConfig) SetSrcDirRWAllowlist(allowlist []string) {
+ sc.srcDirRWAllowlist = allowlist
+}
+
+func (sc *SandboxConfig) SrcDirRWAllowlist() []string {
+ return sc.srcDirRWAllowlist
+}
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index dab0e75..b0a6748 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -145,6 +145,13 @@
func (c *Cmd) wrapSandbox() {
wd, _ := os.Getwd()
+ var srcDirMountFlag string
+ if c.config.sandboxConfig.SrcDirIsRO() {
+ srcDirMountFlag = "-R"
+ } else {
+ srcDirMountFlag = "-B" //Read-Write
+ }
+
sandboxArgs := []string{
// The executable to run
"-x", c.Path,
@@ -184,8 +191,8 @@
// Mount a writable tmp dir
"-B", "/tmp",
- // Mount source are read-write
- "-B", sandboxConfig.srcDir,
+ // Mount source
+ srcDirMountFlag, sandboxConfig.srcDir,
//Mount out dir as read-write
"-B", sandboxConfig.outDir,
@@ -198,6 +205,18 @@
"-q",
}
+ // Mount srcDir RW allowlists as Read-Write
+ if len(c.config.sandboxConfig.SrcDirRWAllowlist()) > 0 && !c.config.sandboxConfig.SrcDirIsRO() {
+ errMsg := `Product source tree has been set as ReadWrite, RW allowlist not necessary.
+ To recover, either
+ 1. Unset BUILD_BROKEN_SRC_DIR_IS_WRITABLE #or
+ 2. Unset BUILD_BROKEN_SRC_DIR_RW_ALLOWLIST`
+ c.ctx.Fatalln(errMsg)
+ }
+ for _, srcDirChild := range c.config.sandboxConfig.SrcDirRWAllowlist() {
+ sandboxArgs = append(sandboxArgs, "-B", srcDirChild)
+ }
+
if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
//Mount dist dir as read-write if it already exists
sandboxArgs = append(sandboxArgs, "-B", sandboxConfig.distDir)
diff --git a/ui/build/sandbox_linux_test.go b/ui/build/sandbox_linux_test.go
new file mode 100644
index 0000000..7bfd750
--- /dev/null
+++ b/ui/build/sandbox_linux_test.go
@@ -0,0 +1,104 @@
+// Copyright 2021 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 build
+
+import (
+ "os"
+ "testing"
+)
+
+func TestMain(m *testing.M) {
+ // set src dir of sandbox
+ sandboxConfig.srcDir = "/my/src/dir"
+ os.Exit(m.Run())
+}
+
+func TestMountFlagsSrcDir(t *testing.T) {
+ testCases := []struct {
+ srcDirIsRO bool
+ expectedSrcDirFlag string
+ }{
+ {
+ srcDirIsRO: false,
+ expectedSrcDirFlag: "-B",
+ },
+ {
+ srcDirIsRO: true,
+ expectedSrcDirFlag: "-R",
+ },
+ }
+ for _, testCase := range testCases {
+ c := testCmd()
+ c.config.sandboxConfig.SetSrcDirIsRO(testCase.srcDirIsRO)
+ c.wrapSandbox()
+ if !isExpectedMountFlag(c.Args, sandboxConfig.srcDir, testCase.expectedSrcDirFlag) {
+ t.Error("Mount flag of srcDir is not correct")
+ }
+ }
+}
+
+func TestMountFlagsSrcDirRWAllowlist(t *testing.T) {
+ testCases := []struct {
+ srcDirRWAllowlist []string
+ }{
+ {
+ srcDirRWAllowlist: []string{},
+ },
+ {
+ srcDirRWAllowlist: []string{"my/path"},
+ },
+ {
+ srcDirRWAllowlist: []string{"my/path1", "my/path2"},
+ },
+ }
+ for _, testCase := range testCases {
+ c := testCmd()
+ c.config.sandboxConfig.SetSrcDirIsRO(true)
+ c.config.sandboxConfig.SetSrcDirRWAllowlist(testCase.srcDirRWAllowlist)
+ c.wrapSandbox()
+ for _, allowlistPath := range testCase.srcDirRWAllowlist {
+ if !isExpectedMountFlag(c.Args, allowlistPath, "-B") {
+ t.Error("Mount flag of srcDirRWAllowlist is not correct, expect -B")
+ }
+ }
+ }
+}
+
+// utils for setting up test
+func testConfig() Config {
+ // create a minimal testConfig
+ env := Environment([]string{})
+ sandboxConfig := SandboxConfig{}
+ return Config{&configImpl{environ: &env,
+ sandboxConfig: &sandboxConfig}}
+}
+
+func testCmd() *Cmd {
+ return Command(testContext(), testConfig(), "sandbox_test", "path/to/nsjail")
+}
+
+func isExpectedMountFlag(cmdArgs []string, dirName string, expectedFlag string) bool {
+ indexOfSrcDir := index(cmdArgs, dirName)
+ return cmdArgs[indexOfSrcDir-1] == expectedFlag
+}
+
+func index(arr []string, target string) int {
+ for idx, element := range arr {
+ if element == target {
+ return idx
+ }
+ }
+ panic("element could not be located in input array")
+}