Support all UnsupportedAppUsage annotations in processor

Add support for the libcore UnsupportedAppUsage annotation to
UnsupportedAppUsageProcessor. This is in order to make the two
annotations even more interchangeable.
Also take the opportunity to correct the documentation:
UnsupportedAppUsageProcessor no longer is involved in creating
greylist.txt, that functionality has been moved to
Class2Greylist.java in the art repository.

Bug: 130721457
Test: m framework-annotation-proc
Change-Id: I5cf1f97ca41349fc053315a2fd5bfd53a80ae128
diff --git a/Android.bp b/Android.bp
index 57f6513..53da6e2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -763,6 +763,7 @@
     srcs: [
         "core/java/android/annotation/IntDef.java",
         "core/java/android/annotation/UnsupportedAppUsage.java",
+        ":unsupportedappusage_annotation_files",
     ],
 }
 
diff --git a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java
index ef29146..5a5703e 100644
--- a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java
+++ b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/SignatureBuilder.java
@@ -20,12 +20,13 @@
 import static javax.tools.Diagnostic.Kind.ERROR;
 import static javax.tools.Diagnostic.Kind.WARNING;
 
-import android.annotation.UnsupportedAppUsage;
-
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableMap;
 import com.sun.tools.javac.code.Type;
 
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -69,6 +70,7 @@
         public SignatureBuilderException(String message) {
             super(message);
         }
+
         public void report(Element offendingElement) {
             mMessager.printMessage(ERROR, getMessage(), offendingElement);
         }
@@ -153,7 +155,7 @@
     /**
      * Get the signature for an executable, either a method or a constructor.
      *
-     * @param name "<init>" for  constructor, else the method name
+     * @param name   "<init>" for  constructor, else the method name
      * @param method The executable element in question.
      */
     private String getExecutableSignature(CharSequence name, ExecutableElement method)
@@ -191,8 +193,13 @@
         return sig.toString();
     }
 
