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

Commit d6ea41c2 authored by Nataniel Borges's avatar Nataniel Borges Committed by Android (Google) Code Review
Browse files

Merge "Remove on-disk WM trace logging"

parents 9c260601 7d37ce2c
Loading
Loading
Loading
Loading
+1 −5
Original line number Diff line number Diff line
@@ -5090,11 +5090,7 @@ public class WindowManagerService extends IWindowManager.Stub

    @Override
    public void startWindowTrace(){
        try {
        mWindowTracing.startTrace(null /* printwriter */);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
+73 −84
Original line number Diff line number Diff line
@@ -20,7 +20,6 @@ import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER;
import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
import static com.android.server.wm.WindowManagerTraceFileProto.MAGIC_NUMBER_L;

import android.os.Trace;
import android.util.proto.ProtoOutputStream;

import com.android.internal.annotations.VisibleForTesting;
@@ -36,24 +35,30 @@ import java.util.Queue;
/**
 * Buffer used for window tracing.
 */
abstract class WindowTraceBuffer {
class WindowTraceBuffer {
    private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;

    final Object mBufferLock = new Object();
    final Queue<ProtoOutputStream> mBuffer = new ArrayDeque<>();
    final File mTraceFile;
    int mBufferSize;
    private final int mBufferCapacity;
    private final Object mBufferLock = new Object();

    WindowTraceBuffer(int size, File traceFile) throws IOException {
        mBufferCapacity = size;
        mTraceFile = traceFile;
    private final Queue<ProtoOutputStream> mBuffer = new ArrayDeque<>();
    private int mBufferUsedSize;
    private int mBufferCapacity;

        initTraceFile();
    WindowTraceBuffer(int bufferCapacity) {
        mBufferCapacity = bufferCapacity;
        resetBuffer();
    }

    int getAvailableSpace() {
        return mBufferCapacity - mBufferSize;
        return mBufferCapacity - mBufferUsedSize;
    }

    int size() {
        return mBuffer.size();
    }

    void setCapacity(int capacity) {
        mBufferCapacity = capacity;
    }

    /**
@@ -70,42 +75,37 @@ abstract class WindowTraceBuffer {
                    + mBufferCapacity + " Object size: " + protoLength);
        }
        synchronized (mBufferLock) {
            boolean canAdd = canAdd(protoLength);
            if (canAdd) {
            discardOldest(protoLength);
            mBuffer.add(proto);
                mBufferSize += protoLength;
            }
            mBufferUsedSize += protoLength;
            mBufferLock.notify();
        }
    }

    /**
     * Stops the buffer execution and flush all buffer content to the disk.
     *
     * @throws IOException if the buffer cannot write its contents to the {@link #mTraceFile}
     */
    void dump() throws IOException, InterruptedException {
        try {
            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeTraceToFile");
            writeTraceToFile();
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
        }
    }

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

    private void initTraceFile() throws IOException {
        mTraceFile.delete();
        try (OutputStream os = new FileOutputStream(mTraceFile)) {
            mTraceFile.setReadable(true, false);
            ProtoOutputStream proto = new ProtoOutputStream(os);
    /**
     * Writes the trace buffer to disk.
     */
    void writeTraceToFile(File traceFile) throws IOException {
        synchronized (mBufferLock) {
            traceFile.delete();
            traceFile.setReadable(true, false);
            try (OutputStream os = new FileOutputStream(traceFile)) {
                ProtoOutputStream proto = new ProtoOutputStream();
                proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
            proto.flush();
                os.write(proto.getBytes());
                while (!mBuffer.isEmpty()) {
                    proto = mBuffer.poll();
                    mBufferUsedSize -= proto.getRawSize();
                    byte[] protoBytes = proto.getBytes();
                    os.write(protoBytes);
                }
                os.flush();
            }
        }
    }

@@ -114,59 +114,48 @@ abstract class WindowTraceBuffer {
     * smaller than the overall buffer size.
     *
     * @param protoLength byte array representation of the Proto object to add
     * @return {@code true} if the element can be added to the buffer or not
     */
    abstract boolean canAdd(int protoLength);
    private void discardOldest(int protoLength) {
        long availableSpace = getAvailableSpace();

    /**
     * Flush all buffer content to the disk.
     *
     * @throws IOException if the buffer cannot write its contents to the {@link #mTraceFile}
     */
    abstract void writeTraceToFile() throws IOException, InterruptedException;
        while (availableSpace < protoLength) {

    /**
     * Builder for a {@code WindowTraceBuffer} which creates a {@link WindowTraceRingBuffer} for
     * continuous mode or a {@link WindowTraceQueueBuffer} otherwise
     */
    static class Builder {
        private boolean mContinuous;
        private File mTraceFile;
        private int mBufferCapacity;

        Builder setContinuousMode(boolean continuous) {
            mContinuous = continuous;
            return this;
            ProtoOutputStream item = mBuffer.poll();
            if (item == null) {
                throw new IllegalStateException("No element to discard from buffer");
            }

        Builder setTraceFile(File traceFile) {
            mTraceFile = traceFile;
            return this;
            mBufferUsedSize -= item.getRawSize();
            availableSpace = getAvailableSpace();
        }

        Builder setBufferCapacity(int size) {
            mBufferCapacity = size;
            return this;
    }

        File getFile() {
            return mTraceFile;
    /**
     * Removes all elements form the buffer
     */
    void resetBuffer() {
        synchronized (mBufferLock) {
            mBuffer.clear();
            mBufferUsedSize = 0;
        }

        WindowTraceBuffer build() throws IOException {
            if (mBufferCapacity <= 0) {
                throw new IllegalStateException("Buffer capacity must be greater than 0.");
    }

            if (mTraceFile == null) {
                throw new IllegalArgumentException("A valid trace file must be specified.");
    @VisibleForTesting
    int getBufferSize() {
        return mBufferUsedSize;
    }

            if (mContinuous) {
                return new WindowTraceRingBuffer(mBufferCapacity, mTraceFile);
            } else {
                return new WindowTraceQueueBuffer(mBufferCapacity, mTraceFile);
            }
    String getStatus() {
        synchronized (mBufferLock) {
            return "Buffer size: "
                    + mBufferCapacity
                    + " bytes"
                    + "\n"
                    + "Buffer usage: "
                    + mBufferUsedSize
                    + " bytes"
                    + "\n"
                    + "Elements in the buffer: "
                    + mBuffer.size();
        }
    }
}
+0 −105
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wm;

import static android.os.Build.IS_USER;

import android.util.Log;
import android.util.proto.ProtoOutputStream;

import com.android.internal.annotations.VisibleForTesting;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * A buffer structure backed by a {@link java.util.concurrent.BlockingQueue} to store the first
 * {@code #size size} bytes of window trace elements.
 * Once the buffer is full it will no longer accepts new elements.
 */
class WindowTraceQueueBuffer extends WindowTraceBuffer {
    private static final String TAG = "WindowTracing";

    private Thread mConsumerThread;
    private boolean mCancel;

    @VisibleForTesting
    WindowTraceQueueBuffer(int size, File traceFile, boolean startConsumerThread)
            throws IOException {
        super(size, traceFile);
        if (startConsumerThread) {
            initializeConsumerThread();
        }
    }

    WindowTraceQueueBuffer(int size, File traceFile) throws IOException {
        this(size, traceFile, !IS_USER);
    }

    private void initializeConsumerThread() {
        mCancel = false;
        mConsumerThread = new Thread(() -> {
            try {
                loop();
            } catch (InterruptedException e) {
                Log.i(TAG, "Interrupting trace consumer thread");
            } catch (IOException e) {
                Log.e(TAG, "Failed to execute trace consumer thread", e);
            }
        }, "window_tracing");
        mConsumerThread.start();
    }

    private void loop() throws IOException, InterruptedException {
        while (!mCancel) {
            ProtoOutputStream proto;
            synchronized (mBufferLock) {
                mBufferLock.wait();
                proto = mBuffer.poll();
                if (proto != null) {
                    mBufferSize -= proto.getRawSize();
                }
            }
            if (proto != null) {
                try (OutputStream os = new FileOutputStream(mTraceFile, true)) {
                    byte[] protoBytes = proto.getBytes();
                    os.write(protoBytes);
                }
            }
        }
    }

    @Override
    boolean canAdd(int protoLength) {
        long availableSpace = getAvailableSpace();
        return availableSpace >= protoLength;
    }

    @Override
    void writeTraceToFile() throws InterruptedException {
        synchronized (mBufferLock) {
            mCancel = true;
            mBufferLock.notify();
        }
        if (mConsumerThread != null) {
            mConsumerThread.join();
            mConsumerThread = null;
        }
    }
}
+0 −70
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.wm;

import android.util.proto.ProtoOutputStream;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * A ring buffer to store the {@code #size size} bytes of window trace data.
 * The buffer operates on a trace entry level, that is, if the new trace data is larger than the
 * available buffer space, the buffer will discard as many full trace entries as necessary to fit
 * the new trace.
 */
class WindowTraceRingBuffer extends WindowTraceBuffer {
    WindowTraceRingBuffer(int size, File traceFile) throws IOException {
        super(size, traceFile);
    }

    @Override
    boolean canAdd(int protoLength) {
        long availableSpace = getAvailableSpace();

        while (availableSpace < protoLength) {
            discardOldest();
            availableSpace = getAvailableSpace();
        }

        return true;
    }

    @Override
    void writeTraceToFile() throws IOException {
        synchronized (mBufferLock) {
            try (OutputStream os = new FileOutputStream(mTraceFile, true)) {
                while (!mBuffer.isEmpty()) {
                    ProtoOutputStream proto = mBuffer.poll();
                    mBufferSize -= proto.getRawSize();
                    byte[] protoBytes = proto.getBytes();
                    os.write(protoBytes);
                }
            }
        }
    }

    private void discardOldest() {
        ProtoOutputStream item = mBuffer.poll();
        if (item == null) {
            throw new IllegalStateException("No element to discard from buffer");
        }
        mBufferSize -= item.getRawSize();
    }
}
+168 −113

File changed.

Preview size limit exceeded, changes collapsed.

Loading