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