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