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:
TreeHugger Robot
2021-12-09 15:54:26 +00:00
committed by Android (Google) Code Review
16 changed files with 493 additions and 47 deletions

View File

@@ -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",

View File

@@ -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) {

View File

@@ -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)

View File

@@ -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()...)

View File

@@ -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}
} }

View 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)
}
}
}

View File

@@ -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

View File

@@ -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())
} }

View File

@@ -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)
}) })
} }

View File

@@ -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())
} }

View File

@@ -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")

View File

@@ -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())
} }

View File

@@ -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() {

View File

@@ -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

View File

@@ -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{

View File

@@ -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",
}
`)
}