• 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.Log;
22 
23 import java.io.FileDescriptor;
24 import java.io.FileNotFoundException;
25 import java.io.FileOutputStream;
26 import java.io.FileReader;
27 import java.io.IOException;
28 import java.io.OutputStreamWriter;
29 import java.io.PrintWriter;
30 import java.io.Reader;
31 import java.lang.reflect.Field;
32 import java.lang.reflect.Modifier;
33 import java.lang.annotation.Target;
34 import java.lang.annotation.ElementType;
35 import java.lang.annotation.Retention;
36 import java.lang.annotation.RetentionPolicy;
37 
38 import org.apache.harmony.dalvik.ddmc.Chunk;
39 import org.apache.harmony.dalvik.ddmc.ChunkHandler;
40 import org.apache.harmony.dalvik.ddmc.DdmServer;
41 
42 import dalvik.bytecode.OpcodeInfo;
43 import dalvik.bytecode.Opcodes;
44 import dalvik.system.VMDebug;
45 
46 
47 /**
48  * Provides various debugging methods 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 =
98         Environment.getLegacyExternalStorageDirectory().getPath() + "/";
99     private static final String DEFAULT_TRACE_BODY = "dmtrace";
100     private static final String DEFAULT_TRACE_EXTENSION = ".trace";
101     private static final String DEFAULT_TRACE_FILE_PATH =
102         DEFAULT_TRACE_PATH_PREFIX + DEFAULT_TRACE_BODY
103         + DEFAULT_TRACE_EXTENSION;
104 
105 
106     /**
107      * This class is used to retrieved various statistics about the memory mappings for this
108      * process. The returns info broken down by dalvik, native, and other. All results are in kB.
109      */
110     public static class MemoryInfo implements Parcelable {
111         /** The proportional set size for dalvik. */
112         public int dalvikPss;
113         /** The private dirty pages used by dalvik. */
114         public int dalvikPrivateDirty;
115         /** The shared dirty pages used by dalvik. */
116         public int dalvikSharedDirty;
117 
118         /** The proportional set size for the native heap. */
119         public int nativePss;
120         /** The private dirty pages used by the native heap. */
121         public int nativePrivateDirty;
122         /** The shared dirty pages used by the native heap. */
123         public int nativeSharedDirty;
124 
125         /** The proportional set size for everything else. */
126         public int otherPss;
127         /** The private dirty pages used by everything else. */
128         public int otherPrivateDirty;
129         /** The shared dirty pages used by everything else. */
130         public int otherSharedDirty;
131 
132         /** @hide */
133         public static final int NUM_OTHER_STATS = 10;
134 
135         private int[] otherStats = new int[NUM_OTHER_STATS*3];
136 
MemoryInfo()137         public MemoryInfo() {
138         }
139 
140         /**
141          * Return total PSS memory usage in kB.
142          */
getTotalPss()143         public int getTotalPss() {
144             return dalvikPss + nativePss + otherPss;
145         }
146 
147         /**
148          * Return total private dirty memory usage in kB.
149          */
getTotalPrivateDirty()150         public int getTotalPrivateDirty() {
151             return dalvikPrivateDirty + nativePrivateDirty + otherPrivateDirty;
152         }
153 
154         /**
155          * Return total shared dirty memory usage in kB.
156          */
getTotalSharedDirty()157         public int getTotalSharedDirty() {
158             return dalvikSharedDirty + nativeSharedDirty + otherSharedDirty;
159         }
160 
161         /* @hide */
getOtherPss(int which)162         public int getOtherPss(int which) {
163             return otherStats[which*3];
164         }
165 
166         /* @hide */
getOtherPrivateDirty(int which)167         public int getOtherPrivateDirty(int which) {
168             return otherStats[which*3 + 1];
169         }
170 
171         /* @hide */
getOtherSharedDirty(int which)172         public int getOtherSharedDirty(int which) {
173             return otherStats[which*3 + 2];
174         }
175 
176 
177         /* @hide */
getOtherLabel(int which)178         public static String getOtherLabel(int which) {
179             switch (which) {
180                 case 0: return "Stack";
181                 case 1: return "Cursor";
182                 case 2: return "Ashmem";
183                 case 3: return "Other dev";
184                 case 4: return ".so mmap";
185                 case 5: return ".jar mmap";
186                 case 6: return ".apk mmap";
187                 case 7: return ".ttf mmap";
188                 case 8: return ".dex mmap";
189                 case 9: return "Other mmap";
190                 default: return "????";
191             }
192         }
193 
describeContents()194         public int describeContents() {
195             return 0;
196         }
197 
writeToParcel(Parcel dest, int flags)198         public void writeToParcel(Parcel dest, int flags) {
199             dest.writeInt(dalvikPss);
200             dest.writeInt(dalvikPrivateDirty);
201             dest.writeInt(dalvikSharedDirty);
202             dest.writeInt(nativePss);
203             dest.writeInt(nativePrivateDirty);
204             dest.writeInt(nativeSharedDirty);
205             dest.writeInt(otherPss);
206             dest.writeInt(otherPrivateDirty);
207             dest.writeInt(otherSharedDirty);
208             dest.writeIntArray(otherStats);
209         }
210 
readFromParcel(Parcel source)211         public void readFromParcel(Parcel source) {
212             dalvikPss = source.readInt();
213             dalvikPrivateDirty = source.readInt();
214             dalvikSharedDirty = source.readInt();
215             nativePss = source.readInt();
216             nativePrivateDirty = source.readInt();
217             nativeSharedDirty = source.readInt();
218             otherPss = source.readInt();
219             otherPrivateDirty = source.readInt();
220             otherSharedDirty = source.readInt();
221             otherStats = source.createIntArray();
222         }
223 
224         public static final Creator<MemoryInfo> CREATOR = new Creator<MemoryInfo>() {
225             public MemoryInfo createFromParcel(Parcel source) {
226                 return new MemoryInfo(source);
227             }
228             public MemoryInfo[] newArray(int size) {
229                 return new MemoryInfo[size];
230             }
231         };
232 
MemoryInfo(Parcel source)233         private MemoryInfo(Parcel source) {
234             readFromParcel(source);
235         }
236     }
237 
238 
239     /**
240      * Wait until a debugger attaches.  As soon as the debugger attaches,
241      * this returns, so you will need to place a breakpoint after the
242      * waitForDebugger() call if you want to start tracing immediately.
243      */
waitForDebugger()244     public static void waitForDebugger() {
245         if (!VMDebug.isDebuggingEnabled()) {
246             //System.out.println("debugging not enabled, not waiting");
247             return;
248         }
249         if (isDebuggerConnected())
250             return;
251 
252         // if DDMS is listening, inform them of our plight
253         System.out.println("Sending WAIT chunk");
254         byte[] data = new byte[] { 0 };     // 0 == "waiting for debugger"
255         Chunk waitChunk = new Chunk(ChunkHandler.type("WAIT"), data, 0, 1);
256         DdmServer.sendChunk(waitChunk);
257 
258         mWaiting = true;
259         while (!isDebuggerConnected()) {
260             try { Thread.sleep(SPIN_DELAY); }
261             catch (InterruptedException ie) {}
262         }
263         mWaiting = false;
264 
265         System.out.println("Debugger has connected");
266 
267         /*
268          * There is no "ready to go" signal from the debugger, and we're
269          * not allowed to suspend ourselves -- the debugger expects us to
270          * be running happily, and gets confused if we aren't.  We need to
271          * allow the debugger a chance to set breakpoints before we start
272          * running again.
273          *
274          * Sit and spin until the debugger has been idle for a short while.
275          */
276         while (true) {
277             long delta = VMDebug.lastDebuggerActivity();
278             if (delta < 0) {
279                 System.out.println("debugger detached?");
280                 break;
281             }
282 
283             if (delta < MIN_DEBUGGER_IDLE) {
284                 System.out.println("waiting for debugger to settle...");
285                 try { Thread.sleep(SPIN_DELAY); }
286                 catch (InterruptedException ie) {}
287             } else {
288                 System.out.println("debugger has settled (" + delta + ")");
289                 break;
290             }
291         }
292     }
293 
294     /**
295      * Returns "true" if one or more threads is waiting for a debugger
296      * to attach.
297      */
waitingForDebugger()298     public static boolean waitingForDebugger() {
299         return mWaiting;
300     }
301 
302     /**
303      * Determine if a debugger is currently attached.
304      */
isDebuggerConnected()305     public static boolean isDebuggerConnected() {
306         return VMDebug.isDebuggerConnected();
307     }
308 
309     /**
310      * Returns an array of strings that identify VM features.  This is
311      * used by DDMS to determine what sorts of operations the VM can
312      * perform.
313      *
314      * @hide
315      */
getVmFeatureList()316     public static String[] getVmFeatureList() {
317         return VMDebug.getVmFeatureList();
318     }
319 
320     /**
321      * Change the JDWP port.
322      *
323      * @deprecated no longer needed or useful
324      */
325     @Deprecated
changeDebugPort(int port)326     public static void changeDebugPort(int port) {}
327 
328     /**
329      * This is the pathname to the sysfs file that enables and disables
330      * tracing on the qemu emulator.
331      */
332     private static final String SYSFS_QEMU_TRACE_STATE = "/sys/qemu_trace/state";
333 
334     /**
335      * Enable qemu tracing. For this to work requires running everything inside
336      * the qemu emulator; otherwise, this method will have no effect. The trace
337      * file is specified on the command line when the emulator is started. For
338      * example, the following command line <br />
339      * <code>emulator -trace foo</code><br />
340      * will start running the emulator and create a trace file named "foo". This
341      * method simply enables writing the trace records to the trace file.
342      *
343      * <p>
344      * The main differences between this and {@link #startMethodTracing()} are
345      * that tracing in the qemu emulator traces every cpu instruction of every
346      * process, including kernel code, so we have more complete information,
347      * including all context switches. We can also get more detailed information
348      * such as cache misses. The sequence of calls is determined by
349      * post-processing the instruction trace. The qemu tracing is also done
350      * without modifying the application or perturbing the timing of calls
351      * because no instrumentation is added to the application being traced.
352      * </p>
353      *
354      * <p>
355      * One limitation of using this method compared to using
356      * {@link #startMethodTracing()} on the real device is that the emulator
357      * does not model all of the real hardware effects such as memory and
358      * bus contention.  The emulator also has a simple cache model and cannot
359      * capture all the complexities of a real cache.
360      * </p>
361      */
startNativeTracing()362     public static void startNativeTracing() {
363         // Open the sysfs file for writing and write "1" to it.
364         PrintWriter outStream = null;
365         try {
366             FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE);
367             outStream = new PrintWriter(new OutputStreamWriter(fos));
368             outStream.println("1");
369         } catch (Exception e) {
370         } finally {
371             if (outStream != null)
372                 outStream.close();
373         }
374 
375         VMDebug.startEmulatorTracing();
376     }
377 
378     /**
379      * Stop qemu tracing.  See {@link #startNativeTracing()} to start tracing.
380      *
381      * <p>Tracing can be started and stopped as many times as desired.  When
382      * the qemu emulator itself is stopped then the buffered trace records
383      * are flushed and written to the trace file.  In fact, it is not necessary
384      * to call this method at all; simply killing qemu is sufficient.  But
385      * starting and stopping a trace is useful for examining a specific
386      * region of code.</p>
387      */
stopNativeTracing()388     public static void stopNativeTracing() {
389         VMDebug.stopEmulatorTracing();
390 
391         // Open the sysfs file for writing and write "0" to it.
392         PrintWriter outStream = null;
393         try {
394             FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE);
395             outStream = new PrintWriter(new OutputStreamWriter(fos));
396             outStream.println("0");
397         } catch (Exception e) {
398             // We could print an error message here but we probably want
399             // to quietly ignore errors if we are not running in the emulator.
400         } finally {
401             if (outStream != null)
402                 outStream.close();
403         }
404     }
405 
406     /**
407      * Enable "emulator traces", in which information about the current
408      * method is made available to the "emulator -trace" feature.  There
409      * is no corresponding "disable" call -- this is intended for use by
410      * the framework when tracing should be turned on and left that way, so
411      * that traces captured with F9/F10 will include the necessary data.
412      *
413      * This puts the VM into "profile" mode, which has performance
414      * consequences.
415      *
416      * To temporarily enable tracing, use {@link #startNativeTracing()}.
417      */
enableEmulatorTraceOutput()418     public static void enableEmulatorTraceOutput() {
419         VMDebug.startEmulatorTracing();
420     }
421 
422     /**
423      * Start method tracing with default log name and buffer size. See <a
424 href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
425      * information about reading these files. Call stopMethodTracing() to stop
426      * tracing.
427      */
startMethodTracing()428     public static void startMethodTracing() {
429         VMDebug.startMethodTracing(DEFAULT_TRACE_FILE_PATH, 0, 0);
430     }
431 
432     /**
433      * Start method tracing, specifying the trace log file name.  The trace
434      * file will be put under "/sdcard" unless an absolute path is given.
435      * See <a
436        href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
437      * information about reading trace files.
438      *
439      * @param traceName Name for the trace log file to create.
440      * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
441      * If the files already exist, they will be truncated.
442      * If the trace file given does not end in ".trace", it will be appended for you.
443      */
startMethodTracing(String traceName)444     public static void startMethodTracing(String traceName) {
445         startMethodTracing(traceName, 0, 0);
446     }
447 
448     /**
449      * Start method tracing, specifying the trace log file name and the
450      * buffer size. The trace files will be put under "/sdcard" unless an
451      * absolute path is given. See <a
452        href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
453      * information about reading trace files.
454      * @param traceName    Name for the trace log file to create.
455      * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
456      * If the files already exist, they will be truncated.
457      * If the trace file given does not end in ".trace", it will be appended for you.
458      *
459      * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
460      */
startMethodTracing(String traceName, int bufferSize)461     public static void startMethodTracing(String traceName, int bufferSize) {
462         startMethodTracing(traceName, bufferSize, 0);
463     }
464 
465     /**
466      * Start method tracing, specifying the trace log file name and the
467      * buffer size. The trace files will be put under "/sdcard" unless an
468      * absolute path is given. See <a
469        href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
470      * information about reading trace files.
471      *
472      * <p>
473      * When method tracing is enabled, the VM will run more slowly than
474      * usual, so the timings from the trace files should only be considered
475      * in relative terms (e.g. was run #1 faster than run #2).  The times
476      * for native methods will not change, so don't try to use this to
477      * compare the performance of interpreted and native implementations of the
478      * same method.  As an alternative, consider using "native" tracing
479      * in the emulator via {@link #startNativeTracing()}.
480      * </p>
481      *
482      * @param traceName    Name for the trace log file to create.
483      * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
484      * If the files already exist, they will be truncated.
485      * If the trace file given does not end in ".trace", it will be appended for you.
486      * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
487      */
startMethodTracing(String traceName, int bufferSize, int flags)488     public static void startMethodTracing(String traceName, int bufferSize,
489         int flags) {
490 
491         String pathName = traceName;
492         if (pathName.charAt(0) != '/')
493             pathName = DEFAULT_TRACE_PATH_PREFIX + pathName;
494         if (!pathName.endsWith(DEFAULT_TRACE_EXTENSION))
495             pathName = pathName + DEFAULT_TRACE_EXTENSION;
496 
497         VMDebug.startMethodTracing(pathName, bufferSize, flags);
498     }
499 
500     /**
501      * Like startMethodTracing(String, int, int), but taking an already-opened
502      * FileDescriptor in which the trace is written.  The file name is also
503      * supplied simply for logging.  Makes a dup of the file descriptor.
504      *
505      * Not exposed in the SDK unless we are really comfortable with supporting
506      * this and find it would be useful.
507      * @hide
508      */
startMethodTracing(String traceName, FileDescriptor fd, int bufferSize, int flags)509     public static void startMethodTracing(String traceName, FileDescriptor fd,
510         int bufferSize, int flags) {
511         VMDebug.startMethodTracing(traceName, fd, bufferSize, flags);
512     }
513 
514     /**
515      * Starts method tracing without a backing file.  When stopMethodTracing
516      * is called, the result is sent directly to DDMS.  (If DDMS is not
517      * attached when tracing ends, the profiling data will be discarded.)
518      *
519      * @hide
520      */
startMethodTracingDdms(int bufferSize, int flags)521     public static void startMethodTracingDdms(int bufferSize, int flags) {
522         VMDebug.startMethodTracingDdms(bufferSize, flags);
523     }
524 
525     /**
526      * Determine whether method tracing is currently active.
527      * @hide
528      */
isMethodTracingActive()529     public static boolean isMethodTracingActive() {
530         return VMDebug.isMethodTracingActive();
531     }
532 
533     /**
534      * Stop method tracing.
535      */
stopMethodTracing()536     public static void stopMethodTracing() {
537         VMDebug.stopMethodTracing();
538     }
539 
540     /**
541      * Get an indication of thread CPU usage.  The value returned
542      * indicates the amount of time that the current thread has spent
543      * executing code or waiting for certain types of I/O.
544      *
545      * The time is expressed in nanoseconds, and is only meaningful
546      * when compared to the result from an earlier call.  Note that
547      * nanosecond resolution does not imply nanosecond accuracy.
548      *
549      * On system which don't support this operation, the call returns -1.
550      */
threadCpuTimeNanos()551     public static long threadCpuTimeNanos() {
552         return VMDebug.threadCpuTimeNanos();
553     }
554 
555     /**
556      * Start counting the number and aggregate size of memory allocations.
557      *
558      * <p>The {@link #startAllocCounting() start} method resets the counts and enables counting.
559      * The {@link #stopAllocCounting() stop} method disables the counting so that the analysis
560      * code doesn't cause additional allocations.  The various <code>get</code> methods return
561      * the specified value. And the various <code>reset</code> methods reset the specified
562      * count.</p>
563      *
564      * <p>Counts are kept for the system as a whole (global) and for each thread.
565      * The per-thread counts for threads other than the current thread
566      * are not cleared by the "reset" or "start" calls.</p>
567      *
568      * @deprecated Accurate counting is a burden on the runtime and may be removed.
569      */
570     @Deprecated
startAllocCounting()571     public static void startAllocCounting() {
572         VMDebug.startAllocCounting();
573     }
574 
575     /**
576      * Stop counting the number and aggregate size of memory allocations.
577      *
578      * @see #startAllocCounting()
579      */
580     @Deprecated
stopAllocCounting()581     public static void stopAllocCounting() {
582         VMDebug.stopAllocCounting();
583     }
584 
585     /**
586      * Returns the global count of objects allocated by the runtime between a
587      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
588      */
getGlobalAllocCount()589     public static int getGlobalAllocCount() {
590         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
591     }
592 
593     /**
594      * Clears the global count of objects allocated.
595      * @see #getGlobalAllocCount()
596      */
resetGlobalAllocCount()597     public static void resetGlobalAllocCount() {
598         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
599     }
600 
601     /**
602      * Returns the global size, in bytes, of objects allocated by the runtime between a
603      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
604      */
getGlobalAllocSize()605     public static int getGlobalAllocSize() {
606         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
607     }
608 
609     /**
610      * Clears the global size of objects allocated.
611      * @see #getGlobalAllocCountSize()
612      */
resetGlobalAllocSize()613     public static void resetGlobalAllocSize() {
614         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
615     }
616 
617     /**
618      * Returns the global count of objects freed by the runtime between a
619      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
620      */
getGlobalFreedCount()621     public static int getGlobalFreedCount() {
622         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
623     }
624 
625     /**
626      * Clears the global count of objects freed.
627      * @see #getGlobalFreedCount()
628      */
resetGlobalFreedCount()629     public static void resetGlobalFreedCount() {
630         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
631     }
632 
633     /**
634      * Returns the global size, in bytes, of objects freed by the runtime between a
635      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
636      */
getGlobalFreedSize()637     public static int getGlobalFreedSize() {
638         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
639     }
640 
641     /**
642      * Clears the global size of objects freed.
643      * @see #getGlobalFreedSize()
644      */
resetGlobalFreedSize()645     public static void resetGlobalFreedSize() {
646         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
647     }
648 
649     /**
650      * Returns the number of non-concurrent GC invocations between a
651      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
652      */
getGlobalGcInvocationCount()653     public static int getGlobalGcInvocationCount() {
654         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
655     }
656 
657     /**
658      * Clears the count of non-concurrent GC invocations.
659      * @see #getGlobalGcInvocationCount()
660      */
resetGlobalGcInvocationCount()661     public static void resetGlobalGcInvocationCount() {
662         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
663     }
664 
665     /**
666      * Returns the number of classes successfully initialized (ie those that executed without
667      * throwing an exception) between a {@link #startAllocCounting() start} and
668      * {@link #stopAllocCounting() stop}.
669      */
getGlobalClassInitCount()670     public static int getGlobalClassInitCount() {
671         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT);
672     }
673 
674     /**
675      * Clears the count of classes initialized.
676      * @see #getGlobalClassInitCount()
677      */
resetGlobalClassInitCount()678     public static void resetGlobalClassInitCount() {
679         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT);
680     }
681 
682     /**
683      * Returns the time spent successfully initializing classes between a
684      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
685      */
getGlobalClassInitTime()686     public static int getGlobalClassInitTime() {
687         /* cumulative elapsed time for class initialization, in usec */
688         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME);
689     }
690 
691     /**
692      * Clears the count of time spent initializing classes.
693      * @see #getGlobalClassInitTime()
694      */
resetGlobalClassInitTime()695     public static void resetGlobalClassInitTime() {
696         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME);
697     }
698 
699     /**
700      * This method exists for compatibility and always returns 0.
701      * @deprecated This method is now obsolete.
702      */
703     @Deprecated
getGlobalExternalAllocCount()704     public static int getGlobalExternalAllocCount() {
705         return 0;
706     }
707 
708     /**
709      * This method exists for compatibility and has no effect.
710      * @deprecated This method is now obsolete.
711      */
712     @Deprecated
resetGlobalExternalAllocSize()713     public static void resetGlobalExternalAllocSize() {}
714 
715     /**
716      * This method exists for compatibility and has no effect.
717      * @deprecated This method is now obsolete.
718      */
719     @Deprecated
resetGlobalExternalAllocCount()720     public static void resetGlobalExternalAllocCount() {}
721 
722     /**
723      * This method exists for compatibility and always returns 0.
724      * @deprecated This method is now obsolete.
725      */
726     @Deprecated
getGlobalExternalAllocSize()727     public static int getGlobalExternalAllocSize() {
728         return 0;
729     }
730 
731     /**
732      * This method exists for compatibility and always returns 0.
733      * @deprecated This method is now obsolete.
734      */
735     @Deprecated
getGlobalExternalFreedCount()736     public static int getGlobalExternalFreedCount() {
737         return 0;
738     }
739 
740     /**
741      * This method exists for compatibility and has no effect.
742      * @deprecated This method is now obsolete.
743      */
744     @Deprecated
resetGlobalExternalFreedCount()745     public static void resetGlobalExternalFreedCount() {}
746 
747     /**
748      * This method exists for compatibility and has no effect.
749      * @deprecated This method is now obsolete.
750      */
751     @Deprecated
getGlobalExternalFreedSize()752     public static int getGlobalExternalFreedSize() {
753         return 0;
754     }
755 
756     /**
757      * This method exists for compatibility and has no effect.
758      * @deprecated This method is now obsolete.
759      */
760     @Deprecated
resetGlobalExternalFreedSize()761     public static void resetGlobalExternalFreedSize() {}
762 
763     /**
764      * Returns the thread-local count of objects allocated by the runtime between a
765      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
766      */
getThreadAllocCount()767     public static int getThreadAllocCount() {
768         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
769     }
770 
771     /**
772      * Clears the thread-local count of objects allocated.
773      * @see #getThreadAllocCount()
774      */
resetThreadAllocCount()775     public static void resetThreadAllocCount() {
776         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
777     }
778 
779     /**
780      * Returns the thread-local size of objects allocated by the runtime between a
781      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
782      * @return The allocated size in bytes.
783      */
getThreadAllocSize()784     public static int getThreadAllocSize() {
785         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
786     }
787 
788     /**
789      * Clears the thread-local count of objects allocated.
790      * @see #getThreadAllocSize()
791      */
resetThreadAllocSize()792     public static void resetThreadAllocSize() {
793         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
794     }
795 
796     /**
797      * This method exists for compatibility and has no effect.
798      * @deprecated This method is now obsolete.
799      */
800     @Deprecated
getThreadExternalAllocCount()801     public static int getThreadExternalAllocCount() {
802         return 0;
803     }
804 
805     /**
806      * This method exists for compatibility and has no effect.
807      * @deprecated This method is now obsolete.
808      */
809     @Deprecated
resetThreadExternalAllocCount()810     public static void resetThreadExternalAllocCount() {}
811 
812     /**
813      * This method exists for compatibility and has no effect.
814      * @deprecated This method is now obsolete.
815      */
816     @Deprecated
getThreadExternalAllocSize()817     public static int getThreadExternalAllocSize() {
818         return 0;
819     }
820 
821     /**
822      * This method exists for compatibility and has no effect.
823      * @deprecated This method is now obsolete.
824      */
825     @Deprecated
resetThreadExternalAllocSize()826     public static void resetThreadExternalAllocSize() {}
827 
828     /**
829      * Returns the number of thread-local non-concurrent GC invocations between a
830      * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}.
831      */
getThreadGcInvocationCount()832     public static int getThreadGcInvocationCount() {
833         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
834     }
835 
836     /**
837      * Clears the thread-local count of non-concurrent GC invocations.
838      * @see #getThreadGcInvocationCount()
839      */
resetThreadGcInvocationCount()840     public static void resetThreadGcInvocationCount() {
841         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
842     }
843 
844     /**
845      * Clears all the global and thread-local memory allocation counters.
846      * @see #startAllocCounting()
847      */
resetAllCounts()848     public static void resetAllCounts() {
849         VMDebug.resetAllocCount(VMDebug.KIND_ALL_COUNTS);
850     }
851 
852     /**
853      * Returns the size of the native heap.
854      * @return The size of the native heap in bytes.
855      */
getNativeHeapSize()856     public static native long getNativeHeapSize();
857 
858     /**
859      * Returns the amount of allocated memory in the native heap.
860      * @return The allocated size in bytes.
861      */
getNativeHeapAllocatedSize()862     public static native long getNativeHeapAllocatedSize();
863 
864     /**
865      * Returns the amount of free memory in the native heap.
866      * @return The freed size in bytes.
867      */
getNativeHeapFreeSize()868     public static native long getNativeHeapFreeSize();
869 
870     /**
871      * Retrieves information about this processes memory usages. This information is broken down by
872      * how much is in use by dalivk, the native heap, and everything else.
873      */
getMemoryInfo(MemoryInfo memoryInfo)874     public static native void getMemoryInfo(MemoryInfo memoryInfo);
875 
876     /**
877      * Note: currently only works when the requested pid has the same UID
878      * as the caller.
879      * @hide
880      */
getMemoryInfo(int pid, MemoryInfo memoryInfo)881     public static native void getMemoryInfo(int pid, MemoryInfo memoryInfo);
882 
883     /**
884      * Retrieves the PSS memory used by the process as given by the
885      * smaps.
886      */
getPss()887     public static native long getPss();
888 
889     /**
890      * Retrieves the PSS memory used by the process as given by the
891      * smaps. @hide
892      */
getPss(int pid)893     public static native long getPss(int pid);
894 
895     /**
896      * Establish an object allocation limit in the current thread.
897      * This feature was never enabled in release builds.  The
898      * allocation limits feature was removed in Honeycomb.  This
899      * method exists for compatibility and always returns -1 and has
900      * no effect.
901      *
902      * @deprecated This method is now obsolete.
903      */
904     @Deprecated
setAllocationLimit(int limit)905     public static int setAllocationLimit(int limit) {
906         return -1;
907     }
908 
909     /**
910      * Establish a global object allocation limit.  This feature was
911      * never enabled in release builds.  The allocation limits feature
912      * was removed in Honeycomb.  This method exists for compatibility
913      * and always returns -1 and has no effect.
914      *
915      * @deprecated This method is now obsolete.
916      */
917     @Deprecated
setGlobalAllocationLimit(int limit)918     public static int setGlobalAllocationLimit(int limit) {
919         return -1;
920     }
921 
922     /**
923      * Dump a list of all currently loaded class to the log file.
924      *
925      * @param flags See constants above.
926      */
printLoadedClasses(int flags)927     public static void printLoadedClasses(int flags) {
928         VMDebug.printLoadedClasses(flags);
929     }
930 
931     /**
932      * Get the number of loaded classes.
933      * @return the number of loaded classes.
934      */
getLoadedClassCount()935     public static int getLoadedClassCount() {
936         return VMDebug.getLoadedClassCount();
937     }
938 
939     /**
940      * Dump "hprof" data to the specified file.  This may cause a GC.
941      *
942      * @param fileName Full pathname of output file (e.g. "/sdcard/dump.hprof").
943      * @throws UnsupportedOperationException if the VM was built without
944      *         HPROF support.
945      * @throws IOException if an error occurs while opening or writing files.
946      */
dumpHprofData(String fileName)947     public static void dumpHprofData(String fileName) throws IOException {
948         VMDebug.dumpHprofData(fileName);
949     }
950 
951     /**
952      * Like dumpHprofData(String), but takes an already-opened
953      * FileDescriptor to which the trace is written.  The file name is also
954      * supplied simply for logging.  Makes a dup of the file descriptor.
955      *
956      * Primarily for use by the "am" shell command.
957      *
958      * @hide
959      */
dumpHprofData(String fileName, FileDescriptor fd)960     public static void dumpHprofData(String fileName, FileDescriptor fd)
961             throws IOException {
962         VMDebug.dumpHprofData(fileName, fd);
963     }
964 
965     /**
966      * Collect "hprof" and send it to DDMS.  This may cause a GC.
967      *
968      * @throws UnsupportedOperationException if the VM was built without
969      *         HPROF support.
970      * @hide
971      */
dumpHprofDataDdms()972     public static void dumpHprofDataDdms() {
973         VMDebug.dumpHprofDataDdms();
974     }
975 
976     /**
977      * Writes native heap data to the specified file descriptor.
978      *
979      * @hide
980      */
dumpNativeHeap(FileDescriptor fd)981     public static native void dumpNativeHeap(FileDescriptor fd);
982 
983     /**
984       * Returns a count of the extant instances of a class.
985      *
986      * @hide
987      */
countInstancesOfClass(Class cls)988     public static long countInstancesOfClass(Class cls) {
989         return VMDebug.countInstancesOfClass(cls, true);
990     }
991 
992     /**
993      * Returns the number of sent transactions from this process.
994      * @return The number of sent transactions or -1 if it could not read t.
995      */
getBinderSentTransactions()996     public static native int getBinderSentTransactions();
997 
998     /**
999      * Returns the number of received transactions from the binder driver.
1000      * @return The number of received transactions or -1 if it could not read the stats.
1001      */
getBinderReceivedTransactions()1002     public static native int getBinderReceivedTransactions();
1003 
1004     /**
1005      * Returns the number of active local Binder objects that exist in the
1006      * current process.
1007      */
getBinderLocalObjectCount()1008     public static final native int getBinderLocalObjectCount();
1009 
1010     /**
1011      * Returns the number of references to remote proxy Binder objects that
1012      * exist in the current process.
1013      */
getBinderProxyObjectCount()1014     public static final native int getBinderProxyObjectCount();
1015 
1016     /**
1017      * Returns the number of death notification links to Binder objects that
1018      * exist in the current process.
1019      */
getBinderDeathObjectCount()1020     public static final native int getBinderDeathObjectCount();
1021 
1022     /**
1023      * Primes the register map cache.
1024      *
1025      * Only works for classes in the bootstrap class loader.  Does not
1026      * cause classes to be loaded if they're not already present.
1027      *
1028      * The classAndMethodDesc argument is a concatentation of the VM-internal
1029      * class descriptor, method name, and method descriptor.  Examples:
1030      *     Landroid/os/Looper;.loop:()V
1031      *     Landroid/app/ActivityThread;.main:([Ljava/lang/String;)V
1032      *
1033      * @param classAndMethodDesc the method to prepare
1034      *
1035      * @hide
1036      */
cacheRegisterMap(String classAndMethodDesc)1037     public static final boolean cacheRegisterMap(String classAndMethodDesc) {
1038         return VMDebug.cacheRegisterMap(classAndMethodDesc);
1039     }
1040 
1041     /**
1042      * Dumps the contents of VM reference tables (e.g. JNI locals and
1043      * globals) to the log file.
1044      *
1045      * @hide
1046      */
dumpReferenceTables()1047     public static final void dumpReferenceTables() {
1048         VMDebug.dumpReferenceTables();
1049     }
1050 
1051     /**
1052      * API for gathering and querying instruction counts.
1053      *
1054      * Example usage:
1055      * <pre>
1056      *   Debug.InstructionCount icount = new Debug.InstructionCount();
1057      *   icount.resetAndStart();
1058      *    [... do lots of stuff ...]
1059      *   if (icount.collect()) {
1060      *       System.out.println("Total instructions executed: "
1061      *           + icount.globalTotal());
1062      *       System.out.println("Method invocations: "
1063      *           + icount.globalMethodInvocations());
1064      *   }
1065      * </pre>
1066      */
1067     public static class InstructionCount {
1068         private static final int NUM_INSTR =
1069             OpcodeInfo.MAXIMUM_PACKED_VALUE + 1;
1070 
1071         private int[] mCounts;
1072 
InstructionCount()1073         public InstructionCount() {
1074             mCounts = new int[NUM_INSTR];
1075         }
1076 
1077         /**
1078          * Reset counters and ensure counts are running.  Counts may
1079          * have already been running.
1080          *
1081          * @return true if counting was started
1082          */
resetAndStart()1083         public boolean resetAndStart() {
1084             try {
1085                 VMDebug.startInstructionCounting();
1086                 VMDebug.resetInstructionCount();
1087             } catch (UnsupportedOperationException uoe) {
1088                 return false;
1089             }
1090             return true;
1091         }
1092 
1093         /**
1094          * Collect instruction counts.  May or may not stop the
1095          * counting process.
1096          */
collect()1097         public boolean collect() {
1098             try {
1099                 VMDebug.stopInstructionCounting();
1100                 VMDebug.getInstructionCount(mCounts);
1101             } catch (UnsupportedOperationException uoe) {
1102                 return false;
1103             }
1104             return true;
1105         }
1106 
1107         /**
1108          * Return the total number of instructions executed globally (i.e. in
1109          * all threads).
1110          */
globalTotal()1111         public int globalTotal() {
1112             int count = 0;
1113 
1114             for (int i = 0; i < NUM_INSTR; i++) {
1115                 count += mCounts[i];
1116             }
1117 
1118             return count;
1119         }
1120 
1121         /**
1122          * Return the total number of method-invocation instructions
1123          * executed globally.
1124          */
globalMethodInvocations()1125         public int globalMethodInvocations() {
1126             int count = 0;
1127 
1128             for (int i = 0; i < NUM_INSTR; i++) {
1129                 if (OpcodeInfo.isInvoke(i)) {
1130                     count += mCounts[i];
1131                 }
1132             }
1133 
1134             return count;
1135         }
1136     }
1137 
1138     /**
1139      * A Map of typed debug properties.
1140      */
1141     private static final TypedProperties debugProperties;
1142 
1143     /*
1144      * Load the debug properties from the standard files into debugProperties.
1145      */
1146     static {
1147         if (false) {
1148             final String TAG = "DebugProperties";
1149             final String[] files = { "/system/debug.prop", "/debug.prop", "/data/debug.prop" };
1150             final TypedProperties tp = new TypedProperties();
1151 
1152             // Read the properties from each of the files, if present.
1153             for (String file : files) {
1154                 Reader r;
1155                 try {
1156                     r = new FileReader(file);
1157                 } catch (FileNotFoundException ex) {
1158                     // It's ok if a file is missing.
1159                     continue;
1160                 }
1161 
1162                 try {
1163                     tp.load(r);
1164                 } catch (Exception ex) {
1165                     throw new RuntimeException("Problem loading " + file, ex);
1166                 } finally {
1167                     try {
r.close()1168                         r.close();
1169                     } catch (IOException ex) {
1170                         // Ignore this error.
1171                     }
1172                 }
1173             }
1174 
1175             debugProperties = tp.isEmpty() ? null : tp;
1176         } else {
1177             debugProperties = null;
1178         }
1179     }
1180 
1181 
1182     /**
1183      * Returns true if the type of the field matches the specified class.
1184      * Handles the case where the class is, e.g., java.lang.Boolean, but
1185      * the field is of the primitive "boolean" type.  Also handles all of
1186      * the java.lang.Number subclasses.
1187      */
fieldTypeMatches(Field field, Class<?> cl)1188     private static boolean fieldTypeMatches(Field field, Class<?> cl) {
1189         Class<?> fieldClass = field.getType();
1190         if (fieldClass == cl) {
1191             return true;
1192         }
1193         Field primitiveTypeField;
1194         try {
1195             /* All of the classes we care about (Boolean, Integer, etc.)
1196              * have a Class field called "TYPE" that points to the corresponding
1197              * primitive class.
1198              */
1199             primitiveTypeField = cl.getField("TYPE");
1200         } catch (NoSuchFieldException ex) {
1201             return false;
1202         }
1203         try {
1204             return fieldClass == (Class<?>) primitiveTypeField.get(null);
1205         } catch (IllegalAccessException ex) {
1206             return false;
1207         }
1208     }
1209 
1210 
1211     /**
1212      * Looks up the property that corresponds to the field, and sets the field's value
1213      * if the types match.
1214      */
modifyFieldIfSet(final Field field, final TypedProperties properties, final String propertyName)1215     private static void modifyFieldIfSet(final Field field, final TypedProperties properties,
1216                                          final String propertyName) {
1217         if (field.getType() == java.lang.String.class) {
1218             int stringInfo = properties.getStringInfo(propertyName);
1219             switch (stringInfo) {
1220                 case TypedProperties.STRING_SET:
1221                     // Handle as usual below.
1222                     break;
1223                 case TypedProperties.STRING_NULL:
1224                     try {
1225                         field.set(null, null);  // null object for static fields; null string
1226                     } catch (IllegalAccessException ex) {
1227                         throw new IllegalArgumentException(
1228                             "Cannot set field for " + propertyName, ex);
1229                     }
1230                     return;
1231                 case TypedProperties.STRING_NOT_SET:
1232                     return;
1233                 case TypedProperties.STRING_TYPE_MISMATCH:
1234                     throw new IllegalArgumentException(
1235                         "Type of " + propertyName + " " +
1236                         " does not match field type (" + field.getType() + ")");
1237                 default:
1238                     throw new IllegalStateException(
1239                         "Unexpected getStringInfo(" + propertyName + ") return value " +
1240                         stringInfo);
1241             }
1242         }
1243         Object value = properties.get(propertyName);
1244         if (value != null) {
1245             if (!fieldTypeMatches(field, value.getClass())) {
1246                 throw new IllegalArgumentException(
1247                     "Type of " + propertyName + " (" + value.getClass() + ") " +
1248                     " does not match field type (" + field.getType() + ")");
1249             }
1250             try {
1251                 field.set(null, value);  // null object for static fields
1252             } catch (IllegalAccessException ex) {
1253                 throw new IllegalArgumentException(
1254                     "Cannot set field for " + propertyName, ex);
1255             }
1256         }
1257     }
1258 
1259 
1260     /**
1261      * Equivalent to <code>setFieldsOn(cl, false)</code>.
1262      *
1263      * @see #setFieldsOn(Class, boolean)
1264      *
1265      * @hide
1266      */
setFieldsOn(Class<?> cl)1267     public static void setFieldsOn(Class<?> cl) {
1268         setFieldsOn(cl, false);
1269     }
1270 
1271     /**
1272      * Reflectively sets static fields of a class based on internal debugging
1273      * properties.  This method is a no-op if false is
1274      * false.
1275      * <p>
1276      * <strong>NOTE TO APPLICATION DEVELOPERS</strong>: false will
1277      * always be false in release builds.  This API is typically only useful
1278      * for platform developers.
1279      * </p>
1280      * Class setup: define a class whose only fields are non-final, static
1281      * primitive types (except for "char") or Strings.  In a static block
1282      * after the field definitions/initializations, pass the class to
1283      * this method, Debug.setFieldsOn(). Example:
1284      * <pre>
1285      * package com.example;
1286      *
1287      * import android.os.Debug;
1288      *
1289      * public class MyDebugVars {
1290      *    public static String s = "a string";
1291      *    public static String s2 = "second string";
1292      *    public static String ns = null;
1293      *    public static boolean b = false;
1294      *    public static int i = 5;
1295      *    @Debug.DebugProperty
1296      *    public static float f = 0.1f;
1297      *    @@Debug.DebugProperty
1298      *    public static double d = 0.5d;
1299      *
1300      *    // This MUST appear AFTER all fields are defined and initialized!
1301      *    static {
1302      *        // Sets all the fields
1303      *        Debug.setFieldsOn(MyDebugVars.class);
1304      *
1305      *        // Sets only the fields annotated with @Debug.DebugProperty
1306      *        // Debug.setFieldsOn(MyDebugVars.class, true);
1307      *    }
1308      * }
1309      * </pre>
1310      * setFieldsOn() may override the value of any field in the class based
1311      * on internal properties that are fixed at boot time.
1312      * <p>
1313      * These properties are only set during platform debugging, and are not
1314      * meant to be used as a general-purpose properties store.
1315      *
1316      * {@hide}
1317      *
1318      * @param cl The class to (possibly) modify
1319      * @param partial If false, sets all static fields, otherwise, only set
1320      *        fields with the {@link android.os.Debug.DebugProperty}
1321      *        annotation
1322      * @throws IllegalArgumentException if any fields are final or non-static,
1323      *         or if the type of the field does not match the type of
1324      *         the internal debugging property value.
1325      */
setFieldsOn(Class<?> cl, boolean partial)1326     public static void setFieldsOn(Class<?> cl, boolean partial) {
1327         if (false) {
1328             if (debugProperties != null) {
1329                 /* Only look for fields declared directly by the class,
1330                  * so we don't mysteriously change static fields in superclasses.
1331                  */
1332                 for (Field field : cl.getDeclaredFields()) {
1333                     if (!partial || field.getAnnotation(DebugProperty.class) != null) {
1334                         final String propertyName = cl.getName() + "." + field.getName();
1335                         boolean isStatic = Modifier.isStatic(field.getModifiers());
1336                         boolean isFinal = Modifier.isFinal(field.getModifiers());
1337 
1338                         if (!isStatic || isFinal) {
1339                             throw new IllegalArgumentException(propertyName +
1340                                 " must be static and non-final");
1341                         }
1342                         modifyFieldIfSet(field, debugProperties, propertyName);
1343                     }
1344                 }
1345             }
1346         } else {
1347             Log.wtf(TAG,
1348                   "setFieldsOn(" + (cl == null ? "null" : cl.getName()) +
1349                   ") called in non-DEBUG build");
1350         }
1351     }
1352 
1353     /**
1354      * Annotation to put on fields you want to set with
1355      * {@link Debug#setFieldsOn(Class, boolean)}.
1356      *
1357      * @hide
1358      */
1359     @Target({ ElementType.FIELD })
1360     @Retention(RetentionPolicy.RUNTIME)
1361     public @interface DebugProperty {
1362     }
1363 
1364     /**
1365      * Get a debugging dump of a system service by name.
1366      *
1367      * <p>Most services require the caller to hold android.permission.DUMP.
1368      *
1369      * @param name of the service to dump
1370      * @param fd to write dump output to (usually an output log file)
1371      * @param args to pass to the service's dump method, may be null
1372      * @return true if the service was dumped successfully, false if
1373      *     the service could not be found or had an error while dumping
1374      */
dumpService(String name, FileDescriptor fd, String[] args)1375     public static boolean dumpService(String name, FileDescriptor fd, String[] args) {
1376         IBinder service = ServiceManager.getService(name);
1377         if (service == null) {
1378             Log.e(TAG, "Can't find service to dump: " + name);
1379             return false;
1380         }
1381 
1382         try {
1383             service.dump(fd, args);
1384             return true;
1385         } catch (RemoteException e) {
1386             Log.e(TAG, "Can't dump service: " + name, e);
1387             return false;
1388         }
1389     }
1390 
1391     /**
1392      * Have the stack traces of the given native process dumped to the
1393      * specified file.  Will be appended to the file.
1394      * @hide
1395      */
dumpNativeBacktraceToFile(int pid, String file)1396     public static native void dumpNativeBacktraceToFile(int pid, String file);
1397 
1398     /**
1399      * Return a String describing the calling method and location at a particular stack depth.
1400      * @param callStack the Thread stack
1401      * @param depth the depth of stack to return information for.
1402      * @return the String describing the caller at that depth.
1403      */
getCaller(StackTraceElement callStack[], int depth)1404     private static String getCaller(StackTraceElement callStack[], int depth) {
1405         // callStack[4] is the caller of the method that called getCallers()
1406         if (4 + depth >= callStack.length) {
1407             return "<bottom of call stack>";
1408         }
1409         StackTraceElement caller = callStack[4 + depth];
1410         return caller.getClassName() + "." + caller.getMethodName() + ":" + caller.getLineNumber();
1411     }
1412 
1413     /**
1414      * Return a string consisting of methods and locations at multiple call stack levels.
1415      * @param depth the number of levels to return, starting with the immediate caller.
1416      * @return a string describing the call stack.
1417      * {@hide}
1418      */
getCallers(final int depth)1419     public static String getCallers(final int depth) {
1420         final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
1421         StringBuffer sb = new StringBuffer();
1422         for (int i = 0; i < depth; i++) {
1423             sb.append(getCaller(callStack, i)).append(" ");
1424         }
1425         return sb.toString();
1426     }
1427 
1428     /**
1429      * Like {@link #getCallers(int)}, but each location is append to the string
1430      * as a new line with <var>linePrefix</var> in front of it.
1431      * @param depth the number of levels to return, starting with the immediate caller.
1432      * @param linePrefix prefix to put in front of each location.
1433      * @return a string describing the call stack.
1434      * {@hide}
1435      */
getCallers(final int depth, String linePrefix)1436     public static String getCallers(final int depth, String linePrefix) {
1437         final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
1438         StringBuffer sb = new StringBuffer();
1439         for (int i = 0; i < depth; i++) {
1440             sb.append(linePrefix).append(getCaller(callStack, i)).append("\n");
1441         }
1442         return sb.toString();
1443     }
1444 
1445     /**
1446      * @return a String describing the immediate caller of the calling method.
1447      * {@hide}
1448      */
getCaller()1449     public static String getCaller() {
1450         return getCaller(Thread.currentThread().getStackTrace(), 0);
1451     }
1452 }
1453