• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.os;
18 
19 import com.android.internal.util.TypedProperties;
20 
21 import android.util.Config;
22 import android.util.Log;
23 
24 import java.io.FileDescriptor;
25 import java.io.FileNotFoundException;
26 import java.io.FileOutputStream;
27 import java.io.FileReader;
28 import java.io.IOException;
29 import java.io.OutputStreamWriter;
30 import java.io.PrintWriter;
31 import java.io.Reader;
32 import java.lang.reflect.Field;
33 import java.lang.reflect.Modifier;
34 import java.lang.annotation.Target;
35 import java.lang.annotation.ElementType;
36 import java.lang.annotation.Retention;
37 import java.lang.annotation.RetentionPolicy;
38 
39 import org.apache.harmony.dalvik.ddmc.Chunk;
40 import org.apache.harmony.dalvik.ddmc.ChunkHandler;
41 import org.apache.harmony.dalvik.ddmc.DdmServer;
42 
43 import dalvik.bytecode.Opcodes;
44 import dalvik.system.VMDebug;
45 
46 
47 /**
48  * Provides various debugging functions for Android applications, including
49  * tracing and allocation counts.
50  * <p><strong>Logging Trace Files</strong></p>
51  * <p>Debug can create log files that give details about an application, such as
52  * a call stack and start/stop times for any running methods. See <a
53 href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
54  * information about reading trace files. To start logging trace files, call one
55  * of the startMethodTracing() methods. To stop tracing, call
56  * {@link #stopMethodTracing()}.
57  */
58 public final class Debug
59 {
60     private static final String TAG = "Debug";
61 
62     /**
63      * Flags for startMethodTracing().  These can be ORed together.
64      *
65      * TRACE_COUNT_ALLOCS adds the results from startAllocCounting to the
66      * trace key file.
67      */
68     public static final int TRACE_COUNT_ALLOCS  = VMDebug.TRACE_COUNT_ALLOCS;
69 
70     /**
71      * Flags for printLoadedClasses().  Default behavior is to only show
72      * the class name.
73      */
74     public static final int SHOW_FULL_DETAIL    = 1;
75     public static final int SHOW_CLASSLOADER    = (1 << 1);
76     public static final int SHOW_INITIALIZED    = (1 << 2);
77 
78     // set/cleared by waitForDebugger()
79     private static volatile boolean mWaiting = false;
80 
Debug()81     private Debug() {}
82 
83     /*
84      * How long to wait for the debugger to finish sending requests.  I've
85      * seen this hit 800msec on the device while waiting for a response
86      * to travel over USB and get processed, so we take that and add
87      * half a second.
88      */
89     private static final int MIN_DEBUGGER_IDLE = 1300;      // msec
90 
91     /* how long to sleep when polling for activity */
92     private static final int SPIN_DELAY = 200;              // msec
93 
94     /**
95      * Default trace file path and file
96      */
97     private static final String DEFAULT_TRACE_PATH_PREFIX = "/sdcard/";
98     private static final String DEFAULT_TRACE_BODY = "dmtrace";
99     private static final String DEFAULT_TRACE_EXTENSION = ".trace";
100     private static final String DEFAULT_TRACE_FILE_PATH =
101         DEFAULT_TRACE_PATH_PREFIX + DEFAULT_TRACE_BODY
102         + DEFAULT_TRACE_EXTENSION;
103 
104 
105     /**
106      * This class is used to retrieved various statistics about the memory mappings for this
107      * process. The returns info broken down by dalvik, native, and other. All results are in kB.
108      */
109     public static class MemoryInfo implements Parcelable {
110         /** The proportional set size for dalvik. */
111         public int dalvikPss;
112         /** The private dirty pages used by dalvik. */
113         public int dalvikPrivateDirty;
114         /** The shared dirty pages used by dalvik. */
115         public int dalvikSharedDirty;
116 
117         /** The proportional set size for the native heap. */
118         public int nativePss;
119         /** The private dirty pages used by the native heap. */
120         public int nativePrivateDirty;
121         /** The shared dirty pages used by the native heap. */
122         public int nativeSharedDirty;
123 
124         /** The proportional set size for everything else. */
125         public int otherPss;
126         /** The private dirty pages used by everything else. */
127         public int otherPrivateDirty;
128         /** The shared dirty pages used by everything else. */
129         public int otherSharedDirty;
130 
MemoryInfo()131         public MemoryInfo() {
132         }
133 
134         /**
135          * Return total PSS memory usage in kB.
136          */
getTotalPss()137         public int getTotalPss() {
138             return dalvikPss + nativePss + otherPss;
139         }
140 
141         /**
142          * Return total private dirty memory usage in kB.
143          */
getTotalPrivateDirty()144         public int getTotalPrivateDirty() {
145             return dalvikPrivateDirty + nativePrivateDirty + otherPrivateDirty;
146         }
147 
148         /**
149          * Return total shared dirty memory usage in kB.
150          */
getTotalSharedDirty()151         public int getTotalSharedDirty() {
152             return dalvikSharedDirty + nativeSharedDirty + otherSharedDirty;
153         }
154 
describeContents()155         public int describeContents() {
156             return 0;
157         }
158 
writeToParcel(Parcel dest, int flags)159         public void writeToParcel(Parcel dest, int flags) {
160             dest.writeInt(dalvikPss);
161             dest.writeInt(dalvikPrivateDirty);
162             dest.writeInt(dalvikSharedDirty);
163             dest.writeInt(nativePss);
164             dest.writeInt(nativePrivateDirty);
165             dest.writeInt(nativeSharedDirty);
166             dest.writeInt(otherPss);
167             dest.writeInt(otherPrivateDirty);
168             dest.writeInt(otherSharedDirty);
169         }
170 
readFromParcel(Parcel source)171         public void readFromParcel(Parcel source) {
172             dalvikPss = source.readInt();
173             dalvikPrivateDirty = source.readInt();
174             dalvikSharedDirty = source.readInt();
175             nativePss = source.readInt();
176             nativePrivateDirty = source.readInt();
177             nativeSharedDirty = source.readInt();
178             otherPss = source.readInt();
179             otherPrivateDirty = source.readInt();
180             otherSharedDirty = source.readInt();
181         }
182 
183         public static final Creator<MemoryInfo> CREATOR = new Creator<MemoryInfo>() {
184             public MemoryInfo createFromParcel(Parcel source) {
185                 return new MemoryInfo(source);
186             }
187             public MemoryInfo[] newArray(int size) {
188                 return new MemoryInfo[size];
189             }
190         };
191 
MemoryInfo(Parcel source)192         private MemoryInfo(Parcel source) {
193             readFromParcel(source);
194         }
195     }
196 
197 
198     /**
199      * Wait until a debugger attaches.  As soon as the debugger attaches,
200      * this returns, so you will need to place a breakpoint after the
201      * waitForDebugger() call if you want to start tracing immediately.
202      */
waitForDebugger()203     public static void waitForDebugger() {
204         if (!VMDebug.isDebuggingEnabled()) {
205             //System.out.println("debugging not enabled, not waiting");
206             return;
207         }
208         if (isDebuggerConnected())
209             return;
210 
211         // if DDMS is listening, inform them of our plight
212         System.out.println("Sending WAIT chunk");
213         byte[] data = new byte[] { 0 };     // 0 == "waiting for debugger"
214         Chunk waitChunk = new Chunk(ChunkHandler.type("WAIT"), data, 0, 1);
215         DdmServer.sendChunk(waitChunk);
216 
217         mWaiting = true;
218         while (!isDebuggerConnected()) {
219             try { Thread.sleep(SPIN_DELAY); }
220             catch (InterruptedException ie) {}
221         }
222         mWaiting = false;
223 
224         System.out.println("Debugger has connected");
225 
226         /*
227          * There is no "ready to go" signal from the debugger, and we're
228          * not allowed to suspend ourselves -- the debugger expects us to
229          * be running happily, and gets confused if we aren't.  We need to
230          * allow the debugger a chance to set breakpoints before we start
231          * running again.
232          *
233          * Sit and spin until the debugger has been idle for a short while.
234          */
235         while (true) {
236             long delta = VMDebug.lastDebuggerActivity();
237             if (delta < 0) {
238                 System.out.println("debugger detached?");
239                 break;
240             }
241 
242             if (delta < MIN_DEBUGGER_IDLE) {
243                 System.out.println("waiting for debugger to settle...");
244                 try { Thread.sleep(SPIN_DELAY); }
245                 catch (InterruptedException ie) {}
246             } else {
247                 System.out.println("debugger has settled (" + delta + ")");
248                 break;
249             }
250         }
251     }
252 
253     /**
254      * Returns "true" if one or more threads is waiting for a debugger
255      * to attach.
256      */
waitingForDebugger()257     public static boolean waitingForDebugger() {
258         return mWaiting;
259     }
260 
261     /**
262      * Determine if a debugger is currently attached.
263      */
isDebuggerConnected()264     public static boolean isDebuggerConnected() {
265         return VMDebug.isDebuggerConnected();
266     }
267 
268     /**
269      * Returns an array of strings that identify VM features.  This is
270      * used by DDMS to determine what sorts of operations the VM can
271      * perform.
272      *
273      * @hide
274      */
getVmFeatureList()275     public static String[] getVmFeatureList() {
276         return VMDebug.getVmFeatureList();
277     }
278 
279     /**
280      * Change the JDWP port.
281      *
282      * @deprecated no longer needed or useful
283      */
284     @Deprecated
changeDebugPort(int port)285     public static void changeDebugPort(int port) {}
286 
287     /**
288      * This is the pathname to the sysfs file that enables and disables
289      * tracing on the qemu emulator.
290      */
291     private static final String SYSFS_QEMU_TRACE_STATE = "/sys/qemu_trace/state";
292 
293     /**
294      * Enable qemu tracing. For this to work requires running everything inside
295      * the qemu emulator; otherwise, this method will have no effect. The trace
296      * file is specified on the command line when the emulator is started. For
297      * example, the following command line <br />
298      * <code>emulator -trace foo</code><br />
299      * will start running the emulator and create a trace file named "foo". This
300      * method simply enables writing the trace records to the trace file.
301      *
302      * <p>
303      * The main differences between this and {@link #startMethodTracing()} are
304      * that tracing in the qemu emulator traces every cpu instruction of every
305      * process, including kernel code, so we have more complete information,
306      * including all context switches. We can also get more detailed information
307      * such as cache misses. The sequence of calls is determined by
308      * post-processing the instruction trace. The qemu tracing is also done
309      * without modifying the application or perturbing the timing of calls
310      * because no instrumentation is added to the application being traced.
311      * </p>
312      *
313      * <p>
314      * One limitation of using this method compared to using
315      * {@link #startMethodTracing()} on the real device is that the emulator
316      * does not model all of the real hardware effects such as memory and
317      * bus contention.  The emulator also has a simple cache model and cannot
318      * capture all the complexities of a real cache.
319      * </p>
320      */
startNativeTracing()321     public static void startNativeTracing() {
322         // Open the sysfs file for writing and write "1" to it.
323         PrintWriter outStream = null;
324         try {
325             FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE);
326             outStream = new PrintWriter(new OutputStreamWriter(fos));
327             outStream.println("1");
328         } catch (Exception e) {
329         } finally {
330             if (outStream != null)
331                 outStream.close();
332         }
333 
334         VMDebug.startEmulatorTracing();
335     }
336 
337     /**
338      * Stop qemu tracing.  See {@link #startNativeTracing()} to start tracing.
339      *
340      * <p>Tracing can be started and stopped as many times as desired.  When
341      * the qemu emulator itself is stopped then the buffered trace records
342      * are flushed and written to the trace file.  In fact, it is not necessary
343      * to call this method at all; simply killing qemu is sufficient.  But
344      * starting and stopping a trace is useful for examining a specific
345      * region of code.</p>
346      */
stopNativeTracing()347     public static void stopNativeTracing() {
348         VMDebug.stopEmulatorTracing();
349 
350         // Open the sysfs file for writing and write "0" to it.
351         PrintWriter outStream = null;
352         try {
353             FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE);
354             outStream = new PrintWriter(new OutputStreamWriter(fos));
355             outStream.println("0");
356         } catch (Exception e) {
357             // We could print an error message here but we probably want
358             // to quietly ignore errors if we are not running in the emulator.
359         } finally {
360             if (outStream != null)
361                 outStream.close();
362         }
363     }
364 
365     /**
366      * Enable "emulator traces", in which information about the current
367      * method is made available to the "emulator -trace" feature.  There
368      * is no corresponding "disable" call -- this is intended for use by
369      * the framework when tracing should be turned on and left that way, so
370      * that traces captured with F9/F10 will include the necessary data.
371      *
372      * This puts the VM into "profile" mode, which has performance
373      * consequences.
374      *
375      * To temporarily enable tracing, use {@link #startNativeTracing()}.
376      */
enableEmulatorTraceOutput()377     public static void enableEmulatorTraceOutput() {
378         VMDebug.startEmulatorTracing();
379     }
380 
381     /**
382      * Start method tracing with default log name and buffer size. See <a
383 href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
384      * information about reading these files. Call stopMethodTracing() to stop
385      * tracing.
386      */
startMethodTracing()387     public static void startMethodTracing() {
388         VMDebug.startMethodTracing(DEFAULT_TRACE_FILE_PATH, 0, 0);
389     }
390 
391     /**
392      * Start method tracing, specifying the trace log file name.  The trace
393      * file will be put under "/sdcard" unless an absolute path is given.
394      * See <a
395        href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
396      * information about reading trace files.
397      *
398      * @param traceName Name for the trace log file to create.
399      * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
400      * If the files already exist, they will be truncated.
401      * If the trace file given does not end in ".trace", it will be appended for you.
402      */
startMethodTracing(String traceName)403     public static void startMethodTracing(String traceName) {
404         startMethodTracing(traceName, 0, 0);
405     }
406 
407     /**
408      * Start method tracing, specifying the trace log file name and the
409      * buffer size. The trace files will be put under "/sdcard" unless an
410      * absolute path is given. See <a
411        href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
412      * information about reading trace files.
413      * @param traceName    Name for the trace log file to create.
414      * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
415      * If the files already exist, they will be truncated.
416      * If the trace file given does not end in ".trace", it will be appended for you.
417      *
418      * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
419      */
startMethodTracing(String traceName, int bufferSize)420     public static void startMethodTracing(String traceName, int bufferSize) {
421         startMethodTracing(traceName, bufferSize, 0);
422     }
423 
424     /**
425      * Start method tracing, specifying the trace log file name and the
426      * buffer size. The trace files will be put under "/sdcard" unless an
427      * absolute path is given. See <a
428        href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
429      * information about reading trace files.
430      *
431      * <p>
432      * When method tracing is enabled, the VM will run more slowly than
433      * usual, so the timings from the trace files should only be considered
434      * in relative terms (e.g. was run #1 faster than run #2).  The times
435      * for native methods will not change, so don't try to use this to
436      * compare the performance of interpreted and native implementations of the
437      * same method.  As an alternative, consider using "native" tracing
438      * in the emulator via {@link #startNativeTracing()}.
439      * </p>
440      *
441      * @param traceName    Name for the trace log file to create.
442      * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
443      * If the files already exist, they will be truncated.
444      * If the trace file given does not end in ".trace", it will be appended for you.
445      * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
446      */
startMethodTracing(String traceName, int bufferSize, int flags)447     public static void startMethodTracing(String traceName, int bufferSize,
448         int flags) {
449 
450         String pathName = traceName;
451         if (pathName.charAt(0) != '/')
452             pathName = DEFAULT_TRACE_PATH_PREFIX + pathName;
453         if (!pathName.endsWith(DEFAULT_TRACE_EXTENSION))
454             pathName = pathName + DEFAULT_TRACE_EXTENSION;
455 
456         VMDebug.startMethodTracing(pathName, bufferSize, flags);
457     }
458 
459     /**
460      * Like startMethodTracing(String, int, int), but taking an already-opened
461      * FileDescriptor in which the trace is written.  The file name is also
462      * supplied simply for logging.  Makes a dup of the file descriptor.
463      *
464      * Not exposed in the SDK unless we are really comfortable with supporting
465      * this and find it would be useful.
466      * @hide
467      */
startMethodTracing(String traceName, FileDescriptor fd, int bufferSize, int flags)468     public static void startMethodTracing(String traceName, FileDescriptor fd,
469         int bufferSize, int flags) {
470         VMDebug.startMethodTracing(traceName, fd, bufferSize, flags);
471     }
472 
473     /**
474      * Starts method tracing without a backing file.  When stopMethodTracing
475      * is called, the result is sent directly to DDMS.  (If DDMS is not
476      * attached when tracing ends, the profiling data will be discarded.)
477      *
478      * @hide
479      */
startMethodTracingDdms(int bufferSize, int flags)480     public static void startMethodTracingDdms(int bufferSize, int flags) {
481         VMDebug.startMethodTracingDdms(bufferSize, flags);
482     }
483 
484     /**
485      * Determine whether method tracing is currently active.
486      * @hide
487      */
isMethodTracingActive()488     public static boolean isMethodTracingActive() {
489         return VMDebug.isMethodTracingActive();
490     }
491 
492     /**
493      * Stop method tracing.
494      */
stopMethodTracing()495     public static void stopMethodTracing() {
496         VMDebug.stopMethodTracing();
497     }
498 
499     /**
500      * Get an indication of thread CPU usage.  The value returned
501      * indicates the amount of time that the current thread has spent
502      * executing code or waiting for certain types of I/O.
503      *
504      * The time is expressed in nanoseconds, and is only meaningful
505      * when compared to the result from an earlier call.  Note that
506      * nanosecond resolution does not imply nanosecond accuracy.
507      *
508      * On system which don't support this operation, the call returns -1.
509      */
threadCpuTimeNanos()510     public static long threadCpuTimeNanos() {
511         return VMDebug.threadCpuTimeNanos();
512     }
513 
514     /**
515      * Count the number and aggregate size of memory allocations between
516      * two points.
517      *
518      * The "start" function resets the counts and enables counting.  The
519      * "stop" function disables the counting so that the analysis code
520      * doesn't cause additional allocations.  The "get" function returns
521      * the specified value.
522      *
523      * Counts are kept for the system as a whole and for each thread.
524      * The per-thread counts for threads other than the current thread
525      * are not cleared by the "reset" or "start" calls.
526      */
startAllocCounting()527     public static void startAllocCounting() {
528         VMDebug.startAllocCounting();
529     }
stopAllocCounting()530     public static void stopAllocCounting() {
531         VMDebug.stopAllocCounting();
532     }
533 
getGlobalAllocCount()534     public static int getGlobalAllocCount() {
535         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
536     }
getGlobalAllocSize()537     public static int getGlobalAllocSize() {
538         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
539     }
getGlobalFreedCount()540     public static int getGlobalFreedCount() {
541         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
542     }
getGlobalFreedSize()543     public static int getGlobalFreedSize() {
544         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
545     }
getGlobalClassInitCount()546     public static int getGlobalClassInitCount() {
547         /* number of classes that have been successfully initialized */
548         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT);
549     }
getGlobalClassInitTime()550     public static int getGlobalClassInitTime() {
551         /* cumulative elapsed time for class initialization, in usec */
552         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME);
553     }
getGlobalExternalAllocCount()554     public static int getGlobalExternalAllocCount() {
555         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_OBJECTS);
556     }
getGlobalExternalAllocSize()557     public static int getGlobalExternalAllocSize() {
558         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_BYTES);
559     }
getGlobalExternalFreedCount()560     public static int getGlobalExternalFreedCount() {
561         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_OBJECTS);
562     }
getGlobalExternalFreedSize()563     public static int getGlobalExternalFreedSize() {
564         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_BYTES);
565     }
getGlobalGcInvocationCount()566     public static int getGlobalGcInvocationCount() {
567         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
568     }
getThreadAllocCount()569     public static int getThreadAllocCount() {
570         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
571     }
getThreadAllocSize()572     public static int getThreadAllocSize() {
573         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
574     }
getThreadExternalAllocCount()575     public static int getThreadExternalAllocCount() {
576         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_OBJECTS);
577     }
getThreadExternalAllocSize()578     public static int getThreadExternalAllocSize() {
579         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_BYTES);
580     }
getThreadGcInvocationCount()581     public static int getThreadGcInvocationCount() {
582         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
583     }
584 
resetGlobalAllocCount()585     public static void resetGlobalAllocCount() {
586         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
587     }
resetGlobalAllocSize()588     public static void resetGlobalAllocSize() {
589         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
590     }
resetGlobalFreedCount()591     public static void resetGlobalFreedCount() {
592         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
593     }
resetGlobalFreedSize()594     public static void resetGlobalFreedSize() {
595         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
596     }
resetGlobalClassInitCount()597     public static void resetGlobalClassInitCount() {
598         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT);
599     }
resetGlobalClassInitTime()600     public static void resetGlobalClassInitTime() {
601         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME);
602     }
resetGlobalExternalAllocCount()603     public static void resetGlobalExternalAllocCount() {
604         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_OBJECTS);
605     }
resetGlobalExternalAllocSize()606     public static void resetGlobalExternalAllocSize() {
607         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_BYTES);
608     }
resetGlobalExternalFreedCount()609     public static void resetGlobalExternalFreedCount() {
610         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_OBJECTS);
611     }
resetGlobalExternalFreedSize()612     public static void resetGlobalExternalFreedSize() {
613         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_BYTES);
614     }
resetGlobalGcInvocationCount()615     public static void resetGlobalGcInvocationCount() {
616         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
617     }
resetThreadAllocCount()618     public static void resetThreadAllocCount() {
619         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
620     }
resetThreadAllocSize()621     public static void resetThreadAllocSize() {
622         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
623     }
resetThreadExternalAllocCount()624     public static void resetThreadExternalAllocCount() {
625         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_OBJECTS);
626     }
resetThreadExternalAllocSize()627     public static void resetThreadExternalAllocSize() {
628         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_BYTES);
629     }
resetThreadGcInvocationCount()630     public static void resetThreadGcInvocationCount() {
631         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
632     }
resetAllCounts()633     public static void resetAllCounts() {
634         VMDebug.resetAllocCount(VMDebug.KIND_ALL_COUNTS);
635     }
636 
637     /**
638      * Returns the size of the native heap.
639      * @return The size of the native heap in bytes.
640      */
getNativeHeapSize()641     public static native long getNativeHeapSize();
642 
643     /**
644      * Returns the amount of allocated memory in the native heap.
645      * @return The allocated size in bytes.
646      */
getNativeHeapAllocatedSize()647     public static native long getNativeHeapAllocatedSize();
648 
649     /**
650      * Returns the amount of free memory in the native heap.
651      * @return The freed size in bytes.
652      */
getNativeHeapFreeSize()653     public static native long getNativeHeapFreeSize();
654 
655     /**
656      * Retrieves information about this processes memory usages. This information is broken down by
657      * how much is in use by dalivk, the native heap, and everything else.
658      */
getMemoryInfo(MemoryInfo memoryInfo)659     public static native void getMemoryInfo(MemoryInfo memoryInfo);
660 
661     /**
662      * Note: currently only works when the requested pid has the same UID
663      * as the caller.
664      * @hide
665      */
getMemoryInfo(int pid, MemoryInfo memoryInfo)666     public static native void getMemoryInfo(int pid, MemoryInfo memoryInfo);
667 
668     /**
669      * Establish an object allocation limit in the current thread.  Useful
670      * for catching regressions in code that is expected to operate
671      * without causing any allocations.
672      *
673      * Pass in the maximum number of allowed allocations.  Use -1 to disable
674      * the limit.  Returns the previous limit.
675      *
676      * The preferred way to use this is:
677      *
678      *  int prevLimit = -1;
679      *  try {
680      *      prevLimit = Debug.setAllocationLimit(0);
681      *      ... do stuff that's not expected to allocate memory ...
682      *  } finally {
683      *      Debug.setAllocationLimit(prevLimit);
684      *  }
685      *
686      * This allows limits to be nested.  The try/finally ensures that the
687      * limit is reset if something fails.
688      *
689      * Exceeding the limit causes a dalvik.system.AllocationLimitError to
690      * be thrown from a memory allocation call.  The limit is reset to -1
691      * when this happens.
692      *
693      * The feature may be disabled in the VM configuration.  If so, this
694      * call has no effect, and always returns -1.
695      */
setAllocationLimit(int limit)696     public static int setAllocationLimit(int limit) {
697         return VMDebug.setAllocationLimit(limit);
698     }
699 
700     /**
701      * Establish a global object allocation limit.  This is similar to
702      * {@link #setAllocationLimit(int)} but applies to all threads in
703      * the VM.  It will coexist peacefully with per-thread limits.
704      *
705      * [ The value of "limit" is currently restricted to 0 (no allocations
706      *   allowed) or -1 (no global limit).  This may be changed in a future
707      *   release. ]
708      */
setGlobalAllocationLimit(int limit)709     public static int setGlobalAllocationLimit(int limit) {
710         if (limit != 0 && limit != -1)
711             throw new IllegalArgumentException("limit must be 0 or -1");
712         return VMDebug.setGlobalAllocationLimit(limit);
713     }
714 
715     /**
716      * Dump a list of all currently loaded class to the log file.
717      *
718      * @param flags See constants above.
719      */
printLoadedClasses(int flags)720     public static void printLoadedClasses(int flags) {
721         VMDebug.printLoadedClasses(flags);
722     }
723 
724     /**
725      * Get the number of loaded classes.
726      * @return the number of loaded classes.
727      */
getLoadedClassCount()728     public static int getLoadedClassCount() {
729         return VMDebug.getLoadedClassCount();
730     }
731 
732     /**
733      * Dump "hprof" data to the specified file.  This will cause a GC.
734      *
735      * @param fileName Full pathname of output file (e.g. "/sdcard/dump.hprof").
736      * @throws UnsupportedOperationException if the VM was built without
737      *         HPROF support.
738      * @throws IOException if an error occurs while opening or writing files.
739      */
dumpHprofData(String fileName)740     public static void dumpHprofData(String fileName) throws IOException {
741         VMDebug.dumpHprofData(fileName);
742     }
743 
744     /**
745      * Collect "hprof" and send it to DDMS.  This will cause a GC.
746      *
747      * @throws UnsupportedOperationException if the VM was built without
748      *         HPROF support.
749      *
750      * @hide
751      */
dumpHprofDataDdms()752     public static void dumpHprofDataDdms() {
753         VMDebug.dumpHprofDataDdms();
754     }
755 
756     /**
757      * Returns the number of sent transactions from this process.
758      * @return The number of sent transactions or -1 if it could not read t.
759      */
getBinderSentTransactions()760     public static native int getBinderSentTransactions();
761 
762     /**
763      * Returns the number of received transactions from the binder driver.
764      * @return The number of received transactions or -1 if it could not read the stats.
765      */
getBinderReceivedTransactions()766     public static native int getBinderReceivedTransactions();
767 
768     /**
769      * Returns the number of active local Binder objects that exist in the
770      * current process.
771      */
getBinderLocalObjectCount()772     public static final native int getBinderLocalObjectCount();
773 
774     /**
775      * Returns the number of references to remote proxy Binder objects that
776      * exist in the current process.
777      */
getBinderProxyObjectCount()778     public static final native int getBinderProxyObjectCount();
779 
780     /**
781      * Returns the number of death notification links to Binder objects that
782      * exist in the current process.
783      */
getBinderDeathObjectCount()784     public static final native int getBinderDeathObjectCount();
785 
786     /**
787      * Primes the register map cache.
788      *
789      * Only works for classes in the bootstrap class loader.  Does not
790      * cause classes to be loaded if they're not already present.
791      *
792      * The classAndMethodDesc argument is a concatentation of the VM-internal
793      * class descriptor, method name, and method descriptor.  Examples:
794      *     Landroid/os/Looper;.loop:()V
795      *     Landroid/app/ActivityThread;.main:([Ljava/lang/String;)V
796      *
797      * @param classAndMethodDesc the method to prepare
798      *
799      * @hide
800      */
cacheRegisterMap(String classAndMethodDesc)801     public static final boolean cacheRegisterMap(String classAndMethodDesc) {
802         return VMDebug.cacheRegisterMap(classAndMethodDesc);
803     }
804 
805     /**
806      * Dumps the contents of VM reference tables (e.g. JNI locals and
807      * globals) to the log file.
808      *
809      * @hide
810      */
dumpReferenceTables()811     public static final void dumpReferenceTables() {
812         VMDebug.dumpReferenceTables();
813     }
814 
815     /**
816      * API for gathering and querying instruction counts.
817      *
818      * Example usage:
819      *   Debug.InstructionCount icount = new Debug.InstructionCount();
820      *   icount.resetAndStart();
821      *    [... do lots of stuff ...]
822      *   if (icount.collect()) {
823      *       System.out.println("Total instructions executed: "
824      *           + icount.globalTotal());
825      *       System.out.println("Method invocations: "
826      *           + icount.globalMethodInvocations());
827      *   }
828      */
829     public static class InstructionCount {
830         private static final int NUM_INSTR = 256;
831 
832         private int[] mCounts;
833 
InstructionCount()834         public InstructionCount() {
835             mCounts = new int[NUM_INSTR];
836         }
837 
838         /**
839          * Reset counters and ensure counts are running.  Counts may
840          * have already been running.
841          *
842          * @return true if counting was started
843          */
resetAndStart()844         public boolean resetAndStart() {
845             try {
846                 VMDebug.startInstructionCounting();
847                 VMDebug.resetInstructionCount();
848             } catch (UnsupportedOperationException uoe) {
849                 return false;
850             }
851             return true;
852         }
853 
854         /**
855          * Collect instruction counts.  May or may not stop the
856          * counting process.
857          */
collect()858         public boolean collect() {
859             try {
860                 VMDebug.stopInstructionCounting();
861                 VMDebug.getInstructionCount(mCounts);
862             } catch (UnsupportedOperationException uoe) {
863                 return false;
864             }
865             return true;
866         }
867 
868         /**
869          * Return the total number of instructions executed globally (i.e. in
870          * all threads).
871          */
globalTotal()872         public int globalTotal() {
873             int count = 0;
874             for (int i = 0; i < NUM_INSTR; i++)
875                 count += mCounts[i];
876             return count;
877         }
878 
879         /**
880          * Return the total number of method-invocation instructions
881          * executed globally.
882          */
globalMethodInvocations()883         public int globalMethodInvocations() {
884             int count = 0;
885 
886             //count += mCounts[Opcodes.OP_EXECUTE_INLINE];
887             count += mCounts[Opcodes.OP_INVOKE_VIRTUAL];
888             count += mCounts[Opcodes.OP_INVOKE_SUPER];
889             count += mCounts[Opcodes.OP_INVOKE_DIRECT];
890             count += mCounts[Opcodes.OP_INVOKE_STATIC];
891             count += mCounts[Opcodes.OP_INVOKE_INTERFACE];
892             count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_RANGE];
893             count += mCounts[Opcodes.OP_INVOKE_SUPER_RANGE];
894             count += mCounts[Opcodes.OP_INVOKE_DIRECT_RANGE];
895             count += mCounts[Opcodes.OP_INVOKE_STATIC_RANGE];
896             count += mCounts[Opcodes.OP_INVOKE_INTERFACE_RANGE];
897             //count += mCounts[Opcodes.OP_INVOKE_DIRECT_EMPTY];
898             count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK];
899             count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK_RANGE];
900             count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK];
901             count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK_RANGE];
902             return count;
903         }
904     }
905 
906 
907     /**
908      * A Map of typed debug properties.
909      */
910     private static final TypedProperties debugProperties;
911 
912     /*
913      * Load the debug properties from the standard files into debugProperties.
914      */
915     static {
916         if (Config.DEBUG) {
917             final String TAG = "DebugProperties";
918             final String[] files = { "/system/debug.prop", "/debug.prop", "/data/debug.prop" };
919             final TypedProperties tp = new TypedProperties();
920 
921             // Read the properties from each of the files, if present.
922             for (String file : files) {
923                 Reader r;
924                 try {
925                     r = new FileReader(file);
926                 } catch (FileNotFoundException ex) {
927                     // It's ok if a file is missing.
928                     continue;
929                 }
930 
931                 try {
932                     tp.load(r);
933                 } catch (Exception ex) {
934                     throw new RuntimeException("Problem loading " + file, ex);
935                 } finally {
936                     try {
r.close()937                         r.close();
938                     } catch (IOException ex) {
939                         // Ignore this error.
940                     }
941                 }
942             }
943 
944             debugProperties = tp.isEmpty() ? null : tp;
945         } else {
946             debugProperties = null;
947         }
948     }
949 
950 
951     /**
952      * Returns true if the type of the field matches the specified class.
953      * Handles the case where the class is, e.g., java.lang.Boolean, but
954      * the field is of the primitive "boolean" type.  Also handles all of
955      * the java.lang.Number subclasses.
956      */
fieldTypeMatches(Field field, Class<?> cl)957     private static boolean fieldTypeMatches(Field field, Class<?> cl) {
958         Class<?> fieldClass = field.getType();
959         if (fieldClass == cl) {
960             return true;
961         }
962         Field primitiveTypeField;
963         try {
964             /* All of the classes we care about (Boolean, Integer, etc.)
965              * have a Class field called "TYPE" that points to the corresponding
966              * primitive class.
967              */
968             primitiveTypeField = cl.getField("TYPE");
969         } catch (NoSuchFieldException ex) {
970             return false;
971         }
972         try {
973             return fieldClass == (Class<?>) primitiveTypeField.get(null);
974         } catch (IllegalAccessException ex) {
975             return false;
976         }
977     }
978 
979 
980     /**
981      * Looks up the property that corresponds to the field, and sets the field's value
982      * if the types match.
983      */
modifyFieldIfSet(final Field field, final TypedProperties properties, final String propertyName)984     private static void modifyFieldIfSet(final Field field, final TypedProperties properties,
985                                          final String propertyName) {
986         if (field.getType() == java.lang.String.class) {
987             int stringInfo = properties.getStringInfo(propertyName);
988             switch (stringInfo) {
989                 case TypedProperties.STRING_SET:
990                     // Handle as usual below.
991                     break;
992                 case TypedProperties.STRING_NULL:
993                     try {
994                         field.set(null, null);  // null object for static fields; null string
995                     } catch (IllegalAccessException ex) {
996                         throw new IllegalArgumentException(
997                             "Cannot set field for " + propertyName, ex);
998                     }
999                     return;
1000                 case TypedProperties.STRING_NOT_SET:
1001                     return;
1002                 case TypedProperties.STRING_TYPE_MISMATCH:
1003                     throw new IllegalArgumentException(
1004                         "Type of " + propertyName + " " +
1005                         " does not match field type (" + field.getType() + ")");
1006                 default:
1007                     throw new IllegalStateException(
1008                         "Unexpected getStringInfo(" + propertyName + ") return value " +
1009                         stringInfo);
1010             }
1011         }
1012         Object value = properties.get(propertyName);
1013         if (value != null) {
1014             if (!fieldTypeMatches(field, value.getClass())) {
1015                 throw new IllegalArgumentException(
1016                     "Type of " + propertyName + " (" + value.getClass() + ") " +
1017                     " does not match field type (" + field.getType() + ")");
1018             }
1019             try {
1020                 field.set(null, value);  // null object for static fields
1021             } catch (IllegalAccessException ex) {
1022                 throw new IllegalArgumentException(
1023                     "Cannot set field for " + propertyName, ex);
1024             }
1025         }
1026     }
1027 
1028 
1029     /**
1030      * Equivalent to <code>setFieldsOn(cl, false)</code>.
1031      *
1032      * @see #setFieldsOn(Class, boolean)
1033      *
1034      * @hide
1035      */
setFieldsOn(Class<?> cl)1036     public static void setFieldsOn(Class<?> cl) {
1037         setFieldsOn(cl, false);
1038     }
1039 
1040     /**
1041      * Reflectively sets static fields of a class based on internal debugging
1042      * properties.  This method is a no-op if android.util.Config.DEBUG is
1043      * false.
1044      * <p>
1045      * <strong>NOTE TO APPLICATION DEVELOPERS</strong>: Config.DEBUG will
1046      * always be false in release builds.  This API is typically only useful
1047      * for platform developers.
1048      * </p>
1049      * Class setup: define a class whose only fields are non-final, static
1050      * primitive types (except for "char") or Strings.  In a static block
1051      * after the field definitions/initializations, pass the class to
1052      * this method, Debug.setFieldsOn(). Example:
1053      * <pre>
1054      * package com.example;
1055      *
1056      * import android.os.Debug;
1057      *
1058      * public class MyDebugVars {
1059      *    public static String s = "a string";
1060      *    public static String s2 = "second string";
1061      *    public static String ns = null;
1062      *    public static boolean b = false;
1063      *    public static int i = 5;
1064      *    @Debug.DebugProperty
1065      *    public static float f = 0.1f;
1066      *    @@Debug.DebugProperty
1067      *    public static double d = 0.5d;
1068      *
1069      *    // This MUST appear AFTER all fields are defined and initialized!
1070      *    static {
1071      *        // Sets all the fields
1072      *        Debug.setFieldsOn(MyDebugVars.class);
1073      *
1074      *        // Sets only the fields annotated with @Debug.DebugProperty
1075      *        // Debug.setFieldsOn(MyDebugVars.class, true);
1076      *    }
1077      * }
1078      * </pre>
1079      * setFieldsOn() may override the value of any field in the class based
1080      * on internal properties that are fixed at boot time.
1081      * <p>
1082      * These properties are only set during platform debugging, and are not
1083      * meant to be used as a general-purpose properties store.
1084      *
1085      * {@hide}
1086      *
1087      * @param cl The class to (possibly) modify
1088      * @param partial If false, sets all static fields, otherwise, only set
1089      *        fields with the {@link android.os.Debug.DebugProperty}
1090      *        annotation
1091      * @throws IllegalArgumentException if any fields are final or non-static,
1092      *         or if the type of the field does not match the type of
1093      *         the internal debugging property value.
1094      */
setFieldsOn(Class<?> cl, boolean partial)1095     public static void setFieldsOn(Class<?> cl, boolean partial) {
1096         if (Config.DEBUG) {
1097             if (debugProperties != null) {
1098                 /* Only look for fields declared directly by the class,
1099                  * so we don't mysteriously change static fields in superclasses.
1100                  */
1101                 for (Field field : cl.getDeclaredFields()) {
1102                     if (!partial || field.getAnnotation(DebugProperty.class) != null) {
1103                         final String propertyName = cl.getName() + "." + field.getName();
1104                         boolean isStatic = Modifier.isStatic(field.getModifiers());
1105                         boolean isFinal = Modifier.isFinal(field.getModifiers());
1106 
1107                         if (!isStatic || isFinal) {
1108                             throw new IllegalArgumentException(propertyName +
1109                                 " must be static and non-final");
1110                         }
1111                         modifyFieldIfSet(field, debugProperties, propertyName);
1112                     }
1113                 }
1114             }
1115         } else {
1116             Log.wtf(TAG,
1117                   "setFieldsOn(" + (cl == null ? "null" : cl.getName()) +
1118                   ") called in non-DEBUG build");
1119         }
1120     }
1121 
1122     /**
1123      * Annotation to put on fields you want to set with
1124      * {@link Debug#setFieldsOn(Class, boolean)}.
1125      *
1126      * @hide
1127      */
1128     @Target({ ElementType.FIELD })
1129     @Retention(RetentionPolicy.RUNTIME)
1130     public @interface DebugProperty {
1131     }
1132 
1133     /**
1134      * Get a debugging dump of a system service by name.
1135      *
1136      * <p>Most services require the caller to hold android.permission.DUMP.
1137      *
1138      * @param name of the service to dump
1139      * @param fd to write dump output to (usually an output log file)
1140      * @param args to pass to the service's dump method, may be null
1141      * @return true if the service was dumped successfully, false if
1142      *     the service could not be found or had an error while dumping
1143      */
dumpService(String name, FileDescriptor fd, String[] args)1144     public static boolean dumpService(String name, FileDescriptor fd, String[] args) {
1145         IBinder service = ServiceManager.getService(name);
1146         if (service == null) {
1147             Log.e(TAG, "Can't find service to dump: " + name);
1148             return false;
1149         }
1150 
1151         try {
1152             service.dump(fd, args);
1153             return true;
1154         } catch (RemoteException e) {
1155             Log.e(TAG, "Can't dump service: " + name, e);
1156             return false;
1157         }
1158     }
1159 }
1160