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