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