summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowTraceBuffer.java157
-rw-r--r--services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java105
-rw-r--r--services/core/java/com/android/server/wm/WindowTraceRingBuffer.java70
-rw-r--r--services/core/java/com/android/server/wm/WindowTracing.java281
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java146
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java9
7 files changed, 303 insertions, 471 deletions
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 168c9adb61be..899bf7c8fd39 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -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);
- }
+ mWindowTracing.startTrace(null /* printwriter */);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowTraceBuffer.java b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
index e4461ea90c91..2ce6e6c1d049 100644
--- a/services/core/java/com/android/server/wm/WindowTraceBuffer.java
+++ b/services/core/java/com/android/server/wm/WindowTraceBuffer.java
@@ -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) {
- mBuffer.add(proto);
- mBufferSize += protoLength;
- }
+ discardOldest(protoLength);
+ mBuffer.add(proto);
+ 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);
- proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
- proto.flush();
+ /**
+ * 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);
+ 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);
-
- /**
- * 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;
-
- /**
- * 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;
- }
+ private void discardOldest(int protoLength) {
+ long availableSpace = getAvailableSpace();
- Builder setTraceFile(File traceFile) {
- mTraceFile = traceFile;
- return this;
- }
+ while (availableSpace < protoLength) {
- Builder setBufferCapacity(int size) {
- mBufferCapacity = size;
- return this;
+ ProtoOutputStream item = mBuffer.poll();
+ if (item == null) {
+ throw new IllegalStateException("No element to discard from buffer");
+ }
+ mBufferUsedSize -= item.getRawSize();
+ availableSpace = getAvailableSpace();
}
+ }
- 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();
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java b/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java
deleted file mode 100644
index 5888b7a799cf..000000000000
--- a/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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;
- }
- }
-}
diff --git a/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java b/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java
deleted file mode 100644
index 77d30be816bc..000000000000
--- a/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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();
- }
-}
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index abc474d756b7..0ce215c88dad 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -31,8 +31,6 @@ import android.util.Log;
import android.util.proto.ProtoOutputStream;
import android.view.Choreographer;
-import com.android.internal.annotations.VisibleForTesting;
-
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
@@ -47,139 +45,191 @@ class WindowTracing {
* Maximum buffer size, currently defined as 512 KB
* Size was experimentally defined to fit between 100 to 150 elements.
*/
- private static final int WINDOW_TRACE_BUFFER_SIZE = 512 * 1024;
+ private static final int BUFFER_CAPACITY_CRITICAL = 512 * 1024;
+ private static final int BUFFER_CAPACITY_TRIM = 2048 * 1024;
+ private static final int BUFFER_CAPACITY_ALL = 4096 * 1024;
+ private static final String TRACE_FILENAME = "/data/misc/wmtrace/wm_trace.pb";
private static final String TAG = "WindowTracing";
private final WindowManagerService mService;
private final Choreographer mChoreographer;
private final WindowManagerGlobalLock mGlobalLock;
- private final Object mLock = new Object();
- private final WindowTraceBuffer.Builder mBufferBuilder;
-
- private WindowTraceBuffer mTraceBuffer;
+ private final Object mEnabledLock = new Object();
+ private final File mTraceFile;
+ private final WindowTraceBuffer mBuffer;
+ private final Choreographer.FrameCallback mFrameCallback = (frameTimeNanos) ->
+ log("onFrame" /* where */);
- private @WindowTraceLogLevel int mWindowTraceLogLevel = WindowTraceLogLevel.TRIM;
- private boolean mContinuousMode;
+ private @WindowTraceLogLevel int mLogLevel = WindowTraceLogLevel.TRIM;
+ private boolean mLogOnFrame = false;
private boolean mEnabled;
private volatile boolean mEnabledLockFree;
private boolean mScheduled;
- private Choreographer.FrameCallback mFrameCallback = (frameTimeNanos) ->
- log("onFrame" /* where */);
- private WindowTracing(File file, WindowManagerService service, Choreographer choreographer) {
- this(file, service, choreographer, service.mGlobalLock);
+ static WindowTracing createDefaultAndStartLooper(WindowManagerService service,
+ Choreographer choreographer) {
+ File file = new File(TRACE_FILENAME);
+ return new WindowTracing(file, service, choreographer, BUFFER_CAPACITY_TRIM);
}
- @VisibleForTesting
- WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
- WindowManagerGlobalLock globalLock) {
- mBufferBuilder = new WindowTraceBuffer.Builder()
- .setTraceFile(file)
- .setBufferCapacity(WINDOW_TRACE_BUFFER_SIZE);
+ private WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
+ int bufferCapacity) {
+ this(file, service, choreographer, service.mGlobalLock, bufferCapacity);
+ }
+ WindowTracing(File file, WindowManagerService service, Choreographer choreographer,
+ WindowManagerGlobalLock globalLock, int bufferCapacity) {
mChoreographer = choreographer;
mService = service;
mGlobalLock = globalLock;
+ mTraceFile = file;
+ mBuffer = new WindowTraceBuffer(bufferCapacity);
+ setLogLevel(WindowTraceLogLevel.TRIM, null /* pw */);
}
- void startTrace(@Nullable PrintWriter pw) throws IOException {
+ void startTrace(@Nullable PrintWriter pw) {
if (IS_USER) {
logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
return;
}
- synchronized (mLock) {
- logAndPrintln(pw, "Start tracing to " + mBufferBuilder.getFile() + ".");
- if (mTraceBuffer != null) {
- writeTraceToFileLocked();
- }
- mTraceBuffer = mBufferBuilder
- .setContinuousMode(mContinuousMode)
- .build();
+ synchronized (mEnabledLock) {
+ logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
+ mBuffer.resetBuffer();
mEnabled = mEnabledLockFree = true;
}
}
- private void logAndPrintln(@Nullable PrintWriter pw, String msg) {
- Log.i(TAG, msg);
- if (pw != null) {
- pw.println(msg);
- pw.flush();
- }
- }
-
void stopTrace(@Nullable PrintWriter pw) {
if (IS_USER) {
logAndPrintln(pw, "Error: Tracing is not supported on user builds.");
return;
}
- synchronized (mLock) {
- logAndPrintln(pw, "Stop tracing to " + mBufferBuilder.getFile()
- + ". Waiting for traces to flush.");
+ synchronized (mEnabledLock) {
+ logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush.");
mEnabled = mEnabledLockFree = false;
- synchronized (mLock) {
- if (mEnabled) {
- logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush.");
- throw new IllegalStateException("tracing enabled while waiting for flush.");
- }
- writeTraceToFileLocked();
- mTraceBuffer = null;
+ if (mEnabled) {
+ logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush.");
+ throw new IllegalStateException("tracing enabled while waiting for flush.");
}
- logAndPrintln(pw, "Trace written to " + mBufferBuilder.getFile() + ".");
+ writeTraceToFileLocked();
+ logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
}
}
- @VisibleForTesting
- void setContinuousMode(boolean continuous, PrintWriter pw) {
- logAndPrintln(pw, "Setting window tracing continuous mode to " + continuous);
+ private void setLogLevel(@WindowTraceLogLevel int logLevel, PrintWriter pw) {
+ logAndPrintln(pw, "Setting window tracing log level to " + logLevel);
+ mLogLevel = logLevel;
- if (mEnabled) {
- logAndPrintln(pw, "Trace is currently active, change will take effect once the "
- + "trace is restarted.");
+ switch (logLevel) {
+ case WindowTraceLogLevel.ALL: {
+ setBufferCapacity(BUFFER_CAPACITY_ALL, pw);
+ break;
+ }
+ case WindowTraceLogLevel.TRIM: {
+ setBufferCapacity(BUFFER_CAPACITY_TRIM, pw);
+ break;
+ }
+ case WindowTraceLogLevel.CRITICAL: {
+ setBufferCapacity(BUFFER_CAPACITY_CRITICAL, pw);
+ break;
+ }
}
- mContinuousMode = continuous;
- mWindowTraceLogLevel = (continuous) ? WindowTraceLogLevel.CRITICAL :
- WindowTraceLogLevel.TRIM;
}
- boolean isEnabled() {
- return mEnabledLockFree;
+ private void setLogFrequency(boolean onFrame, PrintWriter pw) {
+ logAndPrintln(pw, "Setting window tracing log frequency to "
+ + ((onFrame) ? "frame" : "transaction"));
+ mLogOnFrame = onFrame;
}
- static WindowTracing createDefaultAndStartLooper(WindowManagerService service,
- Choreographer choreographer) {
- File file = new File("/data/misc/wmtrace/wm_trace.pb");
- return new WindowTracing(file, service, choreographer);
+ private void setBufferCapacity(int capacity, PrintWriter pw) {
+ logAndPrintln(pw, "Setting window tracing buffer capacity to " + capacity + "bytes");
+ mBuffer.setCapacity(capacity);
+ }
+
+ boolean isEnabled() {
+ return mEnabledLockFree;
}
int onShellCommand(ShellCommand shell) {
PrintWriter pw = shell.getOutPrintWriter();
- try {
- String cmd = shell.getNextArgRequired();
- switch (cmd) {
- case "start":
- startTrace(pw);
- return 0;
- case "stop":
- stopTrace(pw);
- return 0;
- case "continuous":
- setContinuousMode(Boolean.valueOf(shell.getNextArgRequired()), pw);
- return 0;
- default:
- pw.println("Unknown command: " + cmd);
- return -1;
- }
- } catch (IOException e) {
- logAndPrintln(pw, e.toString());
- throw new RuntimeException(e);
+ String cmd = shell.getNextArgRequired();
+ switch (cmd) {
+ case "start":
+ startTrace(pw);
+ return 0;
+ case "stop":
+ stopTrace(pw);
+ return 0;
+ case "status":
+ logAndPrintln(pw, getStatus());
+ return 0;
+ case "frame":
+ setLogFrequency(true /* onFrame */, pw);
+ mBuffer.resetBuffer();
+ return 0;
+ case "transaction":
+ setLogFrequency(false /* onFrame */, pw);
+ mBuffer.resetBuffer();
+ return 0;
+ case "level":
+ String logLevelStr = shell.getNextArgRequired().toLowerCase();
+ switch (logLevelStr) {
+ case "all": {
+ setLogLevel(WindowTraceLogLevel.ALL, pw);
+ break;
+ }
+ case "trim": {
+ setLogLevel(WindowTraceLogLevel.TRIM, pw);
+ break;
+ }
+ case "critical": {
+ setLogLevel(WindowTraceLogLevel.CRITICAL, pw);
+ break;
+ }
+ default: {
+ setLogLevel(WindowTraceLogLevel.TRIM, pw);
+ break;
+ }
+ }
+ mBuffer.resetBuffer();
+ return 0;
+ case "size":
+ setBufferCapacity(Integer.parseInt(shell.getNextArgRequired()) * 1024, pw);
+ mBuffer.resetBuffer();
+ return 0;
+ default:
+ pw.println("Unknown command: " + cmd);
+ pw.println("Window manager trace options:");
+ pw.println(" start: Start logging");
+ pw.println(" stop: Stop logging");
+ pw.println(" frame: Log trace once per frame");
+ pw.println(" transaction: Log each transaction");
+ pw.println(" size: Set the maximum log size (in KB)");
+ pw.println(" level [lvl]: Set the log level between");
+ pw.println(" lvl may be one of:");
+ pw.println(" critical: Only visible windows with reduced information");
+ pw.println(" trim: All windows with reduced");
+ pw.println(" all: All window and information");
+ return -1;
}
}
+ private String getStatus() {
+ return "Status: "
+ + ((isEnabled()) ? "Enabled" : "Disabled")
+ + "\n"
+ + "Log level: "
+ + mLogLevel
+ + "\n"
+ + mBuffer.getStatus();
+ }
+
/**
* If tracing is enabled, log the current state or schedule the next frame to be logged,
- * according to {@link #mContinuousMode}.
+ * according to {@link #mLogOnFrame}.
*
* @param where Logging point descriptor
*/
@@ -188,7 +238,7 @@ class WindowTracing {
return;
}
- if (mContinuousMode) {
+ if (mLogOnFrame) {
schedule();
} else {
log(where);
@@ -215,25 +265,24 @@ class WindowTracing {
private void log(String where) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "traceStateLocked");
try {
- synchronized (mGlobalLock) {
- ProtoOutputStream os = new ProtoOutputStream();
- long tokenOuter = os.start(ENTRY);
- os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
- os.write(WHERE, where);
+ ProtoOutputStream os = new ProtoOutputStream();
+ long tokenOuter = os.start(ENTRY);
+ os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
+ os.write(WHERE, where);
+ long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
+ synchronized (mGlobalLock) {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToProtoLocked");
try {
- long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
- mService.writeToProtoLocked(os, mWindowTraceLogLevel);
- os.end(tokenInner);
+ mService.writeToProtoLocked(os, mLogLevel);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
- os.end(tokenOuter);
- mTraceBuffer.add(os);
-
- mScheduled = false;
}
+ os.end(tokenInner);
+ os.end(tokenOuter);
+ mBuffer.add(os);
+ mScheduled = false;
} catch (Exception e) {
Log.wtf(TAG, "Exception while tracing state", e);
} finally {
@@ -242,31 +291,37 @@ class WindowTracing {
}
/**
- * Writes the trace buffer to disk. This method has no internal synchronization and should be
- * externally synchronized
+ * Writes the trace buffer to new file for the bugreport.
+ *
+ * This method is synchronized with {@code #startTrace(PrintWriter)} and
+ * {@link #stopTrace(PrintWriter)}.
*/
- private void writeTraceToFileLocked() {
- if (mTraceBuffer == null) {
- return;
+ void writeTraceToFile() {
+ synchronized (mEnabledLock) {
+ writeTraceToFileLocked();
}
+ }
- try {
- mTraceBuffer.dump();
- } catch (IOException e) {
- Log.e(TAG, "Unable to write buffer to file", e);
- } catch (InterruptedException e) {
- Log.e(TAG, "Unable to interrupt window tracing file write thread", e);
+ private void logAndPrintln(@Nullable PrintWriter pw, String msg) {
+ Log.i(TAG, msg);
+ if (pw != null) {
+ pw.println(msg);
+ pw.flush();
}
}
/**
- * Writes the trace buffer to disk and clones it into a new file for the bugreport.
- * This method is synchronized with {@code #startTrace(PrintWriter)} and
- * {@link #stopTrace(PrintWriter)}.
+ * Writes the trace buffer to disk. This method has no internal synchronization and should be
+ * externally synchronized
*/
- void writeTraceToFile() {
- synchronized (mLock) {
- writeTraceToFileLocked();
+ private void writeTraceToFileLocked() {
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeTraceToFileLocked");
+ mBuffer.writeTraceToFile(mTraceFile);
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to write buffer to file", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
}
-}
+} \ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
index 2b8e307e23b7..b299f0dd7253 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java
@@ -36,11 +36,10 @@ import org.junit.Before;
import org.junit.Test;
import java.io.File;
-import java.io.IOException;
/**
- * Test class for {@link WindowTraceBuffer} and {@link WindowTraceQueueBuffer}.
+ * Test class for {@link WindowTraceBuffer}.
*
* Build/Install/Run:
* atest WmTests:WindowTraceBufferTest
@@ -49,12 +48,15 @@ import java.io.IOException;
@Presubmit
public class WindowTraceBufferTest {
private File mFile;
+ private WindowTraceBuffer mBuffer;
@Before
public void setUp() throws Exception {
final Context testContext = getInstrumentation().getContext();
mFile = testContext.getFileStreamPath("tracing_test.dat");
mFile.delete();
+
+ mBuffer = new WindowTraceBuffer(10);
}
@After
@@ -63,145 +65,112 @@ public class WindowTraceBufferTest {
}
@Test
- public void testTraceQueueBuffer_addItem() throws Exception {
- ProtoOutputStream toWrite1 = getDummy(1);
- ProtoOutputStream toWrite2 = getDummy(2);
- ProtoOutputStream toWrite3 = getDummy(3);
- final int objectSize = toWrite1.getRawSize();
- final int bufferCapacity = objectSize * 2;
-
- final WindowTraceBuffer buffer = buildQueueBuffer(bufferCapacity);
-
- buffer.add(toWrite1);
- byte[] toWrite1Bytes = toWrite1.getBytes();
- assertTrue("First element should be in the list",
- buffer.contains(toWrite1Bytes));
-
- buffer.add(toWrite2);
- byte[] toWrite2Bytes = toWrite2.getBytes();
- assertTrue("First element should be in the list",
- buffer.contains(toWrite1Bytes));
- assertTrue("Second element should be in the list",
- buffer.contains(toWrite2Bytes));
-
- buffer.add(toWrite3);
- byte[] toWrite3Bytes = toWrite3.getBytes();
- assertTrue("First element should be in the list",
- buffer.contains(toWrite1Bytes));
- assertTrue("Second element should be in the list",
- buffer.contains(toWrite2Bytes));
- assertTrue("Third element should not be in the list",
- !buffer.contains(toWrite3Bytes));
-
- assertEquals("Buffer should have 2 elements", buffer.mBuffer.size(), 2);
- assertEquals(String.format("Buffer is full, used space should be %d", bufferCapacity),
- buffer.mBufferSize, bufferCapacity);
- assertEquals("Buffer is full, available space should be 0",
- buffer.getAvailableSpace(), 0);
- }
-
- @Test
- public void testTraceRingBuffer_addItem() throws Exception {
+ public void test_addItem() {
ProtoOutputStream toWrite = getDummy(1);
final int objectSize = toWrite.getRawSize();
+ mBuffer.setCapacity(objectSize);
+ mBuffer.resetBuffer();
- final WindowTraceBuffer buffer = buildRingBuffer(objectSize);
-
- Preconditions.checkArgument(buffer.mBuffer.isEmpty());
+ Preconditions.checkArgument(mBuffer.size() == 0);
- buffer.add(toWrite);
+ mBuffer.add(toWrite);
- assertEquals("Item was not added to the buffer", buffer.mBuffer.size(), 1);
+ assertEquals("Item was not added to the buffer", 1, mBuffer.size());
assertEquals("Total buffer getSize differs from inserted object",
- buffer.mBufferSize, objectSize);
- assertEquals("Available buffer space does not match used one",
- buffer.getAvailableSpace(), 0);
+ mBuffer.getBufferSize(), objectSize);
+ assertEquals("Available buffer space does not match used one", 0,
+ mBuffer.getAvailableSpace());
}
@Test
- public void testTraceRingBuffer_addItemMustOverwriteOne() throws Exception {
+ public void test_addItemMustOverwriteOne() {
ProtoOutputStream toWrite1 = getDummy(1);
ProtoOutputStream toWrite2 = getDummy(2);
ProtoOutputStream toWrite3 = getDummy(3);
final int objectSize = toWrite1.getRawSize();
-
final int bufferCapacity = objectSize * 2 + 1;
- final WindowTraceBuffer buffer = buildRingBuffer(bufferCapacity);
+ mBuffer.setCapacity(bufferCapacity);
+ mBuffer.resetBuffer();
- buffer.add(toWrite1);
+ mBuffer.add(toWrite1);
byte[] toWrite1Bytes = toWrite1.getBytes();
assertTrue("First element should be in the list",
- buffer.contains(toWrite1Bytes));
+ mBuffer.contains(toWrite1Bytes));
- buffer.add(toWrite2);
+ mBuffer.add(toWrite2);
byte[] toWrite2Bytes = toWrite2.getBytes();
assertTrue("First element should be in the list",
- buffer.contains(toWrite1Bytes));
+ mBuffer.contains(toWrite1Bytes));
assertTrue("Second element should be in the list",
- buffer.contains(toWrite2Bytes));
+ mBuffer.contains(toWrite2Bytes));
- buffer.add(toWrite3);
+ mBuffer.add(toWrite3);
byte[] toWrite3Bytes = toWrite3.getBytes();
assertTrue("First element should not be in the list",
- !buffer.contains(toWrite1Bytes));
+ !mBuffer.contains(toWrite1Bytes));
assertTrue("Second element should be in the list",
- buffer.contains(toWrite2Bytes));
+ mBuffer.contains(toWrite2Bytes));
assertTrue("Third element should be in the list",
- buffer.contains(toWrite3Bytes));
- assertEquals("Buffer should have 2 elements", buffer.mBuffer.size(), 2);
+ mBuffer.contains(toWrite3Bytes));
+ assertEquals("Buffer should have 2 elements", 2, mBuffer.size());
assertEquals(String.format("Buffer is full, used space should be %d", bufferCapacity),
- buffer.mBufferSize, bufferCapacity - 1);
- assertEquals(" Buffer is full, available space should be 0",
- buffer.getAvailableSpace(), 1);
+ mBuffer.getBufferSize(), bufferCapacity - 1);
+ assertEquals(" Buffer is full, available space should be 0", 1,
+ mBuffer.getAvailableSpace());
}
@Test
- public void testTraceRingBuffer_addItemMustOverwriteMultiple() throws Exception {
+ public void test_addItemMustOverwriteMultiple() {
ProtoOutputStream toWriteSmall1 = getDummy(1);
ProtoOutputStream toWriteSmall2 = getDummy(2);
final int objectSize = toWriteSmall1.getRawSize();
-
final int bufferCapacity = objectSize * 2;
- final WindowTraceBuffer buffer = buildRingBuffer(bufferCapacity);
+ mBuffer.setCapacity(bufferCapacity);
+ mBuffer.resetBuffer();
ProtoOutputStream toWriteBig = new ProtoOutputStream();
toWriteBig.write(MAGIC_NUMBER, 1);
toWriteBig.write(MAGIC_NUMBER, 2);
- buffer.add(toWriteSmall1);
+ mBuffer.add(toWriteSmall1);
byte[] toWriteSmall1Bytes = toWriteSmall1.getBytes();
assertTrue("First element should be in the list",
- buffer.contains(toWriteSmall1Bytes));
+ mBuffer.contains(toWriteSmall1Bytes));
- buffer.add(toWriteSmall2);
+ mBuffer.add(toWriteSmall2);
byte[] toWriteSmall2Bytes = toWriteSmall2.getBytes();
assertTrue("First element should be in the list",
- buffer.contains(toWriteSmall1Bytes));
+ mBuffer.contains(toWriteSmall1Bytes));
assertTrue("Second element should be in the list",
- buffer.contains(toWriteSmall2Bytes));
+ mBuffer.contains(toWriteSmall2Bytes));
- buffer.add(toWriteBig);
+ mBuffer.add(toWriteBig);
byte[] toWriteBigBytes = toWriteBig.getBytes();
assertTrue("Third element should overwrite all others",
- !buffer.contains(toWriteSmall1Bytes));
+ !mBuffer.contains(toWriteSmall1Bytes));
assertTrue("Third element should overwrite all others",
- !buffer.contains(toWriteSmall2Bytes));
+ !mBuffer.contains(toWriteSmall2Bytes));
assertTrue("Third element should overwrite all others",
- buffer.contains(toWriteBigBytes));
+ mBuffer.contains(toWriteBigBytes));
- assertEquals(" Buffer should have only 1 big element", buffer.mBuffer.size(), 1);
+ assertEquals(" Buffer should have only 1 big element", 1, mBuffer.size());
assertEquals(String.format(" Buffer is full, used space should be %d", bufferCapacity),
- buffer.mBufferSize, bufferCapacity);
- assertEquals(" Buffer is full, available space should be 0",
- buffer.getAvailableSpace(), 0);
+ mBuffer.getBufferSize(), bufferCapacity);
+ assertEquals(" Buffer is full, available space should be 0", 0,
+ mBuffer.getAvailableSpace());
}
- private WindowTraceBuffer buildRingBuffer(int capacity) throws IOException {
- return new WindowTraceBuffer.Builder()
- .setContinuousMode(true)
- .setBufferCapacity(capacity)
- .setTraceFile(mFile)
- .build();
+ @Test
+ public void test_startResetsBuffer() {
+ ProtoOutputStream toWrite = getDummy(1);
+ mBuffer.resetBuffer();
+ Preconditions.checkArgument(mBuffer.size() == 0);
+
+ mBuffer.add(toWrite);
+ assertEquals("Item was not added to the buffer", 1, mBuffer.size());
+ mBuffer.resetBuffer();
+ assertEquals("Buffer should be empty after reset", 0, mBuffer.size());
+ assertEquals("Buffer size should be 0 after reset", 0, mBuffer.getBufferSize());
}
private ProtoOutputStream getDummy(int value) {
@@ -212,7 +181,4 @@ public class WindowTraceBufferTest {
return toWrite;
}
- private WindowTraceBuffer buildQueueBuffer(int size) throws IOException {
- return new WindowTraceQueueBuffer(size, mFile, false);
- }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
index 3c6e2405adff..8358fdd18e0e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
@@ -88,8 +88,7 @@ public class WindowTracingTest {
mFile.delete();
mWindowTracing = new WindowTracing(mFile, mWmMock, mChoreographer,
- new WindowManagerGlobalLock());
- mWindowTracing.setContinuousMode(false /* continuous */, null /* pw */);
+ new WindowManagerGlobalLock(), 1024);
}
@After
@@ -103,13 +102,13 @@ public class WindowTracingTest {
}
@Test
- public void isEnabled_returnsTrueAfterStart() throws Exception {
+ public void isEnabled_returnsTrueAfterStart() {
mWindowTracing.startTrace(mock(PrintWriter.class));
assertTrue(mWindowTracing.isEnabled());
}
@Test
- public void isEnabled_returnsFalseAfterStop() throws Exception {
+ public void isEnabled_returnsFalseAfterStop() {
mWindowTracing.startTrace(mock(PrintWriter.class));
mWindowTracing.stopTrace(mock(PrintWriter.class));
assertFalse(mWindowTracing.isEnabled());
@@ -133,6 +132,8 @@ public class WindowTracingTest {
mWindowTracing.startTrace(mock(PrintWriter.class));
mWindowTracing.stopTrace(mock(PrintWriter.class));
+ assertTrue("Trace file should exist", mFile.exists());
+
byte[] header = new byte[MAGIC_HEADER.length];
try (InputStream is = new FileInputStream(mFile)) {
assertEquals(MAGIC_HEADER.length, is.read(header));