blob: 07959607fc36a0d4eb5c0133f7ded00d94ff39b9 [file] [log] [blame]
Orion Hodsona4c2a052016-08-17 10:51:42 +01001/*
2 * Copyright (C) 2016 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_InMemoryDexClassLoader_DexData.h"
18
Andreas Gampe46ee31b2016-12-14 10:11:49 -080019#include "android-base/stringprintf.h"
20
Orion Hodsona4c2a052016-08-17 10:51:42 +010021#include "class_linker.h"
22#include "common_throws.h"
23#include "dex_file.h"
24#include "jni_internal.h"
25#include "mem_map.h"
26#include "mirror/class_loader.h"
27#include "mirror/object-inl.h"
David Sehr9aa352e2016-09-15 18:13:52 -070028#include "oat_file.h"
Mathieu Chartier0795f232016-09-27 18:43:30 -070029#include "scoped_thread_state_change-inl.h"
Orion Hodsona4c2a052016-08-17 10:51:42 +010030#include "ScopedUtfChars.h"
31
32namespace art {
33
Andreas Gampe46ee31b2016-12-14 10:11:49 -080034using android::base::StringPrintf;
35
Orion Hodsona4c2a052016-08-17 10:51:42 +010036static std::unique_ptr<MemMap> AllocateDexMemoryMap(JNIEnv* env, jint start, jint end) {
37 if (end <= start) {
38 ScopedObjectAccess soa(env);
39 ThrowWrappedIOException("Bad range");
40 return nullptr;
41 }
42
43 std::string error_message;
44 size_t length = static_cast<size_t>(end - start);
45 std::unique_ptr<MemMap> dex_mem_map(MemMap::MapAnonymous("DEX data",
46 nullptr,
47 length,
48 PROT_READ | PROT_WRITE,
49 /* low_4gb */ false,
50 /* reuse */ false,
51 &error_message));
52 if (dex_mem_map == nullptr) {
53 ScopedObjectAccess soa(env);
54 ThrowWrappedIOException("%s", error_message.c_str());
55 }
56 return dex_mem_map;
57}
58
59static jlong DexFileToCookie(const DexFile* dex_file) {
60 return reinterpret_cast<jlong>(dex_file);
61}
62
63static const DexFile* CookieToDexFile(jlong cookie) {
64 return reinterpret_cast<const DexFile*>(cookie);
65}
66
67static const DexFile* CreateDexFile(JNIEnv* env, std::unique_ptr<MemMap> dex_mem_map) {
68 std::string location = StringPrintf("InMemoryDexClassLoader_DexData@%p-%p",
69 dex_mem_map->Begin(),
70 dex_mem_map->End());
71 std::string error_message;
72 std::unique_ptr<const DexFile> dex_file(DexFile::Open(location,
73 0,
74 std::move(dex_mem_map),
75 /* verify */ true,
76 /* verify_location */ true,
77 &error_message));
78 if (dex_file == nullptr) {
79 ScopedObjectAccess soa(env);
80 ThrowWrappedIOException("%s", error_message.c_str());
81 return nullptr;
82 }
83
84 if (!dex_file->DisableWrite()) {
85 ScopedObjectAccess soa(env);
86 ThrowWrappedIOException("Failed to make dex file read-only");
87 return nullptr;
88 }
89
90 return dex_file.release();
91}
92
93static jlong InMemoryDexClassLoader_DexData_initializeWithDirectBuffer(
94 JNIEnv* env, jclass, jobject buffer, jint start, jint end) {
95 uint8_t* base_address = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
96 if (base_address == nullptr) {
97 ScopedObjectAccess soa(env);
98 ThrowWrappedIOException("dexFileBuffer not direct");
99 return 0;
100 }
101
102 std::unique_ptr<MemMap> dex_mem_map(AllocateDexMemoryMap(env, start, end));
103 if (dex_mem_map == nullptr) {
104 DCHECK(Thread::Current()->IsExceptionPending());
105 return 0;
106 }
107
108 size_t length = static_cast<size_t>(end - start);
109 memcpy(dex_mem_map->Begin(), base_address, length);
110 return DexFileToCookie(CreateDexFile(env, std::move(dex_mem_map)));
111}
112
113static jlong InMemoryDexClassLoader_DexData_initializeWithArray(
114 JNIEnv* env, jclass, jbyteArray buffer, jint start, jint end) {
115 std::unique_ptr<MemMap> dex_mem_map(AllocateDexMemoryMap(env, start, end));
116 if (dex_mem_map == nullptr) {
117 DCHECK(Thread::Current()->IsExceptionPending());
118 return 0;
119 }
120
121 auto destination = reinterpret_cast<jbyte*>(dex_mem_map.get()->Begin());
122 env->GetByteArrayRegion(buffer, start, end - start, destination);
123 return DexFileToCookie(CreateDexFile(env, std::move(dex_mem_map)));
124}
125
126static void InMemoryDexClassLoader_DexData_uninitialize(JNIEnv* env, jclass, jlong cookie) {
127 const DexFile* dex_file = CookieToDexFile(cookie);
128 if (kIsDebugBuild) {
129 ScopedObjectAccess soa(env);
130 ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
Vladimir Markocd556b02017-02-03 11:47:34 +0000131 CHECK(!class_linker->IsDexFileRegistered(soa.Self(), *dex_file));
Orion Hodsona4c2a052016-08-17 10:51:42 +0100132 }
133 delete dex_file;
134}
135
136static jclass InMemoryDexClassLoader_DexData_findClass(
137 JNIEnv* env, jobject dexData, jstring name, jobject loader, jlong cookie) {
138 ScopedUtfChars scoped_class_name(env, name);
139 if (env->ExceptionCheck()) {
140 return nullptr;
141 }
142
143 const char* class_name = scoped_class_name.c_str();
144 const std::string descriptor(DotToDescriptor(class_name));
145 const char* class_descriptor = descriptor.c_str();
146 const size_t hash = ComputeModifiedUtf8Hash(class_descriptor);
147 const DexFile* dex_file = CookieToDexFile(cookie);
David Sehr9aa352e2016-09-15 18:13:52 -0700148 const DexFile::ClassDef* dex_class_def =
149 OatDexFile::FindClassDef(*dex_file, class_descriptor, hash);
Orion Hodsona4c2a052016-08-17 10:51:42 +0100150 if (dex_class_def != nullptr) {
151 ScopedObjectAccess soa(env);
152 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
153 StackHandleScope<1> handle_scope(soa.Self());
154 Handle<mirror::ClassLoader> class_loader(
Mathieu Chartier0795f232016-09-27 18:43:30 -0700155 handle_scope.NewHandle(soa.Decode<mirror::ClassLoader>(loader)));
Vladimir Markocd556b02017-02-03 11:47:34 +0000156 ObjPtr<mirror::DexCache> dex_cache =
157 class_linker->RegisterDexFile(*dex_file, class_loader.Get());
158 if (dex_cache == nullptr) {
159 // OOME or InternalError (dexFile already registered with a different class loader).
160 soa.Self()->AssertPendingException();
161 return nullptr;
162 }
Mathieu Chartierbc5a7952016-10-17 15:46:31 -0700163 ObjPtr<mirror::Class> result = class_linker->DefineClass(
164 soa.Self(),
165 class_descriptor,
166 hash, class_loader,
167 *dex_file,
168 *dex_class_def);
Orion Hodsona4c2a052016-08-17 10:51:42 +0100169 if (result != nullptr) {
170 // Ensure the class table has a strong reference to the
171 // InMemoryClassLoader/DexData instance now that a class has
172 // been loaded.
Mathieu Chartierbc5a7952016-10-17 15:46:31 -0700173 class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object>(dexData),
174 class_loader.Get());
Orion Hodsona4c2a052016-08-17 10:51:42 +0100175 return soa.AddLocalReference<jclass>(result);
176 }
177 }
178
179 VLOG(class_linker) << "Failed to find dex_class_def " << class_name;
180 return nullptr;
181}
182
183static JNINativeMethod gMethods[] = {
184 NATIVE_METHOD(InMemoryDexClassLoader_DexData,
185 initializeWithDirectBuffer,
186 "(Ljava/nio/ByteBuffer;II)J"),
187 NATIVE_METHOD(InMemoryDexClassLoader_DexData, initializeWithArray, "([BII)J"),
188 NATIVE_METHOD(InMemoryDexClassLoader_DexData, uninitialize, "(J)V"),
189 NATIVE_METHOD(InMemoryDexClassLoader_DexData,
190 findClass,
191 "(Ljava/lang/String;Ljava/lang/ClassLoader;J)Ljava/lang/Class;"),
192};
193
194void register_dalvik_system_InMemoryDexClassLoader_DexData(JNIEnv* env) {
195 REGISTER_NATIVE_METHODS("dalvik/system/InMemoryDexClassLoader$DexData");
196}
197
198} // namespace art