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