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

Commit 75f5bf33 authored by Winson Chung's avatar Winson Chung Committed by Android (Google) Code Review
Browse files

Merge changes from topic "winscope-sysui"

* changes:
  Add initial SysUI trace support
  Update trace buffer to support SysUI & Launcher
parents 11dbc1bb a657ac9c
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -210,4 +210,14 @@ oneway interface IStatusBar
     * Cancels toast with token {@code token} in {@code packageName}.
     */
    void hideToast(String packageName, IBinder token);

    /**
     * Notifies SystemUI to start tracing.
     */
    void startTracing();

    /**
     * Notifies SystemUI to stop tracing.
     */
    void stopTracing();
}
+15 −0
Original line number Diff line number Diff line
@@ -124,4 +124,19 @@ interface IStatusBarService
     * Dismiss the warning that the device is about to go to sleep due to user inactivity.
     */
    void dismissInattentiveSleepWarning(boolean animated);

    /**
     * Notifies SystemUI to start tracing.
     */
    void startTracing();

    /**
     * Notifies SystemUI to stop tracing.
     */
    void stopTracing();

    /**
     * Returns whether SystemUI tracing is enabled.
     */
    boolean isTracing();
}
+94 −28
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@
 * limitations under the License.
 */

package com.android.server.utils;
package com.android.internal.util;

import android.util.proto.ProtoOutputStream;

@@ -27,19 +27,87 @@ import java.io.OutputStream;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Queue;
import java.util.function.Consumer;

/**
 * Buffer used for tracing and logging.
 *
 * @param <P> The class type of the proto provider
 * @param <S> The proto class type of the encapsulating proto
 * @param <T> The proto class type of the individual entry protos in the buffer
 *
 * {@hide}
 */
public class TraceBuffer {
public class TraceBuffer<P, S extends P, T extends P> {
    private final Object mBufferLock = new Object();

    private final Queue<ProtoOutputStream> mBuffer = new ArrayDeque<>();
    private final ProtoProvider<P, S, T> mProtoProvider;
    private final Queue<T> mBuffer = new ArrayDeque<>();
    private final Consumer mProtoDequeuedCallback;
    private int mBufferUsedSize;
    private int mBufferCapacity;

    /**
     * An interface to get protos from different sources (ie. fw-proto/proto-lite/nano-proto) for
     * the trace buffer.
     *
     * @param <P> The class type of the proto provider
     * @param <S> The proto class type of the encapsulating proto
     * @param <T> The proto class type of the individual protos in the buffer
     */
    public interface ProtoProvider<P, S extends P, T extends P> {
        /**
         * @return The size of the given proto.
         */
        int getItemSize(P proto);

        /**
         * @return The bytes of the given proto.
         */
        byte[] getBytes(P proto);

        /**
         * Writes the given encapsulating proto and buffer of protos to the given output
         * stream.
         */
        void write(S encapsulatingProto, Queue<T> buffer, OutputStream os) throws IOException;
    }

    /**
     * An implementation of the ProtoProvider that uses only the framework ProtoOutputStream.
     */
    private static class ProtoOutputStreamProvider implements
            ProtoProvider<ProtoOutputStream, ProtoOutputStream, ProtoOutputStream> {
        @Override
        public int getItemSize(ProtoOutputStream proto) {
            return proto.getRawSize();
        }

        @Override
        public byte[] getBytes(ProtoOutputStream proto) {
            return proto.getBytes();
        }

        @Override
        public void write(ProtoOutputStream encapsulatingProto, Queue<ProtoOutputStream> buffer,
                OutputStream os) throws IOException {
            os.write(encapsulatingProto.getBytes());
            for (ProtoOutputStream protoOutputStream : buffer) {
                byte[] protoBytes = protoOutputStream.getBytes();
                os.write(protoBytes);
            }
        }
    }

    public TraceBuffer(int bufferCapacity) {
        this(bufferCapacity, new ProtoOutputStreamProvider(), null);
    }

