summaryrefslogtreecommitdiff
path: root/core/java/android/view/ViewDebug.java
diff options
context:
space:
mode:
authorRomain Guy <romainguy@google.com>2011-07-13 18:46:21 -0700
committerRomain Guy <romainguy@google.com>2011-07-15 11:25:11 -0700
commitf9284695e8c10dad4daf3d2c84f607483bcb56ca (patch)
treebb4d52d7d3f6d9b73c8ba23d55036d3f4cd1ba31 /core/java/android/view/ViewDebug.java
parentfed878d98bc42db61cf04d759235b8406a7d14fd (diff)
Add new ViewDebug APIs to profile the event queue.
Change-Id: I225bf288780b0244f459316e2765cfa29cd22c89
Diffstat (limited to 'core/java/android/view/ViewDebug.java')
-rw-r--r--core/java/android/view/ViewDebug.java168
1 files changed, 143 insertions, 25 deletions
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index f014070d2b9d..f7f5a21399dd 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -16,41 +16,45 @@
package android.view;
-import android.util.Log;
-import android.util.DisplayMetrics;
-import android.content.res.Resources;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
-import android.os.Environment;
import android.os.Debug;
+import android.os.Environment;
+import android.os.Looper;
+import android.os.Message;
import android.os.RemoteException;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.Printer;
+import java.io.BufferedOutputStream;
+import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
import java.io.File;
-import java.io.BufferedWriter;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
-import java.io.FileOutputStream;
-import java.io.DataOutputStream;
-import java.io.OutputStreamWriter;
-import java.io.BufferedOutputStream;
import java.io.OutputStream;
-import java.util.List;
-import java.util.LinkedList;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.lang.annotation.Target;
+import java.io.OutputStreamWriter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
-import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Various debugging/tracing tools related to {@link View} and the view hierarchy.
@@ -106,13 +110,6 @@ public class ViewDebug {
public static final boolean DEBUG_PROFILE_LAYOUT = false;
/**
- * Profiles real fps (times between draws) and displays the result.
- *
- * @hide
- */
- public static final boolean DEBUG_SHOW_FPS = false;
-
- /**
* Enables detailed logging of drag/drop operations.
* @hide
*/
@@ -396,6 +393,9 @@ public class ViewDebug {
private static List<RecyclerTrace> sRecyclerTraces;
private static String sRecyclerTracePrefix;
+ private static final ThreadLocal<LooperProfiler> sLooperProfilerStorage =
+ new ThreadLocal<LooperProfiler>();
+
/**
* Returns the number of instanciated Views.
*
@@ -419,6 +419,124 @@ public class ViewDebug {
}
/**
+ * Starts profiling the looper associated with the current thread.
+ * You must call {@link #stopLooperProfiling} to end profiling
+ * and obtain the traces. Both methods must be invoked on the
+ * same thread.
+ *
+ * @param traceFile The path where to write the looper traces
+ *
+ * @see #stopLooperProfiling()
+ */
+ public static void startLooperProfiling(File traceFile) {
+ if (sLooperProfilerStorage.get() == null) {
+ LooperProfiler profiler = new LooperProfiler(traceFile);
+ sLooperProfilerStorage.set(profiler);
+ Looper.myLooper().setMessageLogging(profiler);
+ }
+ }
+
+ /**
+ * Stops profiling the looper associated with the current thread.
+ *
+ * @see #startLooperProfiling(java.io.File)
+ */
+ public static void stopLooperProfiling() {
+ LooperProfiler profiler = sLooperProfilerStorage.get();
+ if (profiler != null) {
+ sLooperProfilerStorage.remove();
+ Looper.myLooper().setMessageLogging(null);
+ profiler.save();
+ }
+ }
+
+ private static class LooperProfiler implements Looper.Profiler, Printer {
+ private static final int LOOPER_PROFILER_VERSION = 1;
+
+ private static final String LOG_TAG = "LooperProfiler";
+
+ private final ArrayList<Entry> mTraces = new ArrayList<Entry>(512);
+ private final File mTraceFile;
+
+ public LooperProfiler(File traceFile) {
+ mTraceFile = traceFile;
+ }
+
+ @Override
+ public void println(String x) {
+ // Ignore messages
+ }
+
+ @Override
+ public void profile(Message message, long wallStart, long wallTime, long threadTime) {
+ Entry entry = new Entry();
+ entry.messageId = message.what;
+ entry.name = message.getTarget().getMessageName(message);
+ entry.wallStart = wallStart;
+ entry.wallTime = wallTime;
+ entry.threadTime = threadTime;
+
+ mTraces.add(entry);
+ }
+
+ void save() {
+ // Don't block the UI thread
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ saveTraces();
+ }
+ }, "LooperProfiler[" + mTraceFile + "]").start();
+ }
+
+ private void saveTraces() {
+ FileOutputStream fos;
+ try {
+ fos = new FileOutputStream(mTraceFile);
+ } catch (FileNotFoundException e) {
+ Log.e(LOG_TAG, "Could not open trace file: " + mTraceFile);
+ return;
+ }
+
+ DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
+
+ try {
+ out.writeInt(LOOPER_PROFILER_VERSION);
+ out.writeInt(mTraces.size());
+ for (Entry entry : mTraces) {
+ saveTrace(entry, out);
+ }
+
+ Log.d(LOG_TAG, "Looper traces ready: " + mTraceFile);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "Could not write trace file: ", e);
+ } finally {
+ try {
+ out.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+ }
+
+ private void saveTrace(Entry entry, DataOutputStream out) throws IOException {
+ out.writeInt(entry.messageId);
+ out.writeUTF(entry.name);
+ out.writeLong(entry.wallStart);
+ out.writeLong(entry.wallTime);
+ out.writeLong(entry.threadTime);
+ }
+
+ static class Entry {
+ int messageId;
+ String name;
+ long wallStart;
+ long wallTime;
+ long threadTime;
+ }
+ }
+
+ /**
* Outputs a trace to the currently opened recycler traces. The trace records the type of
* recycler action performed on the supplied view as well as a number of parameters.
*