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.VMRuntime
     19  */
     20 #include "Dalvik.h"
     21 #include "ScopedPthreadMutexLock.h"
     22 #include "UniquePtr.h"
     23 #include "alloc/HeapSource.h"
     24 #include "alloc/Visit.h"
     25 #include "libdex/DexClass.h"
     26 #include "native/InternalNativePriv.h"
     27 
     28 #include <limits.h>
     29 
     30 #include <map>
     31 
     32 /*
     33  * public native float getTargetHeapUtilization()
     34  *
     35  * Gets the current ideal heap utilization, represented as a number
     36  * between zero and one.
     37  */
     38 static void Dalvik_dalvik_system_VMRuntime_getTargetHeapUtilization(
     39     const u4* args, JValue* pResult)
     40 {
     41     UNUSED_PARAMETER(args);
     42 
     43     RETURN_FLOAT(dvmGetTargetHeapUtilization());
     44 }
     45 
     46 /*
     47  * native float nativeSetTargetHeapUtilization()
     48  *
     49  * Sets the current ideal heap utilization, represented as a number
     50  * between zero and one.  Returns the old utilization.
     51  *
     52  * Note that this is NOT static.
     53  */
     54 static void Dalvik_dalvik_system_VMRuntime_nativeSetTargetHeapUtilization(
     55     const u4* args, JValue* pResult)
     56 {
     57     dvmSetTargetHeapUtilization(dvmU4ToFloat(args[1]));
     58 
     59     RETURN_VOID();
     60 }
     61 
     62 /*
     63  * public native void startJitCompilation()
     64  *
     65  * Callback function from the framework to indicate that an app has gone
     66  * through the startup phase and it is time to enable the JIT compiler.
     67  */
     68 static void Dalvik_dalvik_system_VMRuntime_startJitCompilation(const u4* args,
     69     JValue* pResult)
     70 {
     71 #if defined(WITH_JIT)
     72     if (gDvm.executionMode == kExecutionModeJit && gDvmJit.disableJit == false) {
     73         ScopedPthreadMutexLock lock(&gDvmJit.compilerLock);
     74         gDvmJit.alreadyEnabledViaFramework = true;
     75         pthread_cond_signal(&gDvmJit.compilerQueueActivity);
     76     }
     77 #endif
     78     RETURN_VOID();
     79 }
     80 
     81 /*
     82  * public native void disableJitCompilation()
     83  *
     84  * Callback function from the framework to indicate that a VM instance wants to
     85  * permanently disable the JIT compiler. Currently only the system server uses
     86  * this interface when it detects system-wide safe mode is enabled.
     87  */
     88 static void Dalvik_dalvik_system_VMRuntime_disableJitCompilation(const u4* args,
     89     JValue* pResult)
     90 {
     91 #if defined(WITH_JIT)
     92     if (gDvm.executionMode == kExecutionModeJit) {
     93         gDvmJit.disableJit = true;
     94     }
     95 #endif
     96     RETURN_VOID();
     97 }
     98 
     99 static void Dalvik_dalvik_system_VMRuntime_newNonMovableArray(const u4* args,
    100     JValue* pResult)
    101 {
    102     ClassObject* elementClass = (ClassObject*) args[1];
    103     int length = args[2];
    104 
    105     if (elementClass == NULL) {
    106         dvmThrowNullPointerException("elementClass == null");
    107         RETURN_VOID();
    108     }
    109     if (length < 0) {
    110         dvmThrowNegativeArraySizeException(length);
    111         RETURN_VOID();
    112     }
    113 
    114     // TODO: right now, we don't have a copying collector, so there's no need
    115     // to do anything special here, but we ought to pass the non-movability
    116     // through to the allocator.
    117     ClassObject* arrayClass = dvmFindArrayClassForElement(elementClass);
    118     ArrayObject* newArray = dvmAllocArrayByClass(arrayClass,
    119                                                  length,
    120                                                  ALLOC_NON_MOVING);
    121     if (newArray == NULL) {
    122         assert(dvmCheckException(dvmThreadSelf()));
    123         RETURN_VOID();
    124     }
    125     dvmReleaseTrackedAlloc((Object*) newArray, NULL);
    126 
    127     RETURN_PTR(newArray);
    128 }
    129 
    130 static void Dalvik_dalvik_system_VMRuntime_addressOf(const u4* args,
    131     JValue* pResult)
    132 {
    133     ArrayObject* array = (ArrayObject*) args[1];
    134     if (!dvmIsArray(array)) {
    135         dvmThrowIllegalArgumentException(NULL);
    136         RETURN_VOID();
    137     }
    138     // TODO: we should also check that this is a non-movable array.
    139     s8 result = (uintptr_t) array->contents;
    140     RETURN_LONG(result);
    141 }
    142 
    143 static void Dalvik_dalvik_system_VMRuntime_clearGrowthLimit(const u4* args,
    144     JValue* pResult)
    145 {
    146     dvmClearGrowthLimit();
    147     RETURN_VOID();
    148 }
    149 
    150 static void Dalvik_dalvik_system_VMRuntime_isDebuggerActive(
    151     const u4* args, JValue* pResult)
    152 {
    153     RETURN_BOOLEAN(gDvm.debuggerActive || gDvm.nativeDebuggerActive);
    154 }
    155 
    156 static void Dalvik_dalvik_system_VMRuntime_properties(const u4* args,
    157     JValue* pResult)
    158 {
    159     ArrayObject* result = dvmCreateStringArray(*gDvm.properties);
    160     dvmReleaseTrackedAlloc((Object*) result, dvmThreadSelf());
    161     RETURN_PTR(result);
    162 }
    163 
    164 static void returnCString(JValue* pResult, const char* s)
    165 {
    166     Object* result = (Object*) dvmCreateStringFromCstr(s);
    167     dvmReleaseTrackedAlloc(result, dvmThreadSelf());
    168     RETURN_PTR(result);
    169 }
    170 
    171 static void Dalvik_dalvik_system_VMRuntime_bootClassPath(const u4* args,
    172     JValue* pResult)
    173 {
    174     returnCString(pResult, gDvm.bootClassPathStr);
    175 }
    176 
    177 static void Dalvik_dalvik_system_VMRuntime_classPath(const u4* args,
    178     JValue* pResult)
    179 {
    180     returnCString(pResult, gDvm.classPathStr);
    181 }
    182 
    183 static void Dalvik_dalvik_system_VMRuntime_vmVersion(const u4* args,
    184     JValue* pResult)
    185 {
    186     char buf[64];
    187     sprintf(buf, "%d.%d.%d",
    188             DALVIK_MAJOR_VERSION, DALVIK_MINOR_VERSION, DALVIK_BUG_VERSION);
    189     returnCString(pResult, buf);
    190 }
    191 
    192 static void Dalvik_dalvik_system_VMRuntime_vmLibrary(const u4* args,
    193     JValue* pResult)
    194 {
    195     returnCString(pResult, "libdvm.so");
    196 }
    197 
    198 static void Dalvik_dalvik_system_VMRuntime_setTargetSdkVersion(const u4* args,
    199     JValue* pResult)
    200 {
    201     // This is the target SDK version of the app we're about to run.
    202     // Note that this value may be CUR_DEVELOPMENT (10000).
    203     // Note that this value may be 0, meaning "current".
    204     int targetSdkVersion = args[1];
    205     if (targetSdkVersion > 0 && targetSdkVersion <= 13 /* honeycomb-mr2 */) {
    206         if (gDvmJni.useCheckJni) {
    207             ALOGI("CheckJNI enabled: not enabling JNI app bug workarounds.");
    208         } else {
    209             ALOGI("Enabling JNI app bug workarounds for target SDK version %i...",
    210                   targetSdkVersion);
    211             gDvmJni.workAroundAppJniBugs = true;
    212         }
    213     }
    214     RETURN_VOID();
    215 }
    216 
    217 static void Dalvik_dalvik_system_VMRuntime_registerNativeAllocation(const u4* args,
    218                                                                     JValue* pResult)
    219 {
    220   int bytes = args[1];
    221   if (bytes < 0) {
    222     dvmThrowRuntimeException("allocation size negative");
    223   } else {
    224     dvmHeapSourceRegisterNativeAllocation(bytes);
    225   }
    226   RETURN_VOID();
    227 }
    228 
    229 static void Dalvik_dalvik_system_VMRuntime_registerNativeFree(const u4* args,
    230                                                               JValue* pResult)
    231 {
    232   int bytes = args[1];
    233   if (bytes < 0) {
    234     dvmThrowRuntimeException("allocation size negative");
    235   } else {
    236     dvmHeapSourceRegisterNativeFree(bytes);
    237   }
    238   RETURN_VOID();
    239 }
    240 
    241 static DvmDex* getDvmDexFromClassPathEntry(ClassPathEntry* cpe) {
    242     if (cpe->kind == kCpeDex) {
    243         return ((RawDexFile*) cpe->ptr)->pDvmDex;
    244     }
    245     if (cpe->kind == kCpeJar) {
    246         return ((JarFile*) cpe->ptr)->pDvmDex;
    247     }
    248     LOG_ALWAYS_FATAL("Unknown cpe->kind=%d", cpe->kind);
    249 }
    250 
    251 typedef std::map<std::string, StringObject*> StringTable;
    252 
    253 static void preloadDexCachesStringsVisitor(void* addr, u4 threadId, RootType type, void* arg) {
    254     StringTable& table = *(StringTable*) arg;
    255     StringObject* strObj = *(StringObject**) addr;
    256     LOG_FATAL_IF(strObj->clazz != gDvm.classJavaLangString, "Unknown class for supposed string");
    257     char* newStr = dvmCreateCstrFromString(strObj);
    258     // ALOGI("VMRuntime.preloadDexCaches interned=%s", newStr);
    259     table[newStr] = strObj;
    260     free(newStr);
    261 }
    262 
    263 // Based on dvmResolveString.
    264 static void preloadDexCachesResolveString(DvmDex* pDvmDex,
    265                                           uint32_t stringIdx,
    266                                           StringTable& strings) {
    267     StringObject* string = dvmDexGetResolvedString(pDvmDex, stringIdx);
    268     if (string != NULL) {
    269         return;
    270     }
    271     const DexFile* pDexFile = pDvmDex->pDexFile;
    272     uint32_t utf16Size;
    273     const char* utf8 = dexStringAndSizeById(pDexFile, stringIdx, &utf16Size);
    274     string = strings[utf8];
    275     if (string == NULL) {
    276         return;
    277     }
    278     // ALOGI("VMRuntime.preloadDexCaches found string=%s", utf8);
    279     dvmDexSetResolvedString(pDvmDex, stringIdx, string);
    280 }
    281 
    282 // Based on dvmResolveClass.
    283 static void preloadDexCachesResolveType(DvmDex* pDvmDex, uint32_t typeIdx) {
    284     ClassObject* clazz = dvmDexGetResolvedClass(pDvmDex, typeIdx);
    285     if (clazz != NULL) {
    286         return;
    287     }
    288     const DexFile* pDexFile = pDvmDex->pDexFile;
    289     const char* className = dexStringByTypeIdx(pDexFile, typeIdx);
    290     if (className[0] != '\0' && className[1] == '\0') {
    291         /* primitive type */
    292         clazz = dvmFindPrimitiveClass(className[0]);
    293     } else {
    294         clazz = dvmLookupClass(className, NULL, true);
    295     }
    296     if (clazz == NULL) {
    297         return;
    298     }
    299     // Skip uninitialized classes because filled cache entry implies it is initialized.
    300     if (!dvmIsClassInitialized(clazz)) {
    301         // ALOGI("VMRuntime.preloadDexCaches uninitialized clazz=%s", className);
    302         return;
    303     }
    304     // ALOGI("VMRuntime.preloadDexCaches found clazz=%s", className);
    305     dvmDexSetResolvedClass(pDvmDex, typeIdx, clazz);
    306 }
    307 
    308 // Based on dvmResolveInstField/dvmResolveStaticField.
    309 static void preloadDexCachesResolveField(DvmDex* pDvmDex, uint32_t fieldIdx, bool instance) {
    310     Field* field = dvmDexGetResolvedField(pDvmDex, fieldIdx);
    311     if (field != NULL) {
    312         return;
    313     }
    314     const DexFile* pDexFile = pDvmDex->pDexFile;
    315     const DexFieldId* pFieldId = dexGetFieldId(pDexFile, fieldIdx);
    316     ClassObject* clazz = dvmDexGetResolvedClass(pDvmDex, pFieldId->classIdx);
    317     if (clazz == NULL) {
    318         return;
    319     }
    320     // Skip static fields for uninitialized classes because a filled
    321     // cache entry implies the class is initialized.
    322     if (!instance && !dvmIsClassInitialized(clazz)) {
    323         return;
    324     }
    325     const char* fieldName = dexStringById(pDexFile, pFieldId->nameIdx);
    326     const char* signature = dexStringByTypeIdx(pDexFile, pFieldId->typeIdx);
    327     if (instance) {
    328         field = dvmFindInstanceFieldHier(clazz, fieldName, signature);
    329     } else {
    330         field = dvmFindStaticFieldHier(clazz, fieldName, signature);
    331     }
    332     if (field == NULL) {
    333         return;
    334     }
    335     // ALOGI("VMRuntime.preloadDexCaches found field %s %s.%s",
    336     //       signature, clazz->descriptor, fieldName);
    337     dvmDexSetResolvedField(pDvmDex, fieldIdx, field);
    338 }
    339 
    340 // Based on dvmResolveMethod.
    341 static void preloadDexCachesResolveMethod(DvmDex* pDvmDex,
    342                                           uint32_t methodIdx,
    343                                           MethodType methodType) {
    344     Method* method = dvmDexGetResolvedMethod(pDvmDex, methodIdx);
    345     if (method != NULL) {
    346         return;
    347     }
    348     const DexFile* pDexFile = pDvmDex->pDexFile;
    349     const DexMethodId* pMethodId = dexGetMethodId(pDexFile, methodIdx);
    350     ClassObject* clazz = dvmDexGetResolvedClass(pDvmDex, pMethodId->classIdx);
    351     if (clazz == NULL) {
    352         return;
    353     }
    354     // Skip static methods for uninitialized classes because a filled
    355     // cache entry implies the class is initialized.
    356     if ((methodType == METHOD_STATIC) && !dvmIsClassInitialized(clazz)) {
    357         return;
    358     }
    359     const char* methodName = dexStringById(pDexFile, pMethodId->nameIdx);
    360     DexProto proto;
    361     dexProtoSetFromMethodId(&proto, pDexFile, pMethodId);
    362 
    363     if (methodType == METHOD_DIRECT) {
    364         method = dvmFindDirectMethod(clazz, methodName, &proto);
    365     } else if (methodType == METHOD_STATIC) {
    366         method = dvmFindDirectMethodHier(clazz, methodName, &proto);
    367     } else {
    368         method = dvmFindVirtualMethodHier(clazz, methodName, &proto);
    369     }
    370     if (method == NULL) {
    371         return;
    372     }
    373     // ALOGI("VMRuntime.preloadDexCaches found method %s.%s",
    374     //        clazz->descriptor, methodName);
    375     dvmDexSetResolvedMethod(pDvmDex, methodIdx, method);
    376 }
    377 
    378 struct DexCacheStats {
    379     uint32_t numStrings;
    380     uint32_t numTypes;
    381     uint32_t numFields;
    382     uint32_t numMethods;
    383     DexCacheStats() : numStrings(0), numTypes(0), numFields(0), numMethods(0) {};
    384 };
    385 
    386 static const bool kPreloadDexCachesEnabled = true;
    387 
    388 // Disabled because it takes a long time (extra half second) but
    389 // gives almost no benefit in terms of saving private dirty pages.
    390 static const bool kPreloadDexCachesStrings = false;
    391 
    392 static const bool kPreloadDexCachesTypes = true;
    393 static const bool kPreloadDexCachesFieldsAndMethods = true;
    394 
    395 static const bool kPreloadDexCachesCollectStats = false;
    396 
    397 static void preloadDexCachesStatsTotal(DexCacheStats* total) {
    398     if (!kPreloadDexCachesCollectStats) {
    399         return;
    400     }
    401 
    402     for (ClassPathEntry* cpe = gDvm.bootClassPath; cpe->kind != kCpeLastEntry; cpe++) {
    403         DvmDex* pDvmDex = getDvmDexFromClassPathEntry(cpe);
    404         const DexHeader* pHeader = pDvmDex->pHeader;
    405         total->numStrings += pHeader->stringIdsSize;
    406         total->numFields += pHeader->fieldIdsSize;
    407         total->numMethods += pHeader->methodIdsSize;
    408         total->numTypes += pHeader->typeIdsSize;
    409     }
    410 }
    411 
    412 static void preloadDexCachesStatsFilled(DexCacheStats* filled) {
    413     if (!kPreloadDexCachesCollectStats) {
    414         return;
    415     }
    416     for (ClassPathEntry* cpe = gDvm.bootClassPath; cpe->kind != kCpeLastEntry; cpe++) {
    417         DvmDex* pDvmDex = getDvmDexFromClassPathEntry(cpe);
    418         const DexHeader* pHeader = pDvmDex->pHeader;
    419         for (size_t i = 0; i < pHeader->stringIdsSize; i++) {
    420             StringObject* string = dvmDexGetResolvedString(pDvmDex, i);
    421             if (string != NULL) {
    422                 filled->numStrings++;
    423             }
    424         }
    425         for (size_t i = 0; i < pHeader->typeIdsSize; i++) {
    426             ClassObject* clazz = dvmDexGetResolvedClass(pDvmDex, i);
    427             if (clazz != NULL) {
    428                 filled->numTypes++;
    429             }
    430         }
    431         for (size_t i = 0; i < pHeader->fieldIdsSize; i++) {
    432             Field* field = dvmDexGetResolvedField(pDvmDex, i);
    433             if (field != NULL) {
    434                 filled->numFields++;
    435             }
    436         }
    437         for (size_t i = 0; i < pHeader->methodIdsSize; i++) {
    438             Method* method = dvmDexGetResolvedMethod(pDvmDex, i);
    439             if (method != NULL) {
    440                 filled->numMethods++;
    441             }
    442         }
    443     }
    444 }
    445 
    446 static void Dalvik_dalvik_system_VMRuntime_preloadDexCaches(const u4* args, JValue* pResult)
    447 {
    448     if (!kPreloadDexCachesEnabled) {
    449         return;
    450     }
    451 
    452     DexCacheStats total;
    453     DexCacheStats before;
    454     if (kPreloadDexCachesCollectStats) {
    455         ALOGI("VMRuntime.preloadDexCaches starting");
    456         preloadDexCachesStatsTotal(&total);
    457         preloadDexCachesStatsFilled(&before);
    458     }
    459 
    460     // We use a std::map to avoid heap allocating StringObjects to lookup in gDvm.literalStrings
    461     StringTable strings;
    462     if (kPreloadDexCachesStrings) {
    463         dvmLockMutex(&gDvm.internLock);
    464         dvmHashTableLock(gDvm.literalStrings);
    465         for (int i = 0; i < gDvm.literalStrings->tableSize; ++i) {
    466             HashEntry *entry = &gDvm.literalStrings->pEntries[i];
    467             if (entry->data != NULL && entry->data != HASH_TOMBSTONE) {
    468                 preloadDexCachesStringsVisitor(&entry->data, 0, ROOT_INTERNED_STRING, &strings);
    469             }
    470         }
    471         dvmHashTableUnlock(gDvm.literalStrings);
    472         dvmUnlockMutex(&gDvm.internLock);
    473     }
    474 
    475     for (ClassPathEntry* cpe = gDvm.bootClassPath; cpe->kind != kCpeLastEntry; cpe++) {
    476         DvmDex* pDvmDex = getDvmDexFromClassPathEntry(cpe);
    477         const DexHeader* pHeader = pDvmDex->pHeader;
    478         const DexFile* pDexFile = pDvmDex->pDexFile;
    479 
    480         if (kPreloadDexCachesStrings) {
    481             for (size_t i = 0; i < pHeader->stringIdsSize; i++) {
    482                 preloadDexCachesResolveString(pDvmDex, i, strings);
    483             }
    484         }
    485 
    486         if (kPreloadDexCachesTypes) {
    487             for (size_t i = 0; i < pHeader->typeIdsSize; i++) {
    488                 preloadDexCachesResolveType(pDvmDex, i);
    489             }
    490         }
    491 
    492         if (kPreloadDexCachesFieldsAndMethods) {
    493             for (size_t classDefIndex = 0;
    494                  classDefIndex < pHeader->classDefsSize;
    495                  classDefIndex++) {
    496                 const DexClassDef* pClassDef = dexGetClassDef(pDexFile, classDefIndex);
    497                 const u1* pEncodedData = dexGetClassData(pDexFile, pClassDef);
    498                 UniquePtr<DexClassData> pClassData(dexReadAndVerifyClassData(&pEncodedData, NULL));
    499                 if (pClassData.get() == NULL) {
    500                     continue;
    501                 }
    502                 for (uint32_t fieldIndex = 0;
    503                      fieldIndex < pClassData->header.staticFieldsSize;
    504                      fieldIndex++) {
    505                     const DexField* pField = &pClassData->staticFields[fieldIndex];
    506                     preloadDexCachesResolveField(pDvmDex, pField->fieldIdx, false);
    507                 }
    508                 for (uint32_t fieldIndex = 0;
    509                      fieldIndex < pClassData->header.instanceFieldsSize;
    510                      fieldIndex++) {
    511                     const DexField* pField = &pClassData->instanceFields[fieldIndex];
    512                     preloadDexCachesResolveField(pDvmDex, pField->fieldIdx, true);
    513                 }
    514                 for (uint32_t methodIndex = 0;
    515                      methodIndex < pClassData->header.directMethodsSize;
    516                      methodIndex++) {
    517                     const DexMethod* pDexMethod = &pClassData->directMethods[methodIndex];
    518                     MethodType methodType = (((pDexMethod->accessFlags & ACC_STATIC) != 0) ?
    519                                              METHOD_STATIC :
    520                                              METHOD_DIRECT);
    521                     preloadDexCachesResolveMethod(pDvmDex, pDexMethod->methodIdx, methodType);
    522                 }
    523                 for (uint32_t methodIndex = 0;
    524                      methodIndex < pClassData->header.virtualMethodsSize;
    525                      methodIndex++) {
    526                     const DexMethod* pDexMethod = &pClassData->virtualMethods[methodIndex];
    527                     preloadDexCachesResolveMethod(pDvmDex, pDexMethod->methodIdx, METHOD_VIRTUAL);
    528                 }
    529             }
    530         }
    531     }
    532 
    533     if (kPreloadDexCachesCollectStats) {
    534         DexCacheStats after;
    535         preloadDexCachesStatsFilled(&after);
    536         ALOGI("VMRuntime.preloadDexCaches strings total=%d before=%d after=%d",
    537               total.numStrings, before.numStrings, after.numStrings);
    538         ALOGI("VMRuntime.preloadDexCaches types total=%d before=%d after=%d",
    539               total.numTypes, before.numTypes, after.numTypes);
    540         ALOGI("VMRuntime.preloadDexCaches fields total=%d before=%d after=%d",
    541               total.numFields, before.numFields, after.numFields);
    542         ALOGI("VMRuntime.preloadDexCaches methods total=%d before=%d after=%d",
    543               total.numMethods, before.numMethods, after.numMethods);
    544         ALOGI("VMRuntime.preloadDexCaches finished");
    545     }
    546 
    547     RETURN_VOID();
    548 }
    549 
    550 const DalvikNativeMethod dvm_dalvik_system_VMRuntime[] = {
    551     { "addressOf", "(Ljava/lang/Object;)J",
    552         Dalvik_dalvik_system_VMRuntime_addressOf },
    553     { "bootClassPath", "()Ljava/lang/String;",
    554         Dalvik_dalvik_system_VMRuntime_bootClassPath },
    555     { "classPath", "()Ljava/lang/String;",
    556         Dalvik_dalvik_system_VMRuntime_classPath },
    557     { "clearGrowthLimit", "()V",
    558         Dalvik_dalvik_system_VMRuntime_clearGrowthLimit },
    559     { "disableJitCompilation", "()V",
    560         Dalvik_dalvik_system_VMRuntime_disableJitCompilation },
    561     { "isDebuggerActive", "()Z",
    562         Dalvik_dalvik_system_VMRuntime_isDebuggerActive },
    563     { "getTargetHeapUtilization", "()F",
    564         Dalvik_dalvik_system_VMRuntime_getTargetHeapUtilization },
    565     { "nativeSetTargetHeapUtilization", "(F)V",
    566         Dalvik_dalvik_system_VMRuntime_nativeSetTargetHeapUtilization },
    567     { "newNonMovableArray", "(Ljava/lang/Class;I)Ljava/lang/Object;",
    568         Dalvik_dalvik_system_VMRuntime_newNonMovableArray },
    569     { "properties", "()[Ljava/lang/String;",
    570         Dalvik_dalvik_system_VMRuntime_properties },
    571     { "setTargetSdkVersion", "(I)V",
    572         Dalvik_dalvik_system_VMRuntime_setTargetSdkVersion },
    573     { "startJitCompilation", "()V",
    574         Dalvik_dalvik_system_VMRuntime_startJitCompilation },
    575     { "vmVersion", "()Ljava/lang/String;",
    576         Dalvik_dalvik_system_VMRuntime_vmVersion },
    577     { "vmLibrary", "()Ljava/lang/String;",
    578         Dalvik_dalvik_system_VMRuntime_vmLibrary },
    579     { "registerNativeAllocation", "(I)V",
    580         Dalvik_dalvik_system_VMRuntime_registerNativeAllocation },
    581     { "registerNativeFree", "(I)V",
    582         Dalvik_dalvik_system_VMRuntime_registerNativeFree },
    583     { "preloadDexCaches", "()V",
    584         Dalvik_dalvik_system_VMRuntime_preloadDexCaches },
    585     { NULL, NULL, NULL },
    586 };
    587