Debug.java revision 599c918d9794b51992de85b42befa0c71d9ec07f
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
17package android.os;
18
19import java.io.FileOutputStream;
20import java.io.IOException;
21import java.io.OutputStreamWriter;
22import java.io.PrintWriter;
23
24import org.apache.harmony.dalvik.ddmc.Chunk;
25import org.apache.harmony.dalvik.ddmc.ChunkHandler;
26import org.apache.harmony.dalvik.ddmc.DdmServer;
27
28import dalvik.bytecode.Opcodes;
29import dalvik.system.VMDebug;
30
31
32/**
33 * Provides various debugging functions for Android applications, including
34 * tracing and allocation counts.
35 * <p><strong>Logging Trace Files</strong></p>
36 * <p>Debug can create log files that give details about an application, such as
37 * a call stack and start/stop times for any running methods. See <a
38href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
39 * information about reading trace files. To start logging trace files, call one
40 * of the startMethodTracing() methods. To stop tracing, call
41 * {@link #stopMethodTracing()}.
42 */
43public final class Debug
44{
45    /**
46     * Flags for startMethodTracing().  These can be ORed together.
47     *
48     * TRACE_COUNT_ALLOCS adds the results from startAllocCounting to the
49     * trace key file.
50     */
51    public static final int TRACE_COUNT_ALLOCS  = VMDebug.TRACE_COUNT_ALLOCS;
52
53    /**
54     * Flags for printLoadedClasses().  Default behavior is to only show
55     * the class name.
56     */
57    public static final int SHOW_FULL_DETAIL    = 1;
58    public static final int SHOW_CLASSLOADER    = (1 << 1);
59    public static final int SHOW_INITIALIZED    = (1 << 2);
60
61    // set/cleared by waitForDebugger()
62    private static volatile boolean mWaiting = false;
63
64    private Debug() {}
65
66    /*
67     * How long to wait for the debugger to finish sending requests.  I've
68     * seen this hit 800msec on the device while waiting for a response
69     * to travel over USB and get processed, so we take that and add
70     * half a second.
71     */
72    private static final int MIN_DEBUGGER_IDLE = 1300;      // msec
73
74    /* how long to sleep when polling for activity */
75    private static final int SPIN_DELAY = 200;              // msec
76
77    /**
78     * Default trace file path and file
79     */
80    private static final String DEFAULT_TRACE_PATH_PREFIX = "/sdcard/";
81    private static final String DEFAULT_TRACE_BODY = "dmtrace";
82    private static final String DEFAULT_TRACE_EXTENSION = ".trace";
83    private static final String DEFAULT_TRACE_FILE_PATH =
84        DEFAULT_TRACE_PATH_PREFIX + DEFAULT_TRACE_BODY
85        + DEFAULT_TRACE_EXTENSION;
86
87
88    /**
89     * This class is used to retrieved various statistics about the memory mappings for this
90     * process. The returns info broken down by dalvik, native, and other. All results are in kB.
91     */
92    public static class MemoryInfo {
93        /** The proportional set size for dalvik. */
94        public int dalvikPss;
95        /** The private dirty pages used by dalvik. */
96        public int dalvikPrivateDirty;
97        /** The shared dirty pages used by dalvik. */
98        public int dalvikSharedDirty;
99
100        /** The proportional set size for the native heap. */
101        public int nativePss;
102        /** The private dirty pages used by the native heap. */
103        public int nativePrivateDirty;
104        /** The shared dirty pages used by the native heap. */
105        public int nativeSharedDirty;
106
107        /** The proportional set size for everything else. */
108        public int otherPss;
109        /** The private dirty pages used by everything else. */
110        public int otherPrivateDirty;
111        /** The shared dirty pages used by everything else. */
112        public int otherSharedDirty;
113    }
114
115
116    /**
117     * Wait until a debugger attaches.  As soon as the debugger attaches,
118     * this returns, so you will need to place a breakpoint after the
119     * waitForDebugger() call if you want to start tracing immediately.
120     */
121    public static void waitForDebugger() {
122        if (!VMDebug.isDebuggingEnabled()) {
123            //System.out.println("debugging not enabled, not waiting");
124            return;
125        }
126        if (isDebuggerConnected())
127            return;
128
129        // if DDMS is listening, inform them of our plight
130        System.out.println("Sending WAIT chunk");
131        byte[] data = new byte[] { 0 };     // 0 == "waiting for debugger"
132        Chunk waitChunk = new Chunk(ChunkHandler.type("WAIT"), data, 0, 1);
133        DdmServer.sendChunk(waitChunk);
134
135        mWaiting = true;
136        while (!isDebuggerConnected()) {
137            try { Thread.sleep(SPIN_DELAY); }
138            catch (InterruptedException ie) {}
139        }
140        mWaiting = false;
141
142        System.out.println("Debugger has connected");
143
144        /*
145         * There is no "ready to go" signal from the debugger, and we're
146         * not allowed to suspend ourselves -- the debugger expects us to
147         * be running happily, and gets confused if we aren't.  We need to
148         * allow the debugger a chance to set breakpoints before we start
149         * running again.
150         *
151         * Sit and spin until the debugger has been idle for a short while.
152         */
153        while (true) {
154            long delta = VMDebug.lastDebuggerActivity();
155            if (delta < 0) {
156                System.out.println("debugger detached?");
157                break;
158            }
159
160            if (delta < MIN_DEBUGGER_IDLE) {
161                System.out.println("waiting for debugger to settle...");
162                try { Thread.sleep(SPIN_DELAY); }
163                catch (InterruptedException ie) {}
164            } else {
165                System.out.println("debugger has settled (" + delta + ")");
166                break;
167            }
168        }
169    }
170
171    /**
172     * Returns "true" if one or more threads is waiting for a debugger
173     * to attach.
174     */
175    public static boolean waitingForDebugger() {
176        return mWaiting;
177    }
178
179    /**
180     * Determine if a debugger is currently attached.
181     */
182    public static boolean isDebuggerConnected() {
183        return VMDebug.isDebuggerConnected();
184    }
185
186    /**
187     * Change the JDWP port.
188     *
189     * @deprecated no longer needed or useful
190     */
191    @Deprecated
192    public static void changeDebugPort(int port) {}
193
194    /**
195     * This is the pathname to the sysfs file that enables and disables
196     * tracing on the qemu emulator.
197     */
198    private static final String SYSFS_QEMU_TRACE_STATE = "/sys/qemu_trace/state";
199
200    /**
201     * Enable qemu tracing. For this to work requires running everything inside
202     * the qemu emulator; otherwise, this method will have no effect. The trace
203     * file is specified on the command line when the emulator is started. For
204     * example, the following command line <br />
205     * <code>emulator -trace foo</code><br />
206     * will start running the emulator and create a trace file named "foo". This
207     * method simply enables writing the trace records to the trace file.
208     *
209     * <p>
210     * The main differences between this and {@link #startMethodTracing()} are
211     * that tracing in the qemu emulator traces every cpu instruction of every
212     * process, including kernel code, so we have more complete information,
213     * including all context switches. We can also get more detailed information
214     * such as cache misses. The sequence of calls is determined by
215     * post-processing the instruction trace. The qemu tracing is also done
216     * without modifying the application or perturbing the timing of calls
217     * because no instrumentation is added to the application being traced.
218     * </p>
219     *
220     * <p>
221     * One limitation of using this method compared to using
222     * {@link #startMethodTracing()} on the real device is that the emulator
223     * does not model all of the real hardware effects such as memory and
224     * bus contention.  The emulator also has a simple cache model and cannot
225     * capture all the complexities of a real cache.
226     * </p>
227     */
228    public static void startNativeTracing() {
229        // Open the sysfs file for writing and write "1" to it.
230        PrintWriter outStream = null;
231        try {
232            FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE);
233            outStream = new PrintWriter(new OutputStreamWriter(fos));
234            outStream.println("1");
235        } catch (Exception e) {
236        } finally {
237            if (outStream != null)
238                outStream.close();
239        }
240
241        VMDebug.startEmulatorTracing();
242    }
243
244    /**
245     * Stop qemu tracing.  See {@link #startNativeTracing()} to start tracing.
246     *
247     * <p>Tracing can be started and stopped as many times as desired.  When
248     * the qemu emulator itself is stopped then the buffered trace records
249     * are flushed and written to the trace file.  In fact, it is not necessary
250     * to call this method at all; simply killing qemu is sufficient.  But
251     * starting and stopping a trace is useful for examining a specific
252     * region of code.</p>
253     */
254    public static void stopNativeTracing() {
255        VMDebug.stopEmulatorTracing();
256
257        // Open the sysfs file for writing and write "0" to it.
258        PrintWriter outStream = null;
259        try {
260            FileOutputStream fos = new FileOutputStream(SYSFS_QEMU_TRACE_STATE);
261            outStream = new PrintWriter(new OutputStreamWriter(fos));
262            outStream.println("0");
263        } catch (Exception e) {
264            // We could print an error message here but we probably want
265            // to quietly ignore errors if we are not running in the emulator.
266        } finally {
267            if (outStream != null)
268                outStream.close();
269        }
270    }
271
272    /**
273     * Enable "emulator traces", in which information about the current
274     * method is made available to the "emulator -trace" feature.  There
275     * is no corresponding "disable" call -- this is intended for use by
276     * the framework when tracing should be turned on and left that way, so
277     * that traces captured with F9/F10 will include the necessary data.
278     *
279     * This puts the VM into "profile" mode, which has performance
280     * consequences.
281     *
282     * To temporarily enable tracing, use {@link #startNativeTracing()}.
283     */
284    public static void enableEmulatorTraceOutput() {
285        VMDebug.startEmulatorTracing();
286    }
287
288    /**
289     * Start method tracing with default log name and buffer size. See <a
290href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
291     * information about reading these files. Call stopMethodTracing() to stop
292     * tracing.
293     */
294    public static void startMethodTracing() {
295        VMDebug.startMethodTracing(DEFAULT_TRACE_FILE_PATH, 0, 0);
296    }
297
298    /**
299     * Start method tracing, specifying the trace log file name.  The trace
300     * file will be put under "/sdcard" unless an absolute path is given.
301     * See <a
302       href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
303     * information about reading trace files.
304     *
305     * @param traceName Name for the trace log file to create.
306     * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
307     * If the files already exist, they will be truncated.
308     * If the trace file given does not end in ".trace", it will be appended for you.
309     */
310    public static void startMethodTracing(String traceName) {
311        startMethodTracing(traceName, 0, 0);
312    }
313
314    /**
315     * Start method tracing, specifying the trace log file name and the
316     * buffer size. The trace files will be put under "/sdcard" unless an
317     * absolute path is given. See <a
318       href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
319     * information about reading trace files.
320     * @param traceName    Name for the trace log file to create.
321     * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
322     * If the files already exist, they will be truncated.
323     * If the trace file given does not end in ".trace", it will be appended for you.
324     *
325     * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
326     */
327    public static void startMethodTracing(String traceName, int bufferSize) {
328        startMethodTracing(traceName, bufferSize, 0);
329    }
330
331    /**
332     * Start method tracing, specifying the trace log file name and the
333     * buffer size. The trace files will be put under "/sdcard" unless an
334     * absolute path is given. See <a
335       href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Log Viewer</a> for
336     * information about reading trace files.
337     *
338     * <p>
339     * When method tracing is enabled, the VM will run more slowly than
340     * usual, so the timings from the trace files should only be considered
341     * in relative terms (e.g. was run #1 faster than run #2).  The times
342     * for native methods will not change, so don't try to use this to
343     * compare the performance of interpreted and native implementations of the
344     * same method.  As an alternative, consider using "native" tracing
345     * in the emulator via {@link #startNativeTracing()}.
346     * </p>
347     *
348     * @param traceName    Name for the trace log file to create.
349     * If no name argument is given, this value defaults to "/sdcard/dmtrace.trace".
350     * If the files already exist, they will be truncated.
351     * If the trace file given does not end in ".trace", it will be appended for you.
352     * @param bufferSize    The maximum amount of trace data we gather. If not given, it defaults to 8MB.
353     */
354    public static void startMethodTracing(String traceName, int bufferSize,
355        int flags) {
356
357        String pathName = traceName;
358        if (pathName.charAt(0) != '/')
359            pathName = DEFAULT_TRACE_PATH_PREFIX + pathName;
360        if (!pathName.endsWith(DEFAULT_TRACE_EXTENSION))
361            pathName = pathName + DEFAULT_TRACE_EXTENSION;
362
363        VMDebug.startMethodTracing(pathName, bufferSize, flags);
364    }
365
366    /**
367     * Determine whether method tracing is currently active.
368     * @hide
369     */
370    public static boolean isMethodTracingActive() {
371        return VMDebug.isMethodTracingActive();
372    }
373
374    /**
375     * Stop method tracing.
376     */
377    public static void stopMethodTracing() {
378        VMDebug.stopMethodTracing();
379    }
380
381    /**
382     * Get an indication of thread CPU usage.  The value returned
383     * indicates the amount of time that the current thread has spent
384     * executing code or waiting for certain types of I/O.
385     *
386     * The time is expressed in nanoseconds, and is only meaningful
387     * when compared to the result from an earlier call.  Note that
388     * nanosecond resolution does not imply nanosecond accuracy.
389     *
390     * On system which don't support this operation, the call returns -1.
391     */
392    public static long threadCpuTimeNanos() {
393        return VMDebug.threadCpuTimeNanos();
394    }
395
396    /**
397     * Count the number and aggregate size of memory allocations between
398     * two points.
399     *
400     * The "start" function resets the counts and enables counting.  The
401     * "stop" function disables the counting so that the analysis code
402     * doesn't cause additional allocations.  The "get" function returns
403     * the specified value.
404     *
405     * Counts are kept for the system as a whole and for each thread.
406     * The per-thread counts for threads other than the current thread
407     * are not cleared by the "reset" or "start" calls.
408     */
409    public static void startAllocCounting() {
410        VMDebug.startAllocCounting();
411    }
412    public static void stopAllocCounting() {
413        VMDebug.stopAllocCounting();
414    }
415
416    public static int getGlobalAllocCount() {
417        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
418    }
419    public static int getGlobalAllocSize() {
420        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
421    }
422    public static int getGlobalFreedCount() {
423        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
424    }
425    public static int getGlobalFreedSize() {
426        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
427    }
428    public static int getGlobalExternalAllocCount() {
429        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_OBJECTS);
430    }
431    public static int getGlobalExternalAllocSize() {
432        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_BYTES);
433    }
434    public static int getGlobalExternalFreedCount() {
435        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_OBJECTS);
436    }
437    public static int getGlobalExternalFreedSize() {
438        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_BYTES);
439    }
440    public static int getGlobalGcInvocationCount() {
441        return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
442    }
443    public static int getThreadAllocCount() {
444        return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
445    }
446    public static int getThreadAllocSize() {
447        return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
448    }
449    public static int getThreadExternalAllocCount() {
450        return VMDebug.getAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_OBJECTS);
451    }
452    public static int getThreadExternalAllocSize() {
453        return VMDebug.getAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_BYTES);
454    }
455    public static int getThreadGcInvocationCount() {
456        return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
457    }
458
459    public static void resetGlobalAllocCount() {
460        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS);
461    }
462    public static void resetGlobalAllocSize() {
463        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES);
464    }
465    public static void resetGlobalFreedCount() {
466        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS);
467    }
468    public static void resetGlobalFreedSize() {
469        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES);
470    }
471    public static void resetGlobalExternalAllocCount() {
472        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_OBJECTS);
473    }
474    public static void resetGlobalExternalAllocSize() {
475        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_ALLOCATED_BYTES);
476    }
477    public static void resetGlobalExternalFreedCount() {
478        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_OBJECTS);
479    }
480    public static void resetGlobalExternalFreedSize() {
481        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_EXT_FREED_BYTES);
482    }
483    public static void resetGlobalGcInvocationCount() {
484        VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS);
485    }
486    public static void resetThreadAllocCount() {
487        VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS);
488    }
489    public static void resetThreadAllocSize() {
490        VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES);
491    }
492    public static void resetThreadExternalAllocCount() {
493        VMDebug.resetAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_OBJECTS);
494    }
495    public static void resetThreadExternalAllocSize() {
496        VMDebug.resetAllocCount(VMDebug.KIND_THREAD_EXT_ALLOCATED_BYTES);
497    }
498    public static void resetThreadGcInvocationCount() {
499        VMDebug.resetAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS);
500    }
501    public static void resetAllCounts() {
502        VMDebug.resetAllocCount(VMDebug.KIND_ALL_COUNTS);
503    }
504
505    /**
506     * Returns the size of the native heap.
507     * @return The size of the native heap in bytes.
508     */
509    public static native long getNativeHeapSize();
510
511    /**
512     * Returns the amount of allocated memory in the native heap.
513     * @return The allocated size in bytes.
514     */
515    public static native long getNativeHeapAllocatedSize();
516
517    /**
518     * Returns the amount of free memory in the native heap.
519     * @return The freed size in bytes.
520     */
521    public static native long getNativeHeapFreeSize();
522
523    /**
524     * Retrieves information about this processes memory usages. This information is broken down by
525     * how much is in use by dalivk, the native heap, and everything else.
526     */
527    public static native void getMemoryInfo(MemoryInfo memoryInfo);
528
529    /**
530     * Establish an object allocation limit in the current thread.  Useful
531     * for catching regressions in code that is expected to operate
532     * without causing any allocations.
533     *
534     * Pass in the maximum number of allowed allocations.  Use -1 to disable
535     * the limit.  Returns the previous limit.
536     *
537     * The preferred way to use this is:
538     *
539     *  int prevLimit = -1;
540     *  try {
541     *      prevLimit = Debug.setAllocationLimit(0);
542     *      ... do stuff that's not expected to allocate memory ...
543     *  } finally {
544     *      Debug.setAllocationLimit(prevLimit);
545     *  }
546     *
547     * This allows limits to be nested.  The try/finally ensures that the
548     * limit is reset if something fails.
549     *
550     * Exceeding the limit causes a dalvik.system.AllocationLimitError to
551     * be thrown from a memory allocation call.  The limit is reset to -1
552     * when this happens.
553     *
554     * The feature may be disabled in the VM configuration.  If so, this
555     * call has no effect, and always returns -1.
556     */
557    public static int setAllocationLimit(int limit) {
558        return VMDebug.setAllocationLimit(limit);
559    }
560
561    /**
562     * Establish a global object allocation limit.  This is similar to
563     * {@link #setAllocationLimit(int)} but applies to all threads in
564     * the VM.  It will coexist peacefully with per-thread limits.
565     *
566     * [ The value of "limit" is currently restricted to 0 (no allocations
567     *   allowed) or -1 (no global limit).  This may be changed in a future
568     *   release. ]
569     */
570    public static int setGlobalAllocationLimit(int limit) {
571        if (limit != 0 && limit != -1)
572            throw new IllegalArgumentException("limit must be 0 or -1");
573        return VMDebug.setGlobalAllocationLimit(limit);
574    }
575
576    /**
577     * Dump a list of all currently loaded class to the log file.
578     *
579     * @param flags See constants above.
580     */
581    public static void printLoadedClasses(int flags) {
582        VMDebug.printLoadedClasses(flags);
583    }
584
585    /**
586     * Get the number of loaded classes.
587     * @return the number of loaded classes.
588     */
589    public static int getLoadedClassCount() {
590        return VMDebug.getLoadedClassCount();
591    }
592
593    /**
594     * Dump "hprof" data to the specified file.  This will cause a GC.
595     *
596     * @param fileName Full pathname of output file (e.g. "/sdcard/dump.hprof").
597     * @throws UnsupportedOperationException if the VM was built without
598     *         HPROF support.
599     * @throws IOException if an error occurs while opening or writing files.
600     */
601    public static void dumpHprofData(String fileName) throws IOException {
602        VMDebug.dumpHprofData(fileName);
603    }
604
605    /**
606     * Returns the number of sent transactions from this process.
607     * @return The number of sent transactions or -1 if it could not read t.
608     */
609    public static native int getBinderSentTransactions();
610
611    /**
612     * Returns the number of received transactions from the binder driver.
613     * @return The number of received transactions or -1 if it could not read the stats.
614     */
615    public static native int getBinderReceivedTransactions();
616
617    /**
618     * Returns the number of active local Binder objects that exist in the
619     * current process.
620     */
621    public static final native int getBinderLocalObjectCount();
622
623    /**
624     * Returns the number of references to remote proxy Binder objects that
625     * exist in the current process.
626     */
627    public static final native int getBinderProxyObjectCount();
628
629    /**
630     * Returns the number of death notification links to Binder objects that
631     * exist in the current process.
632     */
633    public static final native int getBinderDeathObjectCount();
634
635    /**
636     * Primes the register map cache.
637     *
638     * Only works for classes in the bootstrap class loader.  Does not
639     * cause classes to be loaded if they're not already present.
640     *
641     * The classAndMethodDesc argument is a concatentation of the VM-internal
642     * class descriptor, method name, and method descriptor.  Examples:
643     *     Landroid/os/Looper;.loop:()V
644     *     Landroid/app/ActivityThread;.main:([Ljava/lang/String;)V
645     *
646     * @param classAndMethodDesc the method to prepare
647     *
648     * @hide
649     */
650    public static final boolean cacheRegisterMap(String classAndMethodDesc) {
651        return VMDebug.cacheRegisterMap(classAndMethodDesc);
652    }
653
654    /**
655     * API for gathering and querying instruction counts.
656     *
657     * Example usage:
658     *   Debug.InstructionCount icount = new Debug.InstructionCount();
659     *   icount.resetAndStart();
660     *    [... do lots of stuff ...]
661     *   if (icount.collect()) {
662     *       System.out.println("Total instructions executed: "
663     *           + icount.globalTotal());
664     *       System.out.println("Method invocations: "
665     *           + icount.globalMethodInvocations());
666     *   }
667     */
668    public static class InstructionCount {
669        private static final int NUM_INSTR = 256;
670
671        private int[] mCounts;
672
673        public InstructionCount() {
674            mCounts = new int[NUM_INSTR];
675        }
676
677        /**
678         * Reset counters and ensure counts are running.  Counts may
679         * have already been running.
680         *
681         * @return true if counting was started
682         */
683        public boolean resetAndStart() {
684            try {
685                VMDebug.startInstructionCounting();
686                VMDebug.resetInstructionCount();
687            } catch (UnsupportedOperationException uoe) {
688                return false;
689            }
690            return true;
691        }
692
693        /**
694         * Collect instruction counts.  May or may not stop the
695         * counting process.
696         */
697        public boolean collect() {
698            try {
699                VMDebug.stopInstructionCounting();
700                VMDebug.getInstructionCount(mCounts);
701            } catch (UnsupportedOperationException uoe) {
702                return false;
703            }
704            return true;
705        }
706
707        /**
708         * Return the total number of instructions executed globally (i.e. in
709         * all threads).
710         */
711        public int globalTotal() {
712            int count = 0;
713            for (int i = 0; i < NUM_INSTR; i++)
714                count += mCounts[i];
715            return count;
716        }
717
718        /**
719         * Return the total number of method-invocation instructions
720         * executed globally.
721         */
722        public int globalMethodInvocations() {
723            int count = 0;
724
725            //count += mCounts[Opcodes.OP_EXECUTE_INLINE];
726            count += mCounts[Opcodes.OP_INVOKE_VIRTUAL];
727            count += mCounts[Opcodes.OP_INVOKE_SUPER];
728            count += mCounts[Opcodes.OP_INVOKE_DIRECT];
729            count += mCounts[Opcodes.OP_INVOKE_STATIC];
730            count += mCounts[Opcodes.OP_INVOKE_INTERFACE];
731            count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_RANGE];
732            count += mCounts[Opcodes.OP_INVOKE_SUPER_RANGE];
733            count += mCounts[Opcodes.OP_INVOKE_DIRECT_RANGE];
734            count += mCounts[Opcodes.OP_INVOKE_STATIC_RANGE];
735            count += mCounts[Opcodes.OP_INVOKE_INTERFACE_RANGE];
736            //count += mCounts[Opcodes.OP_INVOKE_DIRECT_EMPTY];
737            count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK];
738            count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK_RANGE];
739            count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK];
740            count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK_RANGE];
741            return count;
742        }
743    };
744}
745