Home | History | Annotate | Download | only in native
      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