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