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 dalvik.system;
18 
19 import java.io.FileDescriptor;
20 import java.io.IOException;
21 import java.util.HashMap;
22 import java.util.Map;
23 
24 /**
25  * Provides access to some VM-specific debug features. Though this class and
26  * many of its members are public, this class is meant to be wrapped in a more
27  * friendly way for use by application developers. On the Android platform, the
28  * recommended way to access this functionality is through the class
29  * <code>android.os.Debug</code>.
30  *
31  * @hide
32  */
33 public final class VMDebug {
34     /**
35      * flag for startMethodTracing(), which adds the results from
36      * startAllocCounting to the trace key file.
37      */
38     public static final int TRACE_COUNT_ALLOCS = 1;
39 
40     /* constants for getAllocCount */
41     private static final int KIND_ALLOCATED_OBJECTS     = 1<<0;
42     private static final int KIND_ALLOCATED_BYTES       = 1<<1;
43     private static final int KIND_FREED_OBJECTS         = 1<<2;
44     private static final int KIND_FREED_BYTES           = 1<<3;
45     private static final int KIND_GC_INVOCATIONS        = 1<<4;
46     private static final int KIND_CLASS_INIT_COUNT      = 1<<5;
47     private static final int KIND_CLASS_INIT_TIME       = 1<<6;
48     private static final int KIND_EXT_ALLOCATED_OBJECTS = 1<<12;
49     private static final int KIND_EXT_ALLOCATED_BYTES   = 1<<13;
50     private static final int KIND_EXT_FREED_OBJECTS     = 1<<14;
51     private static final int KIND_EXT_FREED_BYTES       = 1<<15;
52 
53     public static final int KIND_GLOBAL_ALLOCATED_OBJECTS =
54         KIND_ALLOCATED_OBJECTS;
55     public static final int KIND_GLOBAL_ALLOCATED_BYTES =
56         KIND_ALLOCATED_BYTES;
57     public static final int KIND_GLOBAL_FREED_OBJECTS =
58         KIND_FREED_OBJECTS;
59     public static final int KIND_GLOBAL_FREED_BYTES =
60         KIND_FREED_BYTES;
61     public static final int KIND_GLOBAL_GC_INVOCATIONS =
62         KIND_GC_INVOCATIONS;
63     public static final int KIND_GLOBAL_CLASS_INIT_COUNT =
64         KIND_CLASS_INIT_COUNT;
65     public static final int KIND_GLOBAL_CLASS_INIT_TIME =
66         KIND_CLASS_INIT_TIME;
67     public static final int KIND_GLOBAL_EXT_ALLOCATED_OBJECTS =
68         KIND_EXT_ALLOCATED_OBJECTS;
69     public static final int KIND_GLOBAL_EXT_ALLOCATED_BYTES =
70         KIND_EXT_ALLOCATED_BYTES;
71     public static final int KIND_GLOBAL_EXT_FREED_OBJECTS =
72         KIND_EXT_FREED_OBJECTS;
73     public static final int KIND_GLOBAL_EXT_FREED_BYTES =
74         KIND_EXT_FREED_BYTES;
75 
76     public static final int KIND_THREAD_ALLOCATED_OBJECTS =
77         KIND_ALLOCATED_OBJECTS << 16;
78     public static final int KIND_THREAD_ALLOCATED_BYTES =
79         KIND_ALLOCATED_BYTES << 16;
80     public static final int KIND_THREAD_FREED_OBJECTS =
81         KIND_FREED_OBJECTS << 16;
82     public static final int KIND_THREAD_FREED_BYTES =
83         KIND_FREED_BYTES << 16;
84     public static final int KIND_THREAD_GC_INVOCATIONS =
85         KIND_GC_INVOCATIONS << 16;
86     public static final int KIND_THREAD_CLASS_INIT_COUNT =
87         KIND_CLASS_INIT_COUNT << 16;
88     public static final int KIND_THREAD_CLASS_INIT_TIME =
89         KIND_CLASS_INIT_TIME << 16;
90     public static final int KIND_THREAD_EXT_ALLOCATED_OBJECTS =
91         KIND_EXT_ALLOCATED_OBJECTS << 16;
92     public static final int KIND_THREAD_EXT_ALLOCATED_BYTES =
93         KIND_EXT_ALLOCATED_BYTES << 16;
94     public static final int KIND_THREAD_EXT_FREED_OBJECTS =
95         KIND_EXT_FREED_OBJECTS << 16;
96     public static final int KIND_THREAD_EXT_FREED_BYTES =
97         KIND_EXT_FREED_BYTES << 16;
98 
99     public static final int KIND_ALL_COUNTS = 0xffffffff;
100 
101     /* all methods are static */
VMDebug()102     private VMDebug() {}
103 
104     /**
105      * Returns the time since the last known debugger activity.
106      *
107      * @return the time in milliseconds, or -1 if the debugger is not connected
108      */
lastDebuggerActivity()109     public static native long lastDebuggerActivity();
110 
111     /**
112      * Determines if debugging is enabled in this VM.  If debugging is not
113      * enabled, a debugger cannot be attached.
114      *
115      * @return true if debugging is enabled
116      */
isDebuggingEnabled()117     public static native boolean isDebuggingEnabled();
118 
119     /**
120      * Determines if a debugger is currently attached.
121      *
122      * @return true if (and only if) a debugger is connected
123      */
isDebuggerConnected()124     public static native boolean isDebuggerConnected();
125 
126     /**
127      * Returns an array of strings that identify VM features.  This is
128      * used by DDMS to determine what sorts of operations the VM can
129      * perform.
130      */
getVmFeatureList()131     public static native String[] getVmFeatureList();
132 
133     /**
134      * Start method tracing with default name, size, and with <code>0</code>
135      * flags.
136      *
137      * @deprecated Not used, not needed.
138      */
139     @Deprecated
startMethodTracing()140     public static void startMethodTracing() {
141         throw new UnsupportedOperationException();
142     }
143 
144     /**
145      * Start method tracing, specifying a file name as well as a default
146      * buffer size. See <a
147      * href="{@docRoot}guide/developing/tools/traceview.html"> Running the
148      * Traceview Debugging Program</a> for information about reading
149      * trace files.
150      *
151      * <p>You can use either a fully qualified path and
152      * name, or just a name. If only a name is specified, the file will
153      * be created under the /sdcard/ directory. If a name is not given,
154      * the default is /sdcard/dmtrace.trace.</p>
155      *
156      * @param traceFileName name to give the trace file
157      * @param bufferSize the maximum size of both files combined. If passed
158      * as <code>0</code>, it defaults to 8MB.
159      * @param flags flags to control method tracing. The only one that
160      * is currently defined is {@link #TRACE_COUNT_ALLOCS}.
161      * @param samplingEnabled if true, sample profiling is enabled. Otherwise,
162      * method instrumentation is used.
163      * @param intervalUs the time between samples in microseconds when
164      * sampling is enabled.
165      */
startMethodTracing(String traceFileName, int bufferSize, int flags, boolean samplingEnabled, int intervalUs)166     public static void startMethodTracing(String traceFileName, int bufferSize, int flags, boolean samplingEnabled, int intervalUs) {
167         startMethodTracingFilename(traceFileName, checkBufferSize(bufferSize), flags, samplingEnabled, intervalUs);
168     }
169 
170     /**
171      * Like startMethodTracing(String, int, int), but taking an already-opened
172      * FileDescriptor in which the trace is written.  The file name is also
173      * supplied simply for logging.  Makes a dup of the file descriptor.
174      */
startMethodTracing(String traceFileName, FileDescriptor fd, int bufferSize, int flags, boolean samplingEnabled, int intervalUs)175     public static void startMethodTracing(String traceFileName, FileDescriptor fd, int bufferSize, int flags, boolean samplingEnabled, int intervalUs) {
176         if (fd == null) {
177             throw new NullPointerException("fd == null");
178         }
179         startMethodTracingFd(traceFileName, fd, checkBufferSize(bufferSize), flags, samplingEnabled, intervalUs);
180     }
181 
182     /**
183      * Starts method tracing without a backing file.  When stopMethodTracing
184      * is called, the result is sent directly to DDMS.  (If DDMS is not
185      * attached when tracing ends, the profiling data will be discarded.)
186      */
startMethodTracingDdms(int bufferSize, int flags, boolean samplingEnabled, int intervalUs)187     public static void startMethodTracingDdms(int bufferSize, int flags, boolean samplingEnabled, int intervalUs) {
188         startMethodTracingDdmsImpl(checkBufferSize(bufferSize), flags, samplingEnabled, intervalUs);
189     }
190 
checkBufferSize(int bufferSize)191     private static int checkBufferSize(int bufferSize) {
192         if (bufferSize == 0) {
193             // Default to 8MB per the documentation.
194             bufferSize = 8 * 1024 * 1024;
195         }
196         if (bufferSize < 1024) {
197             throw new IllegalArgumentException("buffer size < 1024: " + bufferSize);
198         }
199         return bufferSize;
200     }
201 
startMethodTracingDdmsImpl(int bufferSize, int flags, boolean samplingEnabled, int intervalUs)202     private static native void startMethodTracingDdmsImpl(int bufferSize, int flags, boolean samplingEnabled, int intervalUs);
startMethodTracingFd(String traceFileName, FileDescriptor fd, int bufferSize, int flags, boolean samplingEnabled, int intervalUs)203     private static native void startMethodTracingFd(String traceFileName, FileDescriptor fd, int bufferSize, int flags, boolean samplingEnabled, int intervalUs);
startMethodTracingFilename(String traceFileName, int bufferSize, int flags, boolean samplingEnabled, int intervalUs)204     private static native void startMethodTracingFilename(String traceFileName, int bufferSize, int flags, boolean samplingEnabled, int intervalUs);
205 
206     /**
207      * Determine whether method tracing is currently active and what type is
208      * active.
209      */
getMethodTracingMode()210     public static native int getMethodTracingMode();
211 
212     /**
213      * Stops method tracing.
214      */
stopMethodTracing()215     public static native void stopMethodTracing();
216 
217     /**
218      * Starts sending Dalvik method trace info to the emulator.
219      */
startEmulatorTracing()220     public static native void startEmulatorTracing();
221 
222     /**
223      * Stops sending Dalvik method trace info to the emulator.
224      */
stopEmulatorTracing()225     public static native void stopEmulatorTracing();
226 
227     /**
228      * Get an indication of thread CPU usage. The value returned indicates the
229      * amount of time that the current thread has spent executing code or
230      * waiting for certain types of I/O.
231      * <p>
232      * The time is expressed in nanoseconds, and is only meaningful when
233      * compared to the result from an earlier call. Note that nanosecond
234      * resolution does not imply nanosecond accuracy.
235      *
236      * @return the CPU usage. A value of -1 means the system does not support
237      *         this feature.
238      */
threadCpuTimeNanos()239     public static native long threadCpuTimeNanos();
240 
241     /**
242      * Count the number and aggregate size of memory allocations between
243      * two points.
244      */
startAllocCounting()245     public static native void startAllocCounting();
stopAllocCounting()246     public static native void stopAllocCounting();
getAllocCount(int kind)247     public static native int getAllocCount(int kind);
resetAllocCount(int kinds)248     public static native void resetAllocCount(int kinds);
249 
250     /**
251      * This method exists for binary compatibility.  It was part of
252      * the allocation limits API which was removed in Android 3.0 (Honeycomb).
253      */
254     @Deprecated
setAllocationLimit(int limit)255     public static int setAllocationLimit(int limit) {
256         return -1;
257     }
258 
259     /**
260      * This method exists for binary compatibility.  It was part of
261      * the allocation limits API which was removed in Android 3.0 (Honeycomb).
262      */
263     @Deprecated
setGlobalAllocationLimit(int limit)264     public static int setGlobalAllocationLimit(int limit) {
265         return -1;
266     }
267 
268     /**
269      * Count the number of instructions executed between two points.
270      */
startInstructionCounting()271     public static native void startInstructionCounting();
stopInstructionCounting()272     public static native void stopInstructionCounting();
getInstructionCount(int[] counts)273     public static native void getInstructionCount(int[] counts);
resetInstructionCount()274     public static native void resetInstructionCount();
275 
276     /**
277      * Dumps a list of loaded class to the log file.
278      */
printLoadedClasses(int flags)279     public static native void printLoadedClasses(int flags);
280 
281     /**
282      * Gets the number of loaded classes.
283      *
284      * @return the number of loaded classes
285      */
getLoadedClassCount()286     public static native int getLoadedClassCount();
287 
288     /**
289      * Dumps "hprof" data to the specified file.  This may cause a GC.
290      *
291      * The VM may create a temporary file in the same directory.
292      *
293      * @param filename Full pathname of output file (e.g. "/sdcard/dump.hprof").
294      * @throws UnsupportedOperationException if the VM was built without
295      *         HPROF support.
296      * @throws IOException if an error occurs while opening or writing files.
297      */
dumpHprofData(String filename)298     public static void dumpHprofData(String filename) throws IOException {
299         if (filename == null) {
300             throw new NullPointerException("filename == null");
301         }
302         dumpHprofData(filename, null);
303     }
304 
305     /**
306      * Collects "hprof" heap data and sends it to DDMS.  This may cause a GC.
307      *
308      * @throws UnsupportedOperationException if the VM was built without
309      *         HPROF support.
310      */
dumpHprofDataDdms()311     public static native void dumpHprofDataDdms();
312 
313     /**
314      * Dumps "hprof" heap data to a file, by name or descriptor.
315      *
316      * @param fileName Name of output file.  If fd is non-null, the
317      *        file name is only used in log messages (and may be null).
318      * @param fd Descriptor of open file that will receive the output.
319      *        If this is null, the fileName is used instead.
320      */
dumpHprofData(String fileName, FileDescriptor fd)321     public static native void dumpHprofData(String fileName, FileDescriptor fd)
322             throws IOException;
323 
324     /**
325      * Primes the register map cache.
326      */
cacheRegisterMap(String classAndMethodDesc)327     public static native boolean cacheRegisterMap(String classAndMethodDesc);
328 
329     /**
330      * Dumps the contents of the VM reference tables (e.g. JNI locals and
331      * globals) to the log file.
332      */
dumpReferenceTables()333     public static native void dumpReferenceTables();
334 
335     /**
336      * Crashes the VM.  Seriously.  Dumps the interpreter stack trace for
337      * the current thread and then aborts the VM so you can see the native
338      * stack trace.  Useful for figuring out how you got somewhere when
339      * lots of native code is involved.
340      */
crash()341     public static native void crash();
342 
343     /**
344      * Together with gdb, provide a handy way to stop the VM at user-tagged
345      * locations.
346      */
infopoint(int id)347     public static native void infopoint(int id);
348 
349     /*
350      * Fake method, inserted into dmtrace output when the garbage collector
351      * runs.  Not actually called.
352      */
startGC()353     private static void startGC() {}
354 
355     /*
356      * Fake method, inserted into dmtrace output during class preparation
357      * (loading and linking, but not verification or initialization).  Not
358      * actually called.
359      */
startClassPrep()360     private static void startClassPrep() {}
361 
362     /**
363      * Counts the instances of a class.
364      * It is the caller's responsibility to do GC if they don't want unreachable
365      * objects to get counted.
366      *
367      * @param klass the class to be counted.
368      * @param assignable if false, direct instances of klass are
369      *                   counted.  If true, instances that are
370      *                   assignable to klass, as defined by
371      *                   {@link Class#isAssignableFrom} are counted.
372      * @return the number of matching instances.
373      */
countInstancesOfClass(Class klass, boolean assignable)374     public static native long countInstancesOfClass(Class klass, boolean assignable);
375 
376     /**
377      * Counts the instances of classes.
378      * It is the caller's responsibility to do GC if they don't want unreachable
379      * objects to get counted.
380      *
381      * @param classes the classes to be counted.
382      * @param assignable if false, direct instances of klass are
383      *                   counted.  If true, instances that are
384      *                   assignable to klass, as defined by
385      *                   {@link Class#isAssignableFrom} are counted.
386      * @return an array containing the number of matching instances. The value for
387      * an index is the number of instances of the class at that index in number classes.
388      */
countInstancesOfClasses(Class[] classes, boolean assignable)389     public static native long[] countInstancesOfClasses(Class[] classes, boolean assignable);
390 
391     /**
392      * Export the heap per-space stats for dumpsys meminfo.
393      *
394      * The content of the array is:
395      *
396      * <pre>
397      *   data[0] : the application heap space size
398      *   data[1] : the application heap space allocated bytes
399      *   data[2] : the application heap space free bytes
400      *   data[3] : the zygote heap space size
401      *   data[4] : the zygote heap space allocated size
402      *   data[5] : the zygote heap space free size
403      *   data[6] : the large object space size
404      *   data[7] : the large object space allocated bytes
405      *   data[8] : the large object space free bytes
406      * </pre>
407      *
408      * @param data the array into which the stats are written.
409      */
getHeapSpaceStats(long[] data)410     public static native void getHeapSpaceStats(long[] data);
411 
412     /* Map from the names of the runtime stats supported by getRuntimeStat() to their IDs */
413     private static final HashMap<String, Integer> runtimeStatsMap = new HashMap<>();
414 
415     static {
416         runtimeStatsMap.put("art.gc.gc-count", 0);
417         runtimeStatsMap.put("art.gc.gc-time", 1);
418         runtimeStatsMap.put("art.gc.bytes-allocated", 2);
419         runtimeStatsMap.put("art.gc.bytes-freed", 3);
420         runtimeStatsMap.put("art.gc.blocking-gc-count", 4);
421         runtimeStatsMap.put("art.gc.blocking-gc-time", 5);
422         runtimeStatsMap.put("art.gc.gc-count-rate-histogram", 6);
423         runtimeStatsMap.put("art.gc.blocking-gc-count-rate-histogram", 7);
424     }
425 
426     /**
427      * Returns the value of a particular runtime statistic or {@code null} if no
428      * such runtime statistic exists.
429      *
430      * @param statName
431      *            the name of the runtime statistic to look up.
432      * @return the value of the runtime statistic.
433      */
getRuntimeStat(String statName)434     public static String getRuntimeStat(String statName) {
435         if (statName == null) {
436             throw new NullPointerException("statName == null");
437         }
438         Integer statId = runtimeStatsMap.get(statName);
439         if (statId != null) {
440             return getRuntimeStatInternal(statId);
441         }
442         return null;
443     }
444 
445     /**
446      * Returns a map of the names/values of the runtime statistics
447      * that {@link #getRuntimeStat()} supports.
448      *
449      * @return a map of the names/values of the supported runtime statistics.
450      */
getRuntimeStats()451     public static Map<String, String> getRuntimeStats() {
452         HashMap<String, String> map = new HashMap<>();
453         String[] values = getRuntimeStatsInternal();
454         for (String name : runtimeStatsMap.keySet()) {
455             int id = runtimeStatsMap.get(name);
456             String value = values[id];
457             map.put(name, value);
458         }
459         return map;
460     }
461 
getRuntimeStatInternal(int statId)462     private static native String getRuntimeStatInternal(int statId);
getRuntimeStatsInternal()463     private static native String[] getRuntimeStatsInternal();
464 }
465