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