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