• 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 #include "dalvik_system_VMRuntime.h"
18 
19 #ifdef ART_TARGET_ANDROID
20 #include <sys/time.h>
21 #include <sys/resource.h>
22 extern "C" void android_set_application_target_sdk_version(uint32_t version);
23 #endif
24 #include <limits.h>
25 #include <ScopedUtfChars.h>
26 
27 #pragma GCC diagnostic push
28 #pragma GCC diagnostic ignored "-Wshadow"
29 #include "toStringArray.h"
30 #pragma GCC diagnostic pop
31 
32 #include "android-base/stringprintf.h"
33 
34 #include "art_method-inl.h"
35 #include "arch/instruction_set.h"
36 #include "base/enums.h"
37 #include "class_linker-inl.h"
38 #include "common_throws.h"
39 #include "debugger.h"
40 #include "dex_file-inl.h"
41 #include "dex_file_types.h"
42 #include "gc/accounting/card_table-inl.h"
43 #include "gc/allocator/dlmalloc.h"
44 #include "gc/heap.h"
45 #include "gc/space/dlmalloc_space.h"
46 #include "gc/space/image_space.h"
47 #include "gc/task_processor.h"
48 #include "intern_table.h"
49 #include "java_vm_ext.h"
50 #include "jni_internal.h"
51 #include "mirror/class-inl.h"
52 #include "mirror/dex_cache-inl.h"
53 #include "mirror/object-inl.h"
54 #include "runtime.h"
55 #include "scoped_fast_native_object_access-inl.h"
56 #include "scoped_thread_state_change-inl.h"
57 #include "thread.h"
58 #include "thread_list.h"
59 
60 namespace art {
61 
62 using android::base::StringPrintf;
63 
VMRuntime_getTargetHeapUtilization(JNIEnv *,jobject)64 static jfloat VMRuntime_getTargetHeapUtilization(JNIEnv*, jobject) {
65   return Runtime::Current()->GetHeap()->GetTargetHeapUtilization();
66 }
67 
VMRuntime_nativeSetTargetHeapUtilization(JNIEnv *,jobject,jfloat target)68 static void VMRuntime_nativeSetTargetHeapUtilization(JNIEnv*, jobject, jfloat target) {
69   Runtime::Current()->GetHeap()->SetTargetHeapUtilization(target);
70 }
71 
VMRuntime_startJitCompilation(JNIEnv *,jobject)72 static void VMRuntime_startJitCompilation(JNIEnv*, jobject) {
73 }
74 
VMRuntime_disableJitCompilation(JNIEnv *,jobject)75 static void VMRuntime_disableJitCompilation(JNIEnv*, jobject) {
76 }
77 
VMRuntime_newNonMovableArray(JNIEnv * env,jobject,jclass javaElementClass,jint length)78 static jobject VMRuntime_newNonMovableArray(JNIEnv* env, jobject, jclass javaElementClass,
79                                             jint length) {
80   ScopedFastNativeObjectAccess soa(env);
81   if (UNLIKELY(length < 0)) {
82     ThrowNegativeArraySizeException(length);
83     return nullptr;
84   }
85   ObjPtr<mirror::Class> element_class = soa.Decode<mirror::Class>(javaElementClass);
86   if (UNLIKELY(element_class == nullptr)) {
87     ThrowNullPointerException("element class == null");
88     return nullptr;
89   }
90   Runtime* runtime = Runtime::Current();
91   ObjPtr<mirror::Class> array_class =
92       runtime->GetClassLinker()->FindArrayClass(soa.Self(), &element_class);
93   if (UNLIKELY(array_class == nullptr)) {
94     return nullptr;
95   }
96   gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentNonMovingAllocator();
97   ObjPtr<mirror::Array> result = mirror::Array::Alloc<true>(soa.Self(),
98                                                             array_class,
99                                                             length,
100                                                             array_class->GetComponentSizeShift(),
101                                                             allocator);
102   return soa.AddLocalReference<jobject>(result);
103 }
104 
VMRuntime_newUnpaddedArray(JNIEnv * env,jobject,jclass javaElementClass,jint length)105 static jobject VMRuntime_newUnpaddedArray(JNIEnv* env, jobject, jclass javaElementClass,
106                                           jint length) {
107   ScopedFastNativeObjectAccess soa(env);
108   if (UNLIKELY(length < 0)) {
109     ThrowNegativeArraySizeException(length);
110     return nullptr;
111   }
112   ObjPtr<mirror::Class> element_class = soa.Decode<mirror::Class>(javaElementClass);
113   if (UNLIKELY(element_class == nullptr)) {
114     ThrowNullPointerException("element class == null");
115     return nullptr;
116   }
117   Runtime* runtime = Runtime::Current();
118   ObjPtr<mirror::Class> array_class = runtime->GetClassLinker()->FindArrayClass(soa.Self(),
119                                                                                 &element_class);
120   if (UNLIKELY(array_class == nullptr)) {
121     return nullptr;
122   }
123   gc::AllocatorType allocator = runtime->GetHeap()->GetCurrentAllocator();
124   ObjPtr<mirror::Array> result = mirror::Array::Alloc<true, true>(
125       soa.Self(),
126       array_class,
127       length,
128       array_class->GetComponentSizeShift(),
129       allocator);
130   return soa.AddLocalReference<jobject>(result);
131 }
132 
VMRuntime_addressOf(JNIEnv * env,jobject,jobject javaArray)133 static jlong VMRuntime_addressOf(JNIEnv* env, jobject, jobject javaArray) {
134   if (javaArray == nullptr) {  // Most likely allocation failed
135     return 0;
136   }
137   ScopedFastNativeObjectAccess soa(env);
138   ObjPtr<mirror::Array> array = soa.Decode<mirror::Array>(javaArray);
139   if (!array->IsArrayInstance()) {
140     ThrowIllegalArgumentException("not an array");
141     return 0;
142   }
143   if (Runtime::Current()->GetHeap()->IsMovableObject(array)) {
144     ThrowRuntimeException("Trying to get address of movable array object");
145     return 0;
146   }
147   return reinterpret_cast<uintptr_t>(array->GetRawData(array->GetClass()->GetComponentSize(), 0));
148 }
149 
VMRuntime_clearGrowthLimit(JNIEnv *,jobject)150 static void VMRuntime_clearGrowthLimit(JNIEnv*, jobject) {
151   Runtime::Current()->GetHeap()->ClearGrowthLimit();
152 }
153 
VMRuntime_clampGrowthLimit(JNIEnv *,jobject)154 static void VMRuntime_clampGrowthLimit(JNIEnv*, jobject) {
155   Runtime::Current()->GetHeap()->ClampGrowthLimit();
156 }
157 
VMRuntime_isDebuggerActive(JNIEnv *,jobject)158 static jboolean VMRuntime_isDebuggerActive(JNIEnv*, jobject) {
159   return Dbg::IsDebuggerActive();
160 }
161 
VMRuntime_isNativeDebuggable(JNIEnv *,jobject)162 static jboolean VMRuntime_isNativeDebuggable(JNIEnv*, jobject) {
163   return Runtime::Current()->IsNativeDebuggable();
164 }
165 
VMRuntime_properties(JNIEnv * env,jobject)166 static jobjectArray VMRuntime_properties(JNIEnv* env, jobject) {
167   return toStringArray(env, Runtime::Current()->GetProperties());
168 }
169 
170 // This is for backward compatibility with dalvik which returned the
171 // meaningless "." when no boot classpath or classpath was
172 // specified. Unfortunately, some tests were using java.class.path to
173 // lookup relative file locations, so they are counting on this to be
174 // ".", presumably some applications or libraries could have as well.
DefaultToDot(const std::string & class_path)175 static const char* DefaultToDot(const std::string& class_path) {
176   return class_path.empty() ? "." : class_path.c_str();
177 }
178 
VMRuntime_bootClassPath(JNIEnv * env,jobject)179 static jstring VMRuntime_bootClassPath(JNIEnv* env, jobject) {
180   return env->NewStringUTF(DefaultToDot(Runtime::Current()->GetBootClassPathString()));
181 }
182 
VMRuntime_classPath(JNIEnv * env,jobject)183 static jstring VMRuntime_classPath(JNIEnv* env, jobject) {
184   return env->NewStringUTF(DefaultToDot(Runtime::Current()->GetClassPathString()));
185 }
186 
VMRuntime_vmVersion(JNIEnv * env,jobject)187 static jstring VMRuntime_vmVersion(JNIEnv* env, jobject) {
188   return env->NewStringUTF(Runtime::GetVersion());
189 }
190 
VMRuntime_vmLibrary(JNIEnv * env,jobject)191 static jstring VMRuntime_vmLibrary(JNIEnv* env, jobject) {
192   return env->NewStringUTF(kIsDebugBuild ? "libartd.so" : "libart.so");
193 }
194 
VMRuntime_vmInstructionSet(JNIEnv * env,jobject)195 static jstring VMRuntime_vmInstructionSet(JNIEnv* env, jobject) {
196   InstructionSet isa = Runtime::Current()->GetInstructionSet();
197   const char* isa_string = GetInstructionSetString(isa);
198   return env->NewStringUTF(isa_string);
199 }
200 
VMRuntime_is64Bit(JNIEnv *,jobject)201 static jboolean VMRuntime_is64Bit(JNIEnv*, jobject) {
202   bool is64BitMode = (sizeof(void*) == sizeof(uint64_t));
203   return is64BitMode ? JNI_TRUE : JNI_FALSE;
204 }
205 
VMRuntime_isCheckJniEnabled(JNIEnv * env,jobject)206 static jboolean VMRuntime_isCheckJniEnabled(JNIEnv* env, jobject) {
207   return down_cast<JNIEnvExt*>(env)->vm->IsCheckJniEnabled() ? JNI_TRUE : JNI_FALSE;
208 }
209 
VMRuntime_setTargetSdkVersionNative(JNIEnv *,jobject,jint target_sdk_version)210 static void VMRuntime_setTargetSdkVersionNative(JNIEnv*, jobject, jint target_sdk_version) {
211   // This is the target SDK version of the app we're about to run. It is intended that this a place
212   // where workarounds can be enabled.
213   // Note that targetSdkVersion may be CUR_DEVELOPMENT (10000).
214   // Note that targetSdkVersion may be 0, meaning "current".
215   Runtime::Current()->SetTargetSdkVersion(target_sdk_version);
216 
217 #ifdef ART_TARGET_ANDROID
218   // This part is letting libc/dynamic linker know about current app's
219   // target sdk version to enable compatibility workarounds.
220   android_set_application_target_sdk_version(static_cast<uint32_t>(target_sdk_version));
221 #endif
222 }
223 
VMRuntime_registerNativeAllocation(JNIEnv * env,jobject,jint bytes)224 static void VMRuntime_registerNativeAllocation(JNIEnv* env, jobject, jint bytes) {
225   if (UNLIKELY(bytes < 0)) {
226     ScopedObjectAccess soa(env);
227     ThrowRuntimeException("allocation size negative %d", bytes);
228     return;
229   }
230   Runtime::Current()->GetHeap()->RegisterNativeAllocation(env, static_cast<size_t>(bytes));
231 }
232 
VMRuntime_registerSensitiveThread(JNIEnv *,jobject)233 static void VMRuntime_registerSensitiveThread(JNIEnv*, jobject) {
234   Runtime::Current()->RegisterSensitiveThread();
235 }
236 
VMRuntime_registerNativeFree(JNIEnv * env,jobject,jint bytes)237 static void VMRuntime_registerNativeFree(JNIEnv* env, jobject, jint bytes) {
238   if (UNLIKELY(bytes < 0)) {
239     ScopedObjectAccess soa(env);
240     ThrowRuntimeException("allocation size negative %d", bytes);
241     return;
242   }
243   Runtime::Current()->GetHeap()->RegisterNativeFree(env, static_cast<size_t>(bytes));
244 }
245 
VMRuntime_updateProcessState(JNIEnv *,jobject,jint process_state)246 static void VMRuntime_updateProcessState(JNIEnv*, jobject, jint process_state) {
247   Runtime* runtime = Runtime::Current();
248   runtime->UpdateProcessState(static_cast<ProcessState>(process_state));
249 }
250 
VMRuntime_trimHeap(JNIEnv * env,jobject)251 static void VMRuntime_trimHeap(JNIEnv* env, jobject) {
252   Runtime::Current()->GetHeap()->Trim(ThreadForEnv(env));
253 }
254 
VMRuntime_concurrentGC(JNIEnv * env,jobject)255 static void VMRuntime_concurrentGC(JNIEnv* env, jobject) {
256   Runtime::Current()->GetHeap()->ConcurrentGC(ThreadForEnv(env), gc::kGcCauseBackground, true);
257 }
258 
VMRuntime_requestHeapTrim(JNIEnv * env,jobject)259 static void VMRuntime_requestHeapTrim(JNIEnv* env, jobject) {
260   Runtime::Current()->GetHeap()->RequestTrim(ThreadForEnv(env));
261 }
262 
VMRuntime_requestConcurrentGC(JNIEnv * env,jobject)263 static void VMRuntime_requestConcurrentGC(JNIEnv* env, jobject) {
264   Runtime::Current()->GetHeap()->RequestConcurrentGC(ThreadForEnv(env),
265                                                      gc::kGcCauseBackground,
266                                                      true);
267 }
268 
VMRuntime_startHeapTaskProcessor(JNIEnv * env,jobject)269 static void VMRuntime_startHeapTaskProcessor(JNIEnv* env, jobject) {
270   Runtime::Current()->GetHeap()->GetTaskProcessor()->Start(ThreadForEnv(env));
271 }
272 
VMRuntime_stopHeapTaskProcessor(JNIEnv * env,jobject)273 static void VMRuntime_stopHeapTaskProcessor(JNIEnv* env, jobject) {
274   Runtime::Current()->GetHeap()->GetTaskProcessor()->Stop(ThreadForEnv(env));
275 }
276 
VMRuntime_runHeapTasks(JNIEnv * env,jobject)277 static void VMRuntime_runHeapTasks(JNIEnv* env, jobject) {
278   Runtime::Current()->GetHeap()->GetTaskProcessor()->RunAllTasks(ThreadForEnv(env));
279 }
280 
281 typedef std::map<std::string, ObjPtr<mirror::String>> StringTable;
282 
283 class PreloadDexCachesStringsVisitor : public SingleRootVisitor {
284  public:
PreloadDexCachesStringsVisitor(StringTable * table)285   explicit PreloadDexCachesStringsVisitor(StringTable* table) : table_(table) { }
286 
VisitRoot(mirror::Object * root,const RootInfo & info ATTRIBUTE_UNUSED)287   void VisitRoot(mirror::Object* root, const RootInfo& info ATTRIBUTE_UNUSED)
288       OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
289     ObjPtr<mirror::String> string = root->AsString();
290     table_->operator[](string->ToModifiedUtf8()) = string;
291   }
292 
293  private:
294   StringTable* const table_;
295 };
296 
297 // Based on ClassLinker::ResolveString.
PreloadDexCachesResolveString(Handle<mirror::DexCache> dex_cache,dex::StringIndex string_idx,StringTable & strings)298 static void PreloadDexCachesResolveString(
299     Handle<mirror::DexCache> dex_cache, dex::StringIndex string_idx, StringTable& strings)
300     REQUIRES_SHARED(Locks::mutator_lock_) {
301   ObjPtr<mirror::String>  string = dex_cache->GetResolvedString(string_idx);
302   if (string != nullptr) {
303     return;
304   }
305   const DexFile* dex_file = dex_cache->GetDexFile();
306   const char* utf8 = dex_file->StringDataByIdx(string_idx);
307   string = strings[utf8];
308   if (string == nullptr) {
309     return;
310   }
311   // LOG(INFO) << "VMRuntime.preloadDexCaches resolved string=" << utf8;
312   dex_cache->SetResolvedString(string_idx, string);
313 }
314 
315 // Based on ClassLinker::ResolveType.
PreloadDexCachesResolveType(Thread * self,ObjPtr<mirror::DexCache> dex_cache,dex::TypeIndex type_idx)316 static void PreloadDexCachesResolveType(Thread* self,
317                                         ObjPtr<mirror::DexCache> dex_cache,
318                                         dex::TypeIndex type_idx)
319     REQUIRES_SHARED(Locks::mutator_lock_) {
320   ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(type_idx);
321   if (klass != nullptr) {
322     return;
323   }
324   const DexFile* dex_file = dex_cache->GetDexFile();
325   const char* class_name = dex_file->StringByTypeIdx(type_idx);
326   ClassLinker* linker = Runtime::Current()->GetClassLinker();
327   if (class_name[1] == '\0') {
328     klass = linker->FindPrimitiveClass(class_name[0]);
329   } else {
330     klass = linker->LookupClass(self, class_name, nullptr);
331   }
332   if (klass == nullptr) {
333     return;
334   }
335   // LOG(INFO) << "VMRuntime.preloadDexCaches resolved klass=" << class_name;
336   dex_cache->SetResolvedType(type_idx, klass);
337   // Skip uninitialized classes because filled static storage entry implies it is initialized.
338   if (!klass->IsInitialized()) {
339     // LOG(INFO) << "VMRuntime.preloadDexCaches uninitialized klass=" << class_name;
340     return;
341   }
342   // LOG(INFO) << "VMRuntime.preloadDexCaches static storage klass=" << class_name;
343 }
344 
345 // Based on ClassLinker::ResolveField.
PreloadDexCachesResolveField(Handle<mirror::DexCache> dex_cache,uint32_t field_idx,bool is_static)346 static void PreloadDexCachesResolveField(Handle<mirror::DexCache> dex_cache, uint32_t field_idx,
347                                          bool is_static)
348     REQUIRES_SHARED(Locks::mutator_lock_) {
349   ArtField* field = dex_cache->GetResolvedField(field_idx, kRuntimePointerSize);
350   if (field != nullptr) {
351     return;
352   }
353   const DexFile* dex_file = dex_cache->GetDexFile();
354   const DexFile::FieldId& field_id = dex_file->GetFieldId(field_idx);
355   Thread* const self = Thread::Current();
356   StackHandleScope<1> hs(self);
357   Handle<mirror::Class> klass(hs.NewHandle(dex_cache->GetResolvedType(field_id.class_idx_)));
358   if (klass == nullptr) {
359     return;
360   }
361   if (is_static) {
362     field = mirror::Class::FindStaticField(self, klass.Get(), dex_cache.Get(), field_idx);
363   } else {
364     field = klass->FindInstanceField(dex_cache.Get(), field_idx);
365   }
366   if (field == nullptr) {
367     return;
368   }
369   dex_cache->SetResolvedField(field_idx, field, kRuntimePointerSize);
370 }
371 
372 // Based on ClassLinker::ResolveMethod.
PreloadDexCachesResolveMethod(Handle<mirror::DexCache> dex_cache,uint32_t method_idx,InvokeType invoke_type)373 static void PreloadDexCachesResolveMethod(Handle<mirror::DexCache> dex_cache, uint32_t method_idx,
374                                           InvokeType invoke_type)
375     REQUIRES_SHARED(Locks::mutator_lock_) {
376   ArtMethod* method = dex_cache->GetResolvedMethod(method_idx, kRuntimePointerSize);
377   if (method != nullptr) {
378     return;
379   }
380   const DexFile* dex_file = dex_cache->GetDexFile();
381   const DexFile::MethodId& method_id = dex_file->GetMethodId(method_idx);
382   ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(method_id.class_idx_);
383   if (klass == nullptr) {
384     return;
385   }
386   switch (invoke_type) {
387     case kDirect:
388     case kStatic:
389       method = klass->FindDirectMethod(dex_cache.Get(), method_idx, kRuntimePointerSize);
390       break;
391     case kInterface:
392       method = klass->FindInterfaceMethod(dex_cache.Get(), method_idx, kRuntimePointerSize);
393       break;
394     case kSuper:
395     case kVirtual:
396       method = klass->FindVirtualMethod(dex_cache.Get(), method_idx, kRuntimePointerSize);
397       break;
398     default:
399       LOG(FATAL) << "Unreachable - invocation type: " << invoke_type;
400       UNREACHABLE();
401   }
402   if (method == nullptr) {
403     return;
404   }
405   dex_cache->SetResolvedMethod(method_idx, method, kRuntimePointerSize);
406 }
407 
408 struct DexCacheStats {
409     uint32_t num_strings;
410     uint32_t num_types;
411     uint32_t num_fields;
412     uint32_t num_methods;
DexCacheStatsart::DexCacheStats413     DexCacheStats() : num_strings(0),
414                       num_types(0),
415                       num_fields(0),
416                       num_methods(0) {}
417 };
418 
419 static const bool kPreloadDexCachesEnabled = true;
420 
421 // Disabled because it takes a long time (extra half second) but
422 // gives almost no benefit in terms of saving private dirty pages.
423 static const bool kPreloadDexCachesStrings = false;
424 
425 static const bool kPreloadDexCachesTypes = true;
426 static const bool kPreloadDexCachesFieldsAndMethods = true;
427 
428 static const bool kPreloadDexCachesCollectStats = true;
429 
PreloadDexCachesStatsTotal(DexCacheStats * total)430 static void PreloadDexCachesStatsTotal(DexCacheStats* total) {
431   if (!kPreloadDexCachesCollectStats) {
432     return;
433   }
434 
435   ClassLinker* linker = Runtime::Current()->GetClassLinker();
436   const std::vector<const DexFile*>& boot_class_path = linker->GetBootClassPath();
437   for (size_t i = 0; i< boot_class_path.size(); i++) {
438     const DexFile* dex_file = boot_class_path[i];
439     CHECK(dex_file != nullptr);
440     total->num_strings += dex_file->NumStringIds();
441     total->num_fields += dex_file->NumFieldIds();
442     total->num_methods += dex_file->NumMethodIds();
443     total->num_types += dex_file->NumTypeIds();
444   }
445 }
446 
PreloadDexCachesStatsFilled(DexCacheStats * filled)447 static void PreloadDexCachesStatsFilled(DexCacheStats* filled)
448     REQUIRES_SHARED(Locks::mutator_lock_) {
449   if (!kPreloadDexCachesCollectStats) {
450     return;
451   }
452   // TODO: Update for hash-based DexCache arrays.
453   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
454   Thread* const self = Thread::Current();
455   for (const DexFile* dex_file : class_linker->GetBootClassPath()) {
456     CHECK(dex_file != nullptr);
457     // In fallback mode, not all boot classpath components might be registered, yet.
458     if (!class_linker->IsDexFileRegistered(self, *dex_file)) {
459       continue;
460     }
461     ObjPtr<mirror::DexCache> const dex_cache = class_linker->FindDexCache(self, *dex_file);
462     DCHECK(dex_cache != nullptr);  // Boot class path dex caches are never unloaded.
463     for (size_t j = 0; j < dex_cache->NumStrings(); j++) {
464       ObjPtr<mirror::String> string = dex_cache->GetResolvedString(dex::StringIndex(j));
465       if (string != nullptr) {
466         filled->num_strings++;
467       }
468     }
469     for (size_t j = 0; j < dex_cache->NumResolvedTypes(); j++) {
470       ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(dex::TypeIndex(j));
471       if (klass != nullptr) {
472         filled->num_types++;
473       }
474     }
475     for (size_t j = 0; j < dex_cache->NumResolvedFields(); j++) {
476       ArtField* field = dex_cache->GetResolvedField(j, class_linker->GetImagePointerSize());
477       if (field != nullptr) {
478         filled->num_fields++;
479       }
480     }
481     for (size_t j = 0; j < dex_cache->NumResolvedMethods(); j++) {
482       ArtMethod* method = dex_cache->GetResolvedMethod(j, kRuntimePointerSize);
483       if (method != nullptr) {
484         filled->num_methods++;
485       }
486     }
487   }
488 }
489 
490 // TODO: http://b/11309598 This code was ported over based on the
491 // Dalvik version. However, ART has similar code in other places such
492 // as the CompilerDriver. This code could probably be refactored to
493 // serve both uses.
VMRuntime_preloadDexCaches(JNIEnv * env,jobject)494 static void VMRuntime_preloadDexCaches(JNIEnv* env, jobject) {
495   if (!kPreloadDexCachesEnabled) {
496     return;
497   }
498 
499   ScopedObjectAccess soa(env);
500 
501   DexCacheStats total;
502   DexCacheStats before;
503   if (kPreloadDexCachesCollectStats) {
504     LOG(INFO) << "VMRuntime.preloadDexCaches starting";
505     PreloadDexCachesStatsTotal(&total);
506     PreloadDexCachesStatsFilled(&before);
507   }
508 
509   Runtime* runtime = Runtime::Current();
510   ClassLinker* linker = runtime->GetClassLinker();
511 
512   // We use a std::map to avoid heap allocating StringObjects to lookup in gDvm.literalStrings
513   StringTable strings;
514   if (kPreloadDexCachesStrings) {
515     PreloadDexCachesStringsVisitor visitor(&strings);
516     runtime->GetInternTable()->VisitRoots(&visitor, kVisitRootFlagAllRoots);
517   }
518 
519   const std::vector<const DexFile*>& boot_class_path = linker->GetBootClassPath();
520   for (size_t i = 0; i < boot_class_path.size(); i++) {
521     const DexFile* dex_file = boot_class_path[i];
522     CHECK(dex_file != nullptr);
523     StackHandleScope<1> hs(soa.Self());
524     Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->RegisterDexFile(*dex_file, nullptr)));
525     CHECK(dex_cache != nullptr);  // Boot class path dex caches are never unloaded.
526     if (kPreloadDexCachesStrings) {
527       for (size_t j = 0; j < dex_cache->NumStrings(); j++) {
528         PreloadDexCachesResolveString(dex_cache, dex::StringIndex(j), strings);
529       }
530     }
531 
532     if (kPreloadDexCachesTypes) {
533       for (size_t j = 0; j < dex_cache->NumResolvedTypes(); j++) {
534         PreloadDexCachesResolveType(soa.Self(), dex_cache.Get(), dex::TypeIndex(j));
535       }
536     }
537 
538     if (kPreloadDexCachesFieldsAndMethods) {
539       for (size_t class_def_index = 0;
540            class_def_index < dex_file->NumClassDefs();
541            class_def_index++) {
542         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
543         const uint8_t* class_data = dex_file->GetClassData(class_def);
544         if (class_data == nullptr) {
545           continue;
546         }
547         ClassDataItemIterator it(*dex_file, class_data);
548         for (; it.HasNextStaticField(); it.Next()) {
549           uint32_t field_idx = it.GetMemberIndex();
550           PreloadDexCachesResolveField(dex_cache, field_idx, true);
551         }
552         for (; it.HasNextInstanceField(); it.Next()) {
553           uint32_t field_idx = it.GetMemberIndex();
554           PreloadDexCachesResolveField(dex_cache, field_idx, false);
555         }
556         for (; it.HasNextDirectMethod(); it.Next()) {
557           uint32_t method_idx = it.GetMemberIndex();
558           InvokeType invoke_type = it.GetMethodInvokeType(class_def);
559           PreloadDexCachesResolveMethod(dex_cache, method_idx, invoke_type);
560         }
561         for (; it.HasNextVirtualMethod(); it.Next()) {
562           uint32_t method_idx = it.GetMemberIndex();
563           InvokeType invoke_type = it.GetMethodInvokeType(class_def);
564           PreloadDexCachesResolveMethod(dex_cache, method_idx, invoke_type);
565         }
566       }
567     }
568   }
569 
570   if (kPreloadDexCachesCollectStats) {
571     DexCacheStats after;
572     PreloadDexCachesStatsFilled(&after);
573     LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches strings total=%d before=%d after=%d",
574                               total.num_strings, before.num_strings, after.num_strings);
575     LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches types total=%d before=%d after=%d",
576                               total.num_types, before.num_types, after.num_types);
577     LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches fields total=%d before=%d after=%d",
578                               total.num_fields, before.num_fields, after.num_fields);
579     LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches methods total=%d before=%d after=%d",
580                               total.num_methods, before.num_methods, after.num_methods);
581     LOG(INFO) << StringPrintf("VMRuntime.preloadDexCaches finished");
582   }
583 }
584 
585 
586 /*
587  * This is called by the framework when it knows the application directory and
588  * process name.
589  */
VMRuntime_registerAppInfo(JNIEnv * env,jclass clazz ATTRIBUTE_UNUSED,jstring profile_file,jobjectArray code_paths)590 static void VMRuntime_registerAppInfo(JNIEnv* env,
591                                       jclass clazz ATTRIBUTE_UNUSED,
592                                       jstring profile_file,
593                                       jobjectArray code_paths) {
594   std::vector<std::string> code_paths_vec;
595   int code_paths_length = env->GetArrayLength(code_paths);
596   for (int i = 0; i < code_paths_length; i++) {
597     jstring code_path = reinterpret_cast<jstring>(env->GetObjectArrayElement(code_paths, i));
598     const char* raw_code_path = env->GetStringUTFChars(code_path, nullptr);
599     code_paths_vec.push_back(raw_code_path);
600     env->ReleaseStringUTFChars(code_path, raw_code_path);
601   }
602 
603   const char* raw_profile_file = env->GetStringUTFChars(profile_file, nullptr);
604   std::string profile_file_str(raw_profile_file);
605   env->ReleaseStringUTFChars(profile_file, raw_profile_file);
606 
607   Runtime::Current()->RegisterAppInfo(code_paths_vec, profile_file_str);
608 }
609 
VMRuntime_isBootClassPathOnDisk(JNIEnv * env,jclass,jstring java_instruction_set)610 static jboolean VMRuntime_isBootClassPathOnDisk(JNIEnv* env, jclass, jstring java_instruction_set) {
611   ScopedUtfChars instruction_set(env, java_instruction_set);
612   if (instruction_set.c_str() == nullptr) {
613     return JNI_FALSE;
614   }
615   InstructionSet isa = GetInstructionSetFromString(instruction_set.c_str());
616   if (isa == kNone) {
617     ScopedLocalRef<jclass> iae(env, env->FindClass("java/lang/IllegalArgumentException"));
618     std::string message(StringPrintf("Instruction set %s is invalid.", instruction_set.c_str()));
619     env->ThrowNew(iae.get(), message.c_str());
620     return JNI_FALSE;
621   }
622   std::string error_msg;
623   std::unique_ptr<ImageHeader> image_header(gc::space::ImageSpace::ReadImageHeader(
624       Runtime::Current()->GetImageLocation().c_str(), isa, &error_msg));
625   return image_header.get() != nullptr;
626 }
627 
VMRuntime_getCurrentInstructionSet(JNIEnv * env,jclass)628 static jstring VMRuntime_getCurrentInstructionSet(JNIEnv* env, jclass) {
629   return env->NewStringUTF(GetInstructionSetString(kRuntimeISA));
630 }
631 
VMRuntime_didPruneDalvikCache(JNIEnv * env ATTRIBUTE_UNUSED,jclass klass ATTRIBUTE_UNUSED)632 static jboolean VMRuntime_didPruneDalvikCache(JNIEnv* env ATTRIBUTE_UNUSED,
633                                               jclass klass ATTRIBUTE_UNUSED) {
634   return Runtime::Current()->GetPrunedDalvikCache() ? JNI_TRUE : JNI_FALSE;
635 }
636 
VMRuntime_setSystemDaemonThreadPriority(JNIEnv * env ATTRIBUTE_UNUSED,jclass klass ATTRIBUTE_UNUSED)637 static void VMRuntime_setSystemDaemonThreadPriority(JNIEnv* env ATTRIBUTE_UNUSED,
638                                                     jclass klass ATTRIBUTE_UNUSED) {
639 #ifdef ART_TARGET_ANDROID
640   Thread* self = Thread::Current();
641   DCHECK(self != nullptr);
642   pid_t tid = self->GetTid();
643   // We use a priority lower than the default for the system daemon threads (eg HeapTaskDaemon) to
644   // avoid jank due to CPU contentions between GC and other UI-related threads. b/36631902.
645   // We may use a native priority that doesn't have a corresponding java.lang.Thread-level priority.
646   static constexpr int kSystemDaemonNiceValue = 4;  // priority 124
647   if (setpriority(PRIO_PROCESS, tid, kSystemDaemonNiceValue) != 0) {
648     PLOG(INFO) << *self << " setpriority(PRIO_PROCESS, " << tid << ", "
649                << kSystemDaemonNiceValue << ") failed";
650   }
651 #endif
652 }
653 
654 static JNINativeMethod gMethods[] = {
655   FAST_NATIVE_METHOD(VMRuntime, addressOf, "(Ljava/lang/Object;)J"),
656   NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"),
657   NATIVE_METHOD(VMRuntime, clampGrowthLimit, "()V"),
658   NATIVE_METHOD(VMRuntime, classPath, "()Ljava/lang/String;"),
659   NATIVE_METHOD(VMRuntime, clearGrowthLimit, "()V"),
660   NATIVE_METHOD(VMRuntime, concurrentGC, "()V"),
661   NATIVE_METHOD(VMRuntime, disableJitCompilation, "()V"),
662   NATIVE_METHOD(VMRuntime, getTargetHeapUtilization, "()F"),
663   FAST_NATIVE_METHOD(VMRuntime, isDebuggerActive, "()Z"),
664   FAST_NATIVE_METHOD(VMRuntime, isNativeDebuggable, "()Z"),
665   NATIVE_METHOD(VMRuntime, nativeSetTargetHeapUtilization, "(F)V"),
666   FAST_NATIVE_METHOD(VMRuntime, newNonMovableArray, "(Ljava/lang/Class;I)Ljava/lang/Object;"),
667   FAST_NATIVE_METHOD(VMRuntime, newUnpaddedArray, "(Ljava/lang/Class;I)Ljava/lang/Object;"),
668   NATIVE_METHOD(VMRuntime, properties, "()[Ljava/lang/String;"),
669   NATIVE_METHOD(VMRuntime, setTargetSdkVersionNative, "(I)V"),
670   NATIVE_METHOD(VMRuntime, registerNativeAllocation, "(I)V"),
671   NATIVE_METHOD(VMRuntime, registerSensitiveThread, "()V"),
672   NATIVE_METHOD(VMRuntime, registerNativeFree, "(I)V"),
673   NATIVE_METHOD(VMRuntime, requestConcurrentGC, "()V"),
674   NATIVE_METHOD(VMRuntime, requestHeapTrim, "()V"),
675   NATIVE_METHOD(VMRuntime, runHeapTasks, "()V"),
676   NATIVE_METHOD(VMRuntime, updateProcessState, "(I)V"),
677   NATIVE_METHOD(VMRuntime, startHeapTaskProcessor, "()V"),
678   NATIVE_METHOD(VMRuntime, startJitCompilation, "()V"),
679   NATIVE_METHOD(VMRuntime, stopHeapTaskProcessor, "()V"),
680   NATIVE_METHOD(VMRuntime, trimHeap, "()V"),
681   NATIVE_METHOD(VMRuntime, vmVersion, "()Ljava/lang/String;"),
682   NATIVE_METHOD(VMRuntime, vmLibrary, "()Ljava/lang/String;"),
683   NATIVE_METHOD(VMRuntime, vmInstructionSet, "()Ljava/lang/String;"),
684   FAST_NATIVE_METHOD(VMRuntime, is64Bit, "()Z"),
685   FAST_NATIVE_METHOD(VMRuntime, isCheckJniEnabled, "()Z"),
686   NATIVE_METHOD(VMRuntime, preloadDexCaches, "()V"),
687   NATIVE_METHOD(VMRuntime, registerAppInfo, "(Ljava/lang/String;[Ljava/lang/String;)V"),
688   NATIVE_METHOD(VMRuntime, isBootClassPathOnDisk, "(Ljava/lang/String;)Z"),
689   NATIVE_METHOD(VMRuntime, getCurrentInstructionSet, "()Ljava/lang/String;"),
690   NATIVE_METHOD(VMRuntime, didPruneDalvikCache, "()Z"),
691   NATIVE_METHOD(VMRuntime, setSystemDaemonThreadPriority, "()V"),
692 };
693 
register_dalvik_system_VMRuntime(JNIEnv * env)694 void register_dalvik_system_VMRuntime(JNIEnv* env) {
695   REGISTER_NATIVE_METHODS("dalvik/system/VMRuntime");
696 }
697 
698 }  // namespace art
699