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