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