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