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