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