Loading services/core/java/com/android/server/pm/PackageManagerService.java +212 −114 File changed.Preview size limit exceeded, changes collapsed. Show changes services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java +179 −0 Original line number Diff line number Diff line Loading @@ -18,7 +18,11 @@ package com.android.server.pm; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.fail; import static java.lang.reflect.Modifier.isFinal; import static java.lang.reflect.Modifier.isPrivate; import static java.lang.reflect.Modifier.isProtected; import static java.lang.reflect.Modifier.isPublic; import static java.lang.reflect.Modifier.isStatic; Loading @@ -44,9 +48,12 @@ import org.junit.runner.RunWith; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.regex.Pattern; Loading Loading @@ -393,6 +400,178 @@ public class PackageManagerServiceTest { Assert.assertEquals(3600000003L, multiPackage[1].timeouts.maxPendingTimeUs); } // Report an error from the Computer structure validation test. private void flag(String name, String msg) { fail(name + " " + msg); } // Return a string that identifies a Method. This is not very efficient but it is not // called very often. private String displayName(Method m) { String r = m.getName(); String p = Arrays.toString(m.getGenericParameterTypes()) .replaceAll("([a-zA-Z0-9]+\\.)+", "") .replace("class ", "") .replaceAll("^\\[", "(") .replaceAll("\\]$", ")"); return r + p; } // Match a method to an array of Methods. Matching is on method signature: name and // parameter types. If a method in the declared array matches, return it. Otherwise // return null. private Method matchMethod(Method m, Method[] declared) { String n = m.getName(); Type[] t = m.getGenericParameterTypes(); for (int i = 0; i < declared.length; i++) { Method l = declared[i]; if (l != null && l.getName().equals(n) && Arrays.equals(l.getGenericParameterTypes(), t)) { Method result = l; // Set the method to null since it has been visited already. declared[i] = null; return result; } } return null; } // Return the boolean locked value. A null return means the annotation was not // found. This method will fail if the annotation is found but is not one of the // known constants. private Boolean getOverride(Method m) { final String name = "Computer." + displayName(m); final PackageManagerService.Computer.LiveImplementation annotation = m.getAnnotation(PackageManagerService.Computer.LiveImplementation.class); if (annotation == null) { return null; } final int override = annotation.override(); if (override == PackageManagerService.Computer.LiveImplementation.MANDATORY) { return true; } else if (override == PackageManagerService.Computer.LiveImplementation.NOT_ALLOWED) { return false; } else { flag(name, "invalid Live value: " + override); return null; } } @Test public void testComputerStructure() { // Verify that Copmuter methods are properly annotated and that ComputerLocked is // properly populated per annotations. // Call PackageManagerService.validateComputer(); Class base = PackageManagerService.Computer.class; HashMap<Method, Boolean> methodType = new HashMap<>(); // Verify that all Computer methods are annotated and that the annotation // parameter locked() is valid. for (Method m : base.getDeclaredMethods()) { final String name = "Computer." + displayName(m); Boolean override = getOverride(m); if (override == null) { flag(name, "missing required Live annotation"); } methodType.put(m, override); } Class coreClass = PackageManagerService.ComputerEngine.class; final Method[] coreMethods = coreClass.getDeclaredMethods(); // Examine every method in the core. If it inherits from a base method it must be // "public final" if the base is NOT_ALLOWED or "public" if the base is MANDATORY. // If the core method does not inherit from the base then it must be either // private or protected. for (Method m : base.getDeclaredMethods()) { String name = "Computer." + displayName(m); final boolean locked = methodType.get(m); final Method core = matchMethod(m, coreMethods); if (core == null) { flag(name, "not overridden in ComputerEngine"); continue; } name = "ComputerEngine." + displayName(m); final int modifiers = core.getModifiers(); if (!locked) { if (!isPublic(modifiers)) { flag(name, "is not public"); } if (!isFinal(modifiers)) { flag(name, "is not final"); } } } // Any methods left in the coreMethods array must be private or protected. // Protected methods must be overridden (and final) in the live list. Method[] coreHelpers = new Method[coreMethods.length]; int coreIndex = 0; for (Method m : coreMethods) { if (m != null) { final String name = "ComputerEngine." + displayName(m); final int modifiers = m.getModifiers(); if (isPrivate(modifiers)) { // Okay } else if (isProtected(modifiers)) { coreHelpers[coreIndex++] = m; } else { flag(name, "is neither private nor protected"); } } } Class liveClass = PackageManagerService.ComputerLocked.class; final Method[] liveMethods = liveClass.getDeclaredMethods(); // Examine every method in the live list. Every method must be final and must // inherit either from base or core. If the method inherits from a base method // then the base must be MANDATORY. for (Method m : base.getDeclaredMethods()) { String name = "Computer." + displayName(m); final boolean locked = methodType.get(m); final Method live = matchMethod(m, liveMethods); if (live == null) { if (locked) { flag(name, "not overridden in ComputerLocked"); } continue; } if (!locked) { flag(name, "improperly overridden in ComputerLocked"); continue; } name = "ComputerLocked." + displayName(m); final int modifiers = live.getModifiers(); if (!locked) { if (!isPublic(modifiers)) { flag(name, "is not public"); } if (!isFinal(modifiers)) { flag(name, "is not final"); } } } for (Method m : coreHelpers) { if (m == null) { continue; } String name = "ComputerLocked." + displayName(m); final Method live = matchMethod(m, liveMethods); if (live == null) { flag(name, "is not overridden in ComputerLocked"); continue; } } for (Method m : liveMethods) { if (m != null) { String name = "ComputerLocked." + displayName(m); flag(name, "illegal local method"); } } } private static PerPackageReadTimeouts[] getPerPackageReadTimeouts(String knownDigestersList) { final String defaultTimeouts = "3600000001:3600000002:3600000003"; List<PerPackageReadTimeouts> result = PerPackageReadTimeouts.parseDigestersList( Loading Loading
services/core/java/com/android/server/pm/PackageManagerService.java +212 −114 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/tests/servicestests/src/com/android/server/pm/PackageManagerServiceTest.java +179 −0 Original line number Diff line number Diff line Loading @@ -18,7 +18,11 @@ package com.android.server.pm; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.fail; import static java.lang.reflect.Modifier.isFinal; import static java.lang.reflect.Modifier.isPrivate; import static java.lang.reflect.Modifier.isProtected; import static java.lang.reflect.Modifier.isPublic; import static java.lang.reflect.Modifier.isStatic; Loading @@ -44,9 +48,12 @@ import org.junit.runner.RunWith; import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.regex.Pattern; Loading Loading @@ -393,6 +400,178 @@ public class PackageManagerServiceTest { Assert.assertEquals(3600000003L, multiPackage[1].timeouts.maxPendingTimeUs); } // Report an error from the Computer structure validation test. private void flag(String name, String msg) { fail(name + " " + msg); } // Return a string that identifies a Method. This is not very efficient but it is not // called very often. private String displayName(Method m) { String r = m.getName(); String p = Arrays.toString(m.getGenericParameterTypes()) .replaceAll("([a-zA-Z0-9]+\\.)+", "") .replace("class ", "") .replaceAll("^\\[", "(") .replaceAll("\\]$", ")"); return r + p; } // Match a method to an array of Methods. Matching is on method signature: name and // parameter types. If a method in the declared array matches, return it. Otherwise // return null. private Method matchMethod(Method m, Method[] declared) { String n = m.getName(); Type[] t = m.getGenericParameterTypes(); for (int i = 0; i < declared.length; i++) { Method l = declared[i]; if (l != null && l.getName().equals(n) && Arrays.equals(l.getGenericParameterTypes(), t)) { Method result = l; // Set the method to null since it has been visited already. declared[i] = null; return result; } } return null; } // Return the boolean locked value. A null return means the annotation was not // found. This method will fail if the annotation is found but is not one of the // known constants. private Boolean getOverride(Method m) { final String name = "Computer." + displayName(m); final PackageManagerService.Computer.LiveImplementation annotation = m.getAnnotation(PackageManagerService.Computer.LiveImplementation.class); if (annotation == null) { return null; } final int override = annotation.override(); if (override == PackageManagerService.Computer.LiveImplementation.MANDATORY) { return true; } else if (override == PackageManagerService.Computer.LiveImplementation.NOT_ALLOWED) { return false; } else { flag(name, "invalid Live value: " + override); return null; } } @Test public void testComputerStructure() { // Verify that Copmuter methods are properly annotated and that ComputerLocked is // properly populated per annotations. // Call PackageManagerService.validateComputer(); Class base = PackageManagerService.Computer.class; HashMap<Method, Boolean> methodType = new HashMap<>(); // Verify that all Computer methods are annotated and that the annotation // parameter locked() is valid. for (Method m : base.getDeclaredMethods()) { final String name = "Computer." + displayName(m); Boolean override = getOverride(m); if (override == null) { flag(name, "missing required Live annotation"); } methodType.put(m, override); } Class coreClass = PackageManagerService.ComputerEngine.class; final Method[] coreMethods = coreClass.getDeclaredMethods(); // Examine every method in the core. If it inherits from a base method it must be // "public final" if the base is NOT_ALLOWED or "public" if the base is MANDATORY. // If the core method does not inherit from the base then it must be either // private or protected. for (Method m : base.getDeclaredMethods()) { String name = "Computer." + displayName(m); final boolean locked = methodType.get(m); final Method core = matchMethod(m, coreMethods); if (core == null) { flag(name, "not overridden in ComputerEngine"); continue; } name = "ComputerEngine." + displayName(m); final int modifiers = core.getModifiers(); if (!locked) { if (!isPublic(modifiers)) { flag(name, "is not public"); } if (!isFinal(modifiers)) { flag(name, "is not final"); } } } // Any methods left in the coreMethods array must be private or protected. // Protected methods must be overridden (and final) in the live list. Method[] coreHelpers = new Method[coreMethods.length]; int coreIndex = 0; for (Method m : coreMethods) { if (m != null) { final String name = "ComputerEngine." + displayName(m); final int modifiers = m.getModifiers(); if (isPrivate(modifiers)) { // Okay } else if (isProtected(modifiers)) { coreHelpers[coreIndex++] = m; } else { flag(name, "is neither private nor protected"); } } } Class liveClass = PackageManagerService.ComputerLocked.class; final Method[] liveMethods = liveClass.getDeclaredMethods(); // Examine every method in the live list. Every method must be final and must // inherit either from base or core. If the method inherits from a base method // then the base must be MANDATORY. for (Method m : base.getDeclaredMethods()) { String name = "Computer." + displayName(m); final boolean locked = methodType.get(m); final Method live = matchMethod(m, liveMethods); if (live == null) { if (locked) { flag(name, "not overridden in ComputerLocked"); } continue; } if (!locked) { flag(name, "improperly overridden in ComputerLocked"); continue; } name = "ComputerLocked." + displayName(m); final int modifiers = live.getModifiers(); if (!locked) { if (!isPublic(modifiers)) { flag(name, "is not public"); } if (!isFinal(modifiers)) { flag(name, "is not final"); } } } for (Method m : coreHelpers) { if (m == null) { continue; } String name = "ComputerLocked." + displayName(m); final Method live = matchMethod(m, liveMethods); if (live == null) { flag(name, "is not overridden in ComputerLocked"); continue; } } for (Method m : liveMethods) { if (m != null) { String name = "ComputerLocked." + displayName(m); flag(name, "illegal local method"); } } } private static PerPackageReadTimeouts[] getPerPackageReadTimeouts(String knownDigestersList) { final String defaultTimeouts = "3600000001:3600000002:3600000003"; List<PerPackageReadTimeouts> result = PerPackageReadTimeouts.parseDigestersList( Loading