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