dalvik_system_VMRuntime.cc revision 39c3bfbd03d85c63cfbe69f17ce5800ccc7d6c13
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#include <limits.h> 18 19#include "class_linker-inl.h" 20#include "common_throws.h" 21#include "debugger.h" 22#include "dex_file-inl.h" 23#include "gc/accounting/card_table-inl.h" 24#include "gc/allocator/dlmalloc.h" 25#include "gc/heap.h" 26#include "gc/space/dlmalloc_space.h" 27#include "intern_table.h" 28#include "jni_internal.h" 29#include "mirror/art_method-inl.h" 30#include "mirror/class-inl.h" 31#include "mirror/dex_cache-inl.h" 32#include "mirror/object-inl.h" 33#include "object_utils.h" 34#include "runtime.h" 35#include "scoped_fast_native_object_access.h" 36#include "scoped_thread_state_change.h" 37#include "thread.h" 38#include "thread_list.h" 39#include "toStringArray.h" 40 41namespace art { 42 43static jfloat VMRuntime_getTargetHeapUtilization(JNIEnv*, jobject) { 44 return Runtime::Current()->GetHeap()->GetTargetHeapUtilization(); 45} 46 47static void VMRuntime_nativeSetTargetHeapUtilization(JNIEnv*, jobject, jfloat target) { 48 Runtime::Current()->GetHeap()->SetTargetHeapUtilization(target); 49} 50 51static void VMRuntime_startJitCompilation(JNIEnv*, jobject) { 52} 53 54static void VMRuntime_disableJitCompilation(JNIEnv*, jobject) { 55} 56 57static jobject VMRuntime_newNonMovableArray(JNIEnv* env, jobject, jclass javaElementClass, 58 jint length) { 59 ScopedFastNativeObjectAccess soa(env); 60 if (UNLIKELY(length < 0)) { 61 ThrowNegativeArraySizeException(length); 62 return nullptr; 63 } 64 mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass); 65 if (UNLIKELY(element_class == nullptr)) { 66 ThrowNullPointerException(NULL, "element class == null"); 67 return nullptr; 68 } 69 if (UNLIKELY(element_class->IsPrimitiveVoid())) { 70 ThrowIllegalArgumentException(NULL, "Can't allocate an array of void"); 71 return nullptr; 72 } 73 Runtime* runtime = Runtime::Current(); 74 mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(), element_class); 75 if (UNLIKELY(array_class == nullptr)) { 76 return nullptr; 77 } 78 gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentNonMovingAllocator(); 79 mirror::Array* result = mirror::Array::Alloc<true>(soa.Self(), array_class, length, 80 array_class->GetComponentSize(), allocator); 81 return soa.AddLocalReference<jobject>(result); 82} 83 84static jobject VMRuntime_newUnpaddedArray(JNIEnv* env, jobject, jclass javaElementClass, 85 jint length) { 86 ScopedFastNativeObjectAccess soa(env); 87 if (UNLIKELY(length < 0)) { 88 ThrowNegativeArraySizeException(length); 89 return nullptr; 90 } 91 mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass); 92 if (UNLIKELY(element_class == nullptr)) { 93 ThrowNullPointerException(NULL, "element class == null"); 94 return nullptr; 95 } 96 if (UNLIKELY(element_class->IsPrimitiveVoid())) { 97 ThrowIllegalArgumentException(NULL, "Can't allocate an array of void"); 98 return nullptr; 99 } 100 Runtime* runtime = Runtime::Current(); 101 mirror::Class* array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(), element_class); 102 if (UNLIKELY(array_class == nullptr)) { 103 return nullptr; 104 } 105 gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator(); 106 mirror::Array* result = mirror::Array::Alloc<true>(soa.Self(), array_class, length, 107 array_class->GetComponentSize(), allocator, 108 true); 109 return soa.AddLocalReference<jobject>(result); 110} 111 112static jlong VMRuntime_addressOf(JNIEnv* env, jobject, jobject javaArray) { 113 if (javaArray == NULL) { // Most likely allocation failed 114 return 0; 115 } 116 ScopedFastNativeObjectAccess soa(env); 117 mirror::Array* array = soa.Decode<mirror::Array*>(javaArray); 118 if (!array->IsArrayInstance()) { 119 ThrowIllegalArgumentException(NULL, "not an array"); 120 return 0; 121 } 122 if (Runtime::Current()->GetHeap()->IsMovableObject(array)) { 123 ThrowRuntimeException("Trying to get address of movable array object"); 124 return 0; 125 } 126 return reinterpret_cast<uintptr_t>(array->GetRawData(array->GetClass()->GetComponentSize(), 0)); 127} 128 129static void VMRuntime_clearGrowthLimit(JNIEnv*, jobject) { 130 Runtime::Current()->GetHeap()->ClearGrowthLimit(); 131} 132 133static jboolean VMRuntime_isDebuggerActive(JNIEnv*, jobject) { 134 return Dbg::IsDebuggerActive(); 135} 136 137static jobjectArray VMRuntime_properties(JNIEnv* env, jobject) { 138 return toStringArray(env, Runtime::Current()->GetProperties()); 139} 140 141// This is for backward compatibility with dalvik which returned the 142// meaningless "." when no boot classpath or classpath was 143// specified. Unfortunately, some tests were using java.class.path to 144// lookup relative file locations, so they are counting on this to be 145// ".", presumably some applications or libraries could have as well. 146static const char* DefaultToDot(const std::string& class_path) { 147 return class_path.empty() ? "." : class_path.c_str(); 148} 149 150static jstring VMRuntime_bootClassPath(JNIEnv* env, jobject) { 151 return env->NewStringUTF(DefaultToDot(Runtime::Current()->GetBootClassPathString())); 152} 153 154static jstring VMRuntime_classPath(JNIEnv* env, jobject) { 155 return env->NewStringUTF(DefaultToDot(Runtime::Current()->GetClassPathString())); 156} 157 158static jstring VMRuntime_vmVersion(JNIEnv* env, jobject) { 159 return env->NewStringUTF(Runtime::GetVersion()); 160} 161 162static jstring VMRuntime_vmLibrary(JNIEnv* env, jobject) { 163 return env->NewStringUTF(kIsDebugBuild ? "libartd.so" : "libart.so"); 164} 165 166static void VMRuntime_setTargetSdkVersionNative(JNIEnv* env, jobject, jint targetSdkVersion) { 167 // This is the target SDK version of the app we're about to run. 168 // Note that targetSdkVersion may be CUR_DEVELOPMENT (10000). 169 // Note that targetSdkVersion may be 0, meaning "current". 170 if (targetSdkVersion > 0 && targetSdkVersion <= 13 /* honeycomb-mr2 */) { 171 Runtime* runtime = Runtime::Current(); 172 JavaVMExt* vm = runtime->GetJavaVM(); 173 if (vm->check_jni) { 174 LOG(INFO) << "CheckJNI enabled: not enabling JNI app bug workarounds."; 175 } else { 176 LOG(INFO) << "Turning on JNI app bug workarounds for target SDK version " 177 << targetSdkVersion << "..."; 178 179 vm->work_around_app_jni_bugs = true; 180 LOG(WARNING) << "Permenantly disabling heap compaction due to jni workarounds"; 181 Runtime::Current()->GetHeap()->DisableCompaction(); 182 } 183 } 184} 185 186static void VMRuntime_registerNativeAllocation(JNIEnv* env, jobject, jint bytes) { 187 if (UNLIKELY(bytes < 0)) { 188 ScopedObjectAccess soa(env); 189 ThrowRuntimeException("allocation size negative %d", bytes); 190 return; 191 } 192 Runtime::Current()->GetHeap()->RegisterNativeAllocation(env, bytes); 193} 194 195static void VMRuntime_registerNativeFree(JNIEnv* env, jobject, jint bytes) { 196 if (UNLIKELY(bytes < 0)) { 197 ScopedObjectAccess soa(env); 198 ThrowRuntimeException("allocation size negative %d", bytes); 199 return; 200 } 201 Runtime::Current()->GetHeap()->RegisterNativeFree(env, bytes); 202} 203 204static void VMRuntime_updateProcessState(JNIEnv* env, jobject, jint process_state) { 205 Runtime::Current()->GetHeap()->UpdateProcessState(static_cast<gc::ProcessState>(process_state)); 206 Runtime::Current()->UpdateProfilerState(process_state); 207} 208 209static void VMRuntime_trimHeap(JNIEnv*, jobject) { 210 Runtime::Current()->GetHeap()->DoPendingTransitionOrTrim(); 211} 212 213static void VMRuntime_concurrentGC(JNIEnv* env, jobject) { 214 Runtime::Current()->GetHeap()->ConcurrentGC(ThreadForEnv(env)); 215} 216 217typedef std::map<std::string, mirror::String*> StringTable; 218 219static void PreloadDexCachesStringsCallback(mirror::Object** root, void* arg, 220 uint32_t /*thread_id*/, RootType /*root_type*/) 221 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 222 StringTable& table = *reinterpret_cast<StringTable*>(arg); 223 mirror::String* string = const_cast<mirror::Object*>(*root)->AsString(); 224 table[string->ToModifiedUtf8()] = string; 225} 226 227// Based on ClassLinker::ResolveString. 228static void PreloadDexCachesResolveString(SirtRef<mirror::DexCache>& dex_cache, uint32_t string_idx, 229 StringTable& strings) 230 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 231 mirror::String* string = dex_cache->GetResolvedString(string_idx); 232 if (string != NULL) { 233 return; 234 } 235 const DexFile* dex_file = dex_cache->GetDexFile(); 236 const char* utf8 = dex_file->StringDataByIdx(string_idx); 237 string = strings[utf8]; 238 if (string == NULL) { 239 return; 240 } 241 // LOG(INFO) << "VMRuntime.preloadDexCaches resolved string=" << utf8; 242 dex_cache->SetResolvedString(string_idx, string); 243} 244 245// Based on ClassLinker::ResolveType. 246static void PreloadDexCachesResolveType(mirror::DexCache* dex_cache, uint32_t type_idx) 247 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 248 mirror::Class* klass = dex_cache->GetResolvedType(type_idx); 249 if (klass != NULL) { 250 return; 251 } 252 const DexFile* dex_file = dex_cache->GetDexFile(); 253 const char* class_name = dex_file->StringByTypeIdx(type_idx); 254 ClassLinker* linker = Runtime::Current()->GetClassLinker(); 255 if (class_name[1] == '\0') { 256 klass = linker->FindPrimitiveClass(class_name[0]); 257 } else { 258 klass = linker->LookupClass(class_name, NULL); 259 } 260 if (klass == NULL) { 261 return; 262 } 263 // LOG(INFO) << "VMRuntime.preloadDexCaches resolved klass=" << class_name; 264 dex_cache->SetResolvedType(type_idx, klass); 265 // Skip uninitialized classes because filled static storage entry implies it is initialized. 266 if (!klass->IsInitialized()) { 267 // LOG(INFO) << "VMRuntime.preloadDexCaches uninitialized klass=" << class_name; 268 return; 269 } 270 // LOG(INFO) << "VMRuntime.preloadDexCaches static storage klass=" << class_name; 271} 272 273// Based on ClassLinker::ResolveField. 274static void PreloadDexCachesResolveField(SirtRef<mirror::DexCache>& dex_cache, 275 uint32_t field_idx, 276 bool is_static) 277 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 278 mirror::ArtField* field = dex_cache->GetResolvedField(field_idx); 279 if (field != NULL) { 280 return; 281 } 282 const DexFile* dex_file = dex_cache->GetDexFile(); 283 const DexFile::FieldId& field_id = dex_file->GetFieldId(field_idx); 284 mirror::Class* klass = dex_cache->GetResolvedType(field_id.class_idx_); 285 if (klass == NULL) { 286 return; 287 } 288 if (is_static) { 289 field = klass->FindStaticField(dex_cache.get(), field_idx); 290 } else { 291 field = klass->FindInstanceField(dex_cache.get(), field_idx); 292 } 293 if (field == NULL) { 294 return; 295 } 296 // LOG(INFO) << "VMRuntime.preloadDexCaches resolved field " << PrettyField(field); 297 dex_cache->SetResolvedField(field_idx, field); 298} 299 300// Based on ClassLinker::ResolveMethod. 301static void PreloadDexCachesResolveMethod(SirtRef<mirror::DexCache>& dex_cache, 302 uint32_t method_idx, 303 InvokeType invoke_type) 304 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 305 mirror::ArtMethod* method = dex_cache->GetResolvedMethod(method_idx); 306 if (method != NULL) { 307 return; 308 } 309 const DexFile* dex_file = dex_cache->GetDexFile(); 310 const DexFile::MethodId& method_id = dex_file->GetMethodId(method_idx); 311 mirror::Class* klass = dex_cache->GetResolvedType(method_id.class_idx_); 312 if (klass == NULL) { 313 return; 314 } 315 switch (invoke_type) { 316 case kDirect: 317 case kStatic: 318 method = klass->FindDirectMethod(dex_cache.get(), method_idx); 319 break; 320 case kInterface: 321 method = klass->FindInterfaceMethod(dex_cache.get(), method_idx); 322 break; 323 case kSuper: 324 case kVirtual: 325 method = klass->FindVirtualMethod(dex_cache.get(), method_idx); 326 break; 327 default: 328 LOG(FATAL) << "Unreachable - invocation type: " << invoke_type; 329 } 330 if (method == NULL) { 331 return; 332 } 333 // LOG(INFO) << "VMRuntime.preloadDexCaches resolved method " << PrettyMethod(method); 334 dex_cache->SetResolvedMethod(method_idx, method); 335} 336 337struct DexCacheStats { 338 uint32_t num_strings; 339 uint32_t num_types; 340 uint32_t num_fields; 341 uint32_t num_methods; 342 DexCacheStats() : num_strings(0), 343 num_types(0), 344 num_fields(0), 345 num_methods(0) {} 346}; 347 348static const bool kPreloadDexCachesEnabled = true; 349 350// Disabled because it takes a long time (extra half second) but 351// gives almost no benefit in terms of saving private dirty pages. 352static const bool kPreloadDexCachesStrings = false; 353 354static const bool kPreloadDexCachesTypes = true; 355static const bool kPreloadDexCachesFieldsAndMethods = true; 356 357static const bool kPreloadDexCachesCollectStats = true; 358 359static void PreloadDexCachesStatsTotal(DexCacheStats* total) { 360 if (!kPreloadDexCachesCollectStats) { 361 return; 362 } 363 364 ClassLinker* linker = Runtime::Current()->GetClassLinker(); 365 const std::vector<const DexFile*>& boot_class_path = linker->GetBootClassPath(); 366 for (size_t i = 0; i< boot_class_path.size(); i++) { 367 const DexFile* dex_file = boot_class_path[i]; 368 CHECK(dex_file != NULL); 369 total->num_strings += dex_file->NumStringIds(); 370 total->num_fields += dex_file->NumFieldIds(); 371 total->num_methods += dex_file->NumMethodIds(); 372 total->num_types += dex_file->NumTypeIds(); 373 } 374} 375 376static void PreloadDexCachesStatsFilled(DexCacheStats* filled) 377 SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { 378 if (!kPreloadDexCachesCollectStats) { 379 return; 380 } 381 ClassLinker* linker = Runtime::Current()->GetClassLinker(); 382 const std::vector<const DexFile*>& boot_class_path = linker->GetBootClassPath(); 383 for (size_t i = 0; i< boot_class_path.size(); i++) { 384 const DexFile* dex_file = boot_class_path[i]; 385 CHECK(dex_file != NULL); 386 mirror::DexCache* dex_cache = linker->FindDexCache(*dex_file); 387 for (size_t i = 0; i < dex_cache->NumStrings(); i++) { 388 mirror::String* string = dex_cache->GetResolvedString(i); 389 if (string != NULL) { 390 filled->num_strings++; 391 } 392 } 393 for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) { 394 mirror::Class* klass = dex_cache->GetResolvedType(i); 395 if (klass != NULL) { 396 filled->num_types++; 397 } 398 } 399 for (size_t i = 0; i < dex_cache->NumResolvedFields(); i++) { 400 mirror::ArtField* field = dex_cache->GetResolvedField(i); 401 if (field != NULL) { 402 filled->num_fields++; 403 } 404 } 405 for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) { 406 mirror::ArtMethod* method = dex_cache->GetResolvedMethod(i); 407 if (method != NULL) { 408 filled->num_methods++; 409 } 410 } 411 } 412} 413 414// TODO: http://b/11309598 This code was ported over based on the 415// Dalvik version. However, ART has similar code in other places such 416// as the CompilerDriver. This code could probably be refactored to 417// serve both uses. 418static void VMRuntime_preloadDexCaches(JNIEnv* env, jobject) { 419 if (!kPreloadDexCachesEnabled) { 420 return; 421 } 422 423 ScopedObjectAccess soa(env); 424 425 DexCacheStats total; 426 DexCacheStats before; 427 if (kPreloadDexCachesCollectStats) { 428 LOG(INFO) << "VMRuntime.preloadDexCaches starting"; 429 PreloadDexCachesStatsTotal(&total); 430 PreloadDexCachesStatsFilled(&before); 431 } 432 433 Runtime* runtime = Runtime::Current(); 434 ClassLinker* linker = runtime->GetClassLinker(); 435 Thread* self = ThreadForEnv(env); 436 437 // We use a std::map to avoid heap allocating StringObjects to lookup in gDvm.literalStrings 438 StringTable strings; 439 if (kPreloadDexCachesStrings) { 440 runtime->GetInternTable()->VisitRoots(PreloadDexCachesStringsCallback, &strings, 441 kVisitRootFlagAllRoots); 442 } 443 444 const std::vector<const DexFile*>& boot_class_path = linker->GetBootClassPath(); 445 for (size_t i = 0; i< boot_class_path.size(); i++) { 446 const DexFile* dex_file = boot_class_path[i]; 447 CHECK(dex_file != NULL); 448 SirtRef<mirror::DexCache> dex_cache(self, linker->FindDexCache(*dex_file)); 449 450 if (kPreloadDexCachesStrings) { 451 for (size_t i = 0; i < dex_cache->NumStrings(); i++) { 452 PreloadDexCachesResolveString(dex_cache, i, strings); 453 } 454 } 455 456 if (kPreloadDexCachesTypes) { 457 for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) { 458 PreloadDexCachesResolveType(dex_cache.get(), i); 459 } 460 } 461 462 if (kPreloadDexCachesFieldsAndMethods) { 463 for (size_t class_def_index = 0; 464 class_def_index < dex_file->NumClassDefs(); 465 class_def_index++) { 466 const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); 467 const byte* class_data = dex_file->GetClassData(class_def); 468 if (class_data == NULL) { 469 continue; 470 } 471 ClassDataItemIterator it(*dex_file, class_data); 472 for (; it.HasNextStaticField(); it.Next()) { 473 uint32_t field_idx = it.GetMemberIndex(); 474 PreloadDexCachesResolveField(dex_cache, field_idx, true); 475 } 476 for (; it.HasNextInstanceField(); it.Next()) { 477 uint32_t field_idx = it.GetMemberIndex(); 478 PreloadDexCachesResolveField(dex_cache, field_idx, false); 479 } 480 for (; it.HasNextDirectMethod(); it.Next()) { 481 uint32_t method_idx = it.GetMemberIndex(); 482 InvokeType invoke_type = it.GetMethodInvokeType(class_def); 483 PreloadDexCachesResolveMethod(dex_cache, method_idx, invoke_type); 484 } 485 for (; it.HasNextVirtualMethod(); it.Next()) { 486 uint32_t method_idx = it.GetMemberIndex(); 487 InvokeType invoke_type = it.GetMethodInvokeType(class_def); 488 PreloadDexCachesResolveMethod(dex_cache, method_idx, invoke_type); 489 } 490 } 491 } 492 } 493 494 if (kPreloadDexCachesCollectStats) { 495 DexCacheStats after; 496 PreloadDexCachesStatsFilled(&after); 497 LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches strings total=%d before=%d after=%d", 498 total.num_strings, before.num_strings, after.num_strings); 499 LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches types total=%d before=%d after=%d", 500 total.num_types, before.num_types, after.num_types); 501 LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches fields total=%d before=%d after=%d", 502 total.num_fields, before.num_fields, after.num_fields); 503 LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches methods total=%d before=%d after=%d", 504 total.num_methods, before.num_methods, after.num_methods); 505 LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches finished"); 506 } 507} 508 509 510/* 511 * This is called by the framework when it knows the application directory and 512 * process name. We use this information to start up the sampling profiler for 513 * for ART. 514 */ 515static void VMRuntime_registerAppInfo(JNIEnv* env, jclass, jstring pkgName, jstring appDir, jstring procName) { 516 const char *pkgNameChars = env->GetStringUTFChars(pkgName, NULL); 517 const char *appDirChars = env->GetStringUTFChars(appDir, NULL); 518 const char *procNameChars = env->GetStringUTFChars(procName, NULL); 519 520 std::string profileFile = StringPrintf("/data/dalvik-cache/profiles/%s", pkgNameChars); 521 Runtime::Current()->StartProfiler(profileFile.c_str(), procNameChars); 522 env->ReleaseStringUTFChars(appDir, appDirChars); 523 env->ReleaseStringUTFChars(procName, procNameChars); 524 env->ReleaseStringUTFChars(pkgName, pkgNameChars); 525} 526 527static JNINativeMethod gMethods[] = { 528 NATIVE_METHOD(VMRuntime, addressOf, "!(Ljava/lang/Object;)J"), 529 NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"), 530 NATIVE_METHOD(VMRuntime, classPath, "()Ljava/lang/String;"), 531 NATIVE_METHOD(VMRuntime, clearGrowthLimit, "()V"), 532 NATIVE_METHOD(VMRuntime, concurrentGC, "()V"), 533 NATIVE_METHOD(VMRuntime, disableJitCompilation, "()V"), 534 NATIVE_METHOD(VMRuntime, getTargetHeapUtilization, "()F"), 535 NATIVE_METHOD(VMRuntime, isDebuggerActive, "()Z"), 536 NATIVE_METHOD(VMRuntime, nativeSetTargetHeapUtilization, "(F)V"), 537 NATIVE_METHOD(VMRuntime, newNonMovableArray, "!(Ljava/lang/Class;I)Ljava/lang/Object;"), 538 NATIVE_METHOD(VMRuntime, newUnpaddedArray, "!(Ljava/lang/Class;I)Ljava/lang/Object;"), 539 NATIVE_METHOD(VMRuntime, properties, "()[Ljava/lang/String;"), 540 NATIVE_METHOD(VMRuntime, setTargetSdkVersionNative, "(I)V"), 541 NATIVE_METHOD(VMRuntime, registerNativeAllocation, "(I)V"), 542 NATIVE_METHOD(VMRuntime, registerNativeFree, "(I)V"), 543 NATIVE_METHOD(VMRuntime, updateProcessState, "(I)V"), 544 NATIVE_METHOD(VMRuntime, startJitCompilation, "()V"), 545 NATIVE_METHOD(VMRuntime, trimHeap, "()V"), 546 NATIVE_METHOD(VMRuntime, vmVersion, "()Ljava/lang/String;"), 547 NATIVE_METHOD(VMRuntime, vmLibrary, "()Ljava/lang/String;"), 548 NATIVE_METHOD(VMRuntime, preloadDexCaches, "()V"), 549 NATIVE_METHOD(VMRuntime, registerAppInfo, "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"), 550}; 551 552void register_dalvik_system_VMRuntime(JNIEnv* env) { 553 REGISTER_NATIVE_METHODS("dalvik/system/VMRuntime"); 554} 555 556} // namespace art 557