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