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