    public TraceBuffer(int bufferCapacity, ProtoProvider protoProvider,
            Consumer<T> protoDequeuedCallback) {
        mBufferCapacity = bufferCapacity;
        mProtoProvider = protoProvider;
        mProtoDequeuedCallback = protoDequeuedCallback;
        resetBuffer();
    }

@@ -65,8 +133,8 @@ public class TraceBuffer {
     * @throws IllegalStateException if the element cannot be added because it is larger
     *                               than the buffer size.
     */
    public void add(ProtoOutputStream proto) {
        int protoLength = proto.getRawSize();
    public void add(T proto) {
        int protoLength = mProtoProvider.getItemSize(proto);
        if (protoLength > mBufferCapacity) {
            throw new IllegalStateException("Trace object too large for the buffer. Buffer size:"
                    + mBufferCapacity + " Object size: " + protoLength);
@@ -79,26 +147,22 @@ public class TraceBuffer {
        }
    }

    boolean contains(byte[] other) {
    @VisibleForTesting
    public boolean contains(byte[] other) {
        return mBuffer.stream()
                .anyMatch(p -> Arrays.equals(p.getBytes(), other));
                .anyMatch(p -> Arrays.equals(mProtoProvider.getBytes(p), other));
    }

    /**
     * Writes the trace buffer to disk inside the encapsulatingProto..
     * Writes the trace buffer to disk inside the encapsulatingProto.
     */
    public void writeTraceToFile(File traceFile, ProtoOutputStream encapsulatingProto)
    public void writeTraceToFile(File traceFile, S encapsulatingProto)
            throws IOException {
        synchronized (mBufferLock) {
            traceFile.delete();
            try (OutputStream os = new FileOutputStream(traceFile)) {
                traceFile.setReadable(true /* readable */, false /* ownerOnly */);
                os.write(encapsulatingProto.getBytes());
                for (ProtoOutputStream protoOutputStream : mBuffer) {
                    encapsulatingProto = protoOutputStream;
                    byte[] protoBytes = encapsulatingProto.getBytes();
                    os.write(protoBytes);
                }
                mProtoProvider.write(encapsulatingProto, mBuffer, os);
                os.flush();
            }
        }
@@ -115,12 +179,16 @@ public class TraceBuffer {

        while (availableSpace < protoLength) {

            ProtoOutputStream item = mBuffer.poll();
            P item = mBuffer.poll();
            if (item == null) {
                throw new IllegalStateException("No element to discard from buffer");
            }
            mBufferUsedSize -= item.getRawSize();
            mBufferUsedSize -= mProtoProvider.getItemSize(item);
            availableSpace = getAvailableSpace();

            if (mProtoDequeuedCallback != null) {
                mProtoDequeuedCallback.accept(item);
            }
        }
    }

@@ -129,13 +197,18 @@ public class TraceBuffer {
     */
    public void resetBuffer() {
        synchronized (mBufferLock) {
            if (mProtoDequeuedCallback != null) {
                for (T item : mBuffer) {
                    mProtoDequeuedCallback.accept(item);
                }
            }
            mBuffer.clear();
            mBufferUsedSize = 0;
        }
    }

    @VisibleForTesting
    int getBufferSize() {
    public int getBufferSize() {
        return mBufferUsedSize;
    }

@@ -144,16 +217,9 @@ public class TraceBuffer {
     */
    public String getStatus() {
        synchronized (mBufferLock) {
            return "Buffer size: "
                    + mBufferCapacity
                    + " bytes"
                    + "\n"
                    + "Buffer usage: "
                    + mBufferUsedSize
                    + " bytes"
                    + "\n"
                    + "Elements in the buffer: "
                    + mBuffer.size();
            return "Buffer size: " + mBufferCapacity + " bytes" + "\n"
                    + "Buffer usage: " + mBufferUsedSize + " bytes" + "\n"
                    + "Elements in the buffer: " + mBuffer.size();
        }
    }
}
+0 −1
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@ oneway interface IOverviewProxy {

    void onInitialize(in Bundle params) = 12;


    /**
     * @deprecated
     */
+5 −1
Original line number Diff line number Diff line
@@ -85,6 +85,8 @@ public class QuickStepContract {
    // The notification panel is expanded and interactive (either locked or unlocked), and the
    // quick settings is not expanded
    public static final int SYSUI_STATE_QUICK_SETTINGS_EXPANDED = 1 << 11;
    // Winscope tracing is enabled
    public static final int SYSUI_STATE_TRACING_ENABLED = 1 << 12;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({SYSUI_STATE_SCREEN_PINNING,
@@ -98,7 +100,8 @@ public class QuickStepContract {
            SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED,
            SYSUI_STATE_OVERVIEW_DISABLED,
            SYSUI_STATE_HOME_DISABLED,
            SYSUI_STATE_SEARCH_DISABLED
            SYSUI_STATE_SEARCH_DISABLED,
            SYSUI_STATE_TRACING_ENABLED
    })
    public @interface SystemUiStateFlags {}

@@ -117,6 +120,7 @@ public class QuickStepContract {
        str.add((flags & SYSUI_STATE_BOUNCER_SHOWING) != 0 ? "bouncer_visible" : "");
        str.add((flags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0 ? "a11y_click" : "");
        str.add((flags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0 ? "a11y_long_click" : "");
        str.add((flags & SYSUI_STATE_TRACING_ENABLED) != 0 ? "tracing" : "");
        return str.toString();
    }

Loading