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