Add support for sdk extensions in prebuilt_apis
This makes it possible to pass an extensions_dir containing finalized module APIs to prebuilt_apis. The extension versions are compared to the api level versions to figure out what the "latest" finalized API is for each module. This is done using the base_sdk_extension_version, such that any extension higher than than base_sdk_extension_version is assumed to be finalized after any of the existing api level versions. Bug: 220086085 Test: prebuilt_apis_test.go Test: existing module in prebuilts/sdk Change-Id: Ib792f84202d436f594ba5e8716c6a187f9cd60dc
This commit is contained in:
parent
377318b33f
commit
3a3f169b56
4 changed files with 99 additions and 11 deletions
|
@ -38,6 +38,11 @@ type prebuiltApisProperties struct {
|
||||||
// list of api version directories
|
// list of api version directories
|
||||||
Api_dirs []string
|
Api_dirs []string
|
||||||
|
|
||||||
|
// Directory containing finalized api txt files for extension versions.
|
||||||
|
// Extension versions higher than the base sdk extension version will
|
||||||
|
// be assumed to be finalized later than all Api_dirs.
|
||||||
|
Extensions_dir *string
|
||||||
|
|
||||||
// The next API directory can optionally point to a directory where
|
// The next API directory can optionally point to a directory where
|
||||||
// files incompatibility-tracking files are stored for the current
|
// files incompatibility-tracking files are stored for the current
|
||||||
// "in progress" API. Each module present in one of the api_dirs will have
|
// "in progress" API. Each module present in one of the api_dirs will have
|
||||||
|
@ -152,6 +157,13 @@ func globApiDirs(mctx android.LoadHookContext, p *prebuiltApis, api_dir_glob str
|
||||||
return files
|
return files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// globExtensionDirs collects all the files under the extension dir (for all versions and scopes) that match the given glob
|
||||||
|
// <extension-dir>/<version>/<scope>/<glob> for all version and scope.
|
||||||
|
func globExtensionDirs(mctx android.LoadHookContext, p *prebuiltApis, extension_dir_glob string) []string {
|
||||||
|
// <extensions-dir>/<num>/<extension-dir-glob>
|
||||||
|
return globScopeDir(mctx, *p.properties.Extensions_dir+"/*", extension_dir_glob)
|
||||||
|
}
|
||||||
|
|
||||||
// globScopeDir collects all the files in the given subdir across all scopes that match the given glob, e.g. '*.jar' or 'api/*.txt'.
|
// globScopeDir collects all the files in the given subdir across all scopes that match the given glob, e.g. '*.jar' or 'api/*.txt'.
|
||||||
// <subdir>/<scope>/<glob> for all scope.
|
// <subdir>/<scope>/<glob> for all scope.
|
||||||
func globScopeDir(mctx android.LoadHookContext, subdir string, subdir_glob string) []string {
|
func globScopeDir(mctx android.LoadHookContext, subdir string, subdir_glob string) []string {
|
||||||
|
@ -222,17 +234,32 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) {
|
||||||
version int
|
version int
|
||||||
}
|
}
|
||||||
|
|
||||||
latest := make(map[string]latestApiInfo)
|
getLatest := func(files []string) map[string]latestApiInfo {
|
||||||
for _, f := range apiLevelFiles {
|
m := make(map[string]latestApiInfo)
|
||||||
|
for _, f := range files {
|
||||||
module, version, scope := parseFinalizedPrebuiltPath(mctx, f)
|
module, version, scope := parseFinalizedPrebuiltPath(mctx, f)
|
||||||
if strings.HasSuffix(module, "incompatibilities") {
|
if strings.HasSuffix(module, "incompatibilities") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
key := module + "." + scope
|
key := module + "." + scope
|
||||||
info, exists := latest[key]
|
info, exists := m[key]
|
||||||
if !exists || version > info.version {
|
if !exists || version > info.version {
|
||||||
latest[key] = latestApiInfo{module, scope, f, version}
|
m[key] = latestApiInfo{module, scope, f, version}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
latest := getLatest(apiLevelFiles)
|
||||||
|
if p.properties.Extensions_dir != nil {
|
||||||
|
extensionApiFiles := globExtensionDirs(mctx, p, "api/*.txt")
|
||||||
|
for k, v := range getLatest(extensionApiFiles) {
|
||||||
|
if v.version > mctx.Config().PlatformBaseSdkExtensionVersion() {
|
||||||
|
if _, exists := latest[k]; !exists {
|
||||||
|
mctx.ModuleErrorf("Module %v finalized for extension %d but never during an API level; likely error", v.module, v.version)
|
||||||
|
}
|
||||||
|
latest[k] = v
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,9 +20,14 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"android/soong/android"
|
"android/soong/android"
|
||||||
|
|
||||||
"github.com/google/blueprint"
|
"github.com/google/blueprint"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func intPtr(v int) *int {
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
func TestPrebuiltApis_SystemModulesCreation(t *testing.T) {
|
func TestPrebuiltApis_SystemModulesCreation(t *testing.T) {
|
||||||
result := android.GroupFixturePreparers(
|
result := android.GroupFixturePreparers(
|
||||||
prepareForJavaTest,
|
prepareForJavaTest,
|
||||||
|
@ -54,3 +59,34 @@ func TestPrebuiltApis_SystemModulesCreation(t *testing.T) {
|
||||||
sort.Strings(expected)
|
sort.Strings(expected)
|
||||||
android.AssertArrayString(t, "sdk system modules", expected, sdkSystemModules)
|
android.AssertArrayString(t, "sdk system modules", expected, sdkSystemModules)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrebuiltApis_WithExtensions(t *testing.T) {
|
||||||
|
runTestWithBaseExtensionLevel := func(v int) (foo_input string, bar_input string) {
|
||||||
|
result := android.GroupFixturePreparers(
|
||||||
|
prepareForJavaTest,
|
||||||
|
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
|
||||||
|
variables.Platform_base_sdk_extension_version = intPtr(v)
|
||||||
|
}),
|
||||||
|
FixtureWithPrebuiltApisAndExtensions(map[string][]string{
|
||||||
|
"31": {"foo"},
|
||||||
|
"32": {"foo", "bar"},
|
||||||
|
"current": {"foo", "bar"},
|
||||||
|
}, map[string][]string{
|
||||||
|
"1": {"foo"},
|
||||||
|
"2": {"foo", "bar"},
|
||||||
|
}),
|
||||||
|
).RunTest(t)
|
||||||
|
foo_input = result.ModuleForTests("foo.api.public.latest", "").Rule("generator").Implicits[0].String()
|
||||||
|
bar_input = result.ModuleForTests("bar.api.public.latest", "").Rule("generator").Implicits[0].String()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Here, the base extension level is 1, so extension level 2 is the latest
|
||||||
|
foo_input, bar_input := runTestWithBaseExtensionLevel(1)
|
||||||
|
android.AssertStringEquals(t, "Expected latest = extension level 2", "prebuilts/sdk/extensions/2/public/api/foo.txt", foo_input)
|
||||||
|
android.AssertStringEquals(t, "Expected latest = extension level 2", "prebuilts/sdk/extensions/2/public/api/bar.txt", bar_input)
|
||||||
|
|
||||||
|
// Here, the base extension level is 2, so 2 is not later than 32.
|
||||||
|
foo_input, bar_input = runTestWithBaseExtensionLevel(2)
|
||||||
|
android.AssertStringEquals(t, "Expected latest = api level 32", "prebuilts/sdk/32/public/api/foo.txt", foo_input)
|
||||||
|
android.AssertStringEquals(t, "Expected latest = api level 32", "prebuilts/sdk/32/public/api/bar.txt", bar_input)
|
||||||
|
}
|
||||||
|
|
|
@ -146,6 +146,10 @@ var PrepareForTestWithPrebuiltsOfCurrentApi = FixtureWithPrebuiltApis(map[string
|
||||||
// This defines a file in the mock file system in a predefined location (prebuilts/sdk/Android.bp)
|
// This defines a file in the mock file system in a predefined location (prebuilts/sdk/Android.bp)
|
||||||
// and so only one instance of this can be used in each fixture.
|
// and so only one instance of this can be used in each fixture.
|
||||||
func FixtureWithPrebuiltApis(release2Modules map[string][]string) android.FixturePreparer {
|
func FixtureWithPrebuiltApis(release2Modules map[string][]string) android.FixturePreparer {
|
||||||
|
return FixtureWithPrebuiltApisAndExtensions(release2Modules, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func FixtureWithPrebuiltApisAndExtensions(apiLevel2Modules map[string][]string, extensionLevel2Modules map[string][]string) android.FixturePreparer {
|
||||||
mockFS := android.MockFS{}
|
mockFS := android.MockFS{}
|
||||||
path := "prebuilts/sdk/Android.bp"
|
path := "prebuilts/sdk/Android.bp"
|
||||||
|
|
||||||
|
@ -153,14 +157,20 @@ func FixtureWithPrebuiltApis(release2Modules map[string][]string) android.Fixtur
|
||||||
prebuilt_apis {
|
prebuilt_apis {
|
||||||
name: "sdk",
|
name: "sdk",
|
||||||
api_dirs: ["%s"],
|
api_dirs: ["%s"],
|
||||||
|
extensions_dir: "extensions",
|
||||||
imports_sdk_version: "none",
|
imports_sdk_version: "none",
|
||||||
imports_compile_dex: true,
|
imports_compile_dex: true,
|
||||||
}
|
}
|
||||||
`, strings.Join(android.SortedStringKeys(release2Modules), `", "`))
|
`, strings.Join(android.SortedStringKeys(apiLevel2Modules), `", "`))
|
||||||
|
|
||||||
for release, modules := range release2Modules {
|
for release, modules := range apiLevel2Modules {
|
||||||
mockFS.Merge(prebuiltApisFilesForModules([]string{release}, modules))
|
mockFS.Merge(prebuiltApisFilesForModules([]string{release}, modules))
|
||||||
}
|
}
|
||||||
|
if extensionLevel2Modules != nil {
|
||||||
|
for release, modules := range extensionLevel2Modules {
|
||||||
|
mockFS.Merge(prebuiltExtensionApiFiles([]string{release}, modules))
|
||||||
|
}
|
||||||
|
}
|
||||||
return android.GroupFixturePreparers(
|
return android.GroupFixturePreparers(
|
||||||
android.FixtureAddTextFile(path, bp),
|
android.FixtureAddTextFile(path, bp),
|
||||||
android.FixtureMergeMockFs(mockFS),
|
android.FixtureMergeMockFs(mockFS),
|
||||||
|
@ -198,6 +208,19 @@ func prebuiltApisFilesForModules(apiLevels []string, modules []string) map[strin
|
||||||
return fs
|
return fs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func prebuiltExtensionApiFiles(extensionLevels []string, modules []string) map[string][]byte {
|
||||||
|
fs := make(map[string][]byte)
|
||||||
|
for _, level := range extensionLevels {
|
||||||
|
for _, sdkKind := range []android.SdkKind{android.SdkPublic, android.SdkSystem, android.SdkModule, android.SdkSystemServer} {
|
||||||
|
for _, lib := range modules {
|
||||||
|
fs[fmt.Sprintf("prebuilts/sdk/extensions/%s/%s/api/%s.txt", level, sdkKind, lib)] = nil
|
||||||
|
fs[fmt.Sprintf("prebuilts/sdk/extensions/%s/%s/api/%s-removed.txt", level, sdkKind, lib)] = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fs
|
||||||
|
}
|
||||||
|
|
||||||
// FixtureConfigureBootJars configures the boot jars in both the dexpreopt.GlobalConfig and
|
// FixtureConfigureBootJars configures the boot jars in both the dexpreopt.GlobalConfig and
|
||||||
// Config.productVariables structs. As a side effect that enables dexpreopt.
|
// Config.productVariables structs. As a side effect that enables dexpreopt.
|
||||||
func FixtureConfigureBootJars(bootJars ...string) android.FixturePreparer {
|
func FixtureConfigureBootJars(bootJars ...string) android.FixturePreparer {
|
||||||
|
|
|
@ -23,6 +23,7 @@ TOP=$(pwd)
|
||||||
|
|
||||||
source build/envsetup.sh
|
source build/envsetup.sh
|
||||||
PLATFORM_SDK_VERSION=$(get_build_var PLATFORM_SDK_VERSION)
|
PLATFORM_SDK_VERSION=$(get_build_var PLATFORM_SDK_VERSION)
|
||||||
|
PLATFORM_BASE_SDK_EXTENSION_VERSION=$(get_build_var PLATFORM_BASE_SDK_EXTENSION_VERSION)
|
||||||
PLATFORM_VERSION_ALL_CODENAMES=$(get_build_var PLATFORM_VERSION_ALL_CODENAMES)
|
PLATFORM_VERSION_ALL_CODENAMES=$(get_build_var PLATFORM_VERSION_ALL_CODENAMES)
|
||||||
|
|
||||||
# PLATFORM_VERSION_ALL_CODENAMES is a comma separated list like O,P. We need to
|
# PLATFORM_VERSION_ALL_CODENAMES is a comma separated list like O,P. We need to
|
||||||
|
@ -46,6 +47,7 @@ mkdir -p ${SOONG_OUT}
|
||||||
cat > ${SOONG_OUT}/soong.variables << EOF
|
cat > ${SOONG_OUT}/soong.variables << EOF
|
||||||
{
|
{
|
||||||
"Platform_sdk_version": ${PLATFORM_SDK_VERSION},
|
"Platform_sdk_version": ${PLATFORM_SDK_VERSION},
|
||||||
|
"Platform_base_sdk_extension_version": ${PLATFORM_BASE_SDK_EXTENSION_VERSION},
|
||||||
"Platform_version_active_codenames": ${PLATFORM_VERSION_ALL_CODENAMES},
|
"Platform_version_active_codenames": ${PLATFORM_VERSION_ALL_CODENAMES},
|
||||||
|
|
||||||
"DeviceName": "generic_arm64",
|
"DeviceName": "generic_arm64",
|
||||||
|
|
Loading…
Reference in a new issue