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

Commit cd88fe3c authored by Lee Shombert's avatar Lee Shombert Committed by Automerger Merge Worker
Browse files

Merge "Validate Computer functions" into sc-dev am: a7ff24bf

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14923267

Change-Id: I58f60f4b69ca6d973d3b53571a52d29dcaf64c3d
parents 719f5171 a7ff24bf
Loading
Loading
Loading
Loading
+212 −114

File changed.

Preview size limit exceeded, changes collapsed.

+179 −0
Original line number Original line Diff line number Diff line
@@ -18,7 +18,11 @@ package com.android.server.pm;


import static com.google.common.truth.Truth.assertWithMessage;
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.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.isPublic;
import static java.lang.reflect.Modifier.isStatic;
import static java.lang.reflect.Modifier.isStatic;


@@ -44,9 +48,12 @@ import org.junit.runner.RunWith;


import java.io.File;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
import java.util.Collections;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.Pattern;


@@ -393,6 +400,178 @@ public class PackageManagerServiceTest {
        Assert.assertEquals(3600000003L, multiPackage[1].timeouts.maxPendingTimeUs);
        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) {
    private static PerPackageReadTimeouts[] getPerPackageReadTimeouts(String knownDigestersList) {
        final String defaultTimeouts = "3600000001:3600000002:3600000003";
        final String defaultTimeouts = "3600000001:3600000002:3600000003";
        List<PerPackageReadTimeouts> result = PerPackageReadTimeouts.parseDigestersList(
        List<PerPackageReadTimeouts> result = PerPackageReadTimeouts.parseDigestersList(