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