diff options
7 files changed, 326 insertions, 104 deletions
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8373b44112fe..752c24e7edb6 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6056,6 +6056,7 @@ public class WindowManagerService extends IWindowManager.Stub pw.println(" d[isplays]: active display contents"); pw.println(" t[okens]: token list"); pw.println(" w[indows]: window list"); + pw.println(" trace: write Winscope trace to file"); pw.println(" cmd may also be a NAME to dump windows. NAME may"); pw.println(" be a partial substring in a window name, a"); pw.println(" Window hex object identifier, or"); @@ -6129,6 +6130,11 @@ public class WindowManagerService extends IWindowManager.Stub mRoot.forAllWindows(w -> {pw.println(w);}, true /* traverseTopToBottom */); } return; + } else if ("trace".equals(cmd)) { + synchronized (mGlobalLock) { + mWindowTracing.writeTraceToFile(); + } + return; } else { // Dumping a single name? if (!dumpWindows(pw, cmd, args, opti, dumpAll)) { diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 6865ce305442..83e3c71cbee3 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -72,8 +72,7 @@ public class WindowManagerShellCommand extends ShellCommand { // XXX this should probably be changed to use openFileForSystem() to create // the output trace file, so the shell gets the correct semantics for where // trace files can be written. - return mInternal.mWindowTracing.onShellCommand(this, - getNextArgRequired()); + return mInternal.mWindowTracing.onShellCommand(this); case "set-user-rotation": return runSetDisplayUserRotation(pw); case "set-fix-to-user-rotation": diff --git a/services/core/java/com/android/server/wm/WindowTraceBuffer.java b/services/core/java/com/android/server/wm/WindowTraceBuffer.java index 936ee85697b8..2f672f24cc4f 100644 --- a/services/core/java/com/android/server/wm/WindowTraceBuffer.java +++ b/services/core/java/com/android/server/wm/WindowTraceBuffer.java @@ -23,12 +23,15 @@ 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; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Queue; /** * Buffer used for window tracing. @@ -36,16 +39,15 @@ import java.util.concurrent.LinkedBlockingQueue; abstract class WindowTraceBuffer { private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L; - final Object mBufferSizeLock = new Object(); - final BlockingQueue<byte[]> mBuffer; + final Object mBufferLock = new Object(); + final Queue<byte[]> mBuffer = new ArrayDeque<>(); + final File mTraceFile; int mBufferSize; private final int mBufferCapacity; - private final File mTraceFile; WindowTraceBuffer(int size, File traceFile) throws IOException { mBufferCapacity = size; mTraceFile = traceFile; - mBuffer = new LinkedBlockingQueue<>(); initTraceFile(); } @@ -57,65 +59,45 @@ abstract class WindowTraceBuffer { /** * Inserts the specified element into this buffer. * - * This method is synchronized with {@code #take()} and {@code #clear()} - * for consistency. - * * @param proto the element to add - * @return {@code true} if the inserted item was inserted into the buffer * @throws IllegalStateException if the element cannot be added because it is larger * than the buffer size. */ - boolean add(ProtoOutputStream proto) throws InterruptedException { + void add(ProtoOutputStream proto) { byte[] protoBytes = proto.getBytes(); int protoLength = protoBytes.length; if (protoLength > mBufferCapacity) { throw new IllegalStateException("Trace object too large for the buffer. Buffer size:" + mBufferCapacity + " Object size: " + protoLength); } - synchronized (mBufferSizeLock) { - boolean canAdd = canAdd(protoBytes); + synchronized (mBufferLock) { + boolean canAdd = canAdd(protoLength); if (canAdd) { mBuffer.offer(protoBytes); mBufferSize += protoLength; } - return canAdd; + mBufferLock.notify(); } } - void writeNextBufferElementToFile() throws IOException { - byte[] proto; - try { - proto = take(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return; - } - + /** + * 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, "writeToFile"); - try (OutputStream os = new FileOutputStream(mTraceFile, true)) { - os.write(proto); - } + Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeTraceToFile"); + writeTraceToFile(); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } } - /** - * Retrieves and removes the head of this queue, waiting if necessary - * until an element becomes available. - * - * This method is synchronized with {@code #add(ProtoOutputStream)} and {@code #clear()} - * for consistency. - * - * @return the head of this buffer, or {@code null} if this buffer is empty - */ - private byte[] take() throws InterruptedException { - byte[] item = mBuffer.take(); - synchronized (mBufferSizeLock) { - mBufferSize -= item.length; - return item; - } + @VisibleForTesting + boolean contains(byte[] other) { + return mBuffer.stream() + .anyMatch(p -> Arrays.equals(p, other)); } private void initTraceFile() throws IOException { @@ -132,25 +114,31 @@ abstract class WindowTraceBuffer { * Checks if the element can be added to the buffer. The element is already certain to be * smaller than the overall buffer size. * - * @param protoBytes byte array representation of the Proto object to add - * @return <tt>true<</tt> if the element can be added to the buffer or not + * @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(byte[] protoBytes) throws InterruptedException; + 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 writeToDisk() throws IOException, InterruptedException; + abstract void writeTraceToFile() throws IOException, InterruptedException; /** - * Builder for a {@code WindowTraceBuffer} which creates a {@link WindowTraceQueueBuffer} + * 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; + } Builder setTraceFile(File traceFile) { mTraceFile = traceFile; @@ -175,7 +163,11 @@ abstract class WindowTraceBuffer { throw new IllegalArgumentException("A valid trace file must be specified."); } - return new WindowTraceQueueBuffer(mBufferCapacity, mTraceFile); + if (mContinuous) { + return new WindowTraceRingBuffer(mBufferCapacity, mTraceFile); + } else { + return new WindowTraceQueueBuffer(mBufferCapacity, mTraceFile); + } } } } diff --git a/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java b/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java index b7fc7ac8cb5e..eaedde9ea842 100644 --- a/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java +++ b/services/core/java/com/android/server/wm/WindowTraceQueueBuffer.java @@ -18,10 +18,14 @@ package com.android.server.wm; import static android.os.Build.IS_USER; +import android.util.Log; + 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 @@ -29,14 +33,17 @@ import java.io.IOException; * Once the buffer is full it will no longer accepts new elements. */ class WindowTraceQueueBuffer extends WindowTraceBuffer { - private Thread mWriterThread; + private static final String TAG = "WindowTracing"; + + private Thread mConsumerThread; private boolean mCancel; @VisibleForTesting - WindowTraceQueueBuffer(int size, File traceFile, boolean startWriterThread) throws IOException { + WindowTraceQueueBuffer(int size, File traceFile, boolean startConsumerThread) + throws IOException { super(size, traceFile); - if (startWriterThread) { - initializeWriterThread(); + if (startConsumerThread) { + initializeConsumerThread(); } } @@ -44,45 +51,56 @@ class WindowTraceQueueBuffer extends WindowTraceBuffer { this(size, traceFile, !IS_USER); } - private void initializeWriterThread() { + private void initializeConsumerThread() { mCancel = false; - mWriterThread = new Thread(() -> { + mConsumerThread = new Thread(() -> { try { loop(); + } catch (InterruptedException e) { + Log.i(TAG, "Interrupting trace consumer thread"); } catch (IOException e) { - throw new IllegalStateException("Failed to execute trace write loop thread", e); + Log.e(TAG, "Failed to execute trace consumer thread", e); } }, "window_tracing"); - mWriterThread.start(); + mConsumerThread.start(); } - private void loop() throws IOException { + private void loop() throws IOException, InterruptedException { while (!mCancel) { - writeNextBufferElementToFile(); - } - } + byte[] proto; + synchronized (mBufferLock) { + mBufferLock.wait(); - private void restartWriterThread() throws InterruptedException { - if (mWriterThread != null) { - mCancel = true; - mWriterThread.interrupt(); - mWriterThread.join(); - initializeWriterThread(); + proto = mBuffer.poll(); + if (proto != null) { + mBufferSize -= proto.length; + } + } + + if (proto != null) { + try (OutputStream os = new FileOutputStream(mTraceFile, true)) { + os.write(proto); + } + } } } @Override - boolean canAdd(byte[] protoBytes) { + boolean canAdd(int protoLength) { long availableSpace = getAvailableSpace(); - return availableSpace >= protoBytes.length; + return availableSpace >= protoLength; } @Override - void writeToDisk() throws InterruptedException { - while (!mBuffer.isEmpty()) { - mBufferSizeLock.wait(); - mBufferSizeLock.notify(); + void writeTraceToFile() throws InterruptedException { + synchronized (mBufferLock) { + mCancel = true; + mBufferLock.notify(); + } + + if (mConsumerThread != null) { + mConsumerThread.join(); + mConsumerThread = null; } - restartWriterThread(); } } diff --git a/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java b/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java new file mode 100644 index 000000000000..7c69f2368845 --- /dev/null +++ b/services/core/java/com/android/server/wm/WindowTraceRingBuffer.java @@ -0,0 +1,68 @@ +/* + * 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 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()) { + byte[] proto; + proto = mBuffer.poll(); + mBufferSize -= proto.length; + os.write(proto); + } + } + } + } + + private void discardOldest() { + byte[] item = mBuffer.poll(); + if (item == null) { + throw new IllegalStateException("No element to discard from buffer"); + } + mBufferSize -= item.length; + } +} diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java index 63539c4f9fd9..4c9a917c9248 100644 --- a/services/core/java/com/android/server/wm/WindowTracing.java +++ b/services/core/java/com/android/server/wm/WindowTracing.java @@ -53,6 +53,7 @@ class WindowTracing { private WindowTraceBuffer mTraceBuffer; + private boolean mContinuousMode; private boolean mEnabled; private volatile boolean mEnabledLockFree; @@ -70,13 +71,11 @@ class WindowTracing { synchronized (mLock) { logAndPrintln(pw, "Start tracing to " + mBufferBuilder.getFile() + "."); if (mTraceBuffer != null) { - try { - mTraceBuffer.writeToDisk(); - } catch (InterruptedException e) { - logAndPrintln(pw, "Error: Unable to flush the previous buffer."); - } + writeTraceToFileLocked(); } - mTraceBuffer = mBufferBuilder.build(); + mTraceBuffer = mBufferBuilder + .setContinuousMode(mContinuousMode) + .build(); mEnabled = mEnabledLockFree = true; } } @@ -104,29 +103,29 @@ class WindowTracing { logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush."); throw new IllegalStateException("tracing enabled while waiting for flush."); } - try { - mTraceBuffer.writeToDisk(); - } 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); - } + writeTraceToFileLocked(); + mTraceBuffer = null; } logAndPrintln(pw, "Trace written to " + mBufferBuilder.getFile() + "."); } } + private void setContinuousMode(boolean continuous, PrintWriter pw) { + logAndPrintln(pw, "Setting window tracing continuous mode to " + continuous); + + if (mEnabled) { + logAndPrintln(pw, "Trace is currently active, change will take effect once the " + + "trace is restarted."); + } + mContinuousMode = continuous; + } + private void appendTraceEntry(ProtoOutputStream proto) { if (!mEnabledLockFree) { return; } - try { - mTraceBuffer.add(proto); - } catch (InterruptedException e) { - Log.e(TAG, "Unable to add element to trace", e); - Thread.currentThread().interrupt(); - } + mTraceBuffer.add(proto); } boolean isEnabled() { @@ -138,9 +137,10 @@ class WindowTracing { return new WindowTracing(file); } - int onShellCommand(ShellCommand shell, String cmd) { + int onShellCommand(ShellCommand shell) { PrintWriter pw = shell.getOutPrintWriter(); try { + String cmd = shell.getNextArgRequired(); switch (cmd) { case "start": startTrace(pw); @@ -148,6 +148,9 @@ class WindowTracing { case "stop": stopTrace(pw); return 0; + case "continuous": + setContinuousMode(Boolean.valueOf(shell.getNextArgRequired()), pw); + return 0; default: pw.println("Unknown command: " + cmd); return -1; @@ -162,6 +165,7 @@ class WindowTracing { if (!isEnabled()) { return; } + ProtoOutputStream os = new ProtoOutputStream(); long tokenOuter = os.start(ENTRY); os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos()); @@ -179,4 +183,33 @@ class WindowTracing { appendTraceEntry(os); Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); } + + /** + * Writes the trace buffer to disk. This method has no internal synchronization and should be + * externally synchronized + */ + private void writeTraceToFileLocked() { + if (mTraceBuffer == null) { + return; + } + + 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); + } + } + + /** + * 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)}. + */ + void writeTraceToFile() { + synchronized (mLock) { + writeTraceToFileLocked(); + } + } } 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 8d834974148c..df3ef551d5a1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTraceBufferTest.java @@ -19,8 +19,6 @@ package com.android.server.wm; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 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 static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -31,13 +29,14 @@ import android.util.proto.ProtoOutputStream; import androidx.test.filters.SmallTest; +import com.android.internal.util.Preconditions; + import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.File; import java.io.IOException; -import java.util.Arrays; /** @@ -49,8 +48,6 @@ import java.util.Arrays; @SmallTest @Presubmit public class WindowTraceBufferTest { - private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L; - private File mFile; @Before @@ -81,18 +78,22 @@ public class WindowTraceBufferTest { buffer.add(toWrite1); assertTrue("First element should be in the list", - buffer.mBuffer.stream().anyMatch(p -> Arrays.equals(p, toWrite1Bytes))); + buffer.contains(toWrite1Bytes)); buffer.add(toWrite2); assertTrue("First element should be in the list", - buffer.mBuffer.stream().anyMatch(p -> Arrays.equals(p, toWrite1Bytes))); + buffer.contains(toWrite1Bytes)); assertTrue("Second element should be in the list", - buffer.mBuffer.stream().anyMatch(p -> Arrays.equals(p, toWrite2Bytes))); + buffer.contains(toWrite2Bytes)); buffer.add(toWrite3); + 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.mBuffer.stream().noneMatch(p -> Arrays.equals(p, toWrite3Bytes))); + !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), @@ -101,6 +102,111 @@ public class WindowTraceBufferTest { buffer.getAvailableSpace(), 0); } + @Test + public void testTraceRingBuffer_addItem() throws Exception { + ProtoOutputStream toWrite = getDummy(1); + final int objectSize = toWrite.getBytes().length; + + final WindowTraceBuffer buffer = buildRingBuffer(objectSize); + + Preconditions.checkArgument(buffer.mBuffer.isEmpty()); + + buffer.add(toWrite); + + assertEquals("Item was not added to the buffer", buffer.mBuffer.size(), 1); + assertEquals("Total buffer getSize differs from inserted object", + buffer.mBufferSize, objectSize); + assertEquals("Available buffer space does not match used one", + buffer.getAvailableSpace(), 0); + } + + @Test + public void testTraceRingBuffer_addItemMustOverwriteOne() throws Exception { + ProtoOutputStream toWrite1 = getDummy(1); + ProtoOutputStream toWrite2 = getDummy(2); + ProtoOutputStream toWrite3 = getDummy(3); + byte[] toWrite1Bytes = toWrite1.getBytes(); + byte[] toWrite2Bytes = toWrite2.getBytes(); + byte[] toWrite3Bytes = toWrite3.getBytes(); + final int objectSize = toWrite1.getBytes().length; + + final int bufferCapacity = objectSize * 2 + 1; + final WindowTraceBuffer buffer = buildRingBuffer(bufferCapacity); + + buffer.add(toWrite1); + assertTrue("First element should be in the list", + buffer.contains(toWrite1Bytes)); + + buffer.add(toWrite2); + 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); + assertTrue("First element should not be in the list", + !buffer.contains(toWrite1Bytes)); + assertTrue("Second element should be in the list", + buffer.contains(toWrite2Bytes)); + assertTrue("Third element should 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 - 1); + assertEquals(" Buffer is full, available space should be 0", + buffer.getAvailableSpace(), 1); + } + + @Test + public void testTraceRingBuffer_addItemMustOverwriteMultiple() throws Exception { + ProtoOutputStream toWriteSmall1 = getDummy(1); + ProtoOutputStream toWriteSmall2 = getDummy(2); + byte[] toWriteSmall1Bytes = toWriteSmall1.getBytes(); + byte[] toWriteSmall2Bytes = toWriteSmall2.getBytes(); + final int objectSize = toWriteSmall1.getBytes().length; + + final int bufferCapacity = objectSize * 2; + final WindowTraceBuffer buffer = buildRingBuffer(bufferCapacity); + + ProtoOutputStream toWriteBig = new ProtoOutputStream(); + toWriteBig.write(MAGIC_NUMBER, 1); + toWriteBig.write(MAGIC_NUMBER, 2); + byte[] toWriteBigBytes = toWriteBig.getBytes(); + toWriteBig.flush(); + + buffer.add(toWriteSmall1); + assertTrue("First element should be in the list", + buffer.contains(toWriteSmall1Bytes)); + + buffer.add(toWriteSmall2); + assertTrue("First element should be in the list", + buffer.contains(toWriteSmall1Bytes)); + assertTrue("Second element should be in the list", + buffer.contains(toWriteSmall2Bytes)); + + buffer.add(toWriteBig); + assertTrue("Third element should overwrite all others", + !buffer.contains(toWriteSmall1Bytes)); + assertTrue("Third element should overwrite all others", + !buffer.contains(toWriteSmall2Bytes)); + assertTrue("Third element should overwrite all others", + buffer.contains(toWriteBigBytes)); + + assertEquals(" Buffer should have only 1 big element", buffer.mBuffer.size(), 1); + 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); + } + + private WindowTraceBuffer buildRingBuffer(int capacity) throws IOException { + return new WindowTraceBuffer.Builder() + .setContinuousMode(true) + .setBufferCapacity(capacity) + .setTraceFile(mFile) + .build(); + } + private ProtoOutputStream getDummy(int value) { ProtoOutputStream toWrite = new ProtoOutputStream(); toWrite.write(MAGIC_NUMBER, value); |