-    public String buildSignature(Element element) {
-        UnsupportedAppUsage uba = element.getAnnotation(UnsupportedAppUsage.class);
+    /**
+     * Creates the signature for an annotated element.
+     *
+     * @param annotationType type of annotation being processed.
+     * @param element        element for which we want to create a signature.
+     */
+    public String buildSignature(Class<? extends Annotation> annotationType, Element element) {
         try {
             String signature;
             switch (element.getKind()) {
@@ -208,18 +215,35 @@
                 default:
                     return null;
             }
-            // if we have an expected signature on the annotation, warn if it doesn't match.
-            if (!Strings.isNullOrEmpty(uba.expectedSignature())) {
-                if (!signature.equals(uba.expectedSignature())) {
-                    mMessager.printMessage(
-                            WARNING,
-                            String.format("Expected signature doesn't match generated signature.\n"
-                                            + " Expected:  %s\n Generated: %s",
-                                    uba.expectedSignature(), signature),
-                            element);
-                }
+            // Obtain annotation objects
+            Annotation annotation = element.getAnnotation(annotationType);
+            if (annotation == null) {
+                throw new IllegalStateException(
+                        "Element doesn't have any UnsupportedAppUsage annotation");
             }
-            return signature;
+            try {
+                Method expectedSignatureMethod = annotationType.getMethod("expectedSignature");
+                // If we have an expected signature on the annotation, warn if it doesn't match.
+                String expectedSignature = expectedSignatureMethod.invoke(annotation).toString();
+                if (!Strings.isNullOrEmpty(expectedSignature)) {
+                    if (!signature.equals(expectedSignature)) {
+                        mMessager.printMessage(
+                                WARNING,
+                                String.format(
+                                        "Expected signature doesn't match generated signature.\n"
+                                                + " Expected:  %s\n Generated: %s",
+                                        expectedSignature, signature),
+                                element);
+                    }
+                }
+                return signature;
+            } catch (NoSuchMethodException e) {
+                throw new IllegalStateException(
+                        "Annotation type does not have expectedSignature parameter", e);
+            } catch (IllegalAccessException | InvocationTargetException e) {
+                throw new IllegalStateException(
+                        "Could not get expectedSignature parameter for annotation", e);
+            }
         } catch (SignatureBuilderException problem) {
             problem.report(element);
             return null;
diff --git a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessor.java b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessor.java
index d368136..5bb956a 100644
--- a/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessor.java
+++ b/tools/processors/unsupportedappusage/src/android/processor/unsupportedappusage/UnsupportedAppUsageProcessor.java
@@ -18,9 +18,8 @@
 
 import static javax.tools.StandardLocation.CLASS_OUTPUT;
 
-import android.annotation.UnsupportedAppUsage;
-
 import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableSet;
 import com.sun.tools.javac.model.JavacElements;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.util.Pair;
@@ -28,6 +27,7 @@
 
 import java.io.IOException;
 import java.io.PrintStream;
+import java.lang.annotation.Annotation;
 import java.net.URLEncoder;
 import java.util.Map;
 import java.util.Set;
@@ -47,14 +47,14 @@
 /**
  * Annotation processor for {@link UnsupportedAppUsage} annotations.
  *
- * This processor currently outputs two things:
- * 1. A greylist.txt containing dex signatures of all annotated elements.
- * 2. A CSV file with a mapping of dex signatures to corresponding source positions.
+ * This processor currently outputs a CSV file with a mapping of dex signatures to corresponding
+ * source positions.
  *
- * The first will be used at a later stage of the build to add access flags to the dex file. The
- * second is used for automating updates to the annotations themselves.
+ * This is used for automating updates to the annotations themselves.
  */
-@SupportedAnnotationTypes({"android.annotation.UnsupportedAppUsage"})
+@SupportedAnnotationTypes({"android.annotation.UnsupportedAppUsage",
+        "dalvik.annotation.compat.UnsupportedAppUsage"
+})
 public class UnsupportedAppUsageProcessor extends AbstractProcessor {
 
     // Package name for writing output. Output will be written to the "class output" location within
@@ -62,6 +62,13 @@
     private static final String PACKAGE = "unsupportedappusage";
     private static final String INDEX_CSV = "unsupportedappusage_index.csv";
 
+    private static final ImmutableSet<Class<? extends Annotation>> SUPPORTED_ANNOTATIONS =
+            ImmutableSet.of(android.annotation.UnsupportedAppUsage.class,
+                    dalvik.annotation.compat.UnsupportedAppUsage.class);
+    private static final ImmutableSet<String> SUPPORTED_ANNOTATION_NAMES =
+            SUPPORTED_ANNOTATIONS.stream().map(annotation -> annotation.getCanonicalName()).collect(
+                    ImmutableSet.toImmutableSet());
+
     @Override
     public SourceVersion getSupportedSourceVersion() {
         return SourceVersion.latest();
@@ -92,8 +99,7 @@
     private AnnotationMirror getUnsupportedAppUsageAnnotationMirror(Element e) {
         for (AnnotationMirror m : e.getAnnotationMirrors()) {
             TypeElement type = (TypeElement) m.getAnnotationType().asElement();
-            if (type.getQualifiedName().toString().equals(
-                    UnsupportedAppUsage.class.getCanonicalName())) {
+            if (SUPPORTED_ANNOTATION_NAMES.contains(type.getQualifiedName().toString())) {
                 return m;
             }
         }
@@ -133,12 +139,12 @@
     /**
      * Maps an annotated element to the source position of the @UnsupportedAppUsage annotation
      * attached to it. It returns CSV in the format:
-     *   dex-signature,filename,start-line,start-col,end-line,end-col
+     * dex-signature,filename,start-line,start-col,end-line,end-col
      *
      * The positions refer to the annotation itself, *not* the annotated member. This can therefore
      * be used to read just the annotation from the file, and to perform in-place edits on it.
      *
-     * @param signature the dex signature for the element.
+     * @param signature        the dex signature for the element.
      * @param annotatedElement The annotated element
      * @return A single line of CSV text
      */
@@ -164,28 +170,34 @@
      */
     @Override
     public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
-        Set<? extends Element> annotated = roundEnv.getElementsAnnotatedWith(
-                UnsupportedAppUsage.class);
-        if (annotated.size() == 0) {
-            return true;
-        }
-        // build signatures for each annotated member, and put them in a map of signature to member
         Map<String, Element> signatureMap = new TreeMap<>();
         SignatureBuilder sb = new SignatureBuilder(processingEnv.getMessager());
-        for (Element e : annotated) {
-            String sig = sb.buildSignature(e);
-            if (sig != null) {
-                signatureMap.put(sig, e);
+        for (Class<? extends Annotation> supportedAnnotation : SUPPORTED_ANNOTATIONS) {
+            Set<? extends Element> annotated = roundEnv.getElementsAnnotatedWith(
+                    supportedAnnotation);
+            if (annotated.size() == 0) {
+                continue;
+            }
+            // Build signatures for each annotated member and put them in a map from signature to
+            // member.
+            for (Element e : annotated) {
+                String sig = sb.buildSignature(supportedAnnotation, e);
+                if (sig != null) {
+                    signatureMap.put(sig, e);
+                }
             }
         }
-        try {
-            writeToFile(INDEX_CSV,
-                    getCsvHeaders(),
-                    signatureMap.entrySet()
-                            .stream()
-                            .map(e -> getAnnotationIndex(e.getKey() ,e.getValue())));
-        } catch (IOException e) {
-            throw new RuntimeException("Failed to write output", e);
+
+        if (!signatureMap.isEmpty()) {
+            try {
+                writeToFile(INDEX_CSV,
+                        getCsvHeaders(),
+                        signatureMap.entrySet()
+                                .stream()
+                                .map(e -> getAnnotationIndex(e.getKey(), e.getValue())));
+            } catch (IOException e) {
+                throw new RuntimeException("Failed to write output", e);
+            }
         }
         return true;
     }