• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
Dalvik_dalvik_system_VMRuntime_getTargetHeapUtilization(const u4 * args,JValue * pResult)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  */
Dalvik_dalvik_system_VMRuntime_nativeSetTargetHeapUtilization(const u4 * args,JValue * pResult)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  */
Dalvik_dalvik_system_VMRuntime_startJitCompilation(const u4 * args,JValue * pResult)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  */
Dalvik_dalvik_system_VMRuntime_disableJitCompilation(const u4 * args,JValue * pResult)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 
Dalvik_dalvik_system_VMRuntime_newNonMovableArray(const u4 * args,JValue * pResult)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 
Dalvik_dalvik_system_VMRuntime_addressOf(const u4 * args,JValue * pResult)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 
Dalvik_dalvik_system_VMRuntime_clearGrowthLimit(const u4 * args,JValue * pResult)143 static void Dalvik_dalvik_system_VMRuntime_clearGrowthLimit(const u4* args,
144     JValue* pResult)
145 {
146     dvmClearGrowthLimit();
147     RETURN_VOID();
148 }
149 
Dalvik_dalvik_system_VMRuntime_isDebuggerActive(const u4 * args,JValue * pResult)150 static void Dalvik_dalvik_system_VMRuntime_isDebuggerActive(
151     const u4* args, JValue* pResult)
152 {
153     RETURN_BOOLEAN(gDvm.debuggerActive || gDvm.nativeDebuggerActive);
154 }
155 
Dalvik_dalvik_system_VMRuntime_properties(const u4 * args,JValue * pResult)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 
returnCString(JValue * pResult,const char * s)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 
Dalvik_dalvik_system_VMRuntime_bootClassPath(const u4 * args,JValue * pResult)171 static void Dalvik_dalvik_system_VMRuntime_bootClassPath(const u4* args,
172     JValue* pResult)
173 {
174     returnCString(pResult, gDvm.bootClassPathStr);
175 }
176 
Dalvik_dalvik_system_VMRuntime_classPath(const u4 * args,JValue * pResult)177 static void Dalvik_dalvik_system_VMRuntime_classPath(const u4* args,
178     JValue* pResult)
179 {
180     returnCString(pResult, gDvm.classPathStr);
181 }
182 
Dalvik_dalvik_system_VMRuntime_vmVersion(const u4 * args,JValue * pResult)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 
Dalvik_dalvik_system_VMRuntime_vmLibrary(const u4 * args,JValue * pResult)192 static void Dalvik_dalvik_system_VMRuntime_vmLibrary(const u4* args,
193     JValue* pResult)
194 {
195     returnCString(pResult, "libdvm.so");
196 }
197 
Dalvik_dalvik_system_VMRuntime_setTargetSdkVersion(const u4 * args,JValue * pResult)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 
Dalvik_dalvik_system_VMRuntime_registerNativeAllocation(const u4 * args,JValue * pResult)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 
Dalvik_dalvik_system_VMRuntime_registerNativeFree(const u4 * args,JValue * pResult)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 
getDvmDexFromClassPathEntry(ClassPathEntry * cpe)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 
preloadDexCachesStringsVisitor(void * addr,u4 threadId,RootType type,void * arg)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.
preloadDexCachesResolveString(DvmDex * pDvmDex,uint32_t stringIdx,StringTable & strings)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.
preloadDexCachesResolveType(DvmDex * pDvmDex,uint32_t typeIdx)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.
preloadDexCachesResolveField(DvmDex * pDvmDex,uint32_t fieldIdx,bool instance)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.
preloadDexCachesResolveMethod(DvmDex * pDvmDex,uint32_t methodIdx,MethodType methodType)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;
DexCacheStatsDexCacheStats383     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 
preloadDexCachesStatsTotal(DexCacheStats * total)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 
preloadDexCachesStatsFilled(DexCacheStats * filled)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 
Dalvik_dalvik_system_VMRuntime_preloadDexCaches(const u4 * args,JValue * pResult)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