summaryrefslogtreecommitdiff
path: root/api
diff options
context:
space:
mode:
Diffstat (limited to 'api')
-rw-r--r--api/Android.bp15
-rw-r--r--api/StubLibraries.bp233
-rw-r--r--api/coverage/tools/Android.bp21
-rw-r--r--api/coverage/tools/ExtractFlaggedApis.kt91
-rw-r--r--api/coverage/tools/ExtractFlaggedApisTest.kt160
5 files changed, 415 insertions, 105 deletions
diff --git a/api/Android.bp b/api/Android.bp
index 093ee4beab50..3fa9c600741e 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -342,8 +342,11 @@ stubs_defaults {
"packages/modules/Media/apex/aidl/stable",
"hardware/interfaces/biometrics/common/aidl",
"hardware/interfaces/biometrics/fingerprint/aidl",
+ "hardware/interfaces/common/aidl",
+ "hardware/interfaces/common/fmq/aidl",
"hardware/interfaces/graphics/common/aidl",
"hardware/interfaces/keymaster/aidl",
+ "hardware/interfaces/power/aidl",
"system/hardware/interfaces/media/aidl",
],
},
@@ -379,6 +382,18 @@ stubs_defaults {
],
}
+soong_config_module_type {
+ name: "non_updatable_exportable_droidstubs",
+ module_type: "droidstubs",
+ config_namespace: "ANDROID",
+ bool_variables: [
+ "release_hidden_api_exportable_stubs",
+ ],
+ properties: [
+ "dists",
+ ],
+}
+
// We resolve dependencies on APIs in modules by depending on a prebuilt of the whole
// platform (sdk_system_current_android). That prebuilt does not include module-lib APIs,
// so use the prebuilt module-lib stubs for modules that export module-lib stubs that the
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index c1add03fa31a..f56a95011dee 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -27,7 +27,12 @@
// These modules provide source files for the stub libraries
/////////////////////////////////////////////////////////////////////
-droidstubs {
+soong_config_module_type_import {
+ from: "frameworks/base/api/Android.bp",
+ module_types: ["non_updatable_exportable_droidstubs"],
+}
+
+non_updatable_exportable_droidstubs {
name: "api-stubs-docs-non-updatable",
defaults: [
"android-non-updatable-stubs-defaults",
@@ -49,20 +54,40 @@ droidstubs {
baseline_file: ":non-updatable-lint-baseline.txt",
},
},
- dists: [
- {
- targets: ["sdk"],
- dir: "apistubs/android/public/api",
- dest: "android-non-updatable.txt",
- tag: ".api.txt",
- },
- {
- targets: ["sdk"],
- dir: "apistubs/android/public/api",
- dest: "android-non-updatable-removed.txt",
- tag: ".removed-api.txt",
+ soong_config_variables: {
+ release_hidden_api_exportable_stubs: {
+ dists: [
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "android-non-updatable.txt",
+ tag: ".exportable.api.txt",
+ },
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".exportable.removed-api.txt",
+ },
+ ],
+ conditions_default: {
+ dists: [
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "android-non-updatable.txt",
+ tag: ".api.txt",
+ },
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".removed-api.txt",
+ },
+ ],
+ },
},
- ],
+ },
api_surface: "public",
}
@@ -86,7 +111,7 @@ module_libs = [
"\\)",
]
-droidstubs {
+non_updatable_exportable_droidstubs {
name: "system-api-stubs-docs-non-updatable",
defaults: [
"android-non-updatable-stubs-defaults",
@@ -109,24 +134,44 @@ droidstubs {
baseline_file: ":non-updatable-system-lint-baseline.txt",
},
},
- dists: [
- {
- targets: ["sdk"],
- dir: "apistubs/android/system/api",
- dest: "android-non-updatable.txt",
- tag: ".api.txt",
- },
- {
- targets: ["sdk"],
- dir: "apistubs/android/system/api",
- dest: "android-non-updatable-removed.txt",
- tag: ".removed-api.txt",
+ soong_config_variables: {
+ release_hidden_api_exportable_stubs: {
+ dists: [
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "android-non-updatable.txt",
+ tag: ".exportable.api.txt",
+ },
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".exportable.removed-api.txt",
+ },
+ ],
+ conditions_default: {
+ dists: [
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "android-non-updatable.txt",
+ tag: ".api.txt",
+ },
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/system/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".removed-api.txt",
+ },
+ ],
+ },
},
- ],
+ },
api_surface: "system",
}
-droidstubs {
+non_updatable_exportable_droidstubs {
name: "test-api-stubs-docs-non-updatable",
defaults: [
"android-non-updatable-stubs-defaults",
@@ -144,36 +189,68 @@ droidstubs {
baseline_file: ":non-updatable-test-lint-baseline.txt",
},
},
- dists: [
- {
- targets: ["sdk"],
- dir: "apistubs/android/test/api",
- dest: "android.txt",
- tag: ".api.txt",
- },
- {
- targets: ["sdk"],
- dir: "apistubs/android/test/api",
- dest: "removed.txt",
- tag: ".removed-api.txt",
- },
- {
- targets: ["sdk"],
- dir: "apistubs/android/test/api",
- dest: "android-non-updatable.txt",
- tag: ".api.txt",
- },
- {
- targets: ["sdk"],
- dir: "apistubs/android/test/api",
- dest: "android-non-updatable-removed.txt",
- tag: ".removed-api.txt",
+ soong_config_variables: {
+ release_hidden_api_exportable_stubs: {
+ dists: [
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android.txt",
+ tag: ".exportable.api.txt",
+ },
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "removed.txt",
+ tag: ".exportable.removed-api.txt",
+ },
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android-non-updatable.txt",
+ tag: ".exportable.api.txt",
+ },
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".exportable.removed-api.txt",
+ },
+ ],
+ conditions_default: {
+ dists: [
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android.txt",
+ tag: ".api.txt",
+ },
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "removed.txt",
+ tag: ".removed-api.txt",
+ },
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android-non-updatable.txt",
+ tag: ".api.txt",
+ },
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/test/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".removed-api.txt",
+ },
+ ],
+ },
},
- ],
+ },
api_surface: "test",
}
-droidstubs {
+non_updatable_exportable_droidstubs {
name: "module-lib-api-stubs-docs-non-updatable",
defaults: [
"android-non-updatable-stubs-defaults",
@@ -196,20 +273,40 @@ droidstubs {
baseline_file: ":non-updatable-module-lib-lint-baseline.txt",
},
},
- dists: [
- {
- targets: ["sdk"],
- dir: "apistubs/android/module-lib/api",
- dest: "android-non-updatable.txt",
- tag: ".api.txt",
- },
- {
- targets: ["sdk"],
- dir: "apistubs/android/module-lib/api",
- dest: "android-non-updatable-removed.txt",
- tag: ".removed-api.txt",
+ soong_config_variables: {
+ release_hidden_api_exportable_stubs: {
+ dists: [
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "android-non-updatable.txt",
+ tag: ".exportable.api.txt",
+ },
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".exportable.removed-api.txt",
+ },
+ ],
+ conditions_default: {
+ dists: [
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "android-non-updatable.txt",
+ tag: ".api.txt",
+ },
+ {
+ targets: ["sdk"],
+ dir: "apistubs/android/module-lib/api",
+ dest: "android-non-updatable-removed.txt",
+ tag: ".removed-api.txt",
+ },
+ ],
+ },
},
- ],
+ },
api_surface: "module-lib",
}
diff --git a/api/coverage/tools/Android.bp b/api/coverage/tools/Android.bp
index 3e169120dc48..caaca99bdc45 100644
--- a/api/coverage/tools/Android.bp
+++ b/api/coverage/tools/Android.bp
@@ -30,3 +30,24 @@ java_library_host {
type: "full",
},
}
+
+java_test_host {
+ name: "extract-flagged-apis-test",
+ srcs: ["ExtractFlaggedApisTest.kt"],
+ libs: [
+ "extract_flagged_apis_proto",
+ "junit",
+ "libprotobuf-java-full",
+ ],
+ static_libs: [
+ "truth",
+ "truth-liteproto-extension",
+ "truth-proto-extension",
+ ],
+ data: [
+ ":extract-flagged-apis",
+ ],
+ test_options: {
+ unit_test: true,
+ },
+}
diff --git a/api/coverage/tools/ExtractFlaggedApis.kt b/api/coverage/tools/ExtractFlaggedApis.kt
index caa1929abd54..5178f09f0301 100644
--- a/api/coverage/tools/ExtractFlaggedApis.kt
+++ b/api/coverage/tools/ExtractFlaggedApis.kt
@@ -16,51 +16,68 @@
package android.platform.coverage
+import com.android.tools.metalava.model.ClassItem
+import com.android.tools.metalava.model.MethodItem
import com.android.tools.metalava.model.text.ApiFile
import java.io.File
import java.io.FileWriter
/** Usage: extract-flagged-apis <api text file> <output .pb file> */
fun main(args: Array<String>) {
- var cb = ApiFile.parseApi(listOf(File(args[0])))
- var builder = FlagApiMap.newBuilder()
+ val cb = ApiFile.parseApi(listOf(File(args[0])))
+ val builder = FlagApiMap.newBuilder()
for (pkg in cb.getPackages().packages) {
- var packageName = pkg.qualifiedName()
- pkg.allClasses()
- .filter { it.methods().size > 0 }
- .forEach {
- for (method in it.methods()) {
- val flagValue =
- method.modifiers
- .findAnnotation("android.annotation.FlaggedApi")
- ?.findAttribute("value")
- ?.value
- ?.value()
- if (flagValue != null && flagValue is String) {
- var api =
- JavaMethod.newBuilder()
- .setPackageName(packageName)
- .setClassName(it.fullName())
- .setMethodName(method.name())
- for (param in method.parameters()) {
- api.addParameters(param.type().toTypeString())
- }
- if (builder.containsFlagToApi(flagValue)) {
- var updatedApis =
- builder
- .getFlagToApiOrThrow(flagValue)
- .toBuilder()
- .addJavaMethods(api)
- .build()
- builder.putFlagToApi(flagValue, updatedApis)
- } else {
- var apis = FlaggedApis.newBuilder().addJavaMethods(api).build()
- builder.putFlagToApi(flagValue, apis)
- }
- }
- }
- }
+ val packageName = pkg.qualifiedName()
+ pkg.allClasses().forEach {
+ extractFlaggedApisFromClass(it, it.methods(), packageName, builder)
+ extractFlaggedApisFromClass(it, it.constructors(), packageName, builder)
+ }
}
val flagApiMap = builder.build()
FileWriter(args[1]).use { it.write(flagApiMap.toString()) }
}
+
+fun extractFlaggedApisFromClass(
+ classItem: ClassItem,
+ methods: List<MethodItem>,
+ packageName: String,
+ builder: FlagApiMap.Builder
+) {
+ if (methods.isEmpty()) return
+ val classFlag =
+ classItem.modifiers
+ .findAnnotation("android.annotation.FlaggedApi")
+ ?.findAttribute("value")
+ ?.value
+ ?.value() as? String
+ for (method in methods) {
+ val methodFlag =
+ method.modifiers
+ .findAnnotation("android.annotation.FlaggedApi")
+ ?.findAttribute("value")
+ ?.value
+ ?.value() as? String
+ ?: classFlag
+ val api =
+ JavaMethod.newBuilder()
+ .setPackageName(packageName)
+ .setClassName(classItem.fullName())
+ .setMethodName(method.name())
+ for (param in method.parameters()) {
+ api.addParameters(param.type().toTypeString())
+ }
+ if (methodFlag != null) {
+ addFlaggedApi(builder, api, methodFlag)
+ }
+ }
+}
+
+fun addFlaggedApi(builder: FlagApiMap.Builder, api: JavaMethod.Builder, flag: String) {
+ if (builder.containsFlagToApi(flag)) {
+ val updatedApis = builder.getFlagToApiOrThrow(flag).toBuilder().addJavaMethods(api).build()
+ builder.putFlagToApi(flag, updatedApis)
+ } else {
+ val apis = FlaggedApis.newBuilder().addJavaMethods(api).build()
+ builder.putFlagToApi(flag, apis)
+ }
+}
diff --git a/api/coverage/tools/ExtractFlaggedApisTest.kt b/api/coverage/tools/ExtractFlaggedApisTest.kt
new file mode 100644
index 000000000000..ee5aaf15cb57
--- /dev/null
+++ b/api/coverage/tools/ExtractFlaggedApisTest.kt
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2024 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 android.platform.coverage
+
+import com.google.common.truth.extensions.proto.ProtoTruth.assertThat
+import com.google.protobuf.TextFormat
+import java.nio.file.Files
+import java.nio.file.Path
+import java.nio.file.StandardOpenOption
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class ExtractFlaggedApisTest {
+
+ companion object {
+ const val COMMAND = "java -jar extract-flagged-apis.jar %s %s"
+ }
+
+ private var apiTextFile: Path = Files.createTempFile("current", ".txt")
+ private var flagToApiMap: Path = Files.createTempFile("flag_api_map", ".textproto")
+
+ @Before
+ fun setup() {
+ apiTextFile = Files.createTempFile("current", ".txt")
+ flagToApiMap = Files.createTempFile("flag_api_map", ".textproto")
+ }
+
+ @After
+ fun cleanup() {
+ Files.deleteIfExists(apiTextFile)
+ Files.deleteIfExists(flagToApiMap)
+ }
+
+ @Test
+ fun extractFlaggedApis_onlyMethodFlag_useMethodFlag() {
+ val apiText =
+ """
+ // Signature format: 2.0
+ package android.net.ipsec.ike {
+ public final class IkeSession implements java.lang.AutoCloseable {
+ method @FlaggedApi("com.android.ipsec.flags.dumpsys_api") public void dump(@NonNull java.io.PrintWriter);
+ }
+ }
+ """
+ .trimIndent()
+ Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND)
+
+ val process = Runtime.getRuntime().exec(createCommand())
+ process.waitFor()
+
+ val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8)
+ val result = TextFormat.parse(content, FlagApiMap::class.java)
+
+ val expected = FlagApiMap.newBuilder()
+ val api =
+ JavaMethod.newBuilder()
+ .setPackageName("android.net.ipsec.ike")
+ .setClassName("IkeSession")
+ .setMethodName("dump")
+ api.addParameters("java.io.PrintWriter")
+ addFlaggedApi(expected, api, "com.android.ipsec.flags.dumpsys_api")
+ assertThat(result).isEqualTo(expected.build())
+ }
+
+ @Test
+ fun extractFlaggedApis_onlyClassFlag_useClassFlag() {
+ val apiText =
+ """
+ // Signature format: 2.0
+ package android.net.ipsec.ike {
+ @FlaggedApi("com.android.ipsec.flags.dumpsys_api") public final class IkeSession implements java.lang.AutoCloseable {
+ method public void dump(@NonNull java.io.PrintWriter);
+ }
+ }
+ """
+ .trimIndent()
+ Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND)
+
+ val process = Runtime.getRuntime().exec(createCommand())
+ process.waitFor()
+
+ val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8)
+ val result = TextFormat.parse(content, FlagApiMap::class.java)
+
+ val expected = FlagApiMap.newBuilder()
+ val api =
+ JavaMethod.newBuilder()
+ .setPackageName("android.net.ipsec.ike")
+ .setClassName("IkeSession")
+ .setMethodName("dump")
+ api.addParameters("java.io.PrintWriter")
+ addFlaggedApi(expected, api, "com.android.ipsec.flags.dumpsys_api")
+ assertThat(result).isEqualTo(expected.build())
+ }
+
+ @Test
+ fun extractFlaggedApis_flaggedConstructorsAreFlaggedApis() {
+ val apiText =
+ """
+ // Signature format: 2.0
+ package android.app.pinner {
+ @FlaggedApi("android.app.pinner_service_client_api") public class PinnerServiceClient {
+ ctor @FlaggedApi("android.app.pinner_service_client_api") public PinnerServiceClient();
+ }
+ }
+ """
+ .trimIndent()
+ Files.write(apiTextFile, apiText.toByteArray(Charsets.UTF_8), StandardOpenOption.APPEND)
+
+ val process = Runtime.getRuntime().exec(createCommand())
+ process.waitFor()
+
+ val content = Files.readAllBytes(flagToApiMap).toString(Charsets.UTF_8)
+ val result = TextFormat.parse(content, FlagApiMap::class.java)
+
+ val expected = FlagApiMap.newBuilder()
+ val api =
+ JavaMethod.newBuilder()
+ .setPackageName("android.app.pinner")
+ .setClassName("PinnerServiceClient")
+ .setMethodName("PinnerServiceClient")
+ addFlaggedApi(expected, api, "android.app.pinner_service_client_api")
+ assertThat(result).isEqualTo(expected.build())
+ }
+
+ private fun addFlaggedApi(builder: FlagApiMap.Builder, api: JavaMethod.Builder, flag: String) {
+ if (builder.containsFlagToApi(flag)) {
+ val updatedApis =
+ builder.getFlagToApiOrThrow(flag).toBuilder().addJavaMethods(api).build()
+ builder.putFlagToApi(flag, updatedApis)
+ } else {
+ val apis = FlaggedApis.newBuilder().addJavaMethods(api).build()
+ builder.putFlagToApi(flag, apis)
+ }
+ }
+
+ private fun createCommand(): Array<String> {
+ val command =
+ String.format(COMMAND, apiTextFile.toAbsolutePath(), flagToApiMap.toAbsolutePath())
+ return command.split(" ").toTypedArray()
+ }
+}