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 17 package dalvik.system; 18 19 import java.io.FileDescriptor; 20 import java.io.IOException; 21 import java.util.HashMap; 22 import java.util.Map; 23 24 /** 25 * Provides access to some VM-specific debug features. Though this class and 26 * many of its members are public, this class is meant to be wrapped in a more 27 * friendly way for use by application developers. On the Android platform, the 28 * recommended way to access this functionality is through the class 29 * <code>android.os.Debug</code>. 30 * 31 * @hide 32 */ 33 public final class VMDebug { 34 /** 35 * flag for startMethodTracing(), which adds the results from 36 * startAllocCounting to the trace key file. 37 */ 38 public static final int TRACE_COUNT_ALLOCS = 1; 39 40 /* constants for getAllocCount */ 41 private static final int KIND_ALLOCATED_OBJECTS = 1<<0; 42 private static final int KIND_ALLOCATED_BYTES = 1<<1; 43 private static final int KIND_FREED_OBJECTS = 1<<2; 44 private static final int KIND_FREED_BYTES = 1<<3; 45 private static final int KIND_GC_INVOCATIONS = 1<<4; 46 private static final int KIND_CLASS_INIT_COUNT = 1<<5; 47 private static final int KIND_CLASS_INIT_TIME = 1<<6; 48 private static final int KIND_EXT_ALLOCATED_OBJECTS = 1<<12; 49 private static final int KIND_EXT_ALLOCATED_BYTES = 1<<13; 50 private static final int KIND_EXT_FREED_OBJECTS = 1<<14; 51 private static final int KIND_EXT_FREED_BYTES = 1<<15; 52 53 public static final int KIND_GLOBAL_ALLOCATED_OBJECTS = 54 KIND_ALLOCATED_OBJECTS; 55 public static final int KIND_GLOBAL_ALLOCATED_BYTES = 56 KIND_ALLOCATED_BYTES; 57 public static final int KIND_GLOBAL_FREED_OBJECTS = 58 KIND_FREED_OBJECTS; 59 public static final int KIND_GLOBAL_FREED_BYTES = 60 KIND_FREED_BYTES; 61 public static final int KIND_GLOBAL_GC_INVOCATIONS = 62 KIND_GC_INVOCATIONS; 63 public static final int KIND_GLOBAL_CLASS_INIT_COUNT = 64 KIND_CLASS_INIT_COUNT; 65 public static final int KIND_GLOBAL_CLASS_INIT_TIME = 66 KIND_CLASS_INIT_TIME; 67 public static final int KIND_GLOBAL_EXT_ALLOCATED_OBJECTS = 68 KIND_EXT_ALLOCATED_OBJECTS; 69 public static final int KIND_GLOBAL_EXT_ALLOCATED_BYTES = 70 KIND_EXT_ALLOCATED_BYTES; 71 public static final int KIND_GLOBAL_EXT_FREED_OBJECTS = 72 KIND_EXT_FREED_OBJECTS; 73 public static final int KIND_GLOBAL_EXT_FREED_BYTES = 74 KIND_EXT_FREED_BYTES; 75 76 public static final int KIND_THREAD_ALLOCATED_OBJECTS = 77 KIND_ALLOCATED_OBJECTS << 16; 78 public static final int KIND_THREAD_ALLOCATED_BYTES = 79 KIND_ALLOCATED_BYTES << 16; 80 public static final int KIND_THREAD_FREED_OBJECTS = 81 KIND_FREED_OBJECTS << 16; 82 public static final int KIND_THREAD_FREED_BYTES = 83 KIND_FREED_BYTES << 16; 84 public static final int KIND_THREAD_GC_INVOCATIONS = 85 KIND_GC_INVOCATIONS << 16; 86 public static final int KIND_THREAD_CLASS_INIT_COUNT = 87 KIND_CLASS_INIT_COUNT << 16; 88 public static final int KIND_THREAD_CLASS_INIT_TIME = 89 KIND_CLASS_INIT_TIME << 16; 90 public static final int KIND_THREAD_EXT_ALLOCATED_OBJECTS = 91 KIND_EXT_ALLOCATED_OBJECTS << 16; 92 public static final int KIND_THREAD_EXT_ALLOCATED_BYTES = 93 KIND_EXT_ALLOCATED_BYTES << 16; 94 public static final int KIND_THREAD_EXT_FREED_OBJECTS = 95 KIND_EXT_FREED_OBJECTS << 16; 96 public static final int KIND_THREAD_EXT_FREED_BYTES = 97 KIND_EXT_FREED_BYTES << 16; 98 99 public static final int KIND_ALL_COUNTS = 0xffffffff; 100 101 /* all methods are static */ 102 private VMDebug() {} 103 104 /** 105 * Returns the time since the last known debugger activity. 106 * 107 * @return the time in milliseconds, or -1 if the debugger is not connected 108 */ 109 public static native long lastDebuggerActivity(); 110 111 /** 112 * Determines if debugging is enabled in this VM. If debugging is not 113 * enabled, a debugger cannot be attached. 114 * 115 * @return true if debugging is enabled 116 */ 117 public static native boolean isDebuggingEnabled(); 118 119 /** 120 * Determines if a debugger is currently attached. 121 * 122 * @return true if (and only if) a debugger is connected 123 */ 124 public static native boolean isDebuggerConnected(); 125 126 /** 127 * Returns an array of strings that identify VM features. This is 128 * used by DDMS to determine what sorts of operations the VM can 129 * perform. 130 */ 131 public static native String[] getVmFeatureList(); 132 133 /** 134 * Start method tracing with default name, size, and with <code>0</code> 135 * flags. 136 * 137 * @deprecated Not used, not needed. 138 */ 139 @Deprecated 140 public static void startMethodTracing() { 141 throw new UnsupportedOperationException(); 142 } 143 144 /** 145 * Start method tracing, specifying a file name as well as a default 146 * buffer size. See <a 147 * href="{@docRoot}guide/developing/tools/traceview.html"> Running the 148 * Traceview Debugging Program</a> for information about reading 149 * trace files. 150 * 151 * <p>You can use either a fully qualified path and 152 * name, or just a name. If only a name is specified, the file will 153 * be created under the /sdcard/ directory. If a name is not given, 154 * the default is /sdcard/dmtrace.trace.</p> 155 * 156 * @param traceFileName name to give the trace file 157 * @param bufferSize the maximum size of both files combined. If passed 158 * as <code>0</code>, it defaults to 8MB. 159 * @param flags flags to control method tracing. The only one that 160 * is currently defined is {@link #TRACE_COUNT_ALLOCS}. 161 * @param samplingEnabled if true, sample profiling is enabled. Otherwise, 162 * method instrumentation is used. 163 * @param intervalUs the time between samples in microseconds when 164 * sampling is enabled. 165 */ 166 public static void startMethodTracing(String traceFileName, int bufferSize, int flags, boolean samplingEnabled, int intervalUs) { 167 startMethodTracingFilename(traceFileName, checkBufferSize(bufferSize), flags, samplingEnabled, intervalUs); 168 } 169 170 /** 171 * Like startMethodTracing(String, int, int), but taking an already-opened 172 * FileDescriptor in which the trace is written. The file name is also 173 * supplied simply for logging. Makes a dup of the file descriptor. 174 */ 175 public static void startMethodTracing(String traceFileName, FileDescriptor fd, int bufferSize, int flags, boolean samplingEnabled, int intervalUs) { 176 if (fd == null) { 177 throw new NullPointerException("fd == null"); 178 } 179 startMethodTracingFd(traceFileName, fd, checkBufferSize(bufferSize), flags, samplingEnabled, intervalUs); 180 } 181 182 /** 183 * Starts method tracing without a backing file. When stopMethodTracing 184 * is called, the result is sent directly to DDMS. (If DDMS is not 185 * attached when tracing ends, the profiling data will be discarded.) 186 */ 187 public static void startMethodTracingDdms(int bufferSize, int flags, boolean samplingEnabled, int intervalUs) { 188 startMethodTracingDdmsImpl(checkBufferSize(bufferSize), flags, samplingEnabled, intervalUs); 189 } 190 191 private static int checkBufferSize(int bufferSize) { 192 if (bufferSize == 0) { 193 // Default to 8MB per the documentation. 194 bufferSize = 8 * 1024 * 1024; 195 } 196 if (bufferSize < 1024) { 197 throw new IllegalArgumentException("buffer size < 1024: " + bufferSize); 198 } 199 return bufferSize; 200 } 201 202 private static native void startMethodTracingDdmsImpl(int bufferSize, int flags, boolean samplingEnabled, int intervalUs); 203 private static native void startMethodTracingFd(String traceFileName, FileDescriptor fd, int bufferSize, int flags, boolean samplingEnabled, int intervalUs); 204 private static native void startMethodTracingFilename(String traceFileName, int bufferSize, int flags, boolean samplingEnabled, int intervalUs); 205 206 /** 207 * Determine whether method tracing is currently active and what type is 208 * active. 209 */ 210 public static native int getMethodTracingMode(); 211 212 /** 213 * Stops method tracing. 214 */ 215 public static native void stopMethodTracing(); 216 217 /** 218 * Starts sending Dalvik method trace info to the emulator. 219 */ 220 public static native void startEmulatorTracing(); 221 222 /** 223 * Stops sending Dalvik method trace info to the emulator. 224 */ 225 public static native void stopEmulatorTracing(); 226 227 /** 228 * Get an indication of thread CPU usage. The value returned indicates the 229 * amount of time that the current thread has spent executing code or 230 * waiting for certain types of I/O. 231 * <p> 232 * The time is expressed in nanoseconds, and is only meaningful when 233 * compared to the result from an earlier call. Note that nanosecond 234 * resolution does not imply nanosecond accuracy. 235 * 236 * @return the CPU usage. A value of -1 means the system does not support 237 * this feature. 238 */ 239 public static native long threadCpuTimeNanos(); 240 241 /** 242 * Count the number and aggregate size of memory allocations between 243 * two points. 244 */ 245 public static native void startAllocCounting(); 246 public static native void stopAllocCounting(); 247 public static native int getAllocCount(int kind); 248 public static native void resetAllocCount(int kinds); 249 250 /** 251 * This method exists for binary compatibility. It was part of 252 * the allocation limits API which was removed in Android 3.0 (Honeycomb). 253 */ 254 @Deprecated 255 public static int setAllocationLimit(int limit) { 256 return -1; 257 } 258 259 /** 260 * This method exists for binary compatibility. It was part of 261 * the allocation limits API which was removed in Android 3.0 (Honeycomb). 262 */ 263 @Deprecated 264 public static int setGlobalAllocationLimit(int limit) { 265 return -1; 266 } 267 268 /** 269 * Count the number of instructions executed between two points. 270 */ 271 public static native void startInstructionCounting(); 272 public static native void stopInstructionCounting(); 273 public static native void getInstructionCount(int[] counts); 274 public static native void resetInstructionCount(); 275 276 /** 277 * Dumps a list of loaded class to the log file. 278 */ 279 public static native void printLoadedClasses(int flags); 280 281 /** 282 * Gets the number of loaded classes. 283 * 284 * @return the number of loaded classes 285 */ 286 public static native int getLoadedClassCount(); 287 288 /** 289 * Dumps "hprof" data to the specified file. This may cause a GC. 290 * 291 * The VM may create a temporary file in the same directory. 292 * 293 * @param filename Full pathname of output file (e.g. "/sdcard/dump.hprof"). 294 * @throws UnsupportedOperationException if the VM was built without 295 * HPROF support. 296 * @throws IOException if an error occurs while opening or writing files. 297 */ 298 public static void dumpHprofData(String filename) throws IOException { 299 if (filename == null) { 300 throw new NullPointerException("filename == null"); 301 } 302 dumpHprofData(filename, null); 303 } 304 305 /** 306 * Collects "hprof" heap data and sends it to DDMS. This may cause a GC. 307 * 308 * @throws UnsupportedOperationException if the VM was built without 309 * HPROF support. 310 */ 311 public static native void dumpHprofDataDdms(); 312 313 /** 314 * Dumps "hprof" heap data to a file, by name or descriptor. 315 * 316 * @param fileName Name of output file. If fd is non-null, the 317 * file name is only used in log messages (and may be null). 318 * @param fd Descriptor of open file that will receive the output. 319 * If this is null, the fileName is used instead. 320 */ 321 public static native void dumpHprofData(String fileName, FileDescriptor fd) 322 throws IOException; 323 324 /** 325 * Primes the register map cache. 326 */ 327 public static native boolean cacheRegisterMap(String classAndMethodDesc); 328 329 /** 330 * Dumps the contents of the VM reference tables (e.g. JNI locals and 331 * globals) to the log file. 332 */ 333 public static native void dumpReferenceTables(); 334 335 /** 336 * Crashes the VM. Seriously. Dumps the interpreter stack trace for 337 * the current thread and then aborts the VM so you can see the native 338 * stack trace. Useful for figuring out how you got somewhere when 339 * lots of native code is involved. 340 */ 341 public static native void crash(); 342 343 /** 344 * Together with gdb, provide a handy way to stop the VM at user-tagged 345 * locations. 346 */ 347 public static native void infopoint(int id); 348 349 /* 350 * Fake method, inserted into dmtrace output when the garbage collector 351 * runs. Not actually called. 352 */ 353 private static void startGC() {} 354 355 /* 356 * Fake method, inserted into dmtrace output during class preparation 357 * (loading and linking, but not verification or initialization). Not 358 * actually called. 359 */ 360 private static void startClassPrep() {} 361 362 /** 363 * Counts the instances of a class. 364 * It is the caller's responsibility to do GC if they don't want unreachable 365 * objects to get counted. 366 * 367 * @param klass the class to be counted. 368 * @param assignable if false, direct instances of klass are 369 * counted. If true, instances that are 370 * assignable to klass, as defined by 371 * {@link Class#isAssignableFrom} are counted. 372 * @return the number of matching instances. 373 */ 374 public static native long countInstancesOfClass(Class klass, boolean assignable); 375 376 /** 377 * Counts the instances of classes. 378 * It is the caller's responsibility to do GC if they don't want unreachable 379 * objects to get counted. 380 * 381 * @param classes the classes to be counted. 382 * @param assignable if false, direct instances of klass are 383 * counted. If true, instances that are 384 * assignable to klass, as defined by 385 * {@link Class#isAssignableFrom} are counted. 386 * @return an array containing the number of matching instances. The value for 387 * an index is the number of instances of the class at that index in number classes. 388 */ 389 public static native long[] countInstancesOfClasses(Class[] classes, boolean assignable); 390 391 /** 392 * Export the heap per-space stats for dumpsys meminfo. 393 * 394 * The content of the array is: 395 * 396 * <pre> 397 * data[0] : the application heap space size 398 * data[1] : the application heap space allocated bytes 399 * data[2] : the application heap space free bytes 400 * data[3] : the zygote heap space size 401 * data[4] : the zygote heap space allocated size 402 * data[5] : the zygote heap space free size 403 * data[6] : the large object space size 404 * data[7] : the large object space allocated bytes 405 * data[8] : the large object space free bytes 406 * </pre> 407 * 408 * @param data the array into which the stats are written. 409 */ 410 public static native void getHeapSpaceStats(long[] data); 411 412 /* Map from the names of the runtime stats supported by getRuntimeStat() to their IDs */ 413 private static final HashMap<String, Integer> runtimeStatsMap = new HashMap<>(); 414 415 static { 416 runtimeStatsMap.put("art.gc.gc-count", 0); 417 runtimeStatsMap.put("art.gc.gc-time", 1); 418 runtimeStatsMap.put("art.gc.bytes-allocated", 2); 419 runtimeStatsMap.put("art.gc.bytes-freed", 3); 420 runtimeStatsMap.put("art.gc.blocking-gc-count", 4); 421 runtimeStatsMap.put("art.gc.blocking-gc-time", 5); 422 runtimeStatsMap.put("art.gc.gc-count-rate-histogram", 6); 423 runtimeStatsMap.put("art.gc.blocking-gc-count-rate-histogram", 7); 424 } 425 426 /** 427 * Returns the value of a particular runtime statistic or {@code null} if no 428 * such runtime statistic exists. 429 * 430 * @param statName 431 * the name of the runtime statistic to look up. 432 * @return the value of the runtime statistic. 433 */ 434 public static String getRuntimeStat(String statName) { 435 if (statName == null) { 436 throw new NullPointerException("statName == null"); 437 } 438 Integer statId = runtimeStatsMap.get(statName); 439 if (statId != null) { 440 return getRuntimeStatInternal(statId); 441 } 442 return null; 443 } 444 445 /** 446 * Returns a map of the names/values of the runtime statistics 447 * that {@link #getRuntimeStat()} supports. 448 * 449 * @return a map of the names/values of the supported runtime statistics. 450 */ 451 public static Map<String, String> getRuntimeStats() { 452 HashMap<String, String> map = new HashMap<>(); 453 String[] values = getRuntimeStatsInternal(); 454 for (String name : runtimeStatsMap.keySet()) { 455 int id = runtimeStatsMap.get(name); 456 String value = values[id]; 457 map.put(name, value); 458 } 459 return map; 460 } 461 462 private static native String getRuntimeStatInternal(int statId); 463 private static native String[] getRuntimeStatsInternal(); 464 } 465