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