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

Commit 80f45838 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 9070148 from 413bdfde to tm-qpr1-release

Change-Id: I8a290f054bab50c7c31406c0e740785fc4538204
parents 0527714a 413bdfde
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -287,6 +287,7 @@ package android.app {
    method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void setDreamOverlay(@Nullable android.content.ComponentName);
    method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setScreensaverEnabled(boolean);
    method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void setSystemDreamComponent(@Nullable android.content.ComponentName);
    method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void startDream(@Nullable android.content.ComponentName);
    method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void startDream();
    method @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE) public void stopDream();
  }
+19 −0
Original line number Diff line number Diff line
@@ -84,6 +84,25 @@ public class DreamManager {
                com.android.internal.R.bool.config_dreamsSupported);
    }

    /**
     * Starts dreaming.
     *
     * This API is equivalent to {@link DreamManager#startDream()} but with a nullable component
     * name to be compatible with TM CTS tests.
     *
     * <p>This is only used for testing the dream service APIs.
     *
     * @see DreamManager#startDream()
     *
     * @hide
     */
    @TestApi
    @UserHandleAware
    @RequiresPermission(android.Manifest.permission.WRITE_DREAM_STATE)
    public void startDream(@Nullable ComponentName name) {
        startDream();
    }

    /**
     * Starts dreaming.
     *
+62 −36
Original line number Diff line number Diff line
@@ -391,7 +391,12 @@ public class PropertyInvalidatedCache<Query, Result> {
    private static final boolean DEBUG = false;
    private static final boolean VERIFY = false;

    // Per-Cache performance counters. As some cache instances are declared static,
    /**
     * The object-private lock.
     */
    private final Object mLock = new Object();

    // Per-Cache performance counters.
    @GuardedBy("mLock")
    private long mHits = 0;

