Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "dalvik_system_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