Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (C) 2008 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 /*
     18  * dalvik.system.VMDebug
     19  */
     20 #include "Dalvik.h"
     21 #include "alloc/HeapSource.h"
     22 #include "native/InternalNativePriv.h"
     23 #include "hprof/Hprof.h"
     24 
     25 #include <string.h>
     26 #include <unistd.h>
     27 
     28 
     29 /*
     30  * Extracts the fd from a FileDescriptor object.
     31  *
     32  * If an error is encountered, or the extracted descriptor is numerically
     33  * invalid, this returns -1 with an exception raised.
     34  */
     35 static int getFileDescriptor(Object* obj)
     36 {
     37     assert(obj != NULL);
     38     assert(strcmp(obj->clazz->descriptor, "Ljava/io/FileDescriptor;") == 0);
     39 
     40     int fd = dvmGetFieldInt(obj, gDvm.offJavaIoFileDescriptor_descriptor);
     41     if (fd < 0) {
     42         dvmThrowRuntimeException("Invalid file descriptor");
     43         return -1;
     44     }
     45 
     46     return fd;
     47 }
     48 
     49 /*
     50  * static String[] getVmFeatureList()
     51  *
     52  * Return a set of strings describing available VM features (this is chiefly
     53  * of interest to DDMS).
     54  */
     55 static void Dalvik_dalvik_system_VMDebug_getVmFeatureList(const u4* args, JValue* pResult) {
     56     std::vector<std::string> features;
     57     features.push_back("method-trace-profiling");
     58     features.push_back("method-trace-profiling-streaming");
     59     features.push_back("method-sample-profiling");
     60     features.push_back("hprof-heap-dump");
     61     features.push_back("hprof-heap-dump-streaming");
     62 
     63     ArrayObject* result = dvmCreateStringArray(features);
     64     dvmReleaseTrackedAlloc((Object*) result, dvmThreadSelf());
     65     RETURN_PTR(result);
     66 }
     67 
     68 /* These must match the values in dalvik.system.VMDebug.
     69  */
     70 enum {
     71     KIND_ALLOCATED_OBJECTS      = 1<<0,
     72     KIND_ALLOCATED_BYTES        = 1<<1,
     73     KIND_FREED_OBJECTS          = 1<<2,
     74     KIND_FREED_BYTES            = 1<<3,
     75     KIND_GC_INVOCATIONS         = 1<<4,
     76     KIND_CLASS_INIT_COUNT       = 1<<5,
     77     KIND_CLASS_INIT_TIME        = 1<<6,
     78 
     79     /* These values exist for backward compatibility. */
     80     KIND_EXT_ALLOCATED_OBJECTS = 1<<12,
     81     KIND_EXT_ALLOCATED_BYTES   = 1<<13,
     82     KIND_EXT_FREED_OBJECTS     = 1<<14,
     83     KIND_EXT_FREED_BYTES       = 1<<15,
     84 
     85     KIND_GLOBAL_ALLOCATED_OBJECTS   = KIND_ALLOCATED_OBJECTS,
     86     KIND_GLOBAL_ALLOCATED_BYTES     = KIND_ALLOCATED_BYTES,
     87     KIND_GLOBAL_FREED_OBJECTS       = KIND_FREED_OBJECTS,
     88     KIND_GLOBAL_FREED_BYTES         = KIND_FREED_BYTES,
     89     KIND_GLOBAL_GC_INVOCATIONS      = KIND_GC_INVOCATIONS,
     90     KIND_GLOBAL_CLASS_INIT_COUNT    = KIND_CLASS_INIT_COUNT,
     91     KIND_GLOBAL_CLASS_INIT_TIME     = KIND_CLASS_INIT_TIME,
     92 
     93     KIND_THREAD_ALLOCATED_OBJECTS   = KIND_ALLOCATED_OBJECTS << 16,
     94     KIND_THREAD_ALLOCATED_BYTES     = KIND_ALLOCATED_BYTES << 16,
     95     KIND_THREAD_FREED_OBJECTS       = KIND_FREED_OBJECTS << 16,
     96     KIND_THREAD_FREED_BYTES         = KIND_FREED_BYTES << 16,
     97 
     98     KIND_THREAD_GC_INVOCATIONS      = KIND_GC_INVOCATIONS << 16,
     99 
    100     // TODO: failedAllocCount, failedAllocSize
    101 };
    102 
    103 #define KIND_ALL_COUNTS 0xffffffff
    104 
    105 /*
    106  * Zero out the specified fields.
    107  */
    108 static void clearAllocProfStateFields(AllocProfState *allocProf,
    109     unsigned int kinds)
    110 {
    111     if (kinds & KIND_ALLOCATED_OBJECTS) {
    112         allocProf->allocCount = 0;
    113     }
    114     if (kinds & KIND_ALLOCATED_BYTES) {
    115         allocProf->allocSize = 0;
    116     }
    117     if (kinds & KIND_FREED_OBJECTS) {
    118         allocProf->freeCount = 0;
    119     }
    120     if (kinds & KIND_FREED_BYTES) {
    121         allocProf->freeSize = 0;
    122     }
    123     if (kinds & KIND_GC_INVOCATIONS) {
    124         allocProf->gcCount = 0;
    125     }
    126     if (kinds & KIND_CLASS_INIT_COUNT) {
    127         allocProf->classInitCount = 0;
    128     }
    129     if (kinds & KIND_CLASS_INIT_TIME) {
    130         allocProf->classInitTime = 0;
    131     }
    132 }
    133 
    134 /*
    135  * static void startAllocCounting()
    136  *
    137  * Reset the counters and enable counting.
    138  *
    139  * TODO: this currently only resets the per-thread counters for the current
    140  * thread.  If we actually start using the per-thread counters we'll
    141  * probably want to fix this.
    142  */
    143 static void Dalvik_dalvik_system_VMDebug_startAllocCounting(const u4* args,
    144     JValue* pResult)
    145 {
    146     UNUSED_PARAMETER(args);
    147 
    148     clearAllocProfStateFields(&gDvm.allocProf, KIND_ALL_COUNTS);
    149     clearAllocProfStateFields(&dvmThreadSelf()->allocProf, KIND_ALL_COUNTS);
    150     dvmStartAllocCounting();
    151     RETURN_VOID();
    152 }
    153 
    154 /*
    155  * public static void stopAllocCounting()
    156  */
    157 static void Dalvik_dalvik_system_VMDebug_stopAllocCounting(const u4* args,
    158     JValue* pResult)
    159 {
    160     UNUSED_PARAMETER(args);
    161 
    162     dvmStopAllocCounting();
    163     RETURN_VOID();
    164 }
    165 
    166 /*
    167  * private static int getAllocCount(int kind)
    168  */
    169 static void Dalvik_dalvik_system_VMDebug_getAllocCount(const u4* args,
    170     JValue* pResult)
    171 {
    172     AllocProfState *allocProf;
    173     unsigned int kind = args[0];
    174     if (kind < (1<<16)) {
    175         allocProf = &gDvm.allocProf;
    176     } else {
    177         allocProf = &dvmThreadSelf()->allocProf;
    178         kind >>= 16;
    179     }
    180     switch (kind) {
    181     case KIND_ALLOCATED_OBJECTS:
    182         pResult->i = allocProf->allocCount;
    183         break;
    184     case KIND_ALLOCATED_BYTES:
    185         pResult->i = allocProf->allocSize;
    186         break;
    187     case KIND_FREED_OBJECTS:
    188         pResult->i = allocProf->freeCount;
    189         break;
    190     case KIND_FREED_BYTES:
    191         pResult->i = allocProf->freeSize;
    192         break;
    193     case KIND_GC_INVOCATIONS:
    194         pResult->i = allocProf->gcCount;
    195         break;
    196     case KIND_CLASS_INIT_COUNT:
    197         pResult->i = allocProf->classInitCount;
    198         break;
    199     case KIND_CLASS_INIT_TIME:
    200         /* convert nsec to usec, reduce to 32 bits */
    201         pResult->i = (int) (allocProf->classInitTime / 1000);
    202         break;
    203     case KIND_EXT_ALLOCATED_OBJECTS:
    204     case KIND_EXT_ALLOCATED_BYTES:
    205     case KIND_EXT_FREED_OBJECTS:
    206     case KIND_EXT_FREED_BYTES:
    207         pResult->i = 0;  /* backward compatibility */
    208         break;
    209     default:
    210         assert(false);
    211         pResult->i = -1;
    212     }
    213 }
    214 
    215 /*
    216  * public static void resetAllocCount(int kinds)
    217  */
    218 static void Dalvik_dalvik_system_VMDebug_resetAllocCount(const u4* args,
    219     JValue* pResult)
    220 {
    221     unsigned int kinds = args[0];
    222     clearAllocProfStateFields(&gDvm.allocProf, kinds & 0xffff);
    223     clearAllocProfStateFields(&dvmThreadSelf()->allocProf, kinds >> 16);
    224     RETURN_VOID();
    225 }
    226 
    227 /*
    228  * static void startMethodTracingDdmsImpl(int bufferSize, int flags,
    229  *     boolean samplingEnabled, int intervalUs)
    230  *
    231  * Start method trace profiling, sending results directly to DDMS.
    232  */
    233 static void Dalvik_dalvik_system_VMDebug_startMethodTracingDdmsImpl(const u4* args,
    234     JValue* pResult)
    235 {
    236     int bufferSize = args[0];
    237     int flags = args[1];
    238     bool samplingEnabled = args[2];
    239     int intervalUs = args[3];
    240     dvmMethodTraceStart("[DDMS]", -1, bufferSize, flags, true, samplingEnabled,
    241         intervalUs);
    242     RETURN_VOID();
    243 }
    244 
    245 /*
    246  * static void startMethodTracingFd(String traceFileName, FileDescriptor fd,
    247  *     int bufferSize, int flags)
    248  *
    249  * Start method trace profiling, sending results to a file descriptor.
    250  */
    251 static void Dalvik_dalvik_system_VMDebug_startMethodTracingFd(const u4* args,
    252     JValue* pResult)
    253 {
    254     StringObject* traceFileStr = (StringObject*) args[0];
    255     Object* traceFd = (Object*) args[1];
    256     int bufferSize = args[2];
    257     int flags = args[3];
    258 
    259     int origFd = getFileDescriptor(traceFd);
    260     if (origFd < 0)
    261         RETURN_VOID();
    262 
    263     int fd = dup(origFd);
    264     if (fd < 0) {
    265         dvmThrowExceptionFmt(gDvm.exRuntimeException,
    266             "dup(%d) failed: %s", origFd, strerror(errno));
    267         RETURN_VOID();
    268     }
    269 
    270     char* traceFileName = dvmCreateCstrFromString(traceFileStr);
    271     if (traceFileName == NULL) {
    272         RETURN_VOID();
    273     }
    274 
    275     dvmMethodTraceStart(traceFileName, fd, bufferSize, flags, false, false, 0);
    276     free(traceFileName);
    277     RETURN_VOID();
    278 }
    279 
    280 /*
    281  * static void startMethodTracingFilename(String traceFileName, int bufferSize,
    282  *     int flags)
    283  *
    284  * Start method trace profiling, sending results to a file.
    285  */
    286 static void Dalvik_dalvik_system_VMDebug_startMethodTracingFilename(const u4* args,
    287     JValue* pResult)
    288 {
    289     StringObject* traceFileStr = (StringObject*) args[0];
    290     int bufferSize = args[1];
    291     int flags = args[2];
    292 
    293     char* traceFileName = dvmCreateCstrFromString(traceFileStr);
    294     if (traceFileName == NULL) {
    295         RETURN_VOID();
    296     }
    297 
    298     dvmMethodTraceStart(traceFileName, -1, bufferSize, flags, false, false, 0);
    299     free(traceFileName);
    300     RETURN_VOID();
    301 }
    302 
    303 /*
    304  * static int getMethodTracingMode()
    305  *
    306  * Determine whether method tracing is currently active and what type is active.
    307  */
    308 static void Dalvik_dalvik_system_VMDebug_getMethodTracingMode(const u4* args,
    309     JValue* pResult)
    310 {
    311     UNUSED_PARAMETER(args);
    312 
    313     RETURN_INT(dvmGetMethodTracingMode());
    314 }
    315 
    316 /*
    317  * static void stopMethodTracing()
    318  *
    319  * Stop method tracing.
    320  */
    321 static void Dalvik_dalvik_system_VMDebug_stopMethodTracing(const u4* args,
    322     JValue* pResult)
    323 {
    324     UNUSED_PARAMETER(args);
    325 
    326     dvmMethodTraceStop();
    327     RETURN_VOID();
    328 }
    329 
    330 /*
    331  * static void startEmulatorTracing()
    332  *
    333  * Start sending method trace info to the emulator.
    334  */
    335 static void Dalvik_dalvik_system_VMDebug_startEmulatorTracing(const u4* args,
    336     JValue* pResult)
    337 {
    338     UNUSED_PARAMETER(args);
    339 
    340     dvmEmulatorTraceStart();
    341     RETURN_VOID();
    342 }
    343 
    344 /*
    345  * static void stopEmulatorTracing()
    346  *
    347  * Start sending method trace info to the emulator.
    348  */
    349 static void Dalvik_dalvik_system_VMDebug_stopEmulatorTracing(const u4* args,
    350     JValue* pResult)
    351 {
    352     UNUSED_PARAMETER(args);
    353 
    354     dvmEmulatorTraceStop();
    355     RETURN_VOID();
    356 }
    357 
    358 /*
    359  * static boolean isDebuggerConnected()
    360  *
    361  * Returns "true" if a debugger is attached.
    362  */
    363 static void Dalvik_dalvik_system_VMDebug_isDebuggerConnected(const u4* args,
    364     JValue* pResult)
    365 {
    366     UNUSED_PARAMETER(args);
    367 
    368     RETURN_BOOLEAN(dvmDbgIsDebuggerConnected());
    369 }
    370 
    371 /*
    372  * static boolean isDebuggingEnabled()
    373  *
    374  * Returns "true" if debugging is enabled.
    375  */
    376 static void Dalvik_dalvik_system_VMDebug_isDebuggingEnabled(const u4* args,
    377     JValue* pResult)
    378 {
    379     UNUSED_PARAMETER(args);
    380 
    381     RETURN_BOOLEAN(gDvm.jdwpConfigured);
    382 }
    383 
    384 /*
    385  * static long lastDebuggerActivity()
    386  *
    387  * Returns the time, in msec, since we last had an interaction with the
    388  * debugger (send or receive).
    389  */
    390 static void Dalvik_dalvik_system_VMDebug_lastDebuggerActivity(const u4* args,
    391     JValue* pResult)
    392 {
    393     UNUSED_PARAMETER(args);
    394 
    395     RETURN_LONG(dvmDbgLastDebuggerActivity());
    396 }
    397 
    398 /*
    399  * static void startInstructionCounting()
    400  */
    401 static void Dalvik_dalvik_system_VMDebug_startInstructionCounting(const u4* args,
    402     JValue* pResult)
    403 {
    404     dvmStartInstructionCounting();
    405     RETURN_VOID();
    406 }
    407 
    408 /*
    409  * static void stopInstructionCounting()
    410  */
    411 static void Dalvik_dalvik_system_VMDebug_stopInstructionCounting(const u4* args,
    412     JValue* pResult)
    413 {
    414     dvmStopInstructionCounting();
    415     RETURN_VOID();
    416 }
    417 
    418 /*
    419  * static boolean getInstructionCount(int[] counts)
    420  *
    421  * Grab a copy of the global instruction count array.
    422  *
    423  * Since the instruction counts aren't synchronized, we use sched_yield
    424  * to improve our chances of finishing without contention.  (Only makes
    425  * sense on a uniprocessor.)
    426  */
    427 static void Dalvik_dalvik_system_VMDebug_getInstructionCount(const u4* args,
    428     JValue* pResult)
    429 {
    430     ArrayObject* countArray = (ArrayObject*) args[0];
    431 
    432     if (countArray != NULL) {
    433         int* storage = (int*)(void*)countArray->contents;
    434         u4 length = countArray->length;
    435 
    436         /*
    437          * Ensure that we copy at most kNumPackedOpcodes
    438          * elements, but no more than the length of the given array.
    439          */
    440         if (length > kNumPackedOpcodes) {
    441             length = kNumPackedOpcodes;
    442         }
    443 
    444         sched_yield();
    445         memcpy(storage, gDvm.executedInstrCounts, length * sizeof(int));
    446     }
    447 
    448     RETURN_VOID();
    449 }
    450 
    451 /*
    452  * static boolean resetInstructionCount()
    453  *
    454  * Reset the instruction count array.
    455  */
    456 static void Dalvik_dalvik_system_VMDebug_resetInstructionCount(const u4* args,
    457     JValue* pResult)
    458 {
    459     sched_yield();
    460     memset(gDvm.executedInstrCounts, 0, kNumPackedOpcodes * sizeof(int));
    461     RETURN_VOID();
    462 }
    463 
    464 /*
    465  * static void printLoadedClasses(int flags)
    466  *
    467  * Dump the list of loaded classes.
    468  */
    469 static void Dalvik_dalvik_system_VMDebug_printLoadedClasses(const u4* args,
    470     JValue* pResult)
    471 {
    472     int flags = args[0];
    473 
    474     dvmDumpAllClasses(flags);
    475 
    476     RETURN_VOID();
    477 }
    478 
    479 /*
    480  * static int getLoadedClassCount()
    481  *
    482  * Return the number of loaded classes
    483  */
    484 static void Dalvik_dalvik_system_VMDebug_getLoadedClassCount(const u4* args,
    485     JValue* pResult)
    486 {
    487     int count;
    488 
    489     UNUSED_PARAMETER(args);
    490 
    491     count = dvmGetNumLoadedClasses();
    492 
    493     RETURN_INT(count);
    494 }
    495 
    496 /*
    497  * Returns the thread-specific CPU-time clock value for the current thread,
    498  * or -1 if the feature isn't supported.
    499  */
    500 static void Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos(const u4* args,
    501     JValue* pResult)
    502 {
    503     jlong result;
    504 
    505 #ifdef HAVE_POSIX_CLOCKS
    506     struct timespec now;
    507     clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
    508     result = (jlong) (now.tv_sec*1000000000LL + now.tv_nsec);
    509 #else
    510     result = (jlong) -1;
    511 #endif
    512 
    513     RETURN_LONG(result);
    514 }
    515 
    516 /*
    517  * static void dumpHprofData(String fileName, FileDescriptor fd)
    518  *
    519  * Cause "hprof" data to be dumped.  We can throw an IOException if an
    520  * error occurs during file handling.
    521  */
    522 static void Dalvik_dalvik_system_VMDebug_dumpHprofData(const u4* args,
    523     JValue* pResult)
    524 {
    525     StringObject* fileNameStr = (StringObject*) args[0];
    526     Object* fileDescriptor = (Object*) args[1];
    527     char* fileName;
    528     int result;
    529 
    530     /*
    531      * Only one of these may be NULL.
    532      */
    533     if (fileNameStr == NULL && fileDescriptor == NULL) {
    534         dvmThrowNullPointerException("fileName == null && fd == null");
    535         RETURN_VOID();
    536     }
    537 
    538     if (fileNameStr != NULL) {
    539         fileName = dvmCreateCstrFromString(fileNameStr);
    540         if (fileName == NULL) {
    541             /* unexpected -- malloc failure? */
    542             dvmThrowRuntimeException("malloc failure?");
    543             RETURN_VOID();
    544         }
    545     } else {
    546         fileName = strdup("[fd]");
    547     }
    548 
    549     int fd = -1;
    550     if (fileDescriptor != NULL) {
    551         fd = getFileDescriptor(fileDescriptor);
    552         if (fd < 0) {
    553             free(fileName);
    554             RETURN_VOID();
    555         }
    556     }
    557 
    558     result = hprofDumpHeap(fileName, fd, false);
    559     free(fileName);
    560 
    561     if (result != 0) {
    562         /* ideally we'd throw something more specific based on actual failure */
    563         dvmThrowRuntimeException(
    564             "Failure during heap dump; check log output for details");
    565         RETURN_VOID();
    566     }
    567 
    568     RETURN_VOID();
    569 }
    570 
    571 /*
    572  * static void dumpHprofDataDdms()
    573  *
    574  * Cause "hprof" data to be computed and sent directly to DDMS.
    575  */
    576 static void Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms(const u4* args,
    577     JValue* pResult)
    578 {
    579     int result;
    580 
    581     result = hprofDumpHeap("[DDMS]", -1, true);
    582 
    583     if (result != 0) {
    584         /* ideally we'd throw something more specific based on actual failure */
    585         dvmThrowRuntimeException(
    586             "Failure during heap dump; check log output for details");
    587         RETURN_VOID();
    588     }
    589 
    590     RETURN_VOID();
    591 }
    592 
    593 /*
    594  * static boolean cacheRegisterMap(String classAndMethodDescr)
    595  *
    596  * If the specified class is loaded, and the named method exists, ensure
    597  * that the method's register map is ready for use.  If the class/method
    598  * cannot be found, nothing happens.
    599  *
    600  * This can improve the zygote's sharing of compressed register maps.  Do
    601  * this after class preloading.
    602  *
    603  * Returns true if the register map is cached and ready, either as a result
    604  * of this call or earlier activity.  Returns false if the class isn't loaded,
    605  * if the method couldn't be found, or if the method has no register map.
    606  *
    607  * (Uncomment logs in dvmGetExpandedRegisterMap0() to gather stats.)
    608  */
    609 static void Dalvik_dalvik_system_VMDebug_cacheRegisterMap(const u4* args,
    610     JValue* pResult)
    611 {
    612     StringObject* classAndMethodDescStr = (StringObject*) args[0];
    613     ClassObject* clazz;
    614     bool result = false;
    615 
    616     if (classAndMethodDescStr == NULL) {
    617         dvmThrowNullPointerException("classAndMethodDesc == null");
    618         RETURN_VOID();
    619     }
    620 
    621     char* classAndMethodDesc = NULL;
    622 
    623     /*
    624      * Pick the string apart.  We have a local copy, so just modify it
    625      * in place.
    626      */
    627     classAndMethodDesc = dvmCreateCstrFromString(classAndMethodDescStr);
    628 
    629     char* methodName = strchr(classAndMethodDesc, '.');
    630     if (methodName == NULL) {
    631         dvmThrowRuntimeException("method name not found in string");
    632         RETURN_VOID();
    633     }
    634     *methodName++ = '\0';
    635 
    636     char* methodDescr = strchr(methodName, ':');
    637     if (methodDescr == NULL) {
    638         dvmThrowRuntimeException("method descriptor not found in string");
    639         RETURN_VOID();
    640     }
    641     *methodDescr++ = '\0';
    642 
    643     //ALOGD("GOT: %s %s %s", classAndMethodDesc, methodName, methodDescr);
    644 
    645     /*
    646      * Find the class, but only if it's already loaded.
    647      */
    648     clazz = dvmLookupClass(classAndMethodDesc, NULL, false);
    649     if (clazz == NULL) {
    650         ALOGD("Class %s not found in bootstrap loader", classAndMethodDesc);
    651         goto bail;
    652     }
    653 
    654     Method* method;
    655 
    656     /*
    657      * Find the method, which could be virtual or direct, defined directly
    658      * or inherited.
    659      */
    660     if (methodName[0] == '<') {
    661         /*
    662          * Constructor or class initializer.  Only need to examine the
    663          * "direct" list, and don't need to search up the class hierarchy.
    664          */
    665         method = dvmFindDirectMethodByDescriptor(clazz, methodName,
    666                     methodDescr);
    667     } else {
    668         /*
    669          * Try both lists, and scan up the tree.
    670          */
    671         method = dvmFindVirtualMethodHierByDescriptor(clazz, methodName,
    672                     methodDescr);
    673         if (method == NULL) {
    674             method = dvmFindDirectMethodHierByDescriptor(clazz, methodName,
    675                         methodDescr);
    676         }
    677     }
    678 
    679     if (method != NULL) {
    680         /*
    681          * Got it.  See if there's a register map here.
    682          */
    683         const RegisterMap* pMap;
    684         pMap = dvmGetExpandedRegisterMap(method);
    685         if (pMap == NULL) {
    686             ALOGV("No map for %s.%s %s",
    687                 classAndMethodDesc, methodName, methodDescr);
    688         } else {
    689             ALOGV("Found map %s.%s %s",
    690                 classAndMethodDesc, methodName, methodDescr);
    691             result = true;
    692         }
    693     } else {
    694         ALOGV("Unable to find %s.%s %s",
    695             classAndMethodDesc, methodName, methodDescr);
    696     }
    697 
    698 bail:
    699     free(classAndMethodDesc);
    700     RETURN_BOOLEAN(result);
    701 }
    702 
    703 /*
    704  * static void dumpReferenceTables()
    705  */
    706 static void Dalvik_dalvik_system_VMDebug_dumpReferenceTables(const u4* args,
    707     JValue* pResult)
    708 {
    709     UNUSED_PARAMETER(args);
    710     UNUSED_PARAMETER(pResult);
    711 
    712     ALOGI("--- reference table dump ---");
    713     dvmDumpJniReferenceTables();
    714     // could dump thread's internalLocalRefTable, probably not useful
    715     // ditto for thread's jniMonitorRefTable
    716     ALOGI("---");
    717     RETURN_VOID();
    718 }
    719 
    720 /*
    721  * static void crash()
    722  *
    723  * Dump the current thread's interpreted stack and abort the VM.  Useful
    724  * for seeing both interpreted and native stack traces.
    725  *
    726  * (Might want to restrict this to debuggable processes as a security
    727  * measure, or check SecurityManager.checkExit().)
    728  */
    729 static void Dalvik_dalvik_system_VMDebug_crash(const u4* args,
    730     JValue* pResult)
    731 {
    732     UNUSED_PARAMETER(args);
    733     UNUSED_PARAMETER(pResult);
    734 
    735     ALOGW("Crashing VM on request");
    736     dvmDumpThread(dvmThreadSelf(), false);
    737     dvmAbort();
    738 }
    739 
    740 /*
    741  * static void infopoint(int id)
    742  *
    743  * Provide a hook for gdb to hang to so that the VM can be stopped when
    744  * user-tagged source locations are being executed.
    745  */
    746 static void Dalvik_dalvik_system_VMDebug_infopoint(const u4* args,
    747     JValue* pResult)
    748 {
    749     gDvm.nativeDebuggerActive = true;
    750 
    751     ALOGD("VMDebug infopoint %d hit", args[0]);
    752 
    753     gDvm.nativeDebuggerActive = false;
    754     RETURN_VOID();
    755 }
    756 
    757 static void Dalvik_dalvik_system_VMDebug_countInstancesOfClass(const u4* args,
    758     JValue* pResult)
    759 {
    760     ClassObject* clazz = (ClassObject*)args[0];
    761     bool countAssignable = args[1];
    762     if (clazz == NULL) {
    763         RETURN_LONG(0);
    764     }
    765     if (countAssignable) {
    766         size_t count = dvmCountAssignableInstancesOfClass(clazz);
    767         RETURN_LONG((long long)count);
    768     } else {
    769         size_t count = dvmCountInstancesOfClass(clazz);
    770         RETURN_LONG((long long)count);
    771     }
    772 }
    773 
    774 /*
    775  * public static native void getHeapSpaceStats(long[] data)
    776  */
    777 static void Dalvik_dalvik_system_VMDebug_getHeapSpaceStats(const u4* args,
    778     JValue* pResult)
    779 {
    780     ArrayObject* dataArray = (ArrayObject*) args[0];
    781 
    782     if (dataArray == NULL || dataArray->length < 6) {
    783       RETURN_VOID();
    784     }
    785 
    786     jlong* arr = (jlong*)(void*)dataArray->contents;
    787 
    788     int j = 0;
    789     size_t per_heap_allocated[2];
    790     size_t per_heap_size[2];
    791     memset(per_heap_allocated, 0, sizeof(per_heap_allocated));
    792     memset(per_heap_size, 0, sizeof(per_heap_size));
    793     dvmHeapSourceGetValue(HS_BYTES_ALLOCATED, (size_t*) &per_heap_allocated, 2);
    794     dvmHeapSourceGetValue(HS_FOOTPRINT, (size_t*) &per_heap_size, 2);
    795     jlong heapSize = per_heap_size[0];
    796     jlong heapUsed = per_heap_allocated[0];
    797     jlong heapFree = heapSize - heapUsed;
    798     jlong zygoteSize = per_heap_size[1];
    799     jlong zygoteUsed = per_heap_allocated[1];
    800     jlong zygoteFree = zygoteSize - zygoteUsed;
    801     arr[j++] = heapSize;
    802     arr[j++] = heapUsed;
    803     arr[j++] = heapFree;
    804     arr[j++] = zygoteSize;
    805     arr[j++] = zygoteUsed;
    806     arr[j++] = zygoteFree;
    807 
    808     RETURN_VOID();
    809 }
    810 
    811 const DalvikNativeMethod dvm_dalvik_system_VMDebug[] = {
    812     { "getVmFeatureList",           "()[Ljava/lang/String;",
    813         Dalvik_dalvik_system_VMDebug_getVmFeatureList },
    814     { "getAllocCount",              "(I)I",
    815         Dalvik_dalvik_system_VMDebug_getAllocCount },
    816     { "getHeapSpaceStats",          "([J)V",
    817         Dalvik_dalvik_system_VMDebug_getHeapSpaceStats },
    818     { "resetAllocCount",            "(I)V",
    819         Dalvik_dalvik_system_VMDebug_resetAllocCount },
    820     { "startAllocCounting",         "()V",
    821         Dalvik_dalvik_system_VMDebug_startAllocCounting },
    822     { "stopAllocCounting",          "()V",
    823         Dalvik_dalvik_system_VMDebug_stopAllocCounting },
    824     { "startMethodTracingDdmsImpl", "(IIZI)V",
    825         Dalvik_dalvik_system_VMDebug_startMethodTracingDdmsImpl },
    826     { "startMethodTracingFd",       "(Ljava/lang/String;Ljava/io/FileDescriptor;II)V",
    827         Dalvik_dalvik_system_VMDebug_startMethodTracingFd },
    828     { "startMethodTracingFilename", "(Ljava/lang/String;II)V",
    829         Dalvik_dalvik_system_VMDebug_startMethodTracingFilename },
    830     { "getMethodTracingMode",       "()I",
    831         Dalvik_dalvik_system_VMDebug_getMethodTracingMode },
    832     { "stopMethodTracing",          "()V",
    833         Dalvik_dalvik_system_VMDebug_stopMethodTracing },
    834     { "startEmulatorTracing",       "()V",
    835         Dalvik_dalvik_system_VMDebug_startEmulatorTracing },
    836     { "stopEmulatorTracing",        "()V",
    837         Dalvik_dalvik_system_VMDebug_stopEmulatorTracing },
    838     { "startInstructionCounting",   "()V",
    839         Dalvik_dalvik_system_VMDebug_startInstructionCounting },
    840     { "stopInstructionCounting",    "()V",
    841         Dalvik_dalvik_system_VMDebug_stopInstructionCounting },
    842     { "resetInstructionCount",      "()V",
    843         Dalvik_dalvik_system_VMDebug_resetInstructionCount },
    844     { "getInstructionCount",        "([I)V",
    845         Dalvik_dalvik_system_VMDebug_getInstructionCount },
    846     { "isDebuggerConnected",        "()Z",
    847         Dalvik_dalvik_system_VMDebug_isDebuggerConnected },
    848     { "isDebuggingEnabled",         "()Z",
    849         Dalvik_dalvik_system_VMDebug_isDebuggingEnabled },
    850     { "lastDebuggerActivity",       "()J",
    851         Dalvik_dalvik_system_VMDebug_lastDebuggerActivity },
    852     { "printLoadedClasses",         "(I)V",
    853         Dalvik_dalvik_system_VMDebug_printLoadedClasses },
    854     { "getLoadedClassCount",        "()I",
    855         Dalvik_dalvik_system_VMDebug_getLoadedClassCount },
    856     { "threadCpuTimeNanos",         "()J",
    857         Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos },
    858     { "dumpHprofData",              "(Ljava/lang/String;Ljava/io/FileDescriptor;)V",
    859         Dalvik_dalvik_system_VMDebug_dumpHprofData },
    860     { "dumpHprofDataDdms",          "()V",
    861         Dalvik_dalvik_system_VMDebug_dumpHprofDataDdms },
    862     { "cacheRegisterMap",           "(Ljava/lang/String;)Z",
    863         Dalvik_dalvik_system_VMDebug_cacheRegisterMap },
    864     { "dumpReferenceTables",        "()V",
    865         Dalvik_dalvik_system_VMDebug_dumpReferenceTables },
    866     { "crash",                      "()V",
    867         Dalvik_dalvik_system_VMDebug_crash },
    868     { "infopoint",                 "(I)V",
    869         Dalvik_dalvik_system_VMDebug_infopoint },
    870     { "countInstancesOfClass",     "(Ljava/lang/Class;Z)J",
    871         Dalvik_dalvik_system_VMDebug_countInstancesOfClass },
    872     { NULL, NULL, NULL },
    873 };
    874