Home | History | Annotate | Download | only in os
      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 
     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 = 9;
    134 
    135         private int[] otherStats = new int[NUM_OTHER_STATS*3];
    136 
    137         public MemoryInfo() {
    138         }
    139 
    140         /**
    141          * Return total PSS memory usage in kB.
    142          */
    143         public int getTotalPss() {
    144             return dalvikPss + nativePss + otherPss;
    145         }
    146 
    147         /**
    148          * Return total private dirty memory usage in kB.
    149          */
    150         public int getTotalPrivateDirty() {
    151             return dalvikPrivateDirty + nativePrivateDirty + otherPrivateDirty;
    152         }
    153 
    154         /**
    155          * Return total shared dirty memory usage in kB.
    156          */
    157         public int getTotalSharedDirty() {
    158             return dalvikSharedDirty + nativeSharedDirty + otherSharedDirty;
    159         }
    160 
    161         /* @hide */
    162         public int getOtherPss(int which) {
    163             return otherStats[which*3];
    164         }
    165 
    166         /* @hide */
    167         public int getOtherPrivateDirty(int which) {
    168             return otherStats[which*3 + 1];
    169         }
    170 
    171         /* @hide */
    172         public int getOtherSharedDirty(int which) {
    173             return otherStats[which*3 + 2];
    174         }
    175 
    176 
    177         /* @hide */
    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 
    193         public int describeContents() {
    194             return 0;
    195         }
    196 
    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 
    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 
    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      */
    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      */
    297     public static boolean waitingForDebugger() {
    298         return mWaiting;
    299     }
    300 
    301     /**
    302      * Determine if a debugger is currently attached.
    303      */
    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      */
    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
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    528     public static boolean isMethodTracingActive() {
    529         return VMDebug.isMethodTracingActive();
    530     }
    531 
    532     /**
    533      * Stop method tracing.
    534      */
    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      */
    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      */
    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      */
    576     public static void stopAllocCounting() {
    577         VMDebug.stopAllocCounting();
    578     }
    579 
    580     public static int getGlobalAllocCount() {
    581         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
    582     }
    583     public static int getGlobalAllocSize() {
    584         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
    585     }
    586     public static int getGlobalFreedCount() {
    587         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
    588     }
    589     public static int getGlobalFreedSize() {
    590         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
    591     }
    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     }
    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
    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
    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
    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
    647     public static int getGlobalExternalFreedSize() {
    648         return 0;
    649     }
    650 
    651     public static int getGlobalGcInvocationCount() {
    652         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
    653     }
    654     public static int getThreadAllocCount() {
    655         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
    656     }
    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
    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
    682     public static int getThreadExternalAllocSize() {
    683         return 0;
    684     }
    685 
    686     public static int getThreadGcInvocationCount() {
    687         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
    688     }
    689 
    690     public static void resetGlobalAllocCount() {
    691         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
    692     }
    693     public static void resetGlobalAllocSize() {
    694         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
    695     }
    696     public static void resetGlobalFreedCount() {
    697         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
    698     }
    699     public static void resetGlobalFreedSize() {
    700         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
    701     }
    702     public static void resetGlobalClassInitCount() {
    703         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT);
    704     }
    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
    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
    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
    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
    748     public static void resetGlobalExternalFreedSize() {}
    749 
    750     public static void resetGlobalGcInvocationCount() {
    751         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
    752     }
    753     public static void resetThreadAllocCount() {
    754         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
    755     }
    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
    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
    780     public static void resetThreadExternalAllocSize() {}
    781 
    782     public static void resetThreadGcInvocationCount() {
    783         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
    784     }
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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
    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
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
   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          */
   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          */
   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          */
   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          */
   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 {
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      * Like {@link #getCallers(int)}, but each location is append to the string
   1367      * as a new line with <var>linePrefix</var> in front of it.
   1368      * @param depth the number of levels to return, starting with the immediate caller.
   1369      * @param linePrefix prefix to put in front of each location.
   1370      * @return a string describing the call stack.
   1371      * {@hide}
   1372      */
   1373     public static String getCallers(final int depth, String linePrefix) {
   1374         final StackTraceElement[] callStack = Thread.currentThread().getStackTrace();
   1375         StringBuffer sb = new StringBuffer();
   1376         for (int i = 0; i < depth; i++) {
   1377             sb.append(linePrefix).append(getCaller(callStack, i)).append("\n");
   1378         }
   1379         return sb.toString();
   1380     }
   1381 
   1382     /**
   1383      * @return a String describing the immediate caller of the calling function.
   1384      * {@hide}
   1385      */
   1386     public static String getCaller() {
   1387         return getCaller(Thread.currentThread().getStackTrace(), 0);
   1388     }
   1389 }
   1390