Merge changes from topics "presubmit-am-0a046d9514b34cc1a3b2b3584e857f6c", "presubmit-am-22410ea0b46e4a3d961d51518c65514d", "presubmit-am-2646dd78e751450296e76a7e6fac60eb", "presubmit-am-2762d254a366481180c66eefcb7b8c53", "presubmit-am-36ef44194069468da39e59065e3b9d39", "presubmit-am-6e59a6b21a5047bd940a9bff59c79228", "presubmit-am-855c4e732f2645568065c3c870ecd0da", "presubmit-am-dae9703bfd65425b8b44605c42e9d5b9" into sc-mainline-prod
* changes: Allow java_sdk_library in an APEX to have higher min_sdk_version. Perform CheckMinSdkVersion for java_sdk_library. Add MinSdkVersion(ctx) method to ModuleWithMinSdkVersionCheck interface. Add ModuleWithMinSdkVersionCheck type. Use textproto format for classpaths.proto generation. Propagate min and max sdk versions to classpaths.proto configs. Introduce max_sdk_version device property. Test SdkSpecForm.
This commit is contained in:
committed by
Android (Google) Code Review
commit
aa7b36e681
@@ -110,6 +110,7 @@ bootstrap_go_package {
|
|||||||
"paths_test.go",
|
"paths_test.go",
|
||||||
"prebuilt_test.go",
|
"prebuilt_test.go",
|
||||||
"rule_builder_test.go",
|
"rule_builder_test.go",
|
||||||
|
"sdk_version_test.go",
|
||||||
"singleton_module_test.go",
|
"singleton_module_test.go",
|
||||||
"soong_config_modules_test.go",
|
"soong_config_modules_test.go",
|
||||||
"util_test.go",
|
"util_test.go",
|
||||||
|
@@ -903,16 +903,18 @@ var minSdkVersionAllowlist = func(apiMap map[string]int) map[string]ApiLevel {
|
|||||||
//
|
//
|
||||||
// Return true if the `to` module should be visited, false otherwise.
|
// Return true if the `to` module should be visited, false otherwise.
|
||||||
type PayloadDepsCallback func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool
|
type PayloadDepsCallback func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool
|
||||||
|
type WalkPayloadDepsFunc func(ctx ModuleContext, do PayloadDepsCallback)
|
||||||
|
|
||||||
// UpdatableModule represents updatable APEX/APK
|
// ModuleWithMinSdkVersionCheck represents a module that implements min_sdk_version checks
|
||||||
type UpdatableModule interface {
|
type ModuleWithMinSdkVersionCheck interface {
|
||||||
Module
|
Module
|
||||||
WalkPayloadDeps(ctx ModuleContext, do PayloadDepsCallback)
|
MinSdkVersion(ctx EarlyModuleContext) SdkSpec
|
||||||
|
CheckMinSdkVersion(ctx ModuleContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckMinSdkVersion checks if every dependency of an updatable module sets min_sdk_version
|
// CheckMinSdkVersion checks if every dependency of an updatable module sets min_sdk_version
|
||||||
// accordingly
|
// accordingly
|
||||||
func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion ApiLevel) {
|
func CheckMinSdkVersion(ctx ModuleContext, minSdkVersion ApiLevel, walk WalkPayloadDepsFunc) {
|
||||||
// do not enforce min_sdk_version for host
|
// do not enforce min_sdk_version for host
|
||||||
if ctx.Host() {
|
if ctx.Host() {
|
||||||
return
|
return
|
||||||
@@ -928,7 +930,7 @@ func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion ApiL
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
m.WalkPayloadDeps(ctx, func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool {
|
walk(ctx, func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool {
|
||||||
if externalDep {
|
if externalDep {
|
||||||
// external deps are outside the payload boundary, which is "stable"
|
// external deps are outside the payload boundary, which is "stable"
|
||||||
// interface. We don't have to check min_sdk_version for external
|
// interface. We don't have to check min_sdk_version for external
|
||||||
@@ -938,6 +940,14 @@ func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion ApiL
|
|||||||
if am, ok := from.(DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
|
if am, ok := from.(DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if m, ok := to.(ModuleWithMinSdkVersionCheck); ok {
|
||||||
|
// This dependency performs its own min_sdk_version check, just make sure it sets min_sdk_version
|
||||||
|
// to trigger the check.
|
||||||
|
if !m.MinSdkVersion(ctx).Specified() {
|
||||||
|
ctx.OtherModuleErrorf(m, "must set min_sdk_version")
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil {
|
if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil {
|
||||||
toName := ctx.OtherModuleName(to)
|
toName := ctx.OtherModuleName(to)
|
||||||
if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver.GreaterThan(minSdkVersion) {
|
if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver.GreaterThan(minSdkVersion) {
|
||||||
|
@@ -188,8 +188,8 @@ var FirstNonLibAndroidSupportVersion = uncheckedFinalApiLevel(21)
|
|||||||
// * "30" -> "30"
|
// * "30" -> "30"
|
||||||
// * "R" -> "30"
|
// * "R" -> "30"
|
||||||
// * "S" -> "S"
|
// * "S" -> "S"
|
||||||
func ReplaceFinalizedCodenames(ctx PathContext, raw string) string {
|
func ReplaceFinalizedCodenames(config Config, raw string) string {
|
||||||
num, ok := getFinalCodenamesMap(ctx.Config())[raw]
|
num, ok := getFinalCodenamesMap(config)[raw]
|
||||||
if !ok {
|
if !ok {
|
||||||
return raw
|
return raw
|
||||||
}
|
}
|
||||||
@@ -197,7 +197,7 @@ func ReplaceFinalizedCodenames(ctx PathContext, raw string) string {
|
|||||||
return strconv.Itoa(num)
|
return strconv.Itoa(num)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts the given string `raw` to an ApiLevel, possibly returning an error.
|
// ApiLevelFromUser converts the given string `raw` to an ApiLevel, possibly returning an error.
|
||||||
//
|
//
|
||||||
// `raw` must be non-empty. Passing an empty string results in a panic.
|
// `raw` must be non-empty. Passing an empty string results in a panic.
|
||||||
//
|
//
|
||||||
@@ -212,6 +212,12 @@ func ReplaceFinalizedCodenames(ctx PathContext, raw string) string {
|
|||||||
// Inputs that are not "current", known previews, or convertible to an integer
|
// Inputs that are not "current", known previews, or convertible to an integer
|
||||||
// will return an error.
|
// will return an error.
|
||||||
func ApiLevelFromUser(ctx PathContext, raw string) (ApiLevel, error) {
|
func ApiLevelFromUser(ctx PathContext, raw string) (ApiLevel, error) {
|
||||||
|
return ApiLevelFromUserWithConfig(ctx.Config(), raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApiLevelFromUserWithConfig implements ApiLevelFromUser, see comments for
|
||||||
|
// ApiLevelFromUser for more details.
|
||||||
|
func ApiLevelFromUserWithConfig(config Config, raw string) (ApiLevel, error) {
|
||||||
if raw == "" {
|
if raw == "" {
|
||||||
panic("API level string must be non-empty")
|
panic("API level string must be non-empty")
|
||||||
}
|
}
|
||||||
@@ -220,13 +226,13 @@ func ApiLevelFromUser(ctx PathContext, raw string) (ApiLevel, error) {
|
|||||||
return FutureApiLevel, nil
|
return FutureApiLevel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, preview := range ctx.Config().PreviewApiLevels() {
|
for _, preview := range config.PreviewApiLevels() {
|
||||||
if raw == preview.String() {
|
if raw == preview.String() {
|
||||||
return preview, nil
|
return preview, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
canonical := ReplaceFinalizedCodenames(ctx, raw)
|
canonical := ReplaceFinalizedCodenames(config, raw)
|
||||||
asInt, err := strconv.Atoi(canonical)
|
asInt, err := strconv.Atoi(canonical)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return NoneApiLevel, fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", canonical)
|
return NoneApiLevel, fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", canonical)
|
||||||
|
@@ -698,6 +698,16 @@ func (c *config) PreviewApiLevels() []ApiLevel {
|
|||||||
return levels
|
return levels
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *config) LatestPreviewApiLevel() ApiLevel {
|
||||||
|
level := NoneApiLevel
|
||||||
|
for _, l := range c.PreviewApiLevels() {
|
||||||
|
if l.GreaterThan(level) {
|
||||||
|
level = l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return level
|
||||||
|
}
|
||||||
|
|
||||||
func (c *config) AllSupportedApiLevels() []ApiLevel {
|
func (c *config) AllSupportedApiLevels() []ApiLevel {
|
||||||
var levels []ApiLevel
|
var levels []ApiLevel
|
||||||
levels = append(levels, c.FinalApiLevels()...)
|
levels = append(levels, c.FinalApiLevels()...)
|
||||||
|
@@ -117,7 +117,7 @@ func (s SdkSpec) Stable() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrebuiltSdkAvailableForUnbundledBuilt tells whether this SdkSpec can have a prebuilt SDK
|
// PrebuiltSdkAvailableForUnbundledBuild tells whether this SdkSpec can have a prebuilt SDK
|
||||||
// that can be used for unbundled builds.
|
// that can be used for unbundled builds.
|
||||||
func (s SdkSpec) PrebuiltSdkAvailableForUnbundledBuild() bool {
|
func (s SdkSpec) PrebuiltSdkAvailableForUnbundledBuild() bool {
|
||||||
// "", "none", and "core_platform" are not available for unbundled build
|
// "", "none", and "core_platform" are not available for unbundled build
|
||||||
@@ -212,6 +212,10 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec {
|
func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec {
|
||||||
|
return SdkSpecFromWithConfig(ctx.Config(), str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SdkSpecFromWithConfig(config Config, str string) SdkSpec {
|
||||||
switch str {
|
switch str {
|
||||||
// special cases first
|
// special cases first
|
||||||
case "":
|
case "":
|
||||||
@@ -252,7 +256,7 @@ func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec {
|
|||||||
return SdkSpec{SdkInvalid, NoneApiLevel, str}
|
return SdkSpec{SdkInvalid, NoneApiLevel, str}
|
||||||
}
|
}
|
||||||
|
|
||||||
apiLevel, err := ApiLevelFromUser(ctx, versionString)
|
apiLevel, err := ApiLevelFromUserWithConfig(config, versionString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return SdkSpec{SdkInvalid, apiLevel, str}
|
return SdkSpec{SdkInvalid, apiLevel, str}
|
||||||
}
|
}
|
||||||
|
89
android/sdk_version_test.go
Normal file
89
android/sdk_version_test.go
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
// Copyright 2015 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 android
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSdkSpecFrom(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
input string
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
input: "",
|
||||||
|
expected: "private_current",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "none",
|
||||||
|
expected: "none_(no version)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "core_platform",
|
||||||
|
expected: "core_platform_current",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "_",
|
||||||
|
expected: "invalid_(no version)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "_31",
|
||||||
|
expected: "invalid_(no version)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "system_R",
|
||||||
|
expected: "system_30",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "test_31",
|
||||||
|
expected: "test_31",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "module_current",
|
||||||
|
expected: "module-lib_current",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "31",
|
||||||
|
expected: "public_31",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "S",
|
||||||
|
expected: "public_31",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "current",
|
||||||
|
expected: "public_current",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "Tiramisu",
|
||||||
|
expected: "public_Tiramisu",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
config := NullConfig("")
|
||||||
|
|
||||||
|
config.productVariables = productVariables{
|
||||||
|
Platform_sdk_version: intPtr(31),
|
||||||
|
Platform_sdk_codename: stringPtr("Tiramisu"),
|
||||||
|
Platform_version_active_codenames: []string{"Tiramisu"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
if got := SdkSpecFromWithConfig(config, tc.input).String(); tc.expected != got {
|
||||||
|
t.Errorf("Expected %v, got %v", tc.expected, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
apex/apex.go
18
apex/apex.go
@@ -1632,7 +1632,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|||||||
// 1) do some validity checks such as apex_available, min_sdk_version, etc.
|
// 1) do some validity checks such as apex_available, min_sdk_version, etc.
|
||||||
a.checkApexAvailability(ctx)
|
a.checkApexAvailability(ctx)
|
||||||
a.checkUpdatable(ctx)
|
a.checkUpdatable(ctx)
|
||||||
a.checkMinSdkVersion(ctx)
|
a.CheckMinSdkVersion(ctx)
|
||||||
a.checkStaticLinkingToStubLibraries(ctx)
|
a.checkStaticLinkingToStubLibraries(ctx)
|
||||||
if len(a.properties.Tests) > 0 && !a.testApex {
|
if len(a.properties.Tests) > 0 && !a.testApex {
|
||||||
ctx.PropertyErrorf("tests", "property allowed only in apex_test module type")
|
ctx.PropertyErrorf("tests", "property allowed only in apex_test module type")
|
||||||
@@ -2246,18 +2246,28 @@ func overrideApexFactory() android.Module {
|
|||||||
//
|
//
|
||||||
// TODO(jiyong): move these checks to a separate go file.
|
// TODO(jiyong): move these checks to a separate go file.
|
||||||
|
|
||||||
|
var _ android.ModuleWithMinSdkVersionCheck = (*apexBundle)(nil)
|
||||||
|
|
||||||
// Entures that min_sdk_version of the included modules are equal or less than the min_sdk_version
|
// Entures that min_sdk_version of the included modules are equal or less than the min_sdk_version
|
||||||
// of this apexBundle.
|
// of this apexBundle.
|
||||||
func (a *apexBundle) checkMinSdkVersion(ctx android.ModuleContext) {
|
func (a *apexBundle) CheckMinSdkVersion(ctx android.ModuleContext) {
|
||||||
if a.testApex || a.vndkApex {
|
if a.testApex || a.vndkApex {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// apexBundle::minSdkVersion reports its own errors.
|
// apexBundle::minSdkVersion reports its own errors.
|
||||||
minSdkVersion := a.minSdkVersion(ctx)
|
minSdkVersion := a.minSdkVersion(ctx)
|
||||||
android.CheckMinSdkVersion(a, ctx, minSdkVersion)
|
android.CheckMinSdkVersion(ctx, minSdkVersion, a.WalkPayloadDeps)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) android.ApiLevel {
|
func (a *apexBundle) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
|
||||||
|
return android.SdkSpec{
|
||||||
|
Kind: android.SdkNone,
|
||||||
|
ApiLevel: a.minSdkVersion(ctx),
|
||||||
|
Raw: String(a.properties.Min_sdk_version),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *apexBundle) minSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
|
||||||
ver := proptools.String(a.properties.Min_sdk_version)
|
ver := proptools.String(a.properties.Min_sdk_version)
|
||||||
if ver == "" {
|
if ver == "" {
|
||||||
return android.NoneApiLevel
|
return android.NoneApiLevel
|
||||||
|
@@ -7742,6 +7742,184 @@ func TestApexJavaCoverage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSdkLibraryCanHaveHigherMinSdkVersion(t *testing.T) {
|
||||||
|
preparer := android.GroupFixturePreparers(
|
||||||
|
PrepareForTestWithApexBuildComponents,
|
||||||
|
prepareForTestWithMyapex,
|
||||||
|
java.PrepareForTestWithJavaSdkLibraryFiles,
|
||||||
|
java.PrepareForTestWithJavaDefaultModules,
|
||||||
|
android.PrepareForTestWithAndroidBuildComponents,
|
||||||
|
dexpreopt.FixtureSetApexBootJars("myapex:mybootclasspathlib"),
|
||||||
|
dexpreopt.FixtureSetApexSystemServerJars("myapex:mysystemserverclasspathlib"),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Test java_sdk_library in bootclasspath_fragment may define higher min_sdk_version than the apex
|
||||||
|
t.Run("bootclasspath_fragment jar has higher min_sdk_version than apex", func(t *testing.T) {
|
||||||
|
preparer.RunTestWithBp(t, `
|
||||||
|
apex {
|
||||||
|
name: "myapex",
|
||||||
|
key: "myapex.key",
|
||||||
|
bootclasspath_fragments: ["mybootclasspathfragment"],
|
||||||
|
min_sdk_version: "30",
|
||||||
|
updatable: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
apex_key {
|
||||||
|
name: "myapex.key",
|
||||||
|
public_key: "testkey.avbpubkey",
|
||||||
|
private_key: "testkey.pem",
|
||||||
|
}
|
||||||
|
|
||||||
|
bootclasspath_fragment {
|
||||||
|
name: "mybootclasspathfragment",
|
||||||
|
contents: ["mybootclasspathlib"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_sdk_library {
|
||||||
|
name: "mybootclasspathlib",
|
||||||
|
srcs: ["mybootclasspathlib.java"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
compile_dex: true,
|
||||||
|
unsafe_ignore_missing_latest_api: true,
|
||||||
|
min_sdk_version: "31",
|
||||||
|
static_libs: ["util"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "util",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
min_sdk_version: "31",
|
||||||
|
static_libs: ["another_util"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "another_util",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
min_sdk_version: "31",
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Test java_sdk_library in systemserverclasspath_fragment may define higher min_sdk_version than the apex
|
||||||
|
t.Run("systemserverclasspath_fragment jar has higher min_sdk_version than apex", func(t *testing.T) {
|
||||||
|
preparer.RunTestWithBp(t, `
|
||||||
|
apex {
|
||||||
|
name: "myapex",
|
||||||
|
key: "myapex.key",
|
||||||
|
systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
|
||||||
|
min_sdk_version: "30",
|
||||||
|
updatable: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
apex_key {
|
||||||
|
name: "myapex.key",
|
||||||
|
public_key: "testkey.avbpubkey",
|
||||||
|
private_key: "testkey.pem",
|
||||||
|
}
|
||||||
|
|
||||||
|
systemserverclasspath_fragment {
|
||||||
|
name: "mysystemserverclasspathfragment",
|
||||||
|
contents: ["mysystemserverclasspathlib"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_sdk_library {
|
||||||
|
name: "mysystemserverclasspathlib",
|
||||||
|
srcs: ["mysystemserverclasspathlib.java"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
compile_dex: true,
|
||||||
|
min_sdk_version: "32",
|
||||||
|
unsafe_ignore_missing_latest_api: true,
|
||||||
|
static_libs: ["util"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "util",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
min_sdk_version: "31",
|
||||||
|
static_libs: ["another_util"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "another_util",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
min_sdk_version: "31",
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("bootclasspath_fragment jar must set min_sdk_version", func(t *testing.T) {
|
||||||
|
preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mybootclasspathlib".*must set min_sdk_version`)).
|
||||||
|
RunTestWithBp(t, `
|
||||||
|
apex {
|
||||||
|
name: "myapex",
|
||||||
|
key: "myapex.key",
|
||||||
|
bootclasspath_fragments: ["mybootclasspathfragment"],
|
||||||
|
min_sdk_version: "30",
|
||||||
|
updatable: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
apex_key {
|
||||||
|
name: "myapex.key",
|
||||||
|
public_key: "testkey.avbpubkey",
|
||||||
|
private_key: "testkey.pem",
|
||||||
|
}
|
||||||
|
|
||||||
|
bootclasspath_fragment {
|
||||||
|
name: "mybootclasspathfragment",
|
||||||
|
contents: ["mybootclasspathlib"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_sdk_library {
|
||||||
|
name: "mybootclasspathlib",
|
||||||
|
srcs: ["mybootclasspathlib.java"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
compile_dex: true,
|
||||||
|
unsafe_ignore_missing_latest_api: true,
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("systemserverclasspath_fragment jar must set min_sdk_version", func(t *testing.T) {
|
||||||
|
preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "mysystemserverclasspathlib".*must set min_sdk_version`)).
|
||||||
|
RunTestWithBp(t, `
|
||||||
|
apex {
|
||||||
|
name: "myapex",
|
||||||
|
key: "myapex.key",
|
||||||
|
systemserverclasspath_fragments: ["mysystemserverclasspathfragment"],
|
||||||
|
min_sdk_version: "30",
|
||||||
|
updatable: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
apex_key {
|
||||||
|
name: "myapex.key",
|
||||||
|
public_key: "testkey.avbpubkey",
|
||||||
|
private_key: "testkey.pem",
|
||||||
|
}
|
||||||
|
|
||||||
|
systemserverclasspath_fragment {
|
||||||
|
name: "mysystemserverclasspathfragment",
|
||||||
|
contents: ["mysystemserverclasspathlib"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
}
|
||||||
|
|
||||||
|
java_sdk_library {
|
||||||
|
name: "mysystemserverclasspathlib",
|
||||||
|
srcs: ["mysystemserverclasspathlib.java"],
|
||||||
|
apex_available: ["myapex"],
|
||||||
|
compile_dex: true,
|
||||||
|
unsafe_ignore_missing_latest_api: true,
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
os.Exit(m.Run())
|
os.Exit(m.Run())
|
||||||
}
|
}
|
||||||
|
@@ -122,6 +122,14 @@ func FixtureSetBootJars(bootJars ...string) android.FixturePreparer {
|
|||||||
func FixtureSetApexBootJars(bootJars ...string) android.FixturePreparer {
|
func FixtureSetApexBootJars(bootJars ...string) android.FixturePreparer {
|
||||||
return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
|
return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
|
||||||
dexpreoptConfig.ApexBootJars = android.CreateTestConfiguredJarList(bootJars)
|
dexpreoptConfig.ApexBootJars = android.CreateTestConfiguredJarList(bootJars)
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// FixtureSetApexSystemServerJars sets the ApexSystemServerJars property in the global config.
|
||||||
|
func FixtureSetApexSystemServerJars(jars ...string) android.FixturePreparer {
|
||||||
|
return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) {
|
||||||
|
dexpreoptConfig.ApexSystemServerJars = android.CreateTestConfiguredJarList(jars)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -288,7 +288,7 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
|
|||||||
|
|
||||||
if minSdkVersion, err := a.MinSdkVersion(ctx).EffectiveVersion(ctx); err == nil {
|
if minSdkVersion, err := a.MinSdkVersion(ctx).EffectiveVersion(ctx); err == nil {
|
||||||
a.checkJniLibsSdkVersion(ctx, minSdkVersion)
|
a.checkJniLibsSdkVersion(ctx, minSdkVersion)
|
||||||
android.CheckMinSdkVersion(a, ctx, minSdkVersion)
|
android.CheckMinSdkVersion(ctx, minSdkVersion, a.WalkPayloadDeps)
|
||||||
} else {
|
} else {
|
||||||
ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
|
ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
|
||||||
}
|
}
|
||||||
|
15
java/base.go
15
java/base.go
@@ -185,6 +185,10 @@ type DeviceProperties struct {
|
|||||||
// Defaults to sdk_version if not set.
|
// Defaults to sdk_version if not set.
|
||||||
Min_sdk_version *string
|
Min_sdk_version *string
|
||||||
|
|
||||||
|
// if not blank, set the maximum version of the sdk that the compiled artifacts will run against.
|
||||||
|
// Defaults to empty string "". See sdk_version for possible values.
|
||||||
|
Max_sdk_version *string
|
||||||
|
|
||||||
// if not blank, set the targetSdkVersion in the AndroidManifest.xml.
|
// if not blank, set the targetSdkVersion in the AndroidManifest.xml.
|
||||||
// Defaults to sdk_version if not set.
|
// Defaults to sdk_version if not set.
|
||||||
Target_sdk_version *string
|
Target_sdk_version *string
|
||||||
@@ -367,6 +371,7 @@ type Module struct {
|
|||||||
|
|
||||||
sdkVersion android.SdkSpec
|
sdkVersion android.SdkSpec
|
||||||
minSdkVersion android.SdkSpec
|
minSdkVersion android.SdkSpec
|
||||||
|
maxSdkVersion android.SdkSpec
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
|
func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
|
||||||
@@ -524,6 +529,13 @@ func (j *Module) MinSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
|
|||||||
return j.SdkVersion(ctx)
|
return j.SdkVersion(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (j *Module) MaxSdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
|
||||||
|
maxSdkVersion := proptools.StringDefault(j.deviceProperties.Max_sdk_version, "")
|
||||||
|
// SdkSpecFrom returns SdkSpecPrivate for this, which may be confusing.
|
||||||
|
// TODO(b/208456999): ideally MaxSdkVersion should be an ApiLevel and not SdkSpec.
|
||||||
|
return android.SdkSpecFrom(ctx, maxSdkVersion)
|
||||||
|
}
|
||||||
|
|
||||||
func (j *Module) MinSdkVersionString() string {
|
func (j *Module) MinSdkVersionString() string {
|
||||||
return j.minSdkVersion.Raw
|
return j.minSdkVersion.Raw
|
||||||
}
|
}
|
||||||
@@ -1488,8 +1500,7 @@ func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Implements android.ApexModule
|
// Implements android.ApexModule
|
||||||
func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
|
func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
|
||||||
sdkVersion android.ApiLevel) error {
|
|
||||||
sdkSpec := j.MinSdkVersion(ctx)
|
sdkSpec := j.MinSdkVersion(ctx)
|
||||||
if !sdkSpec.Specified() {
|
if !sdkSpec.Specified() {
|
||||||
return fmt.Errorf("min_sdk_version is not specified")
|
return fmt.Errorf("min_sdk_version is not specified")
|
||||||
|
@@ -84,11 +84,10 @@ func initClasspathFragment(c classpathFragment, classpathType classpathType) {
|
|||||||
|
|
||||||
// Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto
|
// Matches definition of Jar in packages/modules/SdkExtensions/proto/classpaths.proto
|
||||||
type classpathJar struct {
|
type classpathJar struct {
|
||||||
path string
|
path string
|
||||||
classpath classpathType
|
classpath classpathType
|
||||||
// TODO(satayev): propagate min/max sdk versions for the jars
|
minSdkVersion string
|
||||||
minSdkVersion int32
|
maxSdkVersion string
|
||||||
maxSdkVersion int32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// gatherPossibleApexModuleNamesAndStems returns a set of module and stem names from the
|
// gatherPossibleApexModuleNamesAndStems returns a set of module and stem names from the
|
||||||
@@ -120,10 +119,32 @@ func configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars
|
|||||||
jars := make([]classpathJar, 0, len(paths)*len(classpaths))
|
jars := make([]classpathJar, 0, len(paths)*len(classpaths))
|
||||||
for i := 0; i < len(paths); i++ {
|
for i := 0; i < len(paths); i++ {
|
||||||
for _, classpathType := range classpaths {
|
for _, classpathType := range classpaths {
|
||||||
jars = append(jars, classpathJar{
|
jar := classpathJar{
|
||||||
classpath: classpathType,
|
classpath: classpathType,
|
||||||
path: paths[i],
|
path: paths[i],
|
||||||
|
}
|
||||||
|
ctx.VisitDirectDepsIf(func(m android.Module) bool {
|
||||||
|
return m.Name() == configuredJars.Jar(i)
|
||||||
|
}, func(m android.Module) {
|
||||||
|
if s, ok := m.(*SdkLibrary); ok {
|
||||||
|
// TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current"
|
||||||
|
if s.minSdkVersion.Specified() {
|
||||||
|
if s.minSdkVersion.ApiLevel.IsCurrent() {
|
||||||
|
jar.minSdkVersion = ctx.Config().LatestPreviewApiLevel().String()
|
||||||
|
} else {
|
||||||
|
jar.minSdkVersion = s.minSdkVersion.ApiLevel.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if s.maxSdkVersion.Specified() {
|
||||||
|
if s.maxSdkVersion.ApiLevel.IsCurrent() {
|
||||||
|
jar.maxSdkVersion = ctx.Config().LatestPreviewApiLevel().String()
|
||||||
|
} else {
|
||||||
|
jar.maxSdkVersion = s.maxSdkVersion.ApiLevel.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
jars = append(jars, jar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return jars
|
return jars
|
||||||
@@ -136,15 +157,15 @@ func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.M
|
|||||||
c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
|
c.outputFilepath = android.PathForModuleOut(ctx, outputFilename).OutputPath
|
||||||
c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
|
c.installDirPath = android.PathForModuleInstall(ctx, "etc", "classpaths")
|
||||||
|
|
||||||
generatedJson := android.PathForModuleOut(ctx, outputFilename+".json")
|
generatedTextproto := android.PathForModuleOut(ctx, outputFilename+".textproto")
|
||||||
writeClasspathsJson(ctx, generatedJson, jars)
|
writeClasspathsTextproto(ctx, generatedTextproto, jars)
|
||||||
|
|
||||||
rule := android.NewRuleBuilder(pctx, ctx)
|
rule := android.NewRuleBuilder(pctx, ctx)
|
||||||
rule.Command().
|
rule.Command().
|
||||||
BuiltTool("conv_classpaths_proto").
|
BuiltTool("conv_classpaths_proto").
|
||||||
Flag("encode").
|
Flag("encode").
|
||||||
Flag("--format=json").
|
Flag("--format=textproto").
|
||||||
FlagWithInput("--input=", generatedJson).
|
FlagWithInput("--input=", generatedTextproto).
|
||||||
FlagWithOutput("--output=", c.outputFilepath)
|
FlagWithOutput("--output=", c.outputFilepath)
|
||||||
|
|
||||||
rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
|
rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
|
||||||
@@ -159,24 +180,18 @@ func (c *ClasspathFragmentBase) generateClasspathProtoBuildActions(ctx android.M
|
|||||||
ctx.SetProvider(ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo)
|
ctx.SetProvider(ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeClasspathsJson(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
|
func writeClasspathsTextproto(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
|
||||||
var content strings.Builder
|
var content strings.Builder
|
||||||
fmt.Fprintf(&content, "{\n")
|
|
||||||
fmt.Fprintf(&content, "\"jars\": [\n")
|
|
||||||
for idx, jar := range jars {
|
|
||||||
fmt.Fprintf(&content, "{\n")
|
|
||||||
|
|
||||||
fmt.Fprintf(&content, "\"path\": \"%s\",\n", jar.path)
|
for _, jar := range jars {
|
||||||
fmt.Fprintf(&content, "\"classpath\": \"%s\"\n", jar.classpath)
|
fmt.Fprintf(&content, "jars {\n")
|
||||||
|
fmt.Fprintf(&content, "path: \"%s\"\n", jar.path)
|
||||||
if idx < len(jars)-1 {
|
fmt.Fprintf(&content, "classpath: %s\n", jar.classpath)
|
||||||
fmt.Fprintf(&content, "},\n")
|
fmt.Fprintf(&content, "min_sdk_version: \"%s\"\n", jar.minSdkVersion)
|
||||||
} else {
|
fmt.Fprintf(&content, "max_sdk_version: \"%s\"\n", jar.maxSdkVersion)
|
||||||
fmt.Fprintf(&content, "}\n")
|
fmt.Fprintf(&content, "}\n")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&content, "]\n")
|
|
||||||
fmt.Fprintf(&content, "}\n")
|
|
||||||
android.WriteFileRule(ctx, output, content.String())
|
android.WriteFileRule(ctx, output, content.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -487,6 +487,7 @@ func shouldUncompressDex(ctx android.ModuleContext, dexpreopter *dexpreopter) bo
|
|||||||
func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||||
j.sdkVersion = j.SdkVersion(ctx)
|
j.sdkVersion = j.SdkVersion(ctx)
|
||||||
j.minSdkVersion = j.MinSdkVersion(ctx)
|
j.minSdkVersion = j.MinSdkVersion(ctx)
|
||||||
|
j.maxSdkVersion = j.MaxSdkVersion(ctx)
|
||||||
|
|
||||||
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
|
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
|
||||||
if !apexInfo.IsForPlatform() {
|
if !apexInfo.IsForPlatform() {
|
||||||
|
@@ -68,7 +68,6 @@ type platformBootclasspathProperties struct {
|
|||||||
func platformBootclasspathFactory() android.SingletonModule {
|
func platformBootclasspathFactory() android.SingletonModule {
|
||||||
m := &platformBootclasspathModule{}
|
m := &platformBootclasspathModule{}
|
||||||
m.AddProperties(&m.properties)
|
m.AddProperties(&m.properties)
|
||||||
// TODO(satayev): split apex jars into separate configs.
|
|
||||||
initClasspathFragment(m, BOOTCLASSPATH)
|
initClasspathFragment(m, BOOTCLASSPATH)
|
||||||
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
|
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
|
||||||
return m
|
return m
|
||||||
|
@@ -1122,6 +1122,22 @@ func (module *SdkLibrary) getGeneratedApiScopes(ctx android.EarlyModuleContext)
|
|||||||
return generatedScopes
|
return generatedScopes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ android.ModuleWithMinSdkVersionCheck = (*SdkLibrary)(nil)
|
||||||
|
|
||||||
|
func (module *SdkLibrary) CheckMinSdkVersion(ctx android.ModuleContext) {
|
||||||
|
android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx).ApiLevel, func(c android.ModuleContext, do android.PayloadDepsCallback) {
|
||||||
|
ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
|
||||||
|
isExternal := !module.depIsInSameApex(ctx, child)
|
||||||
|
if am, ok := child.(android.ApexModule); ok {
|
||||||
|
if !do(ctx, parent, am, isExternal) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !isExternal
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type sdkLibraryComponentTag struct {
|
type sdkLibraryComponentTag struct {
|
||||||
blueprint.BaseDependencyTag
|
blueprint.BaseDependencyTag
|
||||||
name string
|
name string
|
||||||
@@ -1207,6 +1223,10 @@ func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||||
|
if proptools.String(module.deviceProperties.Min_sdk_version) != "" {
|
||||||
|
module.CheckMinSdkVersion(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
module.generateCommonBuildActions(ctx)
|
module.generateCommonBuildActions(ctx)
|
||||||
|
|
||||||
// Only build an implementation library if required.
|
// Only build an implementation library if required.
|
||||||
@@ -2466,12 +2486,12 @@ func (module *sdkLibraryXml) GenerateAndroidBuildActions(ctx android.ModuleConte
|
|||||||
|
|
||||||
func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
|
func (module *sdkLibraryXml) AndroidMkEntries() []android.AndroidMkEntries {
|
||||||
if module.hideApexVariantFromMake {
|
if module.hideApexVariantFromMake {
|
||||||
return []android.AndroidMkEntries{android.AndroidMkEntries{
|
return []android.AndroidMkEntries{{
|
||||||
Disabled: true,
|
Disabled: true,
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
return []android.AndroidMkEntries{android.AndroidMkEntries{
|
return []android.AndroidMkEntries{{
|
||||||
Class: "ETC",
|
Class: "ETC",
|
||||||
OutputFile: android.OptionalPathForPath(module.outputFilePath),
|
OutputFile: android.OptionalPathForPath(module.outputFilePath),
|
||||||
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
|
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
|
||||||
|
@@ -958,3 +958,87 @@ func TestJavaSdkLibraryDist(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSdkLibrary_CheckMinSdkVersion(t *testing.T) {
|
||||||
|
preparer := android.GroupFixturePreparers(
|
||||||
|
PrepareForTestWithJavaBuildComponents,
|
||||||
|
PrepareForTestWithJavaDefaultModules,
|
||||||
|
PrepareForTestWithJavaSdkLibraryFiles,
|
||||||
|
)
|
||||||
|
|
||||||
|
preparer.RunTestWithBp(t, `
|
||||||
|
java_sdk_library {
|
||||||
|
name: "sdklib",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
static_libs: ["util"],
|
||||||
|
min_sdk_version: "30",
|
||||||
|
unsafe_ignore_missing_latest_api: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "util",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
min_sdk_version: "30",
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
preparer.
|
||||||
|
RunTestWithBp(t, `
|
||||||
|
java_sdk_library {
|
||||||
|
name: "sdklib",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
libs: ["util"],
|
||||||
|
impl_only_libs: ["util"],
|
||||||
|
stub_only_libs: ["util"],
|
||||||
|
stub_only_static_libs: ["util"],
|
||||||
|
min_sdk_version: "30",
|
||||||
|
unsafe_ignore_missing_latest_api: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "util",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "util".*should support min_sdk_version\(30\)`)).
|
||||||
|
RunTestWithBp(t, `
|
||||||
|
java_sdk_library {
|
||||||
|
name: "sdklib",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
static_libs: ["util"],
|
||||||
|
min_sdk_version: "30",
|
||||||
|
unsafe_ignore_missing_latest_api: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "util",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
min_sdk_version: "31",
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
|
||||||
|
preparer.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "another_util".*should support min_sdk_version\(30\)`)).
|
||||||
|
RunTestWithBp(t, `
|
||||||
|
java_sdk_library {
|
||||||
|
name: "sdklib",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
static_libs: ["util"],
|
||||||
|
min_sdk_version: "30",
|
||||||
|
unsafe_ignore_missing_latest_api: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "util",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
static_libs: ["another_util"],
|
||||||
|
min_sdk_version: "30",
|
||||||
|
}
|
||||||
|
|
||||||
|
java_library {
|
||||||
|
name: "another_util",
|
||||||
|
srcs: ["a.java"],
|
||||||
|
min_sdk_version: "31",
|
||||||
|
}
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user