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