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_DexFile.h" 18 19 #include <sstream> 20 21 #include "android-base/stringprintf.h" 22 23 #include "base/casts.h" 24 #include "base/file_utils.h" 25 #include "base/logging.h" 26 #include "base/os.h" 27 #include "base/stl_util.h" 28 #include "base/utils.h" 29 #include "base/zip_archive.h" 30 #include "class_linker.h" 31 #include "class_loader_context.h" 32 #include "common_throws.h" 33 #include "compiler_filter.h" 34 #include "dex/art_dex_file_loader.h" 35 #include "dex/descriptors_names.h" 36 #include "dex/dex_file-inl.h" 37 #include "dex/dex_file_loader.h" 38 #include "handle_scope-inl.h" 39 #include "jit/debugger_interface.h" 40 #include "jni/jni_internal.h" 41 #include "mirror/class_loader.h" 42 #include "mirror/object-inl.h" 43 #include "mirror/string.h" 44 #include "native_util.h" 45 #include "nativehelper/jni_macros.h" 46 #include "nativehelper/scoped_local_ref.h" 47 #include "nativehelper/scoped_utf_chars.h" 48 #include "oat_file.h" 49 #include "oat_file_assistant.h" 50 #include "oat_file_manager.h" 51 #include "runtime.h" 52 #include "scoped_thread_state_change-inl.h" 53 #include "well_known_classes.h" 54 55 namespace art { 56 57 using android::base::StringPrintf; 58 59 static bool ConvertJavaArrayToDexFiles( 60 JNIEnv* env, 61 jobject arrayObject, 62 /*out*/ std::vector<const DexFile*>& dex_files, 63 /*out*/ const OatFile*& oat_file) { 64 jarray array = reinterpret_cast<jarray>(arrayObject); 65 66 jsize array_size = env->GetArrayLength(array); 67 if (env->ExceptionCheck() == JNI_TRUE) { 68 return false; 69 } 70 71 // TODO: Optimize. On 32bit we can use an int array. 72 jboolean is_long_data_copied; 73 jlong* long_data = env->GetLongArrayElements(reinterpret_cast<jlongArray>(array), 74 &is_long_data_copied); 75 if (env->ExceptionCheck() == JNI_TRUE) { 76 return false; 77 } 78 79 oat_file = reinterpret_cast64<const OatFile*>(long_data[kOatFileIndex]); 80 dex_files.reserve(array_size - 1); 81 for (jsize i = kDexFileIndexStart; i < array_size; ++i) { 82 dex_files.push_back(reinterpret_cast64<const DexFile*>(long_data[i])); 83 } 84 85 env->ReleaseLongArrayElements(reinterpret_cast<jlongArray>(array), long_data, JNI_ABORT); 86 return env->ExceptionCheck() != JNI_TRUE; 87 } 88 89 static jlongArray ConvertDexFilesToJavaArray(JNIEnv* env, 90 const OatFile* oat_file, 91 std::vector<std::unique_ptr<const DexFile>>& vec) { 92 // Add one for the oat file. 93 jlongArray long_array = env->NewLongArray(static_cast<jsize>(kDexFileIndexStart + vec.size())); 94 if (env->ExceptionCheck() == JNI_TRUE) { 95 return nullptr; 96 } 97 98 jboolean is_long_data_copied; 99 jlong* long_data = env->GetLongArrayElements(long_array, &is_long_data_copied); 100 if (env->ExceptionCheck() == JNI_TRUE) { 101 return nullptr; 102 } 103 104 long_data[kOatFileIndex] = reinterpret_cast64<jlong>(oat_file); 105 for (size_t i = 0; i < vec.size(); ++i) { 106 long_data[kDexFileIndexStart + i] = reinterpret_cast64<jlong>(vec[i].get()); 107 } 108 109 env->ReleaseLongArrayElements(long_array, long_data, 0); 110 if (env->ExceptionCheck() == JNI_TRUE) { 111 return nullptr; 112 } 113 114 // Now release all the unique_ptrs. 115 for (auto& dex_file : vec) { 116 dex_file.release(); // NOLINT 117 } 118 119 return long_array; 120 } 121 122 // A smart pointer that provides read-only access to a Java string's UTF chars. 123 // Unlike libcore's NullableScopedUtfChars, this will *not* throw NullPointerException if 124 // passed a null jstring. The correct idiom is: 125 // 126 // NullableScopedUtfChars name(env, javaName); 127 // if (env->ExceptionCheck()) { 128 // return null; 129 // } 130 // // ... use name.c_str() 131 // 132 // TODO: rewrite to get rid of this, or change ScopedUtfChars to offer this option. 133 class NullableScopedUtfChars { 134 public: 135 NullableScopedUtfChars(JNIEnv* env, jstring s) : mEnv(env), mString(s) { 136 mUtfChars = (s != nullptr) ? env->GetStringUTFChars(s, nullptr) : nullptr; 137 } 138 139 ~NullableScopedUtfChars() { 140 if (mUtfChars) { 141 mEnv->ReleaseStringUTFChars(mString, mUtfChars); 142 } 143 } 144 145 const char* c_str() const { 146 return mUtfChars; 147 } 148 149 size_t size() const { 150 return strlen(mUtfChars); 151 } 152 153 // Element access. 154 const char& operator[](size_t n) const { 155 return mUtfChars[n]; 156 } 157 158 private: 159 JNIEnv* mEnv; 160 jstring mString; 161 const char* mUtfChars; 162 163 // Disallow copy and assignment. 164 NullableScopedUtfChars(const NullableScopedUtfChars&); 165 void operator=(const NullableScopedUtfChars&); 166 }; 167 168 static jobject CreateCookieFromOatFileManagerResult( 169 JNIEnv* env, 170 std::vector<std::unique_ptr<const DexFile>>& dex_files, 171 const OatFile* oat_file, 172 const std::vector<std::string>& error_msgs) { 173 ClassLinker* linker = Runtime::Current()->GetClassLinker(); 174 if (dex_files.empty()) { 175 ScopedObjectAccess soa(env); 176 CHECK(!error_msgs.empty()); 177 // The most important message is at the end. So set up nesting by going forward, which will 178 // wrap the existing exception as a cause for the following one. 179 auto it = error_msgs.begin(); 180 auto itEnd = error_msgs.end(); 181 for ( ; it != itEnd; ++it) { 182 ThrowWrappedIOException("%s", it->c_str()); 183 } 184 return nullptr; 185 } 186 187 jlongArray array = ConvertDexFilesToJavaArray(env, oat_file, dex_files); 188 if (array == nullptr) { 189 ScopedObjectAccess soa(env); 190 for (auto& dex_file : dex_files) { 191 if (linker->IsDexFileRegistered(soa.Self(), *dex_file)) { 192 dex_file.release(); // NOLINT 193 } 194 } 195 } 196 return array; 197 } 198 199 static MemMap AllocateDexMemoryMap(JNIEnv* env, jint start, jint end) { 200 if (end <= start) { 201 ScopedObjectAccess soa(env); 202 ThrowWrappedIOException("Bad range"); 203 return MemMap::Invalid(); 204 } 205 206 std::string error_message; 207 size_t length = static_cast<size_t>(end - start); 208 MemMap dex_mem_map = MemMap::MapAnonymous("DEX data", 209 length, 210 PROT_READ | PROT_WRITE, 211 /*low_4gb=*/ false, 212 &error_message); 213 if (!dex_mem_map.IsValid()) { 214 ScopedObjectAccess soa(env); 215 ThrowWrappedIOException("%s", error_message.c_str()); 216 return MemMap::Invalid(); 217 } 218 return dex_mem_map; 219 } 220 221 struct ScopedIntArrayAccessor { 222 public: 223 ScopedIntArrayAccessor(JNIEnv* env, jintArray arr) : env_(env), array_(arr) { 224 elements_ = env_->GetIntArrayElements(array_, /* isCopy= */ nullptr); 225 CHECK(elements_ != nullptr); 226 } 227 228 ~ScopedIntArrayAccessor() { 229 env_->ReleaseIntArrayElements(array_, elements_, JNI_ABORT); 230 } 231 232 jint Get(jsize index) const { return elements_[index]; } 233 234 private: 235 JNIEnv* env_; 236 jintArray array_; 237 jint* elements_; 238 }; 239 240 static jobject DexFile_openInMemoryDexFilesNative(JNIEnv* env, 241 jclass, 242 jobjectArray buffers, 243 jobjectArray arrays, 244 jintArray jstarts, 245 jintArray jends, 246 jobject class_loader, 247 jobjectArray dex_elements) { 248 jsize buffers_length = env->GetArrayLength(buffers); 249 CHECK_EQ(buffers_length, env->GetArrayLength(arrays)); 250 CHECK_EQ(buffers_length, env->GetArrayLength(jstarts)); 251 CHECK_EQ(buffers_length, env->GetArrayLength(jends)); 252 253 ScopedIntArrayAccessor starts(env, jstarts); 254 ScopedIntArrayAccessor ends(env, jends); 255 256 // Allocate memory for dex files and copy data from ByteBuffers. 257 std::vector<MemMap> dex_mem_maps; 258 dex_mem_maps.reserve(buffers_length); 259 for (jsize i = 0; i < buffers_length; ++i) { 260 jobject buffer = env->GetObjectArrayElement(buffers, i); 261 jbyteArray array = reinterpret_cast<jbyteArray>(env->GetObjectArrayElement(arrays, i)); 262 jint start = starts.Get(i); 263 jint end = ends.Get(i); 264 265 MemMap dex_data = AllocateDexMemoryMap(env, start, end); 266 if (!dex_data.IsValid()) { 267 DCHECK(Thread::Current()->IsExceptionPending()); 268 return nullptr; 269 } 270 271 if (array == nullptr) { 272 // Direct ByteBuffer 273 uint8_t* base_address = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer)); 274 if (base_address == nullptr) { 275 ScopedObjectAccess soa(env); 276 ThrowWrappedIOException("dexFileBuffer not direct"); 277 return nullptr; 278 } 279 size_t length = static_cast<size_t>(end - start); 280 memcpy(dex_data.Begin(), base_address + start, length); 281 } else { 282 // ByteBuffer backed by a byte array 283 jbyte* destination = reinterpret_cast<jbyte*>(dex_data.Begin()); 284 env->GetByteArrayRegion(array, start, end - start, destination); 285 } 286 287 dex_mem_maps.push_back(std::move(dex_data)); 288 } 289 290 // Hand MemMaps over to OatFileManager to open the dex files and potentially 291 // create a backing OatFile instance from an anonymous vdex. 292 std::vector<std::string> error_msgs; 293 const OatFile* oat_file = nullptr; 294 std::vector<std::unique_ptr<const DexFile>> dex_files = 295 Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(std::move(dex_mem_maps), 296 class_loader, 297 dex_elements, 298 /*out*/ &oat_file, 299 /*out*/ &error_msgs); 300 return CreateCookieFromOatFileManagerResult(env, dex_files, oat_file, error_msgs); 301 } 302 303 // TODO(calin): clean up the unused parameters (here and in libcore). 304 static jobject DexFile_openDexFileNative(JNIEnv* env, 305 jclass, 306 jstring javaSourceName, 307 jstring javaOutputName ATTRIBUTE_UNUSED, 308 jint flags ATTRIBUTE_UNUSED, 309 jobject class_loader, 310 jobjectArray dex_elements) { 311 ScopedUtfChars sourceName(env, javaSourceName); 312 if (sourceName.c_str() == nullptr) { 313 return nullptr; 314 } 315 316 std::vector<std::string> error_msgs; 317 const OatFile* oat_file = nullptr; 318 std::vector<std::unique_ptr<const DexFile>> dex_files = 319 Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(sourceName.c_str(), 320 class_loader, 321 dex_elements, 322 /*out*/ &oat_file, 323 /*out*/ &error_msgs); 324 return CreateCookieFromOatFileManagerResult(env, dex_files, oat_file, error_msgs); 325 } 326 327 static jstring DexFile_getClassLoaderContext(JNIEnv* env, 328 jclass, 329 jobject class_loader, 330 jobjectArray dex_elements) { 331 CHECK(class_loader != nullptr); 332 constexpr const char* kBaseDir = ""; 333 std::unique_ptr<ClassLoaderContext> context = 334 ClassLoaderContext::CreateContextForClassLoader(class_loader, dex_elements); 335 if (context == nullptr || !context->OpenDexFiles(kRuntimeISA, kBaseDir)) { 336 LOG(WARNING) << "Could not establish class loader context"; 337 return nullptr; 338 } 339 std::string str_context = context->EncodeContextForOatFile(kBaseDir); 340 return env->NewStringUTF(str_context.c_str()); 341 } 342 343 static void DexFile_verifyInBackgroundNative(JNIEnv* env, 344 jclass, 345 jobject cookie, 346 jobject class_loader, 347 jstring class_loader_context) { 348 CHECK(cookie != nullptr); 349 CHECK(class_loader != nullptr); 350 351 // Extract list of dex files from the cookie. 352 std::vector<const DexFile*> dex_files; 353 const OatFile* oat_file; 354 if (!ConvertJavaArrayToDexFiles(env, cookie, dex_files, oat_file)) { 355 Thread::Current()->AssertPendingException(); 356 return; 357 } 358 CHECK(oat_file == nullptr) << "Called verifyInBackground on a dex file backed by oat"; 359 360 ScopedUtfChars class_loader_context_utf(env, class_loader_context); 361 if (env->ExceptionCheck()) { 362 LOG(ERROR) << "Failed to unwrap class loader context string"; 363 return; 364 } 365 366 // Hand over to OatFileManager to spawn a verification thread. 367 Runtime::Current()->GetOatFileManager().RunBackgroundVerification( 368 dex_files, 369 class_loader, 370 class_loader_context_utf.c_str()); 371 } 372 373 static jboolean DexFile_closeDexFile(JNIEnv* env, jclass, jobject cookie) { 374 std::vector<const DexFile*> dex_files; 375 const OatFile* oat_file; 376 if (!ConvertJavaArrayToDexFiles(env, cookie, dex_files, oat_file)) { 377 Thread::Current()->AssertPendingException(); 378 return JNI_FALSE; 379 } 380 Runtime* const runtime = Runtime::Current(); 381 bool all_deleted = true; 382 // We need to clear the caches since they may contain pointers to the dex instructions. 383 // Different dex file can be loaded at the same memory location later by chance. 384 Thread::ClearAllInterpreterCaches(); 385 { 386 ScopedObjectAccess soa(env); 387 ObjPtr<mirror::Object> dex_files_object = soa.Decode<mirror::Object>(cookie); 388 ObjPtr<mirror::LongArray> long_dex_files = dex_files_object->AsLongArray(); 389 // Delete dex files associated with this dalvik.system.DexFile since there should not be running 390 // code using it. dex_files is a vector due to multidex. 391 ClassLinker* const class_linker = runtime->GetClassLinker(); 392 int32_t i = kDexFileIndexStart; // Oat file is at index 0. 393 for (const DexFile* dex_file : dex_files) { 394 if (dex_file != nullptr) { 395 RemoveNativeDebugInfoForDex(soa.Self(), dex_file); 396 // Only delete the dex file if the dex cache is not found to prevent runtime crashes 397 // if there are calls to DexFile.close while the ART DexFile is still in use. 398 if (!class_linker->IsDexFileRegistered(soa.Self(), *dex_file)) { 399 // Clear the element in the array so that we can call close again. 400 long_dex_files->Set(i, 0); 401 delete dex_file; 402 } else { 403 all_deleted = false; 404 } 405 } 406 ++i; 407 } 408 } 409 410 // oat_file can be null if we are running without dex2oat. 411 if (all_deleted && oat_file != nullptr) { 412 // If all of the dex files are no longer in use we can unmap the corresponding oat file. 413 VLOG(class_linker) << "Unregistering " << oat_file; 414 runtime->GetOatFileManager().UnRegisterAndDeleteOatFile(oat_file); 415 } 416 return all_deleted ? JNI_TRUE : JNI_FALSE; 417 } 418 419 static jclass DexFile_defineClassNative(JNIEnv* env, 420 jclass, 421 jstring javaName, 422 jobject javaLoader, 423 jobject cookie, 424 jobject dexFile) { 425 std::vector<const DexFile*> dex_files; 426 const OatFile* oat_file; 427 if (!ConvertJavaArrayToDexFiles(env, cookie, /*out*/ dex_files, /*out*/ oat_file)) { 428 VLOG(class_linker) << "Failed to find dex_file"; 429 DCHECK(env->ExceptionCheck()); 430 return nullptr; 431 } 432 433 ScopedUtfChars class_name(env, javaName); 434 if (class_name.c_str() == nullptr) { 435 VLOG(class_linker) << "Failed to find class_name"; 436 return nullptr; 437 } 438 const std::string descriptor(DotToDescriptor(class_name.c_str())); 439 const size_t hash(ComputeModifiedUtf8Hash(descriptor.c_str())); 440 for (auto& dex_file : dex_files) { 441 const dex::ClassDef* dex_class_def = 442 OatDexFile::FindClassDef(*dex_file, descriptor.c_str(), hash); 443 if (dex_class_def != nullptr) { 444 ScopedObjectAccess soa(env); 445 ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 446 StackHandleScope<1> hs(soa.Self()); 447 Handle<mirror::ClassLoader> class_loader( 448 hs.NewHandle(soa.Decode<mirror::ClassLoader>(javaLoader))); 449 ObjPtr<mirror::DexCache> dex_cache = 450 class_linker->RegisterDexFile(*dex_file, class_loader.Get()); 451 if (dex_cache == nullptr) { 452 // OOME or InternalError (dexFile already registered with a different class loader). 453 soa.Self()->AssertPendingException(); 454 return nullptr; 455 } 456 ObjPtr<mirror::Class> result = class_linker->DefineClass(soa.Self(), 457 descriptor.c_str(), 458 hash, 459 class_loader, 460 *dex_file, 461 *dex_class_def); 462 // Add the used dex file. This only required for the DexFile.loadClass API since normal 463 // class loaders already keep their dex files live. 464 class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object>(dexFile), 465 class_loader.Get()); 466 if (result != nullptr) { 467 VLOG(class_linker) << "DexFile_defineClassNative returning " << result 468 << " for " << class_name.c_str(); 469 return soa.AddLocalReference<jclass>(result); 470 } 471 } 472 } 473 VLOG(class_linker) << "Failed to find dex_class_def " << class_name.c_str(); 474 return nullptr; 475 } 476 477 // Needed as a compare functor for sets of const char 478 struct CharPointerComparator { 479 bool operator()(const char *str1, const char *str2) const { 480 return strcmp(str1, str2) < 0; 481 } 482 }; 483 484 // Note: this can be an expensive call, as we sort out duplicates in MultiDex files. 485 static jobjectArray DexFile_getClassNameList(JNIEnv* env, jclass, jobject cookie) { 486 const OatFile* oat_file = nullptr; 487 std::vector<const DexFile*> dex_files; 488 if (!ConvertJavaArrayToDexFiles(env, cookie, /*out */ dex_files, /* out */ oat_file)) { 489 DCHECK(env->ExceptionCheck()); 490 return nullptr; 491 } 492 493 // Push all class descriptors into a set. Use set instead of unordered_set as we want to 494 // retrieve all in the end. 495 std::set<const char*, CharPointerComparator> descriptors; 496 for (auto& dex_file : dex_files) { 497 for (size_t i = 0; i < dex_file->NumClassDefs(); ++i) { 498 const dex::ClassDef& class_def = dex_file->GetClassDef(i); 499 const char* descriptor = dex_file->GetClassDescriptor(class_def); 500 descriptors.insert(descriptor); 501 } 502 } 503 504 // Now create output array and copy the set into it. 505 jobjectArray result = env->NewObjectArray(descriptors.size(), 506 WellKnownClasses::java_lang_String, 507 nullptr); 508 if (result != nullptr) { 509 auto it = descriptors.begin(); 510 auto it_end = descriptors.end(); 511 jsize i = 0; 512 for (; it != it_end; it++, ++i) { 513 std::string descriptor(DescriptorToDot(*it)); 514 ScopedLocalRef<jstring> jdescriptor(env, env->NewStringUTF(descriptor.c_str())); 515 if (jdescriptor.get() == nullptr) { 516 return nullptr; 517 } 518 env->SetObjectArrayElement(result, i, jdescriptor.get()); 519 } 520 } 521 return result; 522 } 523 524 static jint GetDexOptNeeded(JNIEnv* env, 525 const char* filename, 526 const char* instruction_set, 527 const char* compiler_filter_name, 528 const char* class_loader_context, 529 bool profile_changed, 530 bool downgrade) { 531 if ((filename == nullptr) || !OS::FileExists(filename)) { 532 LOG(ERROR) << "DexFile_getDexOptNeeded file '" << filename << "' does not exist"; 533 ScopedLocalRef<jclass> fnfe(env, env->FindClass("java/io/FileNotFoundException")); 534 const char* message = (filename == nullptr) ? "<empty file name>" : filename; 535 env->ThrowNew(fnfe.get(), message); 536 return -1; 537 } 538 539 const InstructionSet target_instruction_set = GetInstructionSetFromString(instruction_set); 540 if (target_instruction_set == InstructionSet::kNone) { 541 ScopedLocalRef<jclass> iae(env, env->FindClass("java/lang/IllegalArgumentException")); 542 std::string message(StringPrintf("Instruction set %s is invalid.", instruction_set)); 543 env->ThrowNew(iae.get(), message.c_str()); 544 return -1; 545 } 546 547 CompilerFilter::Filter filter; 548 if (!CompilerFilter::ParseCompilerFilter(compiler_filter_name, &filter)) { 549 ScopedLocalRef<jclass> iae(env, env->FindClass("java/lang/IllegalArgumentException")); 550 std::string message(StringPrintf("Compiler filter %s is invalid.", compiler_filter_name)); 551 env->ThrowNew(iae.get(), message.c_str()); 552 return -1; 553 } 554 555 std::unique_ptr<ClassLoaderContext> context = nullptr; 556 if (class_loader_context != nullptr) { 557 context = ClassLoaderContext::Create(class_loader_context); 558 559 if (context == nullptr) { 560 ScopedLocalRef<jclass> iae(env, env->FindClass("java/lang/IllegalArgumentException")); 561 std::string message(StringPrintf("Class loader context '%s' is invalid.", 562 class_loader_context)); 563 env->ThrowNew(iae.get(), message.c_str()); 564 return -1; 565 } 566 } 567 568 // TODO: Verify the dex location is well formed, and throw an IOException if 569 // not? 570 571 OatFileAssistant oat_file_assistant(filename, target_instruction_set, false); 572 573 // Always treat elements of the bootclasspath as up-to-date. 574 if (oat_file_assistant.IsInBootClassPath()) { 575 return OatFileAssistant::kNoDexOptNeeded; 576 } 577 578 return oat_file_assistant.GetDexOptNeeded(filter, 579 profile_changed, 580 downgrade, 581 context.get()); 582 } 583 584 static jstring DexFile_getDexFileStatus(JNIEnv* env, 585 jclass, 586 jstring javaFilename, 587 jstring javaInstructionSet) { 588 ScopedUtfChars filename(env, javaFilename); 589 if (env->ExceptionCheck()) { 590 return nullptr; 591 } 592 593 ScopedUtfChars instruction_set(env, javaInstructionSet); 594 if (env->ExceptionCheck()) { 595 return nullptr; 596 } 597 598 const InstructionSet target_instruction_set = GetInstructionSetFromString( 599 instruction_set.c_str()); 600 if (target_instruction_set == InstructionSet::kNone) { 601 ScopedLocalRef<jclass> iae(env, env->FindClass("java/lang/IllegalArgumentException")); 602 std::string message(StringPrintf("Instruction set %s is invalid.", instruction_set.c_str())); 603 env->ThrowNew(iae.get(), message.c_str()); 604 return nullptr; 605 } 606 607 OatFileAssistant oat_file_assistant(filename.c_str(), target_instruction_set, 608 /* load_executable= */ false); 609 return env->NewStringUTF(oat_file_assistant.GetStatusDump().c_str()); 610 } 611 612 // Return an array specifying the optimization status of the given file. 613 // The array specification is [compiler_filter, compiler_reason]. 614 static jobjectArray DexFile_getDexFileOptimizationStatus(JNIEnv* env, 615 jclass, 616 jstring javaFilename, 617 jstring javaInstructionSet) { 618 ScopedUtfChars filename(env, javaFilename); 619 if (env->ExceptionCheck()) { 620 return nullptr; 621 } 622 623 ScopedUtfChars instruction_set(env, javaInstructionSet); 624 if (env->ExceptionCheck()) { 625 return nullptr; 626 } 627 628 const InstructionSet target_instruction_set = GetInstructionSetFromString( 629 instruction_set.c_str()); 630 if (target_instruction_set == InstructionSet::kNone) { 631 ScopedLocalRef<jclass> iae(env, env->FindClass("java/lang/IllegalArgumentException")); 632 std::string message(StringPrintf("Instruction set %s is invalid.", instruction_set.c_str())); 633 env->ThrowNew(iae.get(), message.c_str()); 634 return nullptr; 635 } 636 637 std::string compilation_filter; 638 std::string compilation_reason; 639 OatFileAssistant::GetOptimizationStatus( 640 filename.c_str(), target_instruction_set, &compilation_filter, &compilation_reason); 641 642 ScopedLocalRef<jstring> j_compilation_filter(env, env->NewStringUTF(compilation_filter.c_str())); 643 if (j_compilation_filter.get() == nullptr) { 644 return nullptr; 645 } 646 ScopedLocalRef<jstring> j_compilation_reason(env, env->NewStringUTF(compilation_reason.c_str())); 647 if (j_compilation_reason.get() == nullptr) { 648 return nullptr; 649 } 650 651 // Now create output array and copy the set into it. 652 jobjectArray result = env->NewObjectArray(2, 653 WellKnownClasses::java_lang_String, 654 nullptr); 655 env->SetObjectArrayElement(result, 0, j_compilation_filter.get()); 656 env->SetObjectArrayElement(result, 1, j_compilation_reason.get()); 657 658 return result; 659 } 660 661 static jint DexFile_getDexOptNeeded(JNIEnv* env, 662 jclass, 663 jstring javaFilename, 664 jstring javaInstructionSet, 665 jstring javaTargetCompilerFilter, 666 jstring javaClassLoaderContext, 667 jboolean newProfile, 668 jboolean downgrade) { 669 ScopedUtfChars filename(env, javaFilename); 670 if (env->ExceptionCheck()) { 671 return -1; 672 } 673 674 ScopedUtfChars instruction_set(env, javaInstructionSet); 675 if (env->ExceptionCheck()) { 676 return -1; 677 } 678 679 ScopedUtfChars target_compiler_filter(env, javaTargetCompilerFilter); 680 if (env->ExceptionCheck()) { 681 return -1; 682 } 683 684 NullableScopedUtfChars class_loader_context(env, javaClassLoaderContext); 685 if (env->ExceptionCheck()) { 686 return -1; 687 } 688 689 return GetDexOptNeeded(env, 690 filename.c_str(), 691 instruction_set.c_str(), 692 target_compiler_filter.c_str(), 693 class_loader_context.c_str(), 694 newProfile == JNI_TRUE, 695 downgrade == JNI_TRUE); 696 } 697 698 // public API 699 static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename) { 700 ScopedUtfChars filename_utf(env, javaFilename); 701 if (env->ExceptionCheck()) { 702 return JNI_FALSE; 703 } 704 705 const char* filename = filename_utf.c_str(); 706 if ((filename == nullptr) || !OS::FileExists(filename)) { 707 LOG(ERROR) << "DexFile_isDexOptNeeded file '" << filename << "' does not exist"; 708 ScopedLocalRef<jclass> fnfe(env, env->FindClass("java/io/FileNotFoundException")); 709 const char* message = (filename == nullptr) ? "<empty file name>" : filename; 710 env->ThrowNew(fnfe.get(), message); 711 return JNI_FALSE; 712 } 713 714 OatFileAssistant oat_file_assistant(filename, kRuntimeISA, false); 715 return oat_file_assistant.IsUpToDate() ? JNI_FALSE : JNI_TRUE; 716 } 717 718 static jboolean DexFile_isValidCompilerFilter(JNIEnv* env, 719 jclass javeDexFileClass ATTRIBUTE_UNUSED, 720 jstring javaCompilerFilter) { 721 ScopedUtfChars compiler_filter(env, javaCompilerFilter); 722 if (env->ExceptionCheck()) { 723 return -1; 724 } 725 726 CompilerFilter::Filter filter; 727 return CompilerFilter::ParseCompilerFilter(compiler_filter.c_str(), &filter) 728 ? JNI_TRUE : JNI_FALSE; 729 } 730 731 static jboolean DexFile_isProfileGuidedCompilerFilter(JNIEnv* env, 732 jclass javeDexFileClass ATTRIBUTE_UNUSED, 733 jstring javaCompilerFilter) { 734 ScopedUtfChars compiler_filter(env, javaCompilerFilter); 735 if (env->ExceptionCheck()) { 736 return -1; 737 } 738 739 CompilerFilter::Filter filter; 740 if (!CompilerFilter::ParseCompilerFilter(compiler_filter.c_str(), &filter)) { 741 return JNI_FALSE; 742 } 743 return CompilerFilter::DependsOnProfile(filter) ? JNI_TRUE : JNI_FALSE; 744 } 745 746 static jstring DexFile_getNonProfileGuidedCompilerFilter(JNIEnv* env, 747 jclass javeDexFileClass ATTRIBUTE_UNUSED, 748 jstring javaCompilerFilter) { 749 ScopedUtfChars compiler_filter(env, javaCompilerFilter); 750 if (env->ExceptionCheck()) { 751 return nullptr; 752 } 753 754 CompilerFilter::Filter filter; 755 if (!CompilerFilter::ParseCompilerFilter(compiler_filter.c_str(), &filter)) { 756 return javaCompilerFilter; 757 } 758 759 CompilerFilter::Filter new_filter = CompilerFilter::GetNonProfileDependentFilterFrom(filter); 760 761 // Filter stayed the same, return input. 762 if (filter == new_filter) { 763 return javaCompilerFilter; 764 } 765 766 // Create a new string object and return. 767 std::string new_filter_str = CompilerFilter::NameOfFilter(new_filter); 768 return env->NewStringUTF(new_filter_str.c_str()); 769 } 770 771 static jstring DexFile_getSafeModeCompilerFilter(JNIEnv* env, 772 jclass javeDexFileClass ATTRIBUTE_UNUSED, 773 jstring javaCompilerFilter) { 774 ScopedUtfChars compiler_filter(env, javaCompilerFilter); 775 if (env->ExceptionCheck()) { 776 return nullptr; 777 } 778 779 CompilerFilter::Filter filter; 780 if (!CompilerFilter::ParseCompilerFilter(compiler_filter.c_str(), &filter)) { 781 return javaCompilerFilter; 782 } 783 784 CompilerFilter::Filter new_filter = CompilerFilter::GetSafeModeFilterFrom(filter); 785 786 // Filter stayed the same, return input. 787 if (filter == new_filter) { 788 return javaCompilerFilter; 789 } 790 791 // Create a new string object and return. 792 std::string new_filter_str = CompilerFilter::NameOfFilter(new_filter); 793 return env->NewStringUTF(new_filter_str.c_str()); 794 } 795 796 static jboolean DexFile_isBackedByOatFile(JNIEnv* env, jclass, jobject cookie) { 797 const OatFile* oat_file = nullptr; 798 std::vector<const DexFile*> dex_files; 799 if (!ConvertJavaArrayToDexFiles(env, cookie, /*out */ dex_files, /* out */ oat_file)) { 800 DCHECK(env->ExceptionCheck()); 801 return false; 802 } 803 return oat_file != nullptr; 804 } 805 806 static jobjectArray DexFile_getDexFileOutputPaths(JNIEnv* env, 807 jclass, 808 jstring javaFilename, 809 jstring javaInstructionSet) { 810 ScopedUtfChars filename(env, javaFilename); 811 if (env->ExceptionCheck()) { 812 return nullptr; 813 } 814 815 ScopedUtfChars instruction_set(env, javaInstructionSet); 816 if (env->ExceptionCheck()) { 817 return nullptr; 818 } 819 820 const InstructionSet target_instruction_set = GetInstructionSetFromString( 821 instruction_set.c_str()); 822 if (target_instruction_set == InstructionSet::kNone) { 823 ScopedLocalRef<jclass> iae(env, env->FindClass("java/lang/IllegalArgumentException")); 824 std::string message(StringPrintf("Instruction set %s is invalid.", instruction_set.c_str())); 825 env->ThrowNew(iae.get(), message.c_str()); 826 return nullptr; 827 } 828 829 OatFileAssistant oat_file_assistant(filename.c_str(), 830 target_instruction_set, 831 /* load_executable= */ false); 832 833 std::unique_ptr<OatFile> best_oat_file = oat_file_assistant.GetBestOatFile(); 834 if (best_oat_file == nullptr) { 835 return nullptr; 836 } 837 838 std::string oat_filename = best_oat_file->GetLocation(); 839 std::string vdex_filename = GetVdexFilename(best_oat_file->GetLocation()); 840 841 ScopedLocalRef<jstring> jvdexFilename(env, env->NewStringUTF(vdex_filename.c_str())); 842 if (jvdexFilename.get() == nullptr) { 843 return nullptr; 844 } 845 ScopedLocalRef<jstring> joatFilename(env, env->NewStringUTF(oat_filename.c_str())); 846 if (joatFilename.get() == nullptr) { 847 return nullptr; 848 } 849 850 // Now create output array and copy the set into it. 851 jobjectArray result = env->NewObjectArray(2, 852 WellKnownClasses::java_lang_String, 853 nullptr); 854 env->SetObjectArrayElement(result, 0, jvdexFilename.get()); 855 env->SetObjectArrayElement(result, 1, joatFilename.get()); 856 857 return result; 858 } 859 860 static jlong DexFile_getStaticSizeOfDexFile(JNIEnv* env, jclass, jobject cookie) { 861 const OatFile* oat_file = nullptr; 862 std::vector<const DexFile*> dex_files; 863 if (!ConvertJavaArrayToDexFiles(env, cookie, /*out */ dex_files, /* out */ oat_file)) { 864 DCHECK(env->ExceptionCheck()); 865 return 0; 866 } 867 868 uint64_t file_size = 0; 869 for (auto& dex_file : dex_files) { 870 if (dex_file) { 871 file_size += dex_file->GetHeader().file_size_; 872 } 873 } 874 return static_cast<jlong>(file_size); 875 } 876 877 static void DexFile_setTrusted(JNIEnv* env, jclass, jobject j_cookie) { 878 Runtime* runtime = Runtime::Current(); 879 ScopedObjectAccess soa(env); 880 881 // Currently only allow this for debuggable apps. 882 if (!runtime->IsJavaDebuggable()) { 883 ThrowSecurityException("Can't exempt class, process is not debuggable."); 884 return; 885 } 886 887 std::vector<const DexFile*> dex_files; 888 const OatFile* oat_file; 889 if (!ConvertJavaArrayToDexFiles(env, j_cookie, dex_files, oat_file)) { 890 Thread::Current()->AssertPendingException(); 891 return; 892 } 893 894 // Assign core platform domain as the dex files are allowed to access all the other domains. 895 for (const DexFile* dex_file : dex_files) { 896 const_cast<DexFile*>(dex_file)->SetHiddenapiDomain(hiddenapi::Domain::kCorePlatform); 897 } 898 } 899 900 static JNINativeMethod gMethods[] = { 901 NATIVE_METHOD(DexFile, closeDexFile, "(Ljava/lang/Object;)Z"), 902 NATIVE_METHOD(DexFile, 903 defineClassNative, 904 "(Ljava/lang/String;" 905 "Ljava/lang/ClassLoader;" 906 "Ljava/lang/Object;" 907 "Ldalvik/system/DexFile;" 908 ")Ljava/lang/Class;"), 909 NATIVE_METHOD(DexFile, getClassNameList, "(Ljava/lang/Object;)[Ljava/lang/String;"), 910 NATIVE_METHOD(DexFile, isDexOptNeeded, "(Ljava/lang/String;)Z"), 911 NATIVE_METHOD(DexFile, getDexOptNeeded, 912 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZ)I"), 913 NATIVE_METHOD(DexFile, openDexFileNative, 914 "(Ljava/lang/String;" 915 "Ljava/lang/String;" 916 "I" 917 "Ljava/lang/ClassLoader;" 918 "[Ldalvik/system/DexPathList$Element;" 919 ")Ljava/lang/Object;"), 920 NATIVE_METHOD(DexFile, openInMemoryDexFilesNative, 921 "([Ljava/nio/ByteBuffer;" 922 "[[B" 923 "[I" 924 "[I" 925 "Ljava/lang/ClassLoader;" 926 "[Ldalvik/system/DexPathList$Element;" 927 ")Ljava/lang/Object;"), 928 NATIVE_METHOD(DexFile, getClassLoaderContext, 929 "(Ljava/lang/ClassLoader;" 930 "[Ldalvik/system/DexPathList$Element;" 931 ")Ljava/lang/String;"), 932 NATIVE_METHOD(DexFile, verifyInBackgroundNative, 933 "(Ljava/lang/Object;" 934 "Ljava/lang/ClassLoader;" 935 "Ljava/lang/String;" 936 ")V"), 937 NATIVE_METHOD(DexFile, isValidCompilerFilter, "(Ljava/lang/String;)Z"), 938 NATIVE_METHOD(DexFile, isProfileGuidedCompilerFilter, "(Ljava/lang/String;)Z"), 939 NATIVE_METHOD(DexFile, 940 getNonProfileGuidedCompilerFilter, 941 "(Ljava/lang/String;)Ljava/lang/String;"), 942 NATIVE_METHOD(DexFile, 943 getSafeModeCompilerFilter, 944 "(Ljava/lang/String;)Ljava/lang/String;"), 945 NATIVE_METHOD(DexFile, isBackedByOatFile, "(Ljava/lang/Object;)Z"), 946 NATIVE_METHOD(DexFile, getDexFileStatus, 947 "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"), 948 NATIVE_METHOD(DexFile, getDexFileOutputPaths, 949 "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"), 950 NATIVE_METHOD(DexFile, getStaticSizeOfDexFile, "(Ljava/lang/Object;)J"), 951 NATIVE_METHOD(DexFile, getDexFileOptimizationStatus, 952 "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;"), 953 NATIVE_METHOD(DexFile, setTrusted, "(Ljava/lang/Object;)V") 954 }; 955 956 void register_dalvik_system_DexFile(JNIEnv* env) { 957 REGISTER_NATIVE_METHODS("dalvik/system/DexFile"); 958 } 959 960 } // namespace art 961