SystemApis are exact matched
SignatureTest now ensures that APIs annotated as @SystemAPI is not
altered from the documented API set. Specifically, SystemAPI annotation
is now changed to be retained at runtime and the test gathers all
classes, methods, fields, etc. that have the annotation. If some element
is found in the device which is missing in the documented API, then it
is reported as an error.
Bug: 67891551
Test: cts-tradefed run cts --module CtsSystemCurrentApiSignatureTestCases
shows no additional error
Test: cts/tests/signature/tests/run_unit_tests.sh
Change-Id: I4fbd03aadd609401b3e8bdd3b36165299e999261
diff --git a/tests/signature/api-check/src/android/signature/cts/api/BootClassPathClassesProvider.java b/tests/signature/api-check/src/android/signature/cts/api/BootClassPathClassesProvider.java
index e2c92b3..79b6374 100644
--- a/tests/signature/api-check/src/android/signature/cts/api/BootClassPathClassesProvider.java
+++ b/tests/signature/api-check/src/android/signature/cts/api/BootClassPathClassesProvider.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.signature.cts.api;
import java.io.IOException;
@@ -55,5 +56,4 @@
private String[] getBootJarPaths() {
return System.getProperty("java.boot.class.path").split(":");
}
-
-}
+}
\ No newline at end of file
diff --git a/tests/signature/api-check/src/android/signature/cts/api/SignatureTest.java b/tests/signature/api-check/src/android/signature/cts/api/SignatureTest.java
index 4240588..37ca114 100644
--- a/tests/signature/api-check/src/android/signature/cts/api/SignatureTest.java
+++ b/tests/signature/api-check/src/android/signature/cts/api/SignatureTest.java
@@ -16,15 +16,8 @@
package android.signature.cts.api;
-import android.os.Bundle;
-import android.signature.cts.ApiDocumentParser;
-import android.signature.cts.ClassProvider;
-import android.signature.cts.ApiComplianceChecker;
-import android.signature.cts.FailureType;
-import android.signature.cts.ExcludingClassProvider;
-import android.signature.cts.JDiffClassDescription;
-import android.signature.cts.ReflectionHelper;
-import android.signature.cts.ResultObserver;
+import static android.signature.cts.CurrentApi.API_FILE_DIRECTORY;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -32,14 +25,21 @@
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
-import java.util.function.Predicate;
import org.xmlpull.v1.XmlPullParserException;
+
+import android.os.Bundle;
+import android.signature.cts.ApiComplianceChecker;
+import android.signature.cts.ApiDocumentParser;
+import android.signature.cts.ClassProvider;
+import android.signature.cts.ExcludingClassProvider;
+import android.signature.cts.FailureType;
+import android.signature.cts.JDiffClassDescription;
+import android.signature.cts.ReflectionHelper;
+import android.signature.cts.ResultObserver;
import repackaged.android.test.InstrumentationTestCase;
import repackaged.android.test.InstrumentationTestRunner;
-import static android.signature.cts.CurrentApi.API_FILE_DIRECTORY;
-
/**
* Performs the signature check via a JUnit test.
*/
@@ -71,6 +71,7 @@
private String[] expectedApiFiles;
private String[] unexpectedApiFiles;
+ private String annotationForExactMatch;
private class TestResultObserver implements ResultObserver {
@@ -101,6 +102,7 @@
expectedApiFiles = getCommaSeparatedList(instrumentationArgs, "expected-api-files");
unexpectedApiFiles = getCommaSeparatedList(instrumentationArgs, "unexpected-api-files");
+ annotationForExactMatch = instrumentationArgs.getString("annotation-for-exact-match");
}
private String[] getCommaSeparatedList(Bundle instrumentationArgs, String key) {
@@ -120,10 +122,13 @@
try {
// Prepare for a class provider that loads classes from bootclasspath but filters
- // out known inaccessible classes
+ // out known inaccessible classes.
+ // Note that com.android.internal.R.* inner classes are also excluded as they are
+ // not part of API though exist in the runtime.
ClassProvider classProvider = new ExcludingClassProvider(
new BootClassPathClassesProvider(),
- KNOWN_INACCESSIBLE_CLASSES::contains);
+ name -> KNOWN_INACCESSIBLE_CLASSES.contains(name)
+ || (name != null && name.startsWith("com.android.internal.R.")));
Set<JDiffClassDescription> unexpectedClasses = loadUnexpectedClasses();
for (JDiffClassDescription classDescription : unexpectedClasses) {
@@ -138,6 +143,7 @@
ApiComplianceChecker complianceChecker = new ApiComplianceChecker(mResultObserver,
classProvider);
+ complianceChecker.setAnnotationForExactMatch(annotationForExactMatch);
ApiDocumentParser apiDocumentParser = new ApiDocumentParser(
TAG, new ApiDocumentParser.Listener() {
@Override
@@ -158,6 +164,9 @@
File file = new File(API_FILE_DIRECTORY + "/" + expectedApiFile);
apiDocumentParser.parse(new FileInputStream(file));
}
+
+ // After done parsing all expected API files, check for the exact match.
+ complianceChecker.checkExactMatch();
} catch (Exception e) {
mResultObserver.notifyFailure(FailureType.CAUGHT_EXCEPTION, e.getMessage(),
e.getMessage());
diff --git a/tests/signature/api-check/system-current-api/AndroidTest.xml b/tests/signature/api-check/system-current-api/AndroidTest.xml
index 6c574ea..f958e3d 100644
--- a/tests/signature/api-check/system-current-api/AndroidTest.xml
+++ b/tests/signature/api-check/system-current-api/AndroidTest.xml
@@ -41,6 +41,7 @@
<option name="runner" value="repackaged.android.test.InstrumentationTestRunner" />
<option name="instrumentation-arg" key="expected-api-files" value="system-current.api,system-removed.api" />
<option name="instrumentation-arg" key="unexpected-api-files" value="android-test-mock-current.api,android-test-runner-current.api" />
+ <option name="instrumentation-arg" key="annotation-for-exact-match" value="android.annotation.SystemApi" />
<option name="runtime-hint" value="30s" />
</test>
</configuration>