Forbid services from extending any other interfaces
Test: ./gradlew :privacysandbox:tools:tools-{apigenerator,apicompiler,apipackager,core}:test
Bug: 265266769
Change-Id: I3bdc69dbfa7e0d56f4f8c161e3baed319d173a02
diff --git a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/parser/InterfaceParserTest.kt b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/parser/InterfaceParserTest.kt
index 730e107..98bf7a3 100644
--- a/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/parser/InterfaceParserTest.kt
+++ b/privacysandbox/tools/tools-apicompiler/src/test/java/androidx/privacysandbox/tools/apicompiler/parser/InterfaceParserTest.kt
@@ -265,16 +265,20 @@
"com/mysdk/MySdk.kt", """
package com.mysdk
import androidx.privacysandbox.tools.PrivacySandboxService
+ import androidx.privacysandbox.tools.PrivacySandboxInterface
interface FooInterface {}
@PrivacySandboxService
- interface MySdk : FooInterface {
+ interface MySdk {}
+
+ @PrivacySandboxInterface
+ interface MyInterface : FooInterface {
suspend fun foo(): Int
}"""
)
checkSourceFails(source).containsExactlyErrors(
- "Error in com.mysdk.MySdk: annotated interface inherits prohibited types (" +
+ "Error in com.mysdk.MyInterface: annotated interface inherits prohibited types (" +
"FooInterface)."
)
}
@@ -285,6 +289,7 @@
"com/mysdk/MySdk.kt", """
package com.mysdk
import androidx.privacysandbox.tools.PrivacySandboxService
+ import androidx.privacysandbox.tools.PrivacySandboxInterface
interface A {}
interface B {}
@@ -292,13 +297,16 @@
interface D {}
@PrivacySandboxService
- interface MySdk : B, C, D, A {
+ interface MySdk {}
+
+ @PrivacySandboxInterface
+ interface MyInterface : B, C, D, A {
suspend fun foo(): Int
}"""
)
checkSourceFails(source).containsExactlyErrors(
- "Error in com.mysdk.MySdk: annotated interface inherits prohibited types (A, B, C, " +
- "...)."
+ "Error in com.mysdk.MyInterface: annotated interface inherits prohibited types (A, " +
+ "B, C, ...)."
)
}
diff --git a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/validator/ModelValidator.kt b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/validator/ModelValidator.kt
index 15aa5e0..bc6aeb5 100644
--- a/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/validator/ModelValidator.kt
+++ b/privacysandbox/tools/tools-core/src/main/java/androidx/privacysandbox/tools/core/validator/ModelValidator.kt
@@ -36,6 +36,7 @@
private fun validate(): ValidationResult {
validateSingleService()
+ validateServiceSupertypes()
validateNonSuspendFunctionsReturnUnit()
validateServiceAndInterfaceMethods()
validateValuePropertyTypes()
@@ -52,6 +53,24 @@
}
}
+ private fun validateServiceSupertypes() {
+ val superTypes = api.services.first().superTypes
+ if (superTypes.isNotEmpty()) {
+ if (superTypes.contains(Types.sandboxedUiAdapter)) {
+ errors.add(
+ "Interfaces annotated with @PrivacySandboxService may not extend any other " +
+ "interface. To define a SandboxedUiAdapter, use @PrivacySandboxInterface " +
+ "and return it from this service."
+ )
+ } else {
+ errors.add(
+ "Interfaces annotated with @PrivacySandboxService may not extend any other " +
+ "interface. Found: ${superTypes.joinToString { it.qualifiedName }}."
+ )
+ }
+ }
+ }
+
private fun validateNonSuspendFunctionsReturnUnit() {
val annotatedInterfaces = api.services + api.interfaces
for (annotatedInterface in annotatedInterfaces) {
diff --git a/privacysandbox/tools/tools-core/src/test/java/androidx/privacysandbox/tools/core/validator/ModelValidatorTest.kt b/privacysandbox/tools/tools-core/src/test/java/androidx/privacysandbox/tools/core/validator/ModelValidatorTest.kt
index 3a967ad..ab69a85 100644
--- a/privacysandbox/tools/tools-core/src/test/java/androidx/privacysandbox/tools/core/validator/ModelValidatorTest.kt
+++ b/privacysandbox/tools/tools-core/src/test/java/androidx/privacysandbox/tools/core/validator/ModelValidatorTest.kt
@@ -169,6 +169,25 @@
}
@Test
+ fun serviceExtendsUiAdapter_throws() {
+ val api = ParsedApi(
+ services = setOf(
+ AnnotatedInterface(
+ type = Type(packageName = "com.mysdk", simpleName = "MySdk"),
+ superTypes = listOf(Types.sandboxedUiAdapter),
+ ),
+ )
+ )
+ val validationResult = ModelValidator.validate(api)
+ assertThat(validationResult.isFailure).isTrue()
+ assertThat(validationResult.errors).containsExactly(
+ "Interfaces annotated with @PrivacySandboxService may not extend any other " +
+ "interface. To define a SandboxedUiAdapter, use @PrivacySandboxInterface and " +
+ "return it from this service."
+ )
+ }
+
+ @Test
fun nonSuspendFunctionReturningValue_throws() {
val api = ParsedApi(
services = setOf(