• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.os;
18 
19 import com.android.internal.util.TypedProperties;
20 
21 import android.util.Config;
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.Opcodes;
44 import dalvik.system.VMDebug;
45 
46 
47 /**
48  * Provides various debugging functions for Android applications, including
49  * tracing and allocation counts.
50  * <p><strong>Logging Trace Files</strong></p>
51  * <p>Debug can create log files that give details about an application, such as
52  * a call stack and start/stop times for any running methods. See <a
53 href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
54  * information about reading trace files. To start logging trace files, call one
55  * of the startMethodTracing() methods. To stop tracing, call
56  * {@link #stopMethodTracing()}.
57  */
58 public final class Debug
59 {
60     /**
61      * Flags for startMethodTracing().  These can be ORed together.
62      *
63      * TRACE_COUNT_ALLOCS adds the results from startAllocCounting to the
64      * trace key file.
65      */
66     public static final int TRACE_COUNT_ALLOCS  = VMDebug.TRACE_COUNT_ALLOCS;
67 
68     /**
69      * Flags for printLoadedClasses().  Default behavior is to only show
70      * the class name.
71      */
72     public static final int SHOW_FULL_DETAIL    = 1;
73     public static final int SHOW_CLASSLOADER    = (1 << 1);
74     public static final int SHOW_INITIALIZED    = (1 << 2);
75 
76     // set/cleared by waitForDebugger()
77     private static volatile boolean mWaiting = false;
78 
Debug()79     private Debug() {}
80 
81     /*
82      * How long to wait for the debugger to finish sending requests.  I've
83      * seen this hit 800msec on the device while waiting for a response
84      * to travel over USB and get processed, so we take that and add
85      * half a second.
86      */
87     private static final int MIN_DEBUGGER_IDLE = 1300;      // msec
88 
89     /* how long to sleep when polling for activity */
90     private static final int SPIN_DELAY = 200;              // msec
91 
92     /**
93      * Default trace file path and file
94      */
95     private static final String DEFAULT_TRACE_PATH_PREFIX = "/sdcard/";
96     private static final String DEFAULT_TRACE_BODY = "dmtrace";
97     private static final String DEFAULT_TRACE_EXTENSION = ".trace";
98     private static final String DEFAULT_TRACE_FILE_PATH =
99         DEFAULT_TRACE_PATH_PREFIX + DEFAULT_TRACE_BODY
100         + DEFAULT_TRACE_EXTENSION;
101 
102 
103     /**
104      * This class is used to retrieved various statistics about the memory mappings for this
105      * process. The returns info broken down by dalvik, native, and other. All results are in kB.
106      */
107     public static class MemoryInfo implements Parcelable {
108         /** The proportional set size for dalvik. */
109         public int dalvikPss;
110         /** The private dirty pages used by dalvik. */
111         public int dalvikPrivateDirty;
112         /** The shared dirty pages used by dalvik. */
113         public int dalvikSharedDirty;
114 
115         /** The proportional set size for the native heap. */
116         public int nativePss;
117         /** The private dirty pages used by the native heap. */
118         public int nativePrivateDirty;
119         /** The shared dirty pages used by the native heap. */
120         public int nativeSharedDirty;
121 
122         /** The proportional set size for everything else. */
123         public int otherPss;
124         /** The private dirty pages used by everything else. */
125         public int otherPrivateDirty;
126         /** The shared dirty pages used by everything else. */
127         public int otherSharedDirty;
128 
MemoryInfo()129         public MemoryInfo() {
130         }
131 
132         /**
133          * Return total PSS memory usage in kB.
134          */
getTotalPss()135         public int getTotalPss() {
136             return dalvikPss + nativePss + otherPss;
137         }
138 
139         /**
140          * Return total private dirty memory usage in kB.
141          */
getTotalPrivateDirty()142         public int getTotalPrivateDirty() {
143             return dalvikPrivateDirty + nativePrivateDirty + otherPrivateDirty;
144         }
145 
146         /**
147          * Return total shared dirty memory usage in kB.
148          */
getTotalSharedDirty()149         public int getTotalSharedDirty() {
150             return dalvikSharedDirty + nativeSharedDirty + otherSharedDirty;
151         }
152 
describeContents()153         public int describeContents() {
154             return 0;
155         }
156 
writeToParcel(Parcel dest, int flags)157         public void writeToParcel(Parcel dest, int flags) {
158             dest.writeInt(dalvikPss);
159             dest.writeInt(dalvikPrivateDirty);
160             dest.writeInt(dalvikSharedDirty);
161             dest.writeInt(nativePss);
162             dest.writeInt(nativePrivateDirty);
163             dest.writeInt(nativeSharedDirty);
164             dest.writeInt(otherPss);
165             dest.writeInt(otherPrivateDirty);
166             dest.writeInt(otherSharedDirty);
167         }
168 
readFromParcel(Parcel source)169         public void readFromParcel(Parcel source) {
170             dalvikPss = source.readInt();
171             dalvikPrivateDirty = source.readInt();
172             dalvikSharedDirty = source.readInt();
173             nativePss = source.readInt();
174             nativePrivateDirty = source.readInt();
175             nativeSharedDirty = source.readInt();
176             otherPss = source.readInt();
177             otherPrivateDirty = source.readInt();
178             otherSharedDirty = source.readInt();
179         }
180 
181         public static final Creator<MemoryInfo> CREATOR = new Creator<MemoryInfo>() {
182             public MemoryInfo createFromParcel(Parcel source) {
183                 return new MemoryInfo(source);
184             }
185             public MemoryInfo[] newArray(int size) {
186                 return new MemoryInfo[size];
187             }
188         };
189 
MemoryInfo(Parcel source)190         private MemoryInfo(Parcel source) {
191             readFromParcel(source);
192         }
193     }
194 
195 
196     /**
197      * Wait until a debugger attaches.  As soon as the debugger attaches,
198      * this returns, so you will need to place a breakpoint after the
199      * waitForDebugger() call if you want to start tracing immediately.
200      */
waitForDebugger()201     public static void waitForDebugger() {
202         if (!VMDebug.isDebuggingEnabled()) {
203             //System.out.println("debugging not enabled, not waiting");
204             return;
205         }
206         if (isDebuggerConnected())
207             return;
208 
209         // if DDMS is listening, inform them of our plight
210         System.out.println("Sending WAIT chunk");
211         byte[] data = new byte[] { 0 };     // 0 == "waiting for debugger"
212         Chunk waitChunk = new Chunk(ChunkHandler.type("WAIT"), data, 0, 1);
213         DdmServer.sendChunk(waitChunk);
214 
215         mWaiting = true;
216         while (!isDebuggerConnected()) {
217             try { Thread.sleep(SPIN_DELAY); }
218             catch (InterruptedException ie) {}
219         }
220         mWaiting = false;
221 
222         System.out.println("Debugger has connected");
223 
224         /*
225          * There is no "ready to go" signal from the debugger, and we're
226          * not allowed to suspend ourselves -- the debugger expects us to
227          * be running happily, and gets confused if we aren't.  We need to
228          * allow the debugger a chance to set breakpoints before we start
229          * running again.
230          *
231          * Sit and spin until the debugger has been idle for a short while.
232          */
233         while (true) {
234             long delta = VMDebug.lastDebuggerActivity();
235             if (delta < 0) {
236                 System.out.println("debugger detached?");
237                 break;
238             }
239 
240             if (delta < MIN_DEBUGGER_IDLE) {
241                 System.out.println("waiting for debugger to settle...");
242                 try { Thread.sleep(SPIN_DELAY); }
243                 catch (InterruptedException ie) {}
244             } else {
245                 System.out.println("debugger has settled (" + delta + ")");
246                 break;
247             }
248         }
249     }
250 
251     /**
252      * Returns "true" if one or more threads is waiting for a debugger
253      * to attach.
254      */
waitingForDebugger()255     public static boolean waitingForDebugger() {
256         return mWaiting;
257     }
258 
259     /**
260      * Determine if a debugger is currently attached.
261      */
isDebuggerConnected()262     public static boolean isDebuggerConnected() {
263         return VMDebug.isDebuggerConnected();
264     }
265 
266     /**
267      * Change the JDWP port.
268      *
269      * @deprecated no longer needed or useful
270      */
271     @Deprecated
changeDebugPort(int port)272     public static void changeDebugPort(int port) {}
273 
274     /**
275      * This is the pathname to the sysfs file that enables and disables
276      * tracing on the qemu emulator.
277      */
278     private static final String SYSFS_QEMU_TRACE_STATE = "/sys/qemu_trace/state";
279 
280     /**
281      * Enable qemu tracing. For this to work requires running everything inside
282      * the qemu emulator; otherwise, this method will have no effect. The trace
283      * file is specified on the command line when the emulator is started. For
284      * example, the following command line <br />
285      * <code>emulator -trace foo</code><br />
286      * will start running the emulator and create a trace file named "foo". This
287      * method simply enables writing the trace records to the trace file.
288      *
289      * <p>
290      * The main differences between this and {@link #startMethodTracing()} are
291      * that tracing in the qemu emulator traces every cpu instruction of every
292      * process, including kernel code, so we have more complete information,
293      * including all context switches. We can also get more detailed information
294      * such as cache misses. The sequence of calls is determined by
295      * post-processing the instruction trace. The qemu tracing is also done
296      * without modifying the application or perturbing the timing of calls
297      * because no instrumentation is added to the application being traced.
298      * </p>
299      *
300      * <p>
301      * One limitation of using this method compared to using
302      * {@link #startMethodTracing()} on the real device is that the emulator
303      * does not model all of the real hardware effects such as memory and
304      * bus contention.  The emulator also has a simple cache model and cannot
305      * capture all the complexities of a real cache.
306      * </p>
307      */
startNativeTracing()308     public static void startNativeTracing() {
309         // Open the sysfs file for writing and write "1" to it.
310         PrintWriter outStream = null;
311         try {
312             FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE);
313             outStream = new PrintWriter(new OutputStreamWriter(fos));
314             outStream.println("1");
315         } catch (Exception e) {
316         } finally {
317             if (outStream != null)
318                 outStream.close();
319         }
320 
321         VMDebug.startEmulatorTracing();
322     }
323 
324     /**
325      * Stop qemu tracing.  See {@link #startNativeTracing()} to start tracing.
326      *
327      * <p>Tracing can be started and stopped as many times as desired.  When
328      * the qemu emulator itself is stopped then the buffered trace records
329      * are flushed and written to the trace file.  In fact, it is not necessary
330      * to call this method at all; simply killing qemu is sufficient.  But
331      * starting and stopping a trace is useful for examining a specific
332      * region of code.</p>
333      */
stopNativeTracing()334     public static void stopNativeTracing() {
335         VMDebug.stopEmulatorTracing();
336 
337         // Open the sysfs file for writing and write "0" to it.
338         PrintWriter outStream = null;
339         try {
340             FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE);
341             outStream = new PrintWriter(new OutputStreamWriter(fos));
342             outStream.println("0");
343         } catch (Exception e) {
344             // We could print an error message here but we probably want
345             // to quietly ignore errors if we are not running in the emulator.
346         } finally {
347             if (outStream != null)
348                 outStream.close();
349         }
350     }
351 
352     /**
353      * Enable "emulator traces", in which information about the current
354      * method is made available to the "emulator -trace" feature.  There
355      * is no corresponding "disable" call -- this is intended for use by
356      * the framework when tracing should be turned on and left that way, so
357      * that traces captured with F9/F10 will include the necessary data.
358      *
359      * This puts the VM into "profile" mode, which has performance
360      * consequences.
361      *
362      * To temporarily enable tracing, use {@link #startNativeTracing()}.
363      */
enableEmulatorTraceOutput()364     public static void enableEmulatorTraceOutput() {
365         VMDebug.startEmulatorTracing();
366     }
367 
368     /**
369      * Start method tracing with default log name and buffer size. See <a
370 href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
371      * information about reading these files. Call stopMethodTracing() to stop
372      * tracing.
373      */
startMethodTracing()374     public static void startMethodTracing() {
375         VMDebug.startMethodTracing(DEFAULT_TRACE_FILE_PATH, 0, 0);
376     }
377 
378     /**
379      * Start method tracing, specifying the trace log file name.  The trace
380      * file will be put under "/sdcard" unless an absolute path is given.
381      * See <a
382        href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
383      * information about reading trace files.
384      *
385      * @param traceName Name for the trace log file to create.
386      * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
387      * If the files already exist, they will be truncated.
388      * If the trace file given does not end in ".trace", it will be appended for you.
389      */
startMethodTracing(String traceName)390     public static void startMethodTracing(String traceName) {
391         startMethodTracing(traceName, 0, 0);
392     }
393 
394     /**
395      * Start method tracing, specifying the trace log file name and the
396      * buffer size. The trace files will be put under "/sdcard" unless an
397      * absolute path is given. See <a
398        href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
399      * information about reading trace files.
400      * @param traceName    Name for the trace log file to create.
401      * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
402      * If the files already exist, they will be truncated.
403      * If the trace file given does not end in ".trace", it will be appended for you.
404      *
405      * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
406      */
startMethodTracing(String traceName, int bufferSize)407     public static void startMethodTracing(String traceName, int bufferSize) {
408         startMethodTracing(traceName, bufferSize, 0);
409     }
410 
411     /**
412      * Start method tracing, specifying the trace log file name and the
413      * buffer size. The trace files will be put under "/sdcard" unless an
414      * absolute path is given. See <a
415        href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
416      * information about reading trace files.
417      *
418      * <p>
419      * When method tracing is enabled, the VM will run more slowly than
420      * usual, so the timings from the trace files should only be considered
421      * in relative terms (e.g. was run #1 faster than run #2).  The times
422      * for native methods will not change, so don't try to use this to
423      * compare the performance of interpreted and native implementations of the
424      * same method.  As an alternative, consider using "native" tracing
425      * in the emulator via {@link #startNativeTracing()}.
426      * </p>
427      *
428      * @param traceName    Name for the trace log file to create.
429      * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
430      * If the files already exist, they will be truncated.
431      * If the trace file given does not end in ".trace", it will be appended for you.
432      * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
433      */
startMethodTracing(String traceName, int bufferSize, int flags)434     public static void startMethodTracing(String traceName, int bufferSize,
435         int flags) {
436 
437         String pathName = traceName;
438         if (pathName.charAt(0) != '/')
439             pathName = DEFAULT_TRACE_PATH_PREFIX + pathName;
440         if (!pathName.endsWith(DEFAULT_TRACE_EXTENSION))
441             pathName = pathName + DEFAULT_TRACE_EXTENSION;
442 
443         VMDebug.startMethodTracing(pathName, bufferSize, flags);
444     }
445 
446     /**
447      * Like startMethodTracing(String, int, int), but taking an already-opened
448      * FileDescriptor in which the trace is written.  The file name is also
449      * supplied simply for logging.  Makes a dup of the file descriptor.
450      *
451      * Not exposed in the SDK unless we are really comfortable with supporting
452      * this and find it would be useful.
453      * @hide
454      */
startMethodTracing(String traceName, FileDescriptor fd, int bufferSize, int flags)455     public static void startMethodTracing(String traceName, FileDescriptor fd,
456         int bufferSize, int flags) {
457         VMDebug.startMethodTracing(traceName, fd, bufferSize, flags);
458     }
459 
460     /**
461      * Determine whether method tracing is currently active.
462      * @hide
463      */
isMethodTracingActive()464     public static boolean isMethodTracingActive() {
465         return VMDebug.isMethodTracingActive();
466     }
467 
468     /**
469      * Stop method tracing.
470      */
stopMethodTracing()471     public static void stopMethodTracing() {
472         VMDebug.stopMethodTracing();
473     }
474 
475     /**
476      * Get an indication of thread CPU usage.  The value returned
477      * indicates the amount of time that the current thread has spent
478      * executing code or waiting for certain types of I/O.
479      *
480      * The time is expressed in nanoseconds, and is only meaningful
481      * when compared to the result from an earlier call.  Note that
482      * nanosecond resolution does not imply nanosecond accuracy.
483      *
484      * On system which don't support this operation, the call returns -1.
485      */
threadCpuTimeNanos()486     public static long threadCpuTimeNanos() {
487         return VMDebug.threadCpuTimeNanos();
488     }
489 
490     /**
491      * Count the number and aggregate size of memory allocations between
492      * two points.
493      *
494      * The "start" function resets the counts and enables counting.  The
495      * "stop" function disables the counting so that the analysis code
496      * doesn't cause additional allocations.  The "get" function returns
497      * the specified value.
498      *
499      * Counts are kept for the system as a whole and for each thread.
500      * The per-thread counts for threads other than the current thread
501      * are not cleared by the "reset" or "start" calls.
502      */
startAllocCounting()503     public static void startAllocCounting() {
504         VMDebug.startAllocCounting();
505     }
stopAllocCounting()506     public static void stopAllocCounting() {
507         VMDebug.stopAllocCounting();
508     }
509 
getGlobalAllocCount()510     public static int getGlobalAllocCount() {
511         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
512     }
getGlobalAllocSize()513     public static int getGlobalAllocSize() {
514         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
515     }
getGlobalFreedCount()516     public static int getGlobalFreedCount() {
517         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
518     }
getGlobalFreedSize()519     public static int getGlobalFreedSize() {
520         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
521     }
getGlobalExternalAllocCount()522     public static int getGlobalExternalAllocCount() {
523         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_OBJECTS);
524     }
getGlobalExternalAllocSize()525     public static int getGlobalExternalAllocSize() {
526         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_BYTES);
527     }
getGlobalExternalFreedCount()528     public static int getGlobalExternalFreedCount() {
529         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_OBJECTS);
530     }
getGlobalExternalFreedSize()531     public static int getGlobalExternalFreedSize() {
532         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_BYTES);
533     }
getGlobalGcInvocationCount()534     public static int getGlobalGcInvocationCount() {
535         return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
536     }
getThreadAllocCount()537     public static int getThreadAllocCount() {
538         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
539     }
getThreadAllocSize()540     public static int getThreadAllocSize() {
541         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
542     }
getThreadExternalAllocCount()543     public static int getThreadExternalAllocCount() {
544         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_OBJECTS);
545     }
getThreadExternalAllocSize()546     public static int getThreadExternalAllocSize() {
547         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_BYTES);
548     }
getThreadGcInvocationCount()549     public static int getThreadGcInvocationCount() {
550         return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
551     }
552 
resetGlobalAllocCount()553     public static void resetGlobalAllocCount() {
554         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
555     }
resetGlobalAllocSize()556     public static void resetGlobalAllocSize() {
557         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
558     }
resetGlobalFreedCount()559     public static void resetGlobalFreedCount() {
560         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
561     }
resetGlobalFreedSize()562     public static void resetGlobalFreedSize() {
563         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
564     }
resetGlobalExternalAllocCount()565     public static void resetGlobalExternalAllocCount() {
566         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_OBJECTS);
567     }
resetGlobalExternalAllocSize()568     public static void resetGlobalExternalAllocSize() {
569         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_BYTES);
570     }
resetGlobalExternalFreedCount()571     public static void resetGlobalExternalFreedCount() {
572         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_OBJECTS);
573     }
resetGlobalExternalFreedSize()574     public static void resetGlobalExternalFreedSize() {
575         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_BYTES);
576     }
resetGlobalGcInvocationCount()577     public static void resetGlobalGcInvocationCount() {
578         VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
579     }
resetThreadAllocCount()580     public static void resetThreadAllocCount() {
581         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
582     }
resetThreadAllocSize()583     public static void resetThreadAllocSize() {
584         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
585     }
resetThreadExternalAllocCount()586     public static void resetThreadExternalAllocCount() {
587         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_OBJECTS);
588     }
resetThreadExternalAllocSize()589     public static void resetThreadExternalAllocSize() {
590         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_BYTES);
591     }
resetThreadGcInvocationCount()592     public static void resetThreadGcInvocationCount() {
593         VMDebug.resetAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
594     }
resetAllCounts()595     public static void resetAllCounts() {
596         VMDebug.resetAllocCount(VMDebug.KIND_ALL_COUNTS);
597     }
598 
599     /**
600      * Returns the size of the native heap.
601      * @return The size of the native heap in bytes.
602      */
getNativeHeapSize()603     public static native long getNativeHeapSize();
604 
605     /**
606      * Returns the amount of allocated memory in the native heap.
607      * @return The allocated size in bytes.
608      */
getNativeHeapAllocatedSize()609     public static native long getNativeHeapAllocatedSize();
610 
611     /**
612      * Returns the amount of free memory in the native heap.
613      * @return The freed size in bytes.
614      */
getNativeHeapFreeSize()615     public static native long getNativeHeapFreeSize();
616 
617     /**
618      * Retrieves information about this processes memory usages. This information is broken down by
619      * how much is in use by dalivk, the native heap, and everything else.
620      */
getMemoryInfo(MemoryInfo memoryInfo)621     public static native void getMemoryInfo(MemoryInfo memoryInfo);
622 
623     /**
624      * Note: currently only works when the requested pid has the same UID
625      * as the caller.
626      * @hide
627      */
getMemoryInfo(int pid, MemoryInfo memoryInfo)628     public static native void getMemoryInfo(int pid, MemoryInfo memoryInfo);
629 
630     /**
631      * Establish an object allocation limit in the current thread.  Useful
632      * for catching regressions in code that is expected to operate
633      * without causing any allocations.
634      *
635      * Pass in the maximum number of allowed allocations.  Use -1 to disable
636      * the limit.  Returns the previous limit.
637      *
638      * The preferred way to use this is:
639      *
640      *  int prevLimit = -1;
641      *  try {
642      *      prevLimit = Debug.setAllocationLimit(0);
643      *      ... do stuff that's not expected to allocate memory ...
644      *  } finally {
645      *      Debug.setAllocationLimit(prevLimit);
646      *  }
647      *
648      * This allows limits to be nested.  The try/finally ensures that the
649      * limit is reset if something fails.
650      *
651      * Exceeding the limit causes a dalvik.system.AllocationLimitError to
652      * be thrown from a memory allocation call.  The limit is reset to -1
653      * when this happens.
654      *
655      * The feature may be disabled in the VM configuration.  If so, this
656      * call has no effect, and always returns -1.
657      */
setAllocationLimit(int limit)658     public static int setAllocationLimit(int limit) {
659         return VMDebug.setAllocationLimit(limit);
660     }
661 
662     /**
663      * Establish a global object allocation limit.  This is similar to
664      * {@link #setAllocationLimit(int)} but applies to all threads in
665      * the VM.  It will coexist peacefully with per-thread limits.
666      *
667      * [ The value of "limit" is currently restricted to 0 (no allocations
668      *   allowed) or -1 (no global limit).  This may be changed in a future
669      *   release. ]
670      */
setGlobalAllocationLimit(int limit)671     public static int setGlobalAllocationLimit(int limit) {
672         if (limit != 0 && limit != -1)
673             throw new IllegalArgumentException("limit must be 0 or -1");
674         return VMDebug.setGlobalAllocationLimit(limit);
675     }
676 
677     /**
678      * Dump a list of all currently loaded class to the log file.
679      *
680      * @param flags See constants above.
681      */
printLoadedClasses(int flags)682     public static void printLoadedClasses(int flags) {
683         VMDebug.printLoadedClasses(flags);
684     }
685 
686     /**
687      * Get the number of loaded classes.
688      * @return the number of loaded classes.
689      */
getLoadedClassCount()690     public static int getLoadedClassCount() {
691         return VMDebug.getLoadedClassCount();
692     }
693 
694     /**
695      * Dump "hprof" data to the specified file.  This will cause a GC.
696      *
697      * @param fileName Full pathname of output file (e.g. "/sdcard/dump.hprof").
698      * @throws UnsupportedOperationException if the VM was built without
699      *         HPROF support.
700      * @throws IOException if an error occurs while opening or writing files.
701      */
dumpHprofData(String fileName)702     public static void dumpHprofData(String fileName) throws IOException {
703         VMDebug.dumpHprofData(fileName);
704     }
705 
706     /**
707      * Returns the number of sent transactions from this process.
708      * @return The number of sent transactions or -1 if it could not read t.
709      */
getBinderSentTransactions()710     public static native int getBinderSentTransactions();
711 
712     /**
713      * Returns the number of received transactions from the binder driver.
714      * @return The number of received transactions or -1 if it could not read the stats.
715      */
getBinderReceivedTransactions()716     public static native int getBinderReceivedTransactions();
717 
718     /**
719      * Returns the number of active local Binder objects that exist in the
720      * current process.
721      */
getBinderLocalObjectCount()722     public static final native int getBinderLocalObjectCount();
723 
724     /**
725      * Returns the number of references to remote proxy Binder objects that
726      * exist in the current process.
727      */
getBinderProxyObjectCount()728     public static final native int getBinderProxyObjectCount();
729 
730     /**
731      * Returns the number of death notification links to Binder objects that
732      * exist in the current process.
733      */
getBinderDeathObjectCount()734     public static final native int getBinderDeathObjectCount();
735 
736     /**
737      * Primes the register map cache.
738      *
739      * Only works for classes in the bootstrap class loader.  Does not
740      * cause classes to be loaded if they're not already present.
741      *
742      * The classAndMethodDesc argument is a concatentation of the VM-internal
743      * class descriptor, method name, and method descriptor.  Examples:
744      *     Landroid/os/Looper;.loop:()V
745      *     Landroid/app/ActivityThread;.main:([Ljava/lang/String;)V
746      *
747      * @param classAndMethodDesc the method to prepare
748      *
749      * @hide
750      */
cacheRegisterMap(String classAndMethodDesc)751     public static final boolean cacheRegisterMap(String classAndMethodDesc) {
752         return VMDebug.cacheRegisterMap(classAndMethodDesc);
753     }
754 
755     /**
756      * API for gathering and querying instruction counts.
757      *
758      * Example usage:
759      *   Debug.InstructionCount icount = new Debug.InstructionCount();
760      *   icount.resetAndStart();
761      *    [... do lots of stuff ...]
762      *   if (icount.collect()) {
763      *       System.out.println("Total instructions executed: "
764      *           + icount.globalTotal());
765      *       System.out.println("Method invocations: "
766      *           + icount.globalMethodInvocations());
767      *   }
768      */
769     public static class InstructionCount {
770         private static final int NUM_INSTR = 256;
771 
772         private int[] mCounts;
773 
InstructionCount()774         public InstructionCount() {
775             mCounts = new int[NUM_INSTR];
776         }
777 
778         /**
779          * Reset counters and ensure counts are running.  Counts may
780          * have already been running.
781          *
782          * @return true if counting was started
783          */
resetAndStart()784         public boolean resetAndStart() {
785             try {
786                 VMDebug.startInstructionCounting();
787                 VMDebug.resetInstructionCount();
788             } catch (UnsupportedOperationException uoe) {
789                 return false;
790             }
791             return true;
792         }
793 
794         /**
795          * Collect instruction counts.  May or may not stop the
796          * counting process.
797          */
collect()798         public boolean collect() {
799             try {
800                 VMDebug.stopInstructionCounting();
801                 VMDebug.getInstructionCount(mCounts);
802             } catch (UnsupportedOperationException uoe) {
803                 return false;
804             }
805             return true;
806         }
807 
808         /**
809          * Return the total number of instructions executed globally (i.e. in
810          * all threads).
811          */
globalTotal()812         public int globalTotal() {
813             int count = 0;
814             for (int i = 0; i < NUM_INSTR; i++)
815                 count += mCounts[i];
816             return count;
817         }
818 
819         /**
820          * Return the total number of method-invocation instructions
821          * executed globally.
822          */
globalMethodInvocations()823         public int globalMethodInvocations() {
824             int count = 0;
825 
826             //count += mCounts[Opcodes.OP_EXECUTE_INLINE];
827             count += mCounts[Opcodes.OP_INVOKE_VIRTUAL];
828             count += mCounts[Opcodes.OP_INVOKE_SUPER];
829             count += mCounts[Opcodes.OP_INVOKE_DIRECT];
830             count += mCounts[Opcodes.OP_INVOKE_STATIC];
831             count += mCounts[Opcodes.OP_INVOKE_INTERFACE];
832             count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_RANGE];
833             count += mCounts[Opcodes.OP_INVOKE_SUPER_RANGE];
834             count += mCounts[Opcodes.OP_INVOKE_DIRECT_RANGE];
835             count += mCounts[Opcodes.OP_INVOKE_STATIC_RANGE];
836             count += mCounts[Opcodes.OP_INVOKE_INTERFACE_RANGE];
837             //count += mCounts[Opcodes.OP_INVOKE_DIRECT_EMPTY];
838             count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK];
839             count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK_RANGE];
840             count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK];
841             count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK_RANGE];
842             return count;
843         }
844     }
845 
846 
847     /**
848      * A Map of typed debug properties.
849      */
850     private static final TypedProperties debugProperties;
851 
852     /*
853      * Load the debug properties from the standard files into debugProperties.
854      */
855     static {
856         if (Config.DEBUG) {
857             final String TAG = "DebugProperties";
858             final String[] files = { "/system/debug.prop", "/debug.prop", "/data/debug.prop" };
859             final TypedProperties tp = new TypedProperties();
860 
861             // Read the properties from each of the files, if present.
862             for (String file : files) {
863                 Reader r;
864                 try {
865                     r = new FileReader(file);
866                 } catch (FileNotFoundException ex) {
867                     // It's ok if a file is missing.
868                     continue;
869                 }
870 
871                 try {
872                     tp.load(r);
873                 } catch (Exception ex) {
874                     throw new RuntimeException("Problem loading " + file, ex);
875                 } finally {
876                     try {
r.close()877                         r.close();
878                     } catch (IOException ex) {
879                         // Ignore this error.
880                     }
881                 }
882             }
883 
884             debugProperties = tp.isEmpty() ? null : tp;
885         } else {
886             debugProperties = null;
887         }
888     }
889 
890 
891     /**
892      * Returns true if the type of the field matches the specified class.
893      * Handles the case where the class is, e.g., java.lang.Boolean, but
894      * the field is of the primitive "boolean" type.  Also handles all of
895      * the java.lang.Number subclasses.
896      */
fieldTypeMatches(Field field, Class<?> cl)897     private static boolean fieldTypeMatches(Field field, Class<?> cl) {
898         Class<?> fieldClass = field.getType();
899         if (fieldClass == cl) {
900             return true;
901         }
902         Field primitiveTypeField;
903         try {
904             /* All of the classes we care about (Boolean, Integer, etc.)
905              * have a Class field called "TYPE" that points to the corresponding
906              * primitive class.
907              */
908             primitiveTypeField = cl.getField("TYPE");
909         } catch (NoSuchFieldException ex) {
910             return false;
911         }
912         try {
913             return fieldClass == (Class<?>) primitiveTypeField.get(null);
914         } catch (IllegalAccessException ex) {
915             return false;
916         }
917     }
918 
919 
920     /**
921      * Looks up the property that corresponds to the field, and sets the field's value
922      * if the types match.
923      */
modifyFieldIfSet(final Field field, final TypedProperties properties, final String propertyName)924     private static void modifyFieldIfSet(final Field field, final TypedProperties properties,
925                                          final String propertyName) {
926         if (field.getType() == java.lang.String.class) {
927             int stringInfo = properties.getStringInfo(propertyName);
928             switch (stringInfo) {
929                 case TypedProperties.STRING_SET:
930                     // Handle as usual below.
931                     break;
932                 case TypedProperties.STRING_NULL:
933                     try {
934                         field.set(null, null);  // null object for static fields; null string
935                     } catch (IllegalAccessException ex) {
936                         throw new IllegalArgumentException(
937                             "Cannot set field for " + propertyName, ex);
938                     }
939                     return;
940                 case TypedProperties.STRING_NOT_SET:
941                     return;
942                 case TypedProperties.STRING_TYPE_MISMATCH:
943                     throw new IllegalArgumentException(
944                         "Type of " + propertyName + " " +
945                         " does not match field type (" + field.getType() + ")");
946                 default:
947                     throw new IllegalStateException(
948                         "Unexpected getStringInfo(" + propertyName + ") return value " +
949                         stringInfo);
950             }
951         }
952         Object value = properties.get(propertyName);
953         if (value != null) {
954             if (!fieldTypeMatches(field, value.getClass())) {
955                 throw new IllegalArgumentException(
956                     "Type of " + propertyName + " (" + value.getClass() + ") " +
957                     " does not match field type (" + field.getType() + ")");
958             }
959             try {
960                 field.set(null, value);  // null object for static fields
961             } catch (IllegalAccessException ex) {
962                 throw new IllegalArgumentException(
963                     "Cannot set field for " + propertyName, ex);
964             }
965         }
966     }
967 
968 
969     /**
970      * Equivalent to <code>setFieldsOn(cl, false)</code>.
971      *
972      * @see #setFieldsOn(Class, boolean)
973      *
974      * @hide
975      */
setFieldsOn(Class<?> cl)976     public static void setFieldsOn(Class<?> cl) {
977         setFieldsOn(cl, false);
978     }
979 
980     /**
981      * Reflectively sets static fields of a class based on internal debugging
982      * properties.  This method is a no-op if android.util.Config.DEBUG is
983      * false.
984      * <p>
985      * <strong>NOTE TO APPLICATION DEVELOPERS</strong>: Config.DEBUG will
986      * always be false in release builds.  This API is typically only useful
987      * for platform developers.
988      * </p>
989      * Class setup: define a class whose only fields are non-final, static
990      * primitive types (except for "char") or Strings.  In a static block
991      * after the field definitions/initializations, pass the class to
992      * this method, Debug.setFieldsOn(). Example:
993      * <pre>
994      * package com.example;
995      *
996      * import android.os.Debug;
997      *
998      * public class MyDebugVars {
999      *    public static String s = "a string";
1000      *    public static String s2 = "second string";
1001      *    public static String ns = null;
1002      *    public static boolean b = false;
1003      *    public static int i = 5;
1004      *    @Debug.DebugProperty
1005      *    public static float f = 0.1f;
1006      *    @@Debug.DebugProperty
1007      *    public static double d = 0.5d;
1008      *
1009      *    // This MUST appear AFTER all fields are defined and initialized!
1010      *    static {
1011      *        // Sets all the fields
1012      *        Debug.setFieldsOn(MyDebugVars.class);
1013      *
1014      *        // Sets only the fields annotated with @Debug.DebugProperty
1015      *        // Debug.setFieldsOn(MyDebugVars.class, true);
1016      *    }
1017      * }
1018      * </pre>
1019      * setFieldsOn() may override the value of any field in the class based
1020      * on internal properties that are fixed at boot time.
1021      * <p>
1022      * These properties are only set during platform debugging, and are not
1023      * meant to be used as a general-purpose properties store.
1024      *
1025      * {@hide}
1026      *
1027      * @param cl The class to (possibly) modify
1028      * @param partial If false, sets all static fields, otherwise, only set
1029      *        fields with the {@link android.os.Debug.DebugProperty}
1030      *        annotation
1031      * @throws IllegalArgumentException if any fields are final or non-static,
1032      *         or if the type of the field does not match the type of
1033      *         the internal debugging property value.
1034      */
setFieldsOn(Class<?> cl, boolean partial)1035     public static void setFieldsOn(Class<?> cl, boolean partial) {
1036         if (Config.DEBUG) {
1037             if (debugProperties != null) {
1038                 /* Only look for fields declared directly by the class,
1039                  * so we don't mysteriously change static fields in superclasses.
1040                  */
1041                 for (Field field : cl.getDeclaredFields()) {
1042                     if (!partial || field.getAnnotation(DebugProperty.class) != null) {
1043                         final String propertyName = cl.getName() + "." + field.getName();
1044                         boolean isStatic = Modifier.isStatic(field.getModifiers());
1045                         boolean isFinal = Modifier.isFinal(field.getModifiers());
1046 
1047                         if (!isStatic || isFinal) {
1048                             throw new IllegalArgumentException(propertyName +
1049                                 " must be static and non-final");
1050                         }
1051                         modifyFieldIfSet(field, debugProperties, propertyName);
1052                     }
1053                 }
1054             }
1055         } else {
1056             Log.w("android.os.Debug",
1057                   "setFieldsOn(" + (cl == null ? "null" : cl.getName()) +
1058                   ") called in non-DEBUG build");
1059         }
1060     }
1061 
1062     /**
1063      * Annotation to put on fields you want to set with
1064      * {@link Debug#setFieldsOn(Class, boolean)}.
1065      *
1066      * @hide
1067      */
1068     @Target({ ElementType.FIELD })
1069     @Retention(RetentionPolicy.RUNTIME)
1070     public @interface DebugProperty {
1071     }
1072 }
1073