diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2017-06-07 07:48:09 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2017-06-07 07:48:09 +0000 |
commit | 1b6b717769d4ab8317d292f3b931011c70dee427 (patch) | |
tree | 21d0766bd8078537adce479da8bb273f501253ca | |
parent | 3ecf15551bfc999bcc0be0e6c5e78540a4fb20ae (diff) | |
parent | 4500890636ce6930d9659c5ffa7c029c93569aa6 (diff) | |
download | platform_external_doclava-1b6b717769d4ab8317d292f3b931011c70dee427.tar.gz platform_external_doclava-1b6b717769d4ab8317d292f3b931011c70dee427.tar.bz2 platform_external_doclava-1b6b717769d4ab8317d292f3b931011c70dee427.zip |
release-request-224b654d-e3ad-4f05-a95d-d10d1516b3f6-for-git_oc-release-4075622 snap-temp-L17600000071371496
Change-Id: Ic8d19b59006f70e3b0e31e509dbedd9768ddabfc
-rw-r--r-- | src/com/google/doclava/Doclava.java | 37 | ||||
-rw-r--r-- | src/com/google/doclava/Stubs.java | 77 |
2 files changed, 95 insertions, 19 deletions
diff --git a/src/com/google/doclava/Doclava.java b/src/com/google/doclava/Doclava.java index 9359930..6d26d80 100644 --- a/src/com/google/doclava/Doclava.java +++ b/src/com/google/doclava/Doclava.java @@ -28,6 +28,7 @@ import com.sun.javadoc.*; import java.util.*; import java.util.jar.JarFile; import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.io.*; import java.lang.reflect.Proxy; import java.lang.reflect.Array; @@ -118,6 +119,8 @@ public class Doclava { public static AuxSource auxSource = new EmptyAuxSource(); public static Linter linter = new EmptyLinter(); public static boolean android = false; + public static String manifestFile = null; + public static Map<String, String> manifestPermissions = new HashMap<>(); public static JSilver jSilver = null; @@ -352,12 +355,17 @@ public class Doclava { auxSource = new AndroidAuxSource(); linter = new AndroidLinter(); android = true; + } else if (a[0].equals("-manifest")) { + manifestFile = a[1]; } } if (!readKnownTagsFiles(knownTags, knownTagsFiles)) { return false; } + if (!readManifest()) { + return false; + } // Set up the data structures Converter.makeInfo(r); @@ -591,6 +599,32 @@ public class Doclava { return true; } + private static boolean readManifest() { + manifestPermissions.clear(); + if (manifestFile == null) { + return true; + } + try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(manifestFile)); + ByteArrayOutputStream out = new ByteArrayOutputStream()) { + byte[] buffer = new byte[1024]; + int count; + while ((count = in.read(buffer)) != -1) { + out.write(buffer, 0, count); + } + final Matcher m = Pattern.compile("(?s)<permission " + + "[^>]*android:name=\"([^\">]+)\"" + + "[^>]*android:protectionLevel=\"([^\">]+)\"").matcher(out.toString()); + while (m.find()) { + manifestPermissions.put(m.group(1), m.group(2)); + } + } catch (IOException e) { + Errors.error(Errors.PARSE_ERROR, (SourcePositionInfo) null, + "Failed to parse " + manifestFile + ": " + e); + return false; + } + return true; + } + public static String escape(String s) { if (escapeChars.size() == 0) { return s; @@ -814,6 +848,9 @@ public class Doclava { if (option.equals("-android")) { return 1; } + if (option.equals("-manifest")) { + return 2; + } return 0; } public static boolean validOptions(String[][] options, DocErrorReporter r) { diff --git a/src/com/google/doclava/Stubs.java b/src/com/google/doclava/Stubs.java index added35..fbcff97 100644 --- a/src/com/google/doclava/Stubs.java +++ b/src/com/google/doclava/Stubs.java @@ -1296,7 +1296,7 @@ public class Stubs { // that they're protected with a system permission. if (Doclava.android && Doclava.showAnnotations.contains("android.annotation.SystemApi") && !(predicate instanceof RemovedPredicate)) { - boolean systemService = false; + boolean systemService = "android.content.pm.PackageManager".equals(cl.qualifiedName()); for (AnnotationInstanceInfo a : cl.annotations()) { if (a.type().qualifiedNameMatches("android", "annotation.SystemService")) { systemService = true; @@ -1304,24 +1304,7 @@ public class Stubs { } if (systemService) { for (MethodInfo mi : methods) { - boolean hasPermission = false; - for (AnnotationInstanceInfo a : mi.annotations()) { - if (a.type().qualifiedNameMatches("android", "annotation.RequiresPermission")) { - hasPermission = true; - } - } - for (ParameterInfo pi : mi.parameters()) { - for (AnnotationInstanceInfo a : pi.annotations()) { - if (a.type().qualifiedNameMatches("android", "annotation.RequiresPermission")) { - hasPermission = true; - } - } - } - if (!hasPermission) { - Errors.error(Errors.REQUIRES_PERMISSION, mi, - "Method '" + mi.name() + "' exposed as @SystemApi must be" - + " protected with a system permission."); - } + checkSystemPermissions(mi); } } } @@ -1393,6 +1376,62 @@ public class Stubs { return hasWrittenPackageHead; } + private static void checkSystemPermissions(MethodInfo mi) { + boolean hasAnnotation = false; + for (AnnotationInstanceInfo a : mi.annotations()) { + if (a.type().qualifiedNameMatches("android", "annotation.RequiresPermission")) { + hasAnnotation = true; + for (AnnotationValueInfo val : a.elementValues()) { + ArrayList<AnnotationValueInfo> values = null; + boolean any = false; + switch (val.element().name()) { + case "value": + values = new ArrayList<AnnotationValueInfo>(); + values.add(val); + break; + case "allOf": + values = (ArrayList<AnnotationValueInfo>) val.value(); + break; + case "anyOf": + any = true; + values = (ArrayList<AnnotationValueInfo>) val.value(); + break; + } + + ArrayList<String> system = new ArrayList<>(); + ArrayList<String> nonSystem = new ArrayList<>(); + for (AnnotationValueInfo value : values) { + final String perm = String.valueOf(value.value()); + final String level = Doclava.manifestPermissions.getOrDefault(perm, null); + if (level == null) { + Errors.error(Errors.REMOVED_FIELD, mi.position(), + "Permission '" + perm + "' is not defined by AndroidManifest.xml."); + continue; + } + if (level.contains("normal") || level.contains("dangerous") + || level.contains("ephemeral")) { + nonSystem.add(perm); + } else { + system.add(perm); + } + } + + if (system.isEmpty() && nonSystem.isEmpty()) { + hasAnnotation = false; + } else if ((any && !nonSystem.isEmpty()) || (!any && system.isEmpty())) { + Errors.error(Errors.REQUIRES_PERMISSION, mi, "Method '" + mi.name() + + "' must be protected with a system permission; it currently" + + " allows non-system callers holding " + nonSystem.toString()); + } + } + } + } + if (!hasAnnotation) { + Errors.error(Errors.REQUIRES_PERMISSION, mi, "Method '" + mi.name() + + "' must be protected with a system permission."); + } + } + public static void writeApi(PrintStream apiWriter, Collection<PackageInfo> pkgs) { final PackageInfo[] packages = pkgs.toArray(new PackageInfo[pkgs.size()]); Arrays.sort(packages, PackageInfo.comparator); |