@@ -410,25 +415,19 @@ public class PropertyInvalidatedCache<Query, Result> {
    @GuardedBy("mLock")
    private long mClears = 0;

    // Most invalidation is done in a static context, so the counters need to be accessible.
    @GuardedBy("sCorkLock")
    private static final HashMap<String, Long> sInvalidates = new HashMap<>();

    /**
     * Record the number of invalidate or cork calls that were nops because
     * the cache was already corked.  This is static because invalidation is
     * done in a static context.
     * Protect objects that support corking.  mLock and sGlobalLock must never be taken while this
     * is held.
     */
    @GuardedBy("sCorkLock")
    private static final HashMap<String, Long> sCorkedInvalidates = new HashMap<>();
    private static final Object sCorkLock = new Object();

    /**
     * If sEnabled is false then all cache operations are stubbed out.  Set
     * it to false inside test processes.
     * Record the number of invalidate or cork calls that were nops because the cache was already
     * corked.  This is static because invalidation is done in a static context.  Entries are
     * indexed by the cache property.
     */
    private static boolean sEnabled = true;

    private static final Object sCorkLock = new Object();
    @GuardedBy("sCorkLock")
    private static final HashMap<String, Long> sCorkedInvalidates = new HashMap<>();

    /**
     * A map of cache keys that we've "corked". (The values are counts.)  When a cache key is
@@ -439,22 +438,40 @@ public class PropertyInvalidatedCache<Query, Result> {
    @GuardedBy("sCorkLock")
    private static final HashMap<String, Integer> sCorks = new HashMap<>();

    /**
     * A lock for the global list of caches and cache keys.  This must never be taken inside mLock
     * or sCorkLock.
     */
    private static final Object sGlobalLock = new Object();

    /**
     * A map of cache keys that have been disabled in the local process.  When a key is
     * disabled locally, existing caches are disabled and the key is saved in this map.
     * Future cache instances that use the same key will be disabled in their constructor.
     */
    @GuardedBy("sCorkLock")
    @GuardedBy("sGlobalLock")
    private static final HashSet<String> sDisabledKeys = new HashSet<>();

    /**
     * Weakly references all cache objects in the current process, allowing us to iterate over
     * them all for purposes like issuing debug dumps and reacting to memory pressure.
     */
    @GuardedBy("sCorkLock")
    @GuardedBy("sGlobalLock")
    private static final WeakHashMap<PropertyInvalidatedCache, Void> sCaches = new WeakHashMap<>();

    private final Object mLock = new Object();
    /**
     * Counts of the number of times a cache key was invalidated.  Invalidation occurs in a static
     * context with no cache object available, so this is a static map.  Entries are indexed by
     * the cache property.
     */
    @GuardedBy("sGlobalLock")
    private static final HashMap<String, Long> sInvalidates = new HashMap<>();

    /**
     * If sEnabled is false then all cache operations are stubbed out.  Set
     * it to false inside test processes.
     */
    private static boolean sEnabled = true;

    /**
     * Name of the property that holds the unique value that we use to invalidate the cache.
@@ -595,14 +612,17 @@ public class PropertyInvalidatedCache<Query, Result> {
        };
    }

    // Register the map in the global list.  If the cache is disabled globally, disable it
    // now.
    /**
     * Register the map in the global list.  If the cache is disabled globally, disable it
     * now.  This method is only ever called from the constructor, which means no other thread has
     * access to the object yet.  It can safely be modified outside any lock.
     */
    private void registerCache() {
        synchronized (sCorkLock) {
            sCaches.put(this, null);
        synchronized (sGlobalLock) {
            if (sDisabledKeys.contains(mCacheName)) {
                disableInstance();
            }
            sCaches.put(this, null);
        }
    }

@@ -797,8 +817,9 @@ public class PropertyInvalidatedCache<Query, Result> {
    }

    /**
     * Disable the use of this cache in this process.  This method is using during
     * testing.  To disable a cache in normal code, use disableLocal().
     * Disable the use of this cache in this process.  This method is using internally and during
     * testing.  To disable a cache in normal code, use disableLocal().  A disabled cache cannot
     * be re-enabled.
     * @hide
     */
    @TestApi
@@ -811,17 +832,23 @@ public class PropertyInvalidatedCache<Query, Result> {

    /**
     * Disable the local use of all caches with the same name.  All currently registered caches
     * using the key will be disabled now, and all future cache instances that use the key will be
     * disabled in their constructor.
     * with the name will be disabled now, and all future cache instances that use the name will
     * be disabled in their constructor.
     */
    private static final void disableLocal(@NonNull String name) {
        synchronized (sCorkLock) {
            sDisabledKeys.add(name);
        synchronized (sGlobalLock) {
            if (sDisabledKeys.contains(name)) {
                // The key is already in recorded so there is no further work to be done.
                return;
            }
            for (PropertyInvalidatedCache cache : sCaches.keySet()) {
                if (name.equals(cache.mCacheName)) {
                    cache.disableInstance();
                }
            }
            // Record the disabled key after the iteration.  If an exception occurs during the
            // iteration above, and the code is retried, the function should not exit early.
            sDisabledKeys.add(name);
        }
    }

@@ -834,7 +861,7 @@ public class PropertyInvalidatedCache<Query, Result> {
     */
    @TestApi
    public final void forgetDisableLocal() {
        synchronized (sCorkLock) {
        synchronized (sGlobalLock) {
            sDisabledKeys.remove(mCacheName);
        }
    }
@@ -851,9 +878,9 @@ public class PropertyInvalidatedCache<Query, Result> {
    }

    /**
     * Disable this cache in the current process, and all other caches that use the same
     * name.  This does not affect caches that have a different name but use the same
     * property.
     * Disable this cache in the current process, and all other present and future caches that use
     * the same name.  This does not affect caches that have a different name but use the same
     * property.  Once disabled, a cache cannot be reenabled.
     * @hide
     */
    @TestApi
@@ -1381,11 +1408,10 @@ public class PropertyInvalidatedCache<Query, Result> {
    /**
     * Returns a list of caches alive at the current time.
     */
    @GuardedBy("sGlobalLock")
    private static @NonNull ArrayList<PropertyInvalidatedCache> getActiveCaches() {
        synchronized (sCorkLock) {
        return new ArrayList<PropertyInvalidatedCache>(sCaches.keySet());
    }
    }

    /**
     * Returns a list of the active corks in a process.
@@ -1540,7 +1566,7 @@ public class PropertyInvalidatedCache<Query, Result> {
        boolean detail = anyDetailed(args);

        ArrayList<PropertyInvalidatedCache> activeCaches;
        synchronized (sCorkLock) {
        synchronized (sGlobalLock) {
            activeCaches = getActiveCaches();
            if (!detail) {
                dumpCorkInfo(pw);
+234 −63
Original line number Diff line number Diff line
@@ -16,12 +16,16 @@

package android.ddm;

import static com.android.internal.util.Preconditions.checkArgument;

import android.util.Log;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;

import com.android.internal.annotations.VisibleForTesting;

import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
import org.apache.harmony.dalvik.ddmc.DdmServer;
@@ -34,6 +38,7 @@ import java.io.OutputStreamWriter;
import java.lang.reflect.Method;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

/**
 * Handle various requests related to profiling / debugging of the view system.
@@ -123,15 +128,16 @@ public class DdmHandleViewDebug extends DdmHandle {
        }

        if (type == CHUNK_VURT) {
            if (op == VURT_DUMP_HIERARCHY)
            if (op == VURT_DUMP_HIERARCHY) {
                return dumpHierarchy(rootView, in);
            else if (op == VURT_CAPTURE_LAYERS)
            } else if (op == VURT_CAPTURE_LAYERS) {
                return captureLayers(rootView);
            else if (op == VURT_DUMP_THEME)
            } else if (op == VURT_DUMP_THEME) {
                return dumpTheme(rootView);
            else
            } else {
                return createFailChunk(ERR_INVALID_OP, "Unknown view root operation: " + op);
            }
        }

        final View targetView = getTargetView(rootView, in);
        if (targetView == null) {
@@ -305,16 +311,46 @@ public class DdmHandleViewDebug extends DdmHandle {
     * The method name and its arguments are passed in as inputs via the byte buffer.
     * The buffer contains:<ol>
     * <li> len(method name) </li>
     *  <li> method name </li>
     * <li> method name (encoded as UTF-16 2-byte characters) </li>
     * <li> # of args </li>
     * <li> arguments: Each argument comprises of a type specifier followed by the actual argument.
     *          The type specifier is a single character as used in JNI:
     *          (Z - boolean, B - byte, C - char, S - short, I - int, J - long,
     *          F - float, D - double). <p>
     *          The type specifier is followed by the actual value of argument.
     *          Booleans are encoded via bytes with 0 indicating false.</li>
     * The type specifier is one character modelled after JNI signatures:
     *          <ul>
     *              <li>[ - array<br>
     *                This is followed by a second character according to this spec, indicating the
     *                array type, then the array length as an Int, followed by a repeated encoding
     *                of the actual data.
     *                WARNING: Only <b>byte[]</b> is supported currently.
     *              </li>
     *              <li>Z - boolean<br>
     *                 Booleans are encoded via bytes with 0 indicating false</li>
     *              <li>B - byte</li>
     *              <li>C - char</li>
     *              <li>S - short</li>
     *              <li>I - int</li>
     *              <li>J - long</li>
     *              <li>F - float</li>
     *              <li>D - double</li>
     *              <li>V - void<br>
     *                NOT followed by a value. Only used for return types</li>
     *              <li>R - String (not a real JNI type, but added for convenience)<br>
     *                Strings are encoded as an unsigned short of the number of <b>bytes</b>,
     *                followed by the actual UTF-8 encoded bytes.
     *                WARNING: This is the same encoding as produced by
     *                ViewHierarchyEncoder#writeString. However, note that this encoding is
     *                different to what DdmHandle#getString() expects, which is used in other places
     *                in this class.
     *                WARNING: Since the length is the number of UTF-8 encoded bytes, Strings can
     *                contain up to 64k ASCII characters, yet depending on the actual data, the true
     *                maximum might be as little as 21844 unicode characters.
     *                <b>null</b> String objects are encoded as an empty string
     *              </li>
     *            </ul>
     *   </li>
     * </ol>
     * Methods that take no arguments need only specify the method name.
     *
     * The return value is encoded the same way as a single parameter (type + value)
     */
    private Chunk invokeViewMethod(final View rootView, final View targetView, ByteBuffer in) {
        int l = in.getInt();
@@ -327,54 +363,17 @@ public class DdmHandleViewDebug extends DdmHandle {
            args = new Object[0];
        } else {
            int nArgs = in.getInt();

            argTypes = new Class<?>[nArgs];
            args = new Object[nArgs];

            for (int i = 0; i < nArgs; i++) {
                char c = in.getChar();
                switch (c) {
                    case 'Z':
                        argTypes[i] = boolean.class;
                        args[i] = in.get() == 0 ? false : true;
                        break;
                    case 'B':
                        argTypes[i] = byte.class;
                        args[i] = in.get();
                        break;
                    case 'C':
                        argTypes[i] = char.class;
                        args[i] = in.getChar();
                        break;
                    case 'S':
                        argTypes[i] = short.class;
                        args[i] = in.getShort();
                        break;
                    case 'I':
                        argTypes[i] = int.class;
                        args[i] = in.getInt();
                        break;
                    case 'J':
                        argTypes[i] = long.class;
                        args[i] = in.getLong();
                        break;
                    case 'F':
                        argTypes[i] = float.class;
                        args[i] = in.getFloat();
                        break;
                    case 'D':
                        argTypes[i] = double.class;
                        args[i] = in.getDouble();
                        break;
                    default:
                        Log.e(TAG, "arg " + i + ", unrecognized type: " + c);
                        return createFailChunk(ERR_INVALID_PARAM,
                                "Unsupported parameter type (" + c + ") to invoke view method.");
                }
            try {
                deserializeMethodParameters(args, argTypes, in);
            } catch (ViewMethodInvocationSerializationException e) {
                return createFailChunk(ERR_INVALID_PARAM, e.getMessage());
            }
        }

        Method method = null;
        Method method;
        try {
            method = targetView.getClass().getMethod(methodName, argTypes);
        } catch (NoSuchMethodException e) {
@@ -384,7 +383,10 @@ public class DdmHandleViewDebug extends DdmHandle {
        }

        try {
            ViewDebug.invokeViewMethod(targetView, method, args);
            Object result = ViewDebug.invokeViewMethod(targetView, method, args);
            Class<?> returnType = method.getReturnType();
            byte[] returnValue = serializeReturnValue(returnType, returnType.cast(result));
            return new Chunk(CHUNK_VUOP, returnValue, 0, returnValue.length);
        } catch (Exception e) {
            Log.e(TAG, "Exception while invoking method: " + e.getCause().getMessage());
            String msg = e.getCause().getMessage();
@@ -393,8 +395,6 @@ public class DdmHandleViewDebug extends DdmHandle {
            }
            return createFailChunk(ERR_EXCEPTION, msg);
        }

        return null;
    }

    private Chunk setLayoutParameter(final View rootView, final View targetView, ByteBuffer in) {
@@ -431,4 +431,175 @@ public class DdmHandleViewDebug extends DdmHandle {
        byte[] data = b.toByteArray();
        return new Chunk(CHUNK_VUOP, data, 0, data.length);
    }

    /**
     * Deserializes parameters according to the VUOP_INVOKE_VIEW_METHOD protocol the {@code in}
     * buffer.
     *
     * The length of {@code args} determines how many arguments are read. The {@code argTypes} must
     * be the same length, and will be set to the argument types of the data read.
     *
     * @hide
     */
    @VisibleForTesting
    public static void deserializeMethodParameters(
            Object[] args, Class<?>[] argTypes, ByteBuffer in) throws
            ViewMethodInvocationSerializationException {
        checkArgument(args.length == argTypes.length);

        for (int i = 0; i < args.length; i++) {
            char typeSignature = in.getChar();
            boolean isArray = typeSignature == SIG_ARRAY;
            if (isArray) {
                char arrayType = in.getChar();
                if (arrayType != SIG_BYTE) {
                    // This implementation only supports byte-arrays for now.
                    throw new ViewMethodInvocationSerializationException(
                            "Unsupported array parameter type (" + typeSignature
                                    + ") to invoke view method @argument " + i);
                }

                int arrayLength = in.getInt();
                if (arrayLength > in.remaining()) {
                    // The sender did not actually sent the specified amount of bytes. This
                    // avoids a malformed packet to trigger an out-of-memory error.
                    throw new BufferUnderflowException();
                }

                byte[] byteArray = new byte[arrayLength];
                in.get(byteArray);

                argTypes[i] = byte[].class;
                args[i] = byteArray;
            } else {
                switch (typeSignature) {
                    case SIG_BOOLEAN:
                        argTypes[i] = boolean.class;
                        args[i] = in.get() != 0;
                        break;
                    case SIG_BYTE:
                        argTypes[i] = byte.class;
                        args[i] = in.get();
                        break;
                    case SIG_CHAR:
                        argTypes[i] = char.class;
                        args[i] = in.getChar();
                        break;
                    case SIG_SHORT:
                        argTypes[i] = short.class;
                        args[i] = in.getShort();
                        break;
                    case SIG_INT:
                        argTypes[i] = int.class;
                        args[i] = in.getInt();
                        break;
                    case SIG_LONG:
                        argTypes[i] = long.class;
                        args[i] = in.getLong();
                        break;
                    case SIG_FLOAT:
                        argTypes[i] = float.class;
                        args[i] = in.getFloat();
                        break;
                    case SIG_DOUBLE:
                        argTypes[i] = double.class;
                        args[i] = in.getDouble();
                        break;
                    case SIG_STRING: {
                        argTypes[i] = String.class;
                        int stringUtf8ByteCount = Short.toUnsignedInt(in.getShort());
                        byte[] rawStringBuffer = new byte[stringUtf8ByteCount];
                        in.get(rawStringBuffer);
                        args[i] = new String(rawStringBuffer, StandardCharsets.UTF_8);
                        break;
                    }
                    default:
                        Log.e(TAG, "arg " + i + ", unrecognized type: " + typeSignature);
                        throw new ViewMethodInvocationSerializationException(
                                "Unsupported parameter type (" + typeSignature
                                        + ") to invoke view method.");
                }
            }

        }
    }

    /**
     * Serializes {@code value} to the wire protocol of VUOP_INVOKE_VIEW_METHOD.
     * @hide
     */
    @VisibleForTesting
    public static byte[] serializeReturnValue(Class<?> type, Object value)
            throws ViewMethodInvocationSerializationException, IOException {
        ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream(1024);
        DataOutputStream dos = new DataOutputStream(byteOutStream);

        if (type.isArray()) {
            if (!type.equals(byte[].class)) {
                // Only byte arrays are supported currently.
                throw new ViewMethodInvocationSerializationException(
                        "Unsupported array return type (" + type + ")");
            }
            byte[] byteArray = (byte[]) value;
            dos.writeChar(SIG_ARRAY);
            dos.writeChar(SIG_BYTE);
            dos.writeInt(byteArray.length);
            dos.write(byteArray);
        } else if (boolean.class.equals(type)) {
            dos.writeChar(SIG_BOOLEAN);
            dos.write((boolean) value ? 1 : 0);
        } else if (byte.class.equals(type)) {
            dos.writeChar(SIG_BYTE);
            dos.writeByte((byte) value);
        } else if (char.class.equals(type)) {
            dos.writeChar(SIG_CHAR);
            dos.writeChar((char) value);
        } else if (short.class.equals(type)) {
            dos.writeChar(SIG_SHORT);
            dos.writeShort((short) value);
        } else if (int.class.equals(type)) {
            dos.writeChar(SIG_INT);
            dos.writeInt((int) value);
        } else if (long.class.equals(type)) {
            dos.writeChar(SIG_LONG);
            dos.writeLong((long) value);
        } else if (double.class.equals(type)) {
            dos.writeChar(SIG_DOUBLE);
            dos.writeDouble((double) value);
        } else if (float.class.equals(type)) {
            dos.writeChar(SIG_FLOAT);
            dos.writeFloat((float) value);
        } else if (String.class.equals(type)) {
            dos.writeChar(SIG_STRING);
            dos.writeUTF(value != null ? (String) value : "");
        } else {
            dos.writeChar(SIG_VOID);
        }

        return byteOutStream.toByteArray();
    }

    // Prefixes for simple primitives. These match the JNI definitions.
    private static final char SIG_ARRAY = '[';
    private static final char SIG_BOOLEAN = 'Z';
    private static final char SIG_BYTE = 'B';
    private static final char SIG_SHORT = 'S';
    private static final char SIG_CHAR = 'C';
    private static final char SIG_INT = 'I';
    private static final char SIG_LONG = 'J';
    private static final char SIG_FLOAT = 'F';
    private static final char SIG_DOUBLE = 'D';
    private static final char SIG_VOID = 'V';
    // Prefixes for some commonly used objects
    private static final char SIG_STRING = 'R';

    /**
     * @hide
     */
    @VisibleForTesting
    public static class ViewMethodInvocationSerializationException extends Exception {
        ViewMethodInvocationSerializationException(String message) {
            super(message);
        }
    }
}
+1 −0
Original line number Diff line number Diff line
per-file DdmHandleViewDebug.java = michschn@google.com
Loading