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