Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5e226140 authored by Andrei Onea's avatar Andrei Onea
Browse files

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
parent 5c47b52b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -763,6 +763,7 @@ java_library_host {
    srcs: [
        "core/java/android/annotation/IntDef.java",
        "core/java/android/annotation/UnsupportedAppUsage.java",
        ":unsupportedappusage_annotation_files",
    ],
}

+39 −15
Original line number Diff line number Diff line
@@ -20,12 +20,13 @@ import static javax.lang.model.element.ElementKind.PACKAGE;
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 class SignatureBuilder {
        public SignatureBuilderException(String message) {
            super(message);
        }

        public void report(Element offendingElement) {
            mMessager.printMessage(ERROR, getMessage(), offendingElement);
        }
@@ -191,8 +193,13 @@ public class SignatureBuilder {
        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 @@ public class SignatureBuilder {
                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())) {
            // Obtain annotation objects
            Annotation annotation = element.getAnnotation(annotationType);
            if (annotation == null) {
                throw new IllegalStateException(
                        "Element doesn't have any UnsupportedAppUsage annotation");
            }
            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"
                                String.format(
                                        "Expected signature doesn't match generated signature.\n"
                                                + " Expected:  %s\n Generated: %s",
                                    uba.expectedSignature(), signature),
                                        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;
+42 −30
Original line number Diff line number Diff line
@@ -18,9 +18,8 @@ package android.processor.unsupportedappusage;

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 com.sun.tools.javac.util.Position;

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 @@ import javax.lang.model.element.TypeElement;
/**
 * 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 @@ public class UnsupportedAppUsageProcessor extends AbstractProcessor {
    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 @@ public class UnsupportedAppUsageProcessor extends AbstractProcessor {
    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;
            }
        }
@@ -164,20 +170,25 @@ public class UnsupportedAppUsageProcessor extends AbstractProcessor {
     */
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        Map<String, Element> signatureMap = new TreeMap<>();
        SignatureBuilder sb = new SignatureBuilder(processingEnv.getMessager());
        for (Class<? extends Annotation> supportedAnnotation : SUPPORTED_ANNOTATIONS) {
            Set<? extends Element> annotated = roundEnv.getElementsAnnotatedWith(
                UnsupportedAppUsage.class);
                    supportedAnnotation);
            if (annotated.size() == 0) {
            return true;
                continue;
            }
        // 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());
            // Build signatures for each annotated member and put them in a map from signature to
            // member.
            for (Element e : annotated) {
            String sig = sb.buildSignature(e);
                String sig = sb.buildSignature(supportedAnnotation, e);
                if (sig != null) {
                    signatureMap.put(sig, e);
                }
            }
        }

        if (!signatureMap.isEmpty()) {
            try {
                writeToFile(INDEX_CSV,
                        getCsvHeaders(),
@@ -187,6 +198,7 @@ public class UnsupportedAppUsageProcessor extends AbstractProcessor {
            } catch (IOException e) {
                throw new RuntimeException("Failed to write output", e);
            }
        }
        return true;
    }
}