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