summaryrefslogtreecommitdiff
path: root/api
diff options
context:
space:
mode:
Diffstat (limited to 'api')
-rw-r--r--api/Android.bp111
-rw-r--r--api/Android.mk2
-rw-r--r--api/OWNERS4
-rw-r--r--api/api.go219
-rw-r--r--api/api_test.go68
-rwxr-xr-xapi/api_versions_trimmer.py136
-rw-r--r--api/api_versions_trimmer_unittests.py307
7 files changed, 307 insertions, 540 deletions
diff --git a/api/Android.bp b/api/Android.bp
index 89993e751cf0..9d20eca75f8f 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -31,49 +31,18 @@ bootstrap_go_package {
"blueprint",
"soong",
"soong-android",
+ "soong-bp2build",
"soong-genrule",
"soong-java",
],
srcs: ["api.go"],
+ testSrcs: ["api_test.go"],
pluginFor: ["soong_build"],
}
-python_defaults {
- name: "python3_version_defaults",
- version: {
- py2: {
- enabled: false,
- },
- py3: {
- enabled: true,
- embedded_launcher: false,
- },
- },
-}
-
-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",
- srcs: [
- "api_versions_trimmer_unittests.py",
- "api_versions_trimmer.py",
- ],
- defaults: ["python3_version_defaults"],
- test_options: {
- unit_test: true,
- },
-}
-
python_binary_host {
name: "merge_annotation_zips",
srcs: ["merge_annotation_zips.py"],
- defaults: ["python3_version_defaults"],
}
python_test_host {
@@ -83,7 +52,6 @@ python_test_host {
"merge_annotation_zips.py",
"merge_annotation_zips_test.py",
],
- defaults: ["python3_version_defaults"],
test_options: {
unit_test: true,
},
@@ -126,12 +94,14 @@ combined_apis {
"framework-sdksandbox",
"framework-tethering",
"framework-uwb",
+ "framework-virtualization",
"framework-wifi",
"i18n.module.public.api",
],
system_server_classpath: [
"service-media-s",
"service-permission",
+ "service-rkp",
"service-sdksandbox",
],
}
@@ -194,6 +164,67 @@ genrule {
}
genrule {
+ name: "frameworks-base-api-current.srcjar",
+ tools: ["merge_zips"],
+ out: ["current.srcjar"],
+ cmd: "$(location merge_zips) $(out) $(in)",
+ srcs: [
+ ":api-stubs-docs-non-updatable",
+ ":all-modules-public-stubs-source",
+ ],
+ visibility: ["//visibility:private"], // Used by make module in //development, mind
+}
+
+// This produces the same annotations.zip as framework-doc-stubs, but by using
+// outputs from individual modules instead of all the source code.
+genrule_defaults {
+ name: "sdk-annotations-defaults",
+ out: ["annotations.zip"],
+ tools: [
+ "merge_annotation_zips",
+ "soong_zip",
+ ],
+ cmd: "$(location merge_annotation_zips) $(genDir)/out $(in) && " +
+ "$(location soong_zip) -o $(out) -C $(genDir)/out -D $(genDir)/out",
+}
+
+genrule {
+ name: "sdk-annotations.zip",
+ defaults: ["sdk-annotations-defaults"],
+ srcs: [
+ ":android-non-updatable-doc-stubs{.annotations.zip}",
+ ":all-modules-public-annotations",
+ ],
+}
+
+genrule {
+ name: "sdk-annotations-system.zip",
+ defaults: ["sdk-annotations-defaults"],
+ srcs: [
+ ":android-non-updatable-doc-stubs-system{.annotations.zip}",
+ ":all-modules-system-annotations",
+ ],
+}
+
+genrule {
+ name: "sdk-annotations-module-lib.zip",
+ defaults: ["sdk-annotations-defaults"],
+ srcs: [
+ ":android-non-updatable-doc-stubs-module-lib{.annotations.zip}",
+ ":all-modules-module-lib-annotations",
+ ],
+}
+
+genrule {
+ name: "sdk-annotations-system-server.zip",
+ defaults: ["sdk-annotations-defaults"],
+ srcs: [
+ ":android-non-updatable-doc-stubs-system-server{.annotations.zip}",
+ ":all-modules-system-server-annotations",
+ ],
+}
+
+genrule {
name: "combined-removed-dex",
visibility: [
"//frameworks/base/boot",
@@ -209,3 +240,15 @@ genrule {
out: ["combined-removed-dex.txt"],
cmd: "$(location gen_combined_removed_dex.sh) $(location metalava) $(genDir) $(in) > $(out)",
}
+
+java_genrule {
+ name: "api_fingerprint",
+ srcs: [
+ ":frameworks-base-api-current.txt",
+ ":frameworks-base-api-system-current.txt",
+ ":frameworks-base-api-module-lib-current.txt",
+ ":frameworks-base-api-system-server-current.txt",
+ ],
+ out: ["api_fingerprint.txt"],
+ cmd: "cat $(in) | md5sum | cut -d' ' -f1 > $(out)",
+}
diff --git a/api/Android.mk b/api/Android.mk
new file mode 100644
index 000000000000..ce5f995033c5
--- /dev/null
+++ b/api/Android.mk
@@ -0,0 +1,2 @@
+.PHONY: checkapi
+checkapi: frameworks-base-api-current-compat frameworks-base-api-system-current-compat frameworks-base-api-module-lib-current-compat
diff --git a/api/OWNERS b/api/OWNERS
index 4d8ed0347f43..bf6216c168e8 100644
--- a/api/OWNERS
+++ b/api/OWNERS
@@ -3,7 +3,7 @@ hansson@google.com
# Modularization team
file:platform/packages/modules/common:/OWNERS
-per-file Android.bp = file:platform/build/soong:/OWNERS
+per-file Android.bp = file:platform/build/soong:/OWNERS #{LAST_RESORT_SUGGESTION}
# 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
+per-file Android.bp = aurimas@google.com,emberrose@google.com,sjgilbert@google.com
diff --git a/api/api.go b/api/api.go
index ce8cd1426661..09c238336a39 100644
--- a/api/api.go
+++ b/api/api.go
@@ -20,6 +20,7 @@ import (
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/bazel"
"android/soong/genrule"
"android/soong/java"
)
@@ -27,9 +28,20 @@ import (
const art = "art.module.public.api"
const conscrypt = "conscrypt.module.public.api"
const i18n = "i18n.module.public.api"
+const virtualization = "framework-virtualization"
var core_libraries_modules = []string{art, conscrypt, i18n}
+// List of modules that are not yet updatable, and hence they can still compile
+// against hidden APIs. These modules are filtered out when building the
+// updatable-framework-module-impl (because updatable-framework-module-impl is
+// built against module_current SDK). Instead they are directly statically
+// linked into the all-framework-module-lib, which is building against hidden
+// APIs.
+// In addition, the modules in this list are allowed to contribute to test APIs
+// stubs.
+var non_updatable_modules = []string{virtualization}
+
// 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
@@ -49,6 +61,7 @@ type CombinedApisProperties struct {
type CombinedApis struct {
android.ModuleBase
+ android.BazelModuleBase
properties CombinedApisProperties
}
@@ -89,6 +102,19 @@ type fgProps struct {
Visibility []string
}
+type Bazel_module struct {
+ Bp2build_available *bool
+}
+type bazelProperties struct {
+ *Bazel_module
+}
+
+var bp2buildNotAvailable = bazelProperties{
+ &Bazel_module{
+ Bp2build_available: proptools.BoolPtr(false),
+ },
+}
+
// Struct to pass parameters for the various merged [current|removed].txt file modules we create.
type MergedTxtDefinition struct {
// "current.txt" or "removed.txt"
@@ -134,54 +160,38 @@ func createMergedTxt(ctx android.LoadHookContext, txt MergedTxtDefinition) {
},
}
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)
+ ctx.CreateModule(genrule.GenRuleFactory, &props, &bp2buildNotAvailable)
}
-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 createMergedAnnotationsFilegroups(ctx android.LoadHookContext, modules, system_server_modules []string) {
+ for _, i := range []struct{
+ name string
+ tag string
+ modules []string
+ }{
+ {
+ name: "all-modules-public-annotations",
+ tag: "{.public.annotations.zip}",
+ modules: modules,
+ }, {
+ name: "all-modules-system-annotations",
+ tag: "{.system.annotations.zip}",
+ modules: modules,
+ }, {
+ name: "all-modules-module-lib-annotations",
+ tag: "{.module-lib.annotations.zip}",
+ modules: modules,
+ }, {
+ name: "all-modules-system-server-annotations",
+ tag: "{.system-server.annotations.zip}",
+ modules: system_server_modules,
+ },
+ } {
+ props := fgProps{}
+ props.Name = proptools.StringPtr(i.name)
+ props.Srcs = createSrcs(i.modules, i.tag)
+ ctx.CreateModule(android.FileGroupFactory, &props, &bp2buildNotAvailable)
+ }
}
func createMergedPublicStubs(ctx android.LoadHookContext, modules []string) {
@@ -194,9 +204,33 @@ func createMergedPublicStubs(ctx android.LoadHookContext, modules []string) {
}
func createMergedSystemStubs(ctx android.LoadHookContext, modules []string) {
+ // First create the all-updatable-modules-system-stubs
+ {
+ updatable_modules := removeAll(modules, non_updatable_modules)
+ props := libraryProps{}
+ props.Name = proptools.StringPtr("all-updatable-modules-system-stubs")
+ props.Static_libs = transformArray(updatable_modules, "", ".stubs.system")
+ props.Sdk_version = proptools.StringPtr("module_current")
+ props.Visibility = []string{"//frameworks/base"}
+ ctx.CreateModule(java.LibraryFactory, &props)
+ }
+ // Now merge all-updatable-modules-system-stubs and stubs from non-updatable modules
+ // into all-modules-system-stubs.
+ {
+ props := libraryProps{}
+ props.Name = proptools.StringPtr("all-modules-system-stubs")
+ props.Static_libs = transformArray(non_updatable_modules, "", ".stubs.system")
+ props.Static_libs = append(props.Static_libs, "all-updatable-modules-system-stubs")
+ props.Sdk_version = proptools.StringPtr("module_current")
+ props.Visibility = []string{"//frameworks/base"}
+ ctx.CreateModule(java.LibraryFactory, &props)
+ }
+}
+
+func createMergedTestStubsForNonUpdatableModules(ctx android.LoadHookContext) {
props := libraryProps{}
- props.Name = proptools.StringPtr("all-modules-system-stubs")
- props.Static_libs = transformArray(modules, "", ".stubs.system")
+ props.Name = proptools.StringPtr("all-non-updatable-modules-test-stubs")
+ props.Static_libs = transformArray(non_updatable_modules, "", ".stubs.test")
props.Sdk_version = proptools.StringPtr("module_current")
props.Visibility = []string{"//frameworks/base"}
ctx.CreateModule(java.LibraryFactory, &props)
@@ -205,12 +239,31 @@ func createMergedSystemStubs(ctx android.LoadHookContext, modules []string) {
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)
- props := libraryProps{}
- props.Name = proptools.StringPtr("all-framework-module-impl")
- props.Static_libs = transformArray(modules, "", ".impl")
- props.Sdk_version = proptools.StringPtr("module_current")
- props.Visibility = []string{"//frameworks/base"}
- ctx.CreateModule(java.LibraryFactory, &props)
+ // Remove the modules that belong to non-updatable APEXes since those are allowed to compile
+ // against unstable APIs.
+ modules = removeAll(modules, non_updatable_modules)
+ // First create updatable-framework-module-impl, which contains all updatable modules.
+ // This module compiles against module_lib SDK.
+ {
+ props := libraryProps{}
+ props.Name = proptools.StringPtr("updatable-framework-module-impl")
+ props.Static_libs = transformArray(modules, "", ".impl")
+ props.Sdk_version = proptools.StringPtr("module_current")
+ props.Visibility = []string{"//frameworks/base"}
+ ctx.CreateModule(java.LibraryFactory, &props)
+ }
+
+ // Now create all-framework-module-impl, which contains updatable-framework-module-impl
+ // and all non-updatable modules. This module compiles against hidden APIs.
+ {
+ props := libraryProps{}
+ props.Name = proptools.StringPtr("all-framework-module-impl")
+ props.Static_libs = transformArray(non_updatable_modules, "", ".impl")
+ props.Static_libs = append(props.Static_libs, "updatable-framework-module-impl")
+ props.Sdk_version = proptools.StringPtr("core_platform")
+ props.Visibility = []string{"//frameworks/base"}
+ ctx.CreateModule(java.LibraryFactory, &props)
+ }
}
func createMergedFrameworkModuleLibStubs(ctx android.LoadHookContext, modules []string) {
@@ -229,7 +282,7 @@ func createPublicStubsSourceFilegroup(ctx android.LoadHookContext, modules []str
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)
+ ctx.CreateModule(android.FileGroupFactory, &props, &bp2buildNotAvailable)
}
func createMergedTxts(ctx android.LoadHookContext, bootclasspath, system_server_classpath []string) {
@@ -278,22 +331,20 @@ func createMergedTxts(ctx android.LoadHookContext, bootclasspath, system_server_
func (a *CombinedApis) createInternalModules(ctx android.LoadHookContext) {
bootclasspath := a.properties.Bootclasspath
+ system_server_classpath := a.properties.System_server_classpath
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)
+ createMergedTxts(ctx, bootclasspath, system_server_classpath)
createMergedPublicStubs(ctx, bootclasspath)
createMergedSystemStubs(ctx, bootclasspath)
+ createMergedTestStubsForNonUpdatableModules(ctx)
createMergedFrameworkModuleLibStubs(ctx, bootclasspath)
createMergedFrameworkImpl(ctx, bootclasspath)
- createMergedAnnotations(ctx, bootclasspath)
-
- createFilteredApiVersions(ctx, bootclasspath)
+ createMergedAnnotationsFilegroups(ctx, bootclasspath, system_server_classpath)
createPublicStubsSourceFilegroup(ctx, bootclasspath)
}
@@ -303,9 +354,55 @@ func combinedApisModuleFactory() android.Module {
module.AddProperties(&module.properties)
android.InitAndroidModule(module)
android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.createInternalModules(ctx) })
+ android.InitBazelModule(module)
return module
}
+type bazelCombinedApisAttributes struct {
+ Scope bazel.StringAttribute
+ Base bazel.LabelAttribute
+ Deps bazel.LabelListAttribute
+}
+
+// combined_apis bp2build converter
+func (a *CombinedApis) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
+ basePrefix := "non-updatable"
+ scopeToSuffix := map[string]string{
+ "public": "-current.txt",
+ "system": "-system-current.txt",
+ "module-lib": "-module-lib-current.txt",
+ "system-server": "-system-server-current.txt",
+ }
+
+ for scopeName, suffix := range scopeToSuffix{
+ name := a.Name() + suffix
+
+ var scope bazel.StringAttribute
+ scope.SetValue(scopeName)
+
+ var base bazel.LabelAttribute
+ base.SetValue(android.BazelLabelForModuleDepSingle(ctx, basePrefix+suffix))
+
+ var deps bazel.LabelListAttribute
+ classpath := a.properties.Bootclasspath
+ if scopeName == "system-server" {
+ classpath = a.properties.System_server_classpath
+ }
+ deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, classpath))
+
+ attrs := bazelCombinedApisAttributes{
+ Scope: scope,
+ Base: base,
+ Deps: deps,
+ }
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "merged_txts",
+ Bzl_load_location: "//build/bazel/rules/java:merged_txts.bzl",
+ }
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: name}, &attrs)
+ }
+}
+
// Various utility methods below.
// Creates an array of ":<m><tag>" for each m in <modules>.
diff --git a/api/api_test.go b/api/api_test.go
new file mode 100644
index 000000000000..15b695ca0d36
--- /dev/null
+++ b/api/api_test.go
@@ -0,0 +1,68 @@
+// Copyright (C) 2023 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 (
+ "testing"
+
+ "android/soong/android"
+ "android/soong/bp2build"
+)
+
+func runCombinedApisTestCaseWithRegistrationCtxFunc(t *testing.T, tc bp2build.Bp2buildTestCase, registrationCtxFunc func(ctx android.RegistrationContext)) {
+ t.Helper()
+ (&tc).ModuleTypeUnderTest = "combined_apis"
+ (&tc).ModuleTypeUnderTestFactory = combinedApisModuleFactory
+ bp2build.RunBp2BuildTestCase(t, registrationCtxFunc, tc)
+}
+
+func runCombinedApisTestCase(t *testing.T, tc bp2build.Bp2buildTestCase) {
+ t.Helper()
+ runCombinedApisTestCaseWithRegistrationCtxFunc(t, tc, func(ctx android.RegistrationContext) {})
+}
+
+func TestCombinedApisGeneral(t *testing.T) {
+ runCombinedApisTestCase(t, bp2build.Bp2buildTestCase{
+ Description: "combined_apis, general case",
+ Blueprint: `combined_apis {
+ name: "foo",
+ bootclasspath: ["bcp"],
+ system_server_classpath: ["ssc"],
+}
+`,
+ ExpectedBazelTargets: []string{
+ bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-current.txt", bp2build.AttrNameToString{
+ "scope": `"public"`,
+ "base": `":non-updatable-current.txt__BP2BUILD__MISSING__DEP"`,
+ "deps": `[":bcp__BP2BUILD__MISSING__DEP"]`,
+ }),
+ bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-system-current.txt", bp2build.AttrNameToString{
+ "scope": `"system"`,
+ "base": `":non-updatable-system-current.txt__BP2BUILD__MISSING__DEP"`,
+ "deps": `[":bcp__BP2BUILD__MISSING__DEP"]`,
+ }),
+ bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-module-lib-current.txt", bp2build.AttrNameToString{
+ "scope": `"module-lib"`,
+ "base": `":non-updatable-module-lib-current.txt__BP2BUILD__MISSING__DEP"`,
+ "deps": `[":bcp__BP2BUILD__MISSING__DEP"]`,
+ }),
+ bp2build.MakeBazelTargetNoRestrictions("merged_txts", "foo-system-server-current.txt", bp2build.AttrNameToString{
+ "scope": `"system-server"`,
+ "base": `":non-updatable-system-server-current.txt__BP2BUILD__MISSING__DEP"`,
+ "deps": `[":ssc__BP2BUILD__MISSING__DEP"]`,
+ }),
+ },
+ })
+}
diff --git a/api/api_versions_trimmer.py b/api/api_versions_trimmer.py
deleted file mode 100755
index 9afd95a3003a..000000000000
--- a/api/api_versions_trimmer.py
+++ /dev/null
@@ -1,136 +0,0 @@
-#!/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 remove mainline APIs from the api-versions.xml."""
-
-import argparse
-import re
-import xml.etree.ElementTree as ET
-import zipfile
-
-
-def read_classes(stubs):
- """Read classes from the stubs file.
-
- Args:
- stubs: argument can be a path to a file (a string), a file-like object or a
- path-like object
-
- Returns:
- a set of the classes found in the file (set of strings)
- """
- classes = set()
- with zipfile.ZipFile(stubs) as z:
- for info in z.infolist():
- if (not info.is_dir()
- and info.filename.endswith(".class")
- and not info.filename.startswith("META-INF")):
- # drop ".class" extension
- classes.add(info.filename[:-6])
- return classes
-
-
-def filter_method_tag(method, classes_to_remove):
- """Updates the signature of this method by calling filter_method_signature.
-
- Updates the method passed into this function.
-
- Args:
- method: xml element that represents a method
- classes_to_remove: set of classes you to remove
- """
- filtered = filter_method_signature(method.get("name"), classes_to_remove)
- method.set("name", filtered)
-
-
-def filter_method_signature(signature, classes_to_remove):
- """Removes mentions of certain classes from this method signature.
-
- Replaces any existing classes that need to be removed, with java/lang/Object
-
- Args:
- signature: string that is a java representation of a method signature
- classes_to_remove: set of classes you to remove
- """
- regex = re.compile("L.*?;")
- start = signature.find("(")
- matches = set(regex.findall(signature[start:]))
- for m in matches:
- # m[1:-1] to drop the leading `L` and `;` ending
- if m[1:-1] in classes_to_remove:
- signature = signature.replace(m, "Ljava/lang/Object;")
- return signature
-
-
-def filter_lint_database(database, classes_to_remove, output):
- """Reads a lint database and writes a filtered version without some classes.
-
- Reads database from api-versions.xml and removes any references to classes
- in the second argument. Writes the result (another xml with the same format
- of the database) to output.
-
- Args:
- database: path to xml with lint database to read
- classes_to_remove: iterable (ideally a set or similar for quick
- lookups) that enumerates the classes that should be removed
- output: path to write the filtered database
- """
- xml = ET.parse(database)
- root = xml.getroot()
- for c in xml.findall("class"):
- cname = c.get("name")
- if cname in classes_to_remove:
- root.remove(c)
- else:
- # find the <extends /> tag inside this class to see if the parent
- # has been removed from the known classes (attribute called name)
- super_classes = c.findall("extends")
- for super_class in super_classes:
- super_class_name = super_class.get("name")
- if super_class_name in classes_to_remove:
- super_class.set("name", "java/lang/Object")
- interfaces = c.findall("implements")
- for interface in interfaces:
- interface_name = interface.get("name")
- if interface_name in classes_to_remove:
- c.remove(interface)
- for method in c.findall("method"):
- filter_method_tag(method, classes_to_remove)
- xml.write(output)
-
-
-def main():
- """Run the program."""
- parser = argparse.ArgumentParser(
- description=
- ("Read a lint database (api-versions.xml) and many stubs jar files. "
- "Produce another database file that doesn't include the classes present "
- "in the stubs file(s)."))
- parser.add_argument("output", help="Destination of the result (xml file).")
- parser.add_argument(
- "api_versions",
- help="The lint database (api-versions.xml file) to read data from"
- )
- parser.add_argument("stubs", nargs="+", help="The stubs jar file(s)")
- parsed = parser.parse_args()
- classes = set()
- for stub in parsed.stubs:
- classes.update(read_classes(stub))
- filter_lint_database(parsed.api_versions, classes, parsed.output)
-
-
-if __name__ == "__main__":
- main()
diff --git a/api/api_versions_trimmer_unittests.py b/api/api_versions_trimmer_unittests.py
deleted file mode 100644
index d2e5b7d1a07e..000000000000
--- a/api/api_versions_trimmer_unittests.py
+++ /dev/null
@@ -1,307 +0,0 @@
-#!/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
-import re
-import unittest
-import xml.etree.ElementTree as ET
-import zipfile
-
-import api_versions_trimmer
-
-
-def create_in_memory_zip_file(files):
- f = io.BytesIO()
- with zipfile.ZipFile(f, "w") as z:
- for fname in files:
- with z.open(fname, mode="w") as class_file:
- class_file.write(b"")
- return f
-
-
-def indent(elem, level=0):
- i = "\n" + level * " "
- j = "\n" + (level - 1) * " "
- if len(elem):
- if not elem.text or not elem.text.strip():
- elem.text = i + " "
- if not elem.tail or not elem.tail.strip():
- elem.tail = i
- for subelem in elem:
- indent(subelem, level + 1)
- if not elem.tail or not elem.tail.strip():
- elem.tail = j
- else:
- if level and (not elem.tail or not elem.tail.strip()):
- elem.tail = j
- return elem
-
-
-def pretty_print(s):
- tree = ET.parse(io.StringIO(s))
- el = indent(tree.getroot())
- res = ET.tostring(el).decode("utf-8")
- # remove empty lines inside the result because this still breaks some
- # comparisons
- return re.sub(r"\n\s*\n", "\n", res, re.MULTILINE)
-
-
-class ApiVersionsTrimmerUnittests(unittest.TestCase):
-
- def setUp(self):
- # so it prints diffs in long strings (xml files)
- self.maxDiff = None
-
- def test_read_classes(self):
- f = create_in_memory_zip_file(
- ["a/b/C.class",
- "a/b/D.class",
- ]
- )
- res = api_versions_trimmer.read_classes(f)
- self.assertEqual({"a/b/C", "a/b/D"}, res)
-
- def test_read_classes_ignore_dex(self):
- f = create_in_memory_zip_file(
- ["a/b/C.class",
- "a/b/D.class",
- "a/b/E.dex",
- "f.dex",
- ]
- )
- res = api_versions_trimmer.read_classes(f)
- self.assertEqual({"a/b/C", "a/b/D"}, res)
-
- def test_read_classes_ignore_manifest(self):
- f = create_in_memory_zip_file(
- ["a/b/C.class",
- "a/b/D.class",
- "META-INFO/G.class"
- ]
- )
- res = api_versions_trimmer.read_classes(f)
- self.assertEqual({"a/b/C", "a/b/D"}, res)
-
- def test_filter_method_signature(self):
- xml = """
- <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" since="24"/>
- """
- method = ET.fromstring(xml)
- classes_to_remove = {"android/accessibilityservice/GestureDescription"}
- expected = "dispatchGesture(Ljava/lang/Object;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z"
- api_versions_trimmer.filter_method_tag(method, classes_to_remove)
- self.assertEqual(expected, method.get("name"))
-
- def test_filter_method_signature_with_L_in_method(self):
- xml = """
- <method name="dispatchLeftGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" since="24"/>
- """
- method = ET.fromstring(xml)
- classes_to_remove = {"android/accessibilityservice/GestureDescription"}
- expected = "dispatchLeftGesture(Ljava/lang/Object;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z"
- api_versions_trimmer.filter_method_tag(method, classes_to_remove)
- self.assertEqual(expected, method.get("name"))
-
- def test_filter_method_signature_with_L_in_class(self):
- xml = """
- <method name="dispatchGesture(Landroid/accessibilityservice/LeftGestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" since="24"/>
- """
- method = ET.fromstring(xml)
- classes_to_remove = {"android/accessibilityservice/LeftGestureDescription"}
- expected = "dispatchGesture(Ljava/lang/Object;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z"
- api_versions_trimmer.filter_method_tag(method, classes_to_remove)
- self.assertEqual(expected, method.get("name"))
-
- def test_filter_method_signature_with_inner_class(self):
- xml = """
- <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription$Inner;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z" since="24"/>
- """
- method = ET.fromstring(xml)
- classes_to_remove = {"android/accessibilityservice/GestureDescription$Inner"}
- expected = "dispatchGesture(Ljava/lang/Object;Landroid/accessibilityservice/AccessibilityService$GestureResultCallback;Landroid/os/Handler;)Z"
- api_versions_trimmer.filter_method_tag(method, classes_to_remove)
- self.assertEqual(expected, method.get("name"))
-
- def _run_filter_db_test(self, database_str, expected):
- """Performs the pattern of testing the filter_lint_database method.
-
- Filters instances of the class "a/b/C" (hard-coded) from the database string
- and compares the result with the expected result (performs formatting of
- the xml of both inputs)
-
- Args:
- database_str: string, the contents of the lint database (api-versions.xml)
- expected: string, the expected result after filtering the original
- database
- """
- database = io.StringIO(database_str)
- classes_to_remove = {"a/b/C"}
- output = io.BytesIO()
- api_versions_trimmer.filter_lint_database(
- database,
- classes_to_remove,
- output
- )
- expected = pretty_print(expected)
- res = pretty_print(output.getvalue().decode("utf-8"))
- self.assertEqual(expected, res)
-
- def test_filter_lint_database_updates_method_signature_params(self):
- self._run_filter_db_test(
- database_str="""
- <api version="2">
- <!-- will be removed -->
- <class name="a/b/C" since="1">
- <extends name="java/lang/Object"/>
- </class>
-
- <class name="a/b/E" since="1">
- <!-- extends will be modified -->
- <extends name="a/b/C"/>
- <!-- first parameter will be modified -->
- <method name="dispatchGesture(La/b/C;Landroid/os/Handler;)Z" since="24"/>
- <!-- second should remain untouched -->
- <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
-sultCallback;Landroid/os/Handler;)Z" since="24"/>
- </class>
- </api>
- """,
- expected="""
- <api version="2">
- <class name="a/b/E" since="1">
- <extends name="java/lang/Object"/>
- <method name="dispatchGesture(Ljava/lang/Object;Landroid/os/Handler;)Z" since="24"/>
- <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
-sultCallback;Landroid/os/Handler;)Z" since="24"/>
- </class>
- </api>
- """)
-
- def test_filter_lint_database_updates_method_signature_return(self):
- self._run_filter_db_test(
- database_str="""
- <api version="2">
- <!-- will be removed -->
- <class name="a/b/C" since="1">
- <extends name="java/lang/Object"/>
- </class>
-
- <class name="a/b/E" since="1">
- <!-- extends will be modified -->
- <extends name="a/b/C"/>
- <!-- return type should be changed -->
- <method name="gestureIdToString(I)La/b/C;" since="24"/>
- </class>
- </api>
- """,
- expected="""
- <api version="2">
- <class name="a/b/E" since="1">
-
- <extends name="java/lang/Object"/>
-
- <method name="gestureIdToString(I)Ljava/lang/Object;" since="24"/>
- </class>
- </api>
- """)
-
- def test_filter_lint_database_removes_implements(self):
- self._run_filter_db_test(
- database_str="""
- <api version="2">
- <!-- will be removed -->
- <class name="a/b/C" since="1">
- <extends name="java/lang/Object"/>
- </class>
-
- <class name="a/b/D" since="1">
- <extends name="java/lang/Object"/>
- <implements name="a/b/C"/>
- <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
-sultCallback;Landroid/os/Handler;)Z" since="24"/>
- </class>
- </api>
- """,
- expected="""
- <api version="2">
-
- <class name="a/b/D" since="1">
- <extends name="java/lang/Object"/>
- <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
-sultCallback;Landroid/os/Handler;)Z" since="24"/>
- </class>
- </api>
- """)
-
- def test_filter_lint_database_updates_extends(self):
- self._run_filter_db_test(
- database_str="""
- <api version="2">
- <!-- will be removed -->
- <class name="a/b/C" since="1">
- <extends name="java/lang/Object"/>
- </class>
-
- <class name="a/b/E" since="1">
- <!-- extends will be modified -->
- <extends name="a/b/C"/>
- <method name="dispatchGesture(Ljava/lang/Object;Landroid/os/Handler;)Z" since="24"/>
- <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
-sultCallback;Landroid/os/Handler;)Z" since="24"/>
- </class>
- </api>
- """,
- expected="""
- <api version="2">
- <class name="a/b/E" since="1">
- <extends name="java/lang/Object"/>
- <method name="dispatchGesture(Ljava/lang/Object;Landroid/os/Handler;)Z" since="24"/>
- <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
-sultCallback;Landroid/os/Handler;)Z" since="24"/>
- </class>
- </api>
- """)
-
- def test_filter_lint_database_removes_class(self):
- self._run_filter_db_test(
- database_str="""
- <api version="2">
- <!-- will be removed -->
- <class name="a/b/C" since="1">
- <extends name="java/lang/Object"/>
- </class>
-
- <class name="a/b/D" since="1">
- <extends name="java/lang/Object"/>
- <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
-sultCallback;Landroid/os/Handler;)Z" since="24"/>
- </class>
- </api>
- """,
- expected="""
- <api version="2">
-
- <class name="a/b/D" since="1">
- <extends name="java/lang/Object"/>
- <method name="dispatchGesture(Landroid/accessibilityservice/GestureDescription;Landroid/accessibilityservice/AccessibilityService$GestureRe
-sultCallback;Landroid/os/Handler;)Z" since="24"/>
- </class>
- </api>
- """)
-
-
-if __name__ == "__main__":
- unittest.main(verbosity=2)