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