diff options
Diffstat (limited to 'api')
| -rw-r--r-- | api/Android.bp | 460 | ||||
| -rw-r--r-- | api/OWNERS | 3 | ||||
| -rw-r--r-- | api/api.go | 341 | ||||
| -rw-r--r-- | api/api_versions_trimmer_unittests.py | 2 | ||||
| -rwxr-xr-x | api/merge_annotation_zips.py | 71 | ||||
| -rw-r--r-- | api/merge_annotation_zips_test.py | 124 |
6 files changed, 620 insertions, 381 deletions
diff --git a/api/Android.bp b/api/Android.bp index 2ea180ebf598..69d602a34380 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -24,9 +24,22 @@ package { default_applicable_licenses: ["frameworks_base_license"], } -python_binary_host { - name: "api_versions_trimmer", - srcs: ["api_versions_trimmer.py"], +bootstrap_go_package { + name: "soong-api", + pkgPath: "android/soong/api", + deps: [ + "blueprint", + "soong", + "soong-android", + "soong-genrule", + "soong-java", + ], + srcs: ["api.go"], + pluginFor: ["soong_build"], +} + +python_defaults { + name: "python3_version_defaults", version: { py2: { enabled: false, @@ -38,6 +51,12 @@ python_binary_host { }, } +python_binary_host { + name: "api_versions_trimmer", + srcs: ["api_versions_trimmer.py"], + defaults: ["python3_version_defaults"], +} + python_test_host { name: "api_versions_trimmer_unittests", main: "api_versions_trimmer_unittests.py", @@ -45,24 +64,35 @@ python_test_host { "api_versions_trimmer_unittests.py", "api_versions_trimmer.py", ], + defaults: ["python3_version_defaults"], test_options: { unit_test: true, }, - version: { - py2: { - enabled: false, - }, - py3: { - enabled: true, - embedded_launcher: false, - }, +} + +python_binary_host { + name: "merge_annotation_zips", + srcs: ["merge_annotation_zips.py"], + defaults: ["python3_version_defaults"], +} + +python_test_host { + name: "merge_annotation_zips_test", + main: "merge_annotation_zips_test.py", + srcs: [ + "merge_annotation_zips.py", + "merge_annotation_zips_test.py", + ], + defaults: ["python3_version_defaults"], + test_options: { + unit_test: true, }, } metalava_cmd = "$(location metalava)" // Silence reflection warnings. See b/168689341 metalava_cmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED " -metalava_cmd += " --no-banner --format=v2 " +metalava_cmd += " --quiet --no-banner --format=v2 " genrule { name: "current-api-xml", @@ -73,46 +103,32 @@ genrule { visibility: ["//visibility:public"], } -genrule { - name: "frameworks-base-api-current.txt", - srcs: [ - ":android.net.ipsec.ike{.public.api.txt}", - ":art.module.public.api{.public.api.txt}", - ":conscrypt.module.public.api{.public.api.txt}", - ":framework-appsearch{.public.api.txt}", - ":framework-connectivity{.public.api.txt}", - ":framework-graphics{.public.api.txt}", - ":framework-media{.public.api.txt}", - ":framework-mediaprovider{.public.api.txt}", - ":framework-permission{.public.api.txt}", - ":framework-permission-s{.public.api.txt}", - ":framework-scheduling{.public.api.txt}", - ":framework-sdkextensions{.public.api.txt}", - ":framework-statsd{.public.api.txt}", - ":framework-tethering{.public.api.txt}", - ":framework-wifi{.public.api.txt}", - ":i18n.module.public.api{.public.api.txt}", - ":non-updatable-current.txt", +combined_apis { + name: "frameworks-base-api", + bootclasspath: [ + "android.net.ipsec.ike", + "art.module.public.api", + "conscrypt.module.public.api", + "framework-appsearch", + "framework-bluetooth", + "framework-connectivity", + "framework-connectivity-t", + "framework-graphics", + "framework-media", + "framework-mediaprovider", + "framework-permission", + "framework-permission-s", + "framework-scheduling", + "framework-sdkextensions", + "framework-statsd", + "framework-tethering", + "framework-wifi", + "i18n.module.public.api", + ], + system_server_classpath: [ + "service-media-s", + "service-permission", ], - out: ["current.txt"], - tools: ["metalava"], - cmd: metalava_cmd + "$(in) --api $(out)", - dists: [ - { - targets: ["droidcore"], - dir: "api", - dest: "current.txt", - }, - { - targets: [ - "sdk", - "win_sdk", - ], - dir: "apistubs/android/public/api", - dest: "android.txt", - }, - ], - visibility: ["//visibility:public"], } genrule { @@ -122,121 +138,13 @@ genrule { ":android-incompatibilities.api.public.latest", ":frameworks-base-api-current.txt", ], - out: ["stdout.txt"], + out: ["updated-baseline.txt"], tools: ["metalava"], cmd: metalava_cmd + "--check-compatibility:api:released $(location :android.api.public.latest) " + "--baseline:compatibility:released $(location :android-incompatibilities.api.public.latest) " + - "$(location :frameworks-base-api-current.txt) " + - "> $(genDir)/stdout.txt", -} - -genrule { - name: "frameworks-base-api-current.srcjar", - srcs: [ - ":android.net.ipsec.ike{.public.stubs.source}", - ":api-stubs-docs-non-updatable", - ":art.module.public.api{.public.stubs.source}", - ":conscrypt.module.public.api{.public.stubs.source}", - ":framework-appsearch{.public.stubs.source}", - ":framework-connectivity{.public.stubs.source}", - ":framework-graphics{.public.stubs.source}", - ":framework-media{.public.stubs.source}", - ":framework-mediaprovider{.public.stubs.source}", - ":framework-permission{.public.stubs.source}", - ":framework-permission-s{.public.stubs.source}", - ":framework-scheduling{.public.stubs.source}", - ":framework-sdkextensions{.public.stubs.source}", - ":framework-statsd{.public.stubs.source}", - ":framework-tethering{.public.stubs.source}", - ":framework-wifi{.public.stubs.source}", - ":i18n.module.public.api{.public.stubs.source}", - ], - out: ["current.srcjar"], - tools: ["merge_zips"], - cmd: "$(location merge_zips) $(out) $(in)", - visibility: ["//visibility:private"], // Used by make module in //development, mind. -} - -genrule { - name: "frameworks-base-api-removed.txt", - srcs: [ - ":android.net.ipsec.ike{.public.removed-api.txt}", - ":art.module.public.api{.public.removed-api.txt}", - ":conscrypt.module.public.api{.public.removed-api.txt}", - ":framework-appsearch{.public.removed-api.txt}", - ":framework-connectivity{.public.removed-api.txt}", - ":framework-graphics{.public.removed-api.txt}", - ":framework-media{.public.removed-api.txt}", - ":framework-mediaprovider{.public.removed-api.txt}", - ":framework-permission{.public.removed-api.txt}", - ":framework-permission-s{.public.removed-api.txt}", - ":framework-scheduling{.public.removed-api.txt}", - ":framework-sdkextensions{.public.removed-api.txt}", - ":framework-statsd{.public.removed-api.txt}", - ":framework-tethering{.public.removed-api.txt}", - ":framework-wifi{.public.removed-api.txt}", - ":i18n.module.public.api{.public.removed-api.txt}", - ":non-updatable-removed.txt", - ], - out: ["removed.txt"], - tools: ["metalava"], - cmd: metalava_cmd + "$(in) --api $(out)", - dists: [ - { - targets: ["droidcore"], - dir: "api", - dest: "removed.txt", - }, - { - targets: [ - "sdk", - "win_sdk", - ], - dir: "apistubs/android/public/api", - dest: "removed.txt", - }, - ], -} - -genrule { - name: "frameworks-base-api-system-current.txt", - srcs: [ - ":art.module.public.api{.system.api.txt}", - ":android.net.ipsec.ike{.system.api.txt}", - ":framework-appsearch{.system.api.txt}", - ":framework-connectivity{.system.api.txt}", - ":framework-graphics{.system.api.txt}", - ":framework-media{.system.api.txt}", - ":framework-mediaprovider{.system.api.txt}", - ":framework-permission{.system.api.txt}", - ":framework-permission-s{.system.api.txt}", - ":framework-scheduling{.system.api.txt}", - ":framework-sdkextensions{.system.api.txt}", - ":framework-statsd{.system.api.txt}", - ":framework-tethering{.system.api.txt}", - ":framework-wifi{.system.api.txt}", - ":non-updatable-system-current.txt", - ], - out: ["system-current.txt"], - tools: ["metalava"], - cmd: metalava_cmd + "$(in) --api $(out)", - dists: [ - { - targets: ["droidcore"], - dir: "api", - dest: "system-current.txt", - }, - { - targets: [ - "sdk", - "win_sdk", - ], - dir: "apistubs/android/system/api", - dest: "android.txt", - }, - ], - visibility: ["//visibility:public"], + "--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " + + "$(location :frameworks-base-api-current.txt)", } genrule { @@ -247,93 +155,14 @@ genrule { ":frameworks-base-api-current.txt", ":frameworks-base-api-system-current.txt", ], - out: ["stdout.txt"], + out: ["updated-baseline.txt"], tools: ["metalava"], cmd: metalava_cmd + "--check-compatibility:api:released $(location :android.api.system.latest) " + "--check-compatibility:base $(location :frameworks-base-api-current.txt) " + "--baseline:compatibility:released $(location :android-incompatibilities.api.system.latest) " + - "$(location :frameworks-base-api-system-current.txt) " + - "> $(genDir)/stdout.txt", -} - -genrule { - name: "frameworks-base-api-system-removed.txt", - srcs: [ - ":art.module.public.api{.system.removed-api.txt}", - ":android.net.ipsec.ike{.system.removed-api.txt}", - ":framework-appsearch{.system.removed-api.txt}", - ":framework-connectivity{.system.removed-api.txt}", - ":framework-graphics{.system.removed-api.txt}", - ":framework-media{.system.removed-api.txt}", - ":framework-mediaprovider{.system.removed-api.txt}", - ":framework-permission{.system.removed-api.txt}", - ":framework-permission-s{.system.removed-api.txt}", - ":framework-scheduling{.system.removed-api.txt}", - ":framework-sdkextensions{.system.removed-api.txt}", - ":framework-statsd{.system.removed-api.txt}", - ":framework-tethering{.system.removed-api.txt}", - ":framework-wifi{.system.removed-api.txt}", - ":non-updatable-system-removed.txt", - ], - out: ["system-removed.txt"], - tools: ["metalava"], - cmd: metalava_cmd + "$(in) --api $(out)", - dists: [ - { - targets: ["droidcore"], - dir: "api", - dest: "system-removed.txt", - }, - { - targets: [ - "sdk", - "win_sdk", - ], - dir: "apistubs/android/system/api", - dest: "removed.txt", - }, - ], - visibility: ["//visibility:public"], -} - -genrule { - name: "frameworks-base-api-module-lib-current.txt", - srcs: [ - ":art.module.public.api{.module-lib.api.txt}", - ":android.net.ipsec.ike{.module-lib.api.txt}", - ":framework-appsearch{.module-lib.api.txt}", - ":framework-connectivity{.module-lib.api.txt}", - ":framework-graphics{.module-lib.api.txt}", - ":framework-media{.module-lib.api.txt}", - ":framework-mediaprovider{.module-lib.api.txt}", - ":framework-permission{.module-lib.api.txt}", - ":framework-permission-s{.module-lib.api.txt}", - ":framework-scheduling{.module-lib.api.txt}", - ":framework-sdkextensions{.module-lib.api.txt}", - ":framework-statsd{.module-lib.api.txt}", - ":framework-tethering{.module-lib.api.txt}", - ":framework-wifi{.module-lib.api.txt}", - ":non-updatable-module-lib-current.txt", - ], - out: ["module-lib-current.txt"], - tools: ["metalava"], - cmd: metalava_cmd + "$(in) --api $(out)", - dists: [ - { - targets: ["droidcore"], - dir: "api", - dest: "module-lib-current.txt", - }, - { - targets: [ - "sdk", - "win_sdk", - ], - dir: "apistubs/android/module-lib/api", - dest: "android.txt", - }, - ], + "--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " + + "$(location :frameworks-base-api-system-current.txt)", } genrule { @@ -344,56 +173,19 @@ genrule { ":frameworks-base-api-current.txt", ":frameworks-base-api-module-lib-current.txt", ], - out: ["stdout.txt"], + out: ["updated-baseline.txt"], tools: ["metalava"], cmd: metalava_cmd + "--check-compatibility:api:released $(location :android.api.module-lib.latest) " + // Note: having "public" be the base of module-lib is not perfect -- it should - // ideally be a merged public+system), but this will help when migrating from - // MODULE_LIBS -> public. + // ideally be a merged public+system (which metalava is not currently able to generate). + // This "base" will help when migrating from MODULE_LIBS -> public, but not when + // migrating from MODULE_LIBS -> system (where it needs to instead be listed as + // an incompatibility). "--check-compatibility:base $(location :frameworks-base-api-current.txt) " + "--baseline:compatibility:released $(location :android-incompatibilities.api.module-lib.latest) " + - "$(location :frameworks-base-api-module-lib-current.txt) " + - "> $(genDir)/stdout.txt", -} - -genrule { - name: "frameworks-base-api-module-lib-removed.txt", - srcs: [ - ":art.module.public.api{.module-lib.removed-api.txt}", - ":android.net.ipsec.ike{.module-lib.removed-api.txt}", - ":framework-appsearch{.module-lib.removed-api.txt}", - ":framework-connectivity{.module-lib.removed-api.txt}", - ":framework-graphics{.module-lib.removed-api.txt}", - ":framework-media{.module-lib.removed-api.txt}", - ":framework-mediaprovider{.module-lib.removed-api.txt}", - ":framework-permission{.module-lib.removed-api.txt}", - ":framework-permission-s{.module-lib.removed-api.txt}", - ":framework-scheduling{.module-lib.removed-api.txt}", - ":framework-sdkextensions{.module-lib.removed-api.txt}", - ":framework-statsd{.module-lib.removed-api.txt}", - ":framework-tethering{.module-lib.removed-api.txt}", - ":framework-wifi{.module-lib.removed-api.txt}", - ":non-updatable-module-lib-removed.txt", - ], - out: ["module-lib-removed.txt"], - tools: ["metalava"], - cmd: metalava_cmd + "$(in) --api $(out)", - dists: [ - { - targets: ["droidcore"], - dir: "api", - dest: "module-lib-removed.txt", - }, - { - targets: [ - "sdk", - "win_sdk", - ], - dir: "apistubs/android/module-lib/api", - dest: "removed.txt", - }, - ], + "--update-baseline:compatibility:released $(genDir)/updated-baseline.txt " + + "$(location :frameworks-base-api-module-lib-current.txt)", } genrule { @@ -412,95 +204,3 @@ genrule { out: ["combined-removed-dex.txt"], cmd: "$(location gen_combined_removed_dex.sh) $(location metalava) $(genDir) $(in) > $(out)", } - -genrule { - name: "services-system-server-current.txt", - srcs: [ - ":service-media-s{.system-server.api.txt}", - ":service-permission{.system-server.api.txt}", - ":non-updatable-system-server-current.txt", - ], - out: ["system-server-current.txt"], - tools: ["metalava"], - cmd: metalava_cmd + "$(in) --api $(out)", - dists: [ - { - targets: ["droidcore"], - dir: "api", - dest: "system-server-current.txt", - }, - { - targets: [ - "sdk", - "win_sdk", - ], - dir: "apistubs/android/system-server/api", - dest: "android.txt", - }, - ], -} - -genrule { - name: "services-system-server-removed.txt", - srcs: [ - ":service-media-s{.system-server.removed-api.txt}", - ":service-permission{.system-server.removed-api.txt}", - ":non-updatable-system-server-removed.txt", - ], - out: ["system-server-removed.txt"], - tools: ["metalava"], - cmd: metalava_cmd + "$(in) --api $(out)", - dists: [ - { - targets: ["droidcore"], - dir: "api", - dest: "system-server-removed.txt", - }, - { - targets: [ - "sdk", - "win_sdk", - ], - dir: "apistubs/android/system-server/api", - dest: "removed.txt", - }, - ], -} - -// This rule will filter classes present in the jar files of mainline modules -// from the lint database in api-versions.xml. -// This is done to reduce the number of false positive NewApi findings in -// java libraries that compile against the module SDK -genrule { - name: "api-versions-xml-public-filtered", - srcs: [ - // Note: order matters: first parameter is the full api-versions.xml - // after that the stubs files in any order - // stubs files are all modules that export API surfaces EXCEPT ART - ":framework-doc-stubs{.api_versions.xml}", - ":android.net.ipsec.ike.stubs{.jar}", - ":conscrypt.module.public.api.stubs{.jar}", - ":framework-appsearch.stubs{.jar}", - ":framework-connectivity.stubs{.jar}", - ":framework-graphics.stubs{.jar}", - ":framework-media.stubs{.jar}", - ":framework-mediaprovider.stubs{.jar}", - ":framework-permission.stubs{.jar}", - ":framework-permission-s.stubs{.jar}", - ":framework-scheduling.stubs{.jar}", - ":framework-sdkextensions.stubs{.jar}", - ":framework-statsd.stubs{.jar}", - ":framework-tethering.stubs{.jar}", - ":framework-wifi.stubs{.jar}", - ":i18n.module.public.api.stubs{.jar}", - ], - out: ["api-versions-public-filtered.xml"], - tools: ["api_versions_trimmer"], - cmd: "$(location api_versions_trimmer) $(out) $(in)", - dist: { - targets: [ - "sdk", - "win_sdk", - ], - }, -} diff --git a/api/OWNERS b/api/OWNERS index a0272709ffc0..4d8ed0347f43 100644 --- a/api/OWNERS +++ b/api/OWNERS @@ -4,3 +4,6 @@ hansson@google.com file:platform/packages/modules/common:/OWNERS per-file Android.bp = file:platform/build/soong:/OWNERS + +# For metalava team to disable lint checks in platform +per-file Android.bp = aurimas@google.com,emberrose@google.com,sjgilbert@google.com
\ No newline at end of file diff --git a/api/api.go b/api/api.go new file mode 100644 index 000000000000..5e5f60ee993f --- /dev/null +++ b/api/api.go @@ -0,0 +1,341 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// 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 api + +import ( + "sort" + + "github.com/google/blueprint/proptools" + + "android/soong/android" + "android/soong/genrule" + "android/soong/java" +) + +const art = "art.module.public.api" +const conscrypt = "conscrypt.module.public.api" +const i18n = "i18n.module.public.api" +var core_libraries_modules = []string{art, conscrypt, i18n} + +// The intention behind this soong plugin is to generate a number of "merged" +// API-related modules that would otherwise require a large amount of very +// similar Android.bp boilerplate to define. For example, the merged current.txt +// API definitions (created by merging the non-updatable current.txt with all +// the module current.txts). This simplifies the addition of new android +// modules, by reducing the number of genrules etc a new module must be added to. + +// The properties of the combined_apis module type. +type CombinedApisProperties struct { + // Module libraries in the bootclasspath + Bootclasspath []string + // Module libraries on the bootclasspath if include_nonpublic_framework_api is true. + Conditional_bootclasspath []string + // Module libraries in system server + System_server_classpath []string +} + +type CombinedApis struct { + android.ModuleBase + + properties CombinedApisProperties +} + +func init() { + registerBuildComponents(android.InitRegistrationContext) +} + +func registerBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterModuleType("combined_apis", combinedApisModuleFactory) +} + +var PrepareForCombinedApisTest = android.FixtureRegisterWithContext(registerBuildComponents) + +func (a *CombinedApis) GenerateAndroidBuildActions(ctx android.ModuleContext) { +} + +type genruleProps struct { + Name *string + Cmd *string + Dists []android.Dist + Out []string + Srcs []string + Tools []string + Visibility []string +} + +type libraryProps struct { + Name *string + Sdk_version *string + Static_libs []string + Visibility []string +} + +type fgProps struct { + Name *string + Srcs []string + Visibility []string +} + +// Struct to pass parameters for the various merged [current|removed].txt file modules we create. +type MergedTxtDefinition struct { + // "current.txt" or "removed.txt" + TxtFilename string + // The module for the non-updatable / non-module part of the api. + BaseTxt string + // The list of modules that are relevant for this merged txt. + Modules []string + // The output tag for each module to use.e.g. {.public.api.txt} for current.txt + ModuleTag string + // public, system, module-lib or system-server + Scope string +} + +func createMergedTxt(ctx android.LoadHookContext, txt MergedTxtDefinition) { + metalavaCmd := "$(location metalava)" + // Silence reflection warnings. See b/168689341 + metalavaCmd += " -J--add-opens=java.base/java.util=ALL-UNNAMED " + metalavaCmd += " --quiet --no-banner --format=v2 " + + filename := txt.TxtFilename + if txt.Scope != "public" { + filename = txt.Scope + "-" + filename + } + + props := genruleProps{} + props.Name = proptools.StringPtr(ctx.ModuleName() + "-" + filename) + props.Tools = []string{"metalava"} + props.Out = []string{filename} + props.Cmd = proptools.StringPtr(metalavaCmd + "$(in) --api $(out)") + props.Srcs = append([]string{txt.BaseTxt}, createSrcs(txt.Modules, txt.ModuleTag)...) + props.Dists = []android.Dist{ + { + Targets: []string{"droidcore"}, + Dir: proptools.StringPtr("api"), + Dest: proptools.StringPtr(filename), + }, + { + Targets: []string{"sdk"}, + Dir: proptools.StringPtr("apistubs/android/" + txt.Scope + "/api"), + Dest: proptools.StringPtr(txt.TxtFilename), + }, + } + props.Visibility = []string{"//visibility:public"} + ctx.CreateModule(genrule.GenRuleFactory, &props) +} + +func createMergedStubsSrcjar(ctx android.LoadHookContext, modules []string) { + props := genruleProps{} + props.Name = proptools.StringPtr(ctx.ModuleName() + "-current.srcjar") + props.Tools = []string{"merge_zips"} + props.Out = []string{"current.srcjar"} + props.Cmd = proptools.StringPtr("$(location merge_zips) $(out) $(in)") + props.Srcs = append([]string{":api-stubs-docs-non-updatable"}, createSrcs(modules, "{.public.stubs.source}")...) + props.Visibility = []string{"//visibility:private"} // Used by make module in //development, mind + ctx.CreateModule(genrule.GenRuleFactory, &props) +} + +// This produces the same annotations.zip as framework-doc-stubs, but by using +// outputs from individual modules instead of all the source code. +func createMergedAnnotations(ctx android.LoadHookContext, modules []string) { + props := genruleProps{} + props.Name = proptools.StringPtr("sdk-annotations.zip") + props.Tools = []string{"merge_annotation_zips", "soong_zip"} + props.Out = []string{"annotations.zip"} + props.Cmd = proptools.StringPtr("$(location merge_annotation_zips) $(genDir)/out $(in) && " + + "$(location soong_zip) -o $(out) -C $(genDir)/out -D $(genDir)/out") + props.Srcs = append([]string{":android-non-updatable-doc-stubs{.annotations.zip}"}, createSrcs(modules, "{.public.annotations.zip}")...) + ctx.CreateModule(genrule.GenRuleFactory, &props) +} + +func createFilteredApiVersions(ctx android.LoadHookContext, modules []string) { + // For the filtered api versions, we prune all APIs except art module's APIs. because + // 1) ART apis are available by default to all modules, while other module-to-module deps are + // explicit and probably receive more scrutiny anyway + // 2) The number of ART/libcore APIs is large, so not linting them would create a large gap + // 3) It's a compromise. Ideally we wouldn't be filtering out any module APIs, and have + // per-module lint databases that excludes just that module's APIs. Alas, that's more + // difficult to achieve. + modules = remove(modules, art) + + props := genruleProps{} + props.Name = proptools.StringPtr("api-versions-xml-public-filtered") + props.Tools = []string{"api_versions_trimmer"} + props.Out = []string{"api-versions-public-filtered.xml"} + props.Cmd = proptools.StringPtr("$(location api_versions_trimmer) $(out) $(in)") + // Note: order matters: first parameter is the full api-versions.xml + // after that the stubs files in any order + // stubs files are all modules that export API surfaces EXCEPT ART + props.Srcs = append([]string{":framework-doc-stubs{.api_versions.xml}"}, createSrcs(modules, ".stubs{.jar}")...) + props.Dists = []android.Dist{{Targets: []string{"sdk"}}} + ctx.CreateModule(genrule.GenRuleFactory, &props) +} + +func createMergedPublicStubs(ctx android.LoadHookContext, modules []string) { + props := libraryProps{} + props.Name = proptools.StringPtr("all-modules-public-stubs") + props.Static_libs = transformArray(modules, "", ".stubs") + props.Sdk_version = proptools.StringPtr("module_current") + props.Visibility = []string{"//frameworks/base"} + ctx.CreateModule(java.LibraryFactory, &props) +} + +func createMergedSystemStubs(ctx android.LoadHookContext, modules []string) { + props := libraryProps{} + props.Name = proptools.StringPtr("all-modules-system-stubs") + props.Static_libs = transformArray(modules, "", ".stubs.system") + props.Sdk_version = proptools.StringPtr("module_current") + props.Visibility = []string{"//frameworks/base"} + ctx.CreateModule(java.LibraryFactory, &props) +} + +func createMergedFrameworkImpl(ctx android.LoadHookContext, modules []string) { + // This module is for the "framework-all" module, which should not include the core libraries. + modules = removeAll(modules, core_libraries_modules) + // TODO(b/214988855): remove the line below when framework-bluetooth has an impl jar. + modules = remove(modules, "framework-bluetooth") + props := libraryProps{} + props.Name = proptools.StringPtr("all-framework-module-impl") + props.Static_libs = transformArray(modules, "", ".impl") + // Media module's impl jar is called "updatable-media" + for i, v := range props.Static_libs { + if v == "framework-media.impl" { + props.Static_libs[i] = "updatable-media" + } + } + props.Sdk_version = proptools.StringPtr("module_current") + props.Visibility = []string{"//frameworks/base"} + ctx.CreateModule(java.LibraryFactory, &props) +} + +func createMergedFrameworkModuleLibStubs(ctx android.LoadHookContext, modules []string) { + // The user of this module compiles against the "core" SDK, so remove core libraries to avoid dupes. + modules = removeAll(modules, core_libraries_modules) + props := libraryProps{} + props.Name = proptools.StringPtr("framework-updatable-stubs-module_libs_api") + props.Static_libs = transformArray(modules, "", ".stubs.module_lib") + props.Sdk_version = proptools.StringPtr("module_current") + props.Visibility = []string{"//frameworks/base"} + ctx.CreateModule(java.LibraryFactory, &props) +} + +func createPublicStubsSourceFilegroup(ctx android.LoadHookContext, modules []string) { + props := fgProps{} + props.Name = proptools.StringPtr("all-modules-public-stubs-source") + props.Srcs = createSrcs(modules, "{.public.stubs.source}") + props.Visibility = []string{"//frameworks/base"} + ctx.CreateModule(android.FileGroupFactory, &props) +} + +func createMergedTxts(ctx android.LoadHookContext, bootclasspath, system_server_classpath []string) { + var textFiles []MergedTxtDefinition + + tagSuffix := []string{".api.txt}", ".removed-api.txt}"} + for i, f := range []string{"current.txt", "removed.txt"} { + textFiles = append(textFiles, MergedTxtDefinition{ + TxtFilename: f, + BaseTxt: ":non-updatable-" + f, + Modules: bootclasspath, + ModuleTag: "{.public" + tagSuffix[i], + Scope: "public", + }) + textFiles = append(textFiles, MergedTxtDefinition{ + TxtFilename: f, + BaseTxt: ":non-updatable-system-" + f, + Modules: bootclasspath, + ModuleTag: "{.system" + tagSuffix[i], + Scope: "system", + }) + textFiles = append(textFiles, MergedTxtDefinition{ + TxtFilename: f, + BaseTxt: ":non-updatable-module-lib-" + f, + Modules: bootclasspath, + ModuleTag: "{.module-lib" + tagSuffix[i], + Scope: "module-lib", + }) + textFiles = append(textFiles, MergedTxtDefinition{ + TxtFilename: f, + BaseTxt: ":non-updatable-system-server-" + f, + Modules: system_server_classpath, + ModuleTag: "{.system-server" + tagSuffix[i], + Scope: "system-server", + }) + } + for _, txt := range textFiles { + createMergedTxt(ctx, txt) + } +} + +func (a *CombinedApis) createInternalModules(ctx android.LoadHookContext) { + bootclasspath := a.properties.Bootclasspath + if ctx.Config().VendorConfig("ANDROID").Bool("include_nonpublic_framework_api") { + bootclasspath = append(bootclasspath, a.properties.Conditional_bootclasspath...) + sort.Strings(bootclasspath) + } + createMergedTxts(ctx, bootclasspath, a.properties.System_server_classpath) + + createMergedStubsSrcjar(ctx, bootclasspath) + + createMergedPublicStubs(ctx, bootclasspath) + createMergedSystemStubs(ctx, bootclasspath) + createMergedFrameworkModuleLibStubs(ctx, bootclasspath) + createMergedFrameworkImpl(ctx, bootclasspath) + + createMergedAnnotations(ctx, bootclasspath) + + createFilteredApiVersions(ctx, bootclasspath) + + createPublicStubsSourceFilegroup(ctx, bootclasspath) +} + +func combinedApisModuleFactory() android.Module { + module := &CombinedApis{} + module.AddProperties(&module.properties) + android.InitAndroidModule(module) + android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.createInternalModules(ctx) }) + return module +} + +// Various utility methods below. + +// Creates an array of ":<m><tag>" for each m in <modules>. +func createSrcs(modules []string, tag string) []string { + return transformArray(modules, ":", tag) +} + +// Creates an array of "<prefix><m><suffix>", for each m in <modules>. +func transformArray(modules []string, prefix, suffix string) []string { + a := make([]string, 0, len(modules)) + for _, module := range modules { + a = append(a, prefix+module+suffix) + } + return a +} + +func removeAll(s []string, vs []string) []string { + for _, v := range vs { + s = remove(s, v) + } + return s +} + +func remove(s []string, v string) []string { + s2 := make([]string, 0, len(s)) + for _, sv := range s { + if sv != v { + s2 = append(s2, sv) + } + } + return s2 +} diff --git a/api/api_versions_trimmer_unittests.py b/api/api_versions_trimmer_unittests.py index 4eb929ea1b5d..d2e5b7d1a07e 100644 --- a/api/api_versions_trimmer_unittests.py +++ b/api/api_versions_trimmer_unittests.py @@ -304,4 +304,4 @@ sultCallback;Landroid/os/Handler;)Z" since="24"/> if __name__ == "__main__": - unittest.main() + unittest.main(verbosity=2) diff --git a/api/merge_annotation_zips.py b/api/merge_annotation_zips.py new file mode 100755 index 000000000000..9c67d7bded76 --- /dev/null +++ b/api/merge_annotation_zips.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 The Android Open Source Project +# +# 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. + +"""Script to merge annotation XML files (created by e.g. metalava).""" + +from pathlib import Path +import sys +import xml.etree.ElementTree as ET +import zipfile + + +def validate_xml_assumptions(root): + """Verify the format of the annotations XML matches expectations""" + prevName = "" + assert root.tag == 'root' + for child in root: + assert child.tag == 'item', 'unexpected tag: %s' % child.tag + assert list(child.attrib.keys()) == ['name'], 'unexpected attribs: %s' % child.attrib.keys() + assert prevName < child.get('name'), 'items unexpectedly not strictly sorted (possibly duplicate entries)' + prevName = child.get('name') + + +def merge_xml(a, b): + """Merge two annotation xml files""" + for xml in [a, b]: + validate_xml_assumptions(xml) + a.extend(b[:]) + a[:] = sorted(a[:], key=lambda x: x.get('name')) + validate_xml_assumptions(a) + + +def merge_zip_file(out_dir, zip_file): + """Merge the content of the zip_file into out_dir""" + for filename in zip_file.namelist(): + path = Path(out_dir, filename) + if path.exists(): + existing_xml = ET.parse(path) + with zip_file.open(filename) as other_file: + other_xml = ET.parse(other_file) + merge_xml(existing_xml.getroot(), other_xml.getroot()) + existing_xml.write(path, encoding='UTF-8', xml_declaration=True) + else: + zip_file.extract(filename, out_dir) + + +def main(): + out_dir = Path(sys.argv[1]) + zip_filenames = sys.argv[2:] + + assert not out_dir.exists() + out_dir.mkdir() + for zip_filename in zip_filenames: + with zipfile.ZipFile(zip_filename) as zip_file: + merge_zip_file(out_dir, zip_file) + + +if __name__ == "__main__": + main() diff --git a/api/merge_annotation_zips_test.py b/api/merge_annotation_zips_test.py new file mode 100644 index 000000000000..26795c47af9e --- /dev/null +++ b/api/merge_annotation_zips_test.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2021 The Android Open Source Project +# +# 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. + +import io +from pathlib import Path +import tempfile +import unittest +import zipfile + +import merge_annotation_zips + + +zip_a = { + 'android/provider/annotations.xml': + """<?xml version="1.0" encoding="UTF-8"?> +<root> + <item name="android.provider.BlockedNumberContract boolean isBlocked(android.content.Context, java.lang.String)"> + <annotation name="androidx.annotation.WorkerThread"/> + </item> + <item name="android.provider.SimPhonebookContract.SimRecords android.net.Uri getItemUri(int, int, int) 2"> + <annotation name="androidx.annotation.IntRange"> + <val name="from" val="1" /> + </annotation> + </item> +</root>""", + 'android/os/annotations.xml': + """<?xml version="1.0" encoding="UTF-8"?> +<root> + <item name="android.app.ActionBar void setCustomView(int) 0"> + <annotation name="androidx.annotation.LayoutRes"/> + </item> +</root> +""" +} + +zip_b = { + 'android/provider/annotations.xml': + """<?xml version="1.0" encoding="UTF-8"?> +<root> + <item name="android.provider.MediaStore QUERY_ARG_MATCH_FAVORITE"> + <annotation name="androidx.annotation.IntDef"> + <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" /> + <val name="flag" val="true" /> + </annotation> + </item> + <item name="android.provider.MediaStore QUERY_ARG_MATCH_PENDING"> + <annotation name="androidx.annotation.IntDef"> + <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" /> + <val name="flag" val="true" /> + </annotation> + </item> +</root>""" +} + +zip_c = { + 'android/app/annotations.xml': + """<?xml version="1.0" encoding="UTF-8"?> +<root> + <item name="android.app.ActionBar void setCustomView(int) 0"> + <annotation name="androidx.annotation.LayoutRes"/> + </item> +</root>""" +} + +merged_provider = """<?xml version='1.0' encoding='UTF-8'?> +<root> + <item name="android.provider.BlockedNumberContract boolean isBlocked(android.content.Context, java.lang.String)"> + <annotation name="androidx.annotation.WorkerThread" /> + </item> + <item name="android.provider.MediaStore QUERY_ARG_MATCH_FAVORITE"> + <annotation name="androidx.annotation.IntDef"> + <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" /> + <val name="flag" val="true" /> + </annotation> + </item> + <item name="android.provider.MediaStore QUERY_ARG_MATCH_PENDING"> + <annotation name="androidx.annotation.IntDef"> + <val name="value" val="{android.provider.MediaStore.MATCH_DEFAULT, android.provider.MediaStore.MATCH_INCLUDE, android.provider.MediaStore.MATCH_EXCLUDE, android.provider.MediaStore.MATCH_ONLY}" /> + <val name="flag" val="true" /> + </annotation> + </item> +<item name="android.provider.SimPhonebookContract.SimRecords android.net.Uri getItemUri(int, int, int) 2"> + <annotation name="androidx.annotation.IntRange"> + <val name="from" val="1" /> + </annotation> + </item> +</root>""" + + + +class MergeAnnotationZipsTest(unittest.TestCase): + + def test_merge_zips(self): + with tempfile.TemporaryDirectory() as out_dir: + for zip_content in [zip_a, zip_b, zip_c]: + f = io.BytesIO() + with zipfile.ZipFile(f, "w") as zip_file: + for filename, content in zip_content.items(): + zip_file.writestr(filename, content) + merge_annotation_zips.merge_zip_file(out_dir, zip_file) + + # Unchanged + self.assertEqual(zip_a['android/os/annotations.xml'], Path(out_dir, 'android/os/annotations.xml').read_text()) + self.assertEqual(zip_c['android/app/annotations.xml'], Path(out_dir, 'android/app/annotations.xml').read_text()) + + # Merged + self.assertEqual(merged_provider, Path(out_dir, 'android/provider/annotations.xml').read_text()) + + +if __name__ == "__main__": + unittest.main(verbosity=2) |