blob: e32545bc2ec3909cc83093716cec51f973ab82af [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
Orion Hodsona4c2a052016-08-17 10:51:42 +010019#include "class_linker.h"
20#include "common_throws.h"
21#include "dex_file.h"
22#include "jni_internal.h"
23#include "mem_map.h"
24#include "mirror/class_loader.h"
25#include "mirror/object-inl.h"
David Sehr9aa352e2016-09-15 18:13:52 -070026#include "oat_file.h"
Mathieu Chartier0795f232016-09-27 18:43:30 -070027#include "scoped_thread_state_change-inl.h"
Orion Hodsona4c2a052016-08-17 10:51:42 +010028#include "ScopedUtfChars.h"
29
30namespace art {
31
32static std::unique_ptr<MemMap> AllocateDexMemoryMap(JNIEnv* env, jint start, jint end) {
33 if (end <= start) {
34 ScopedObjectAccess soa(env);
35 ThrowWrappedIOException("Bad range");
36 return nullptr;
37 }
38
39 std::string error_message;
40 size_t length = static_cast<size_t>(end - start);
41 std::unique_ptr<MemMap> dex_mem_map(MemMap::MapAnonymous("DEX data",
42 nullptr,
43 length,
44 PROT_READ | PROT_WRITE,
45 /* low_4gb */ false,
46 /* reuse */ false,
47 &error_message));
48 if (dex_mem_map == nullptr) {
49 ScopedObjectAccess soa(env);
50 ThrowWrappedIOException("%s", error_message.c_str());
51 }
52 return dex_mem_map;
53}
54
55static jlong DexFileToCookie(const DexFile* dex_file) {
56 return reinterpret_cast<jlong>(dex_file);
57}
58
59static const DexFile* CookieToDexFile(jlong cookie) {
60 return reinterpret_cast<const DexFile*>(cookie);
61}
62
63static const DexFile* CreateDexFile(JNIEnv* env, std::unique_ptr<MemMap> dex_mem_map) {
64 std::string location = StringPrintf("InMemoryDexClassLoader_DexData@%p-%p",
65 dex_mem_map->Begin(),
66 dex_mem_map->End());
67 std::string error_message;
68 std::unique_ptr<const DexFile> dex_file(DexFile::Open(location,
69 0,
70 std::move(dex_mem_map),
71 /* verify */ true,
72 /* verify_location */ true,
73 &error_message));
74 if (dex_file == nullptr) {
75 ScopedObjectAccess soa(env);
76 ThrowWrappedIOException("%s", error_message.c_str());
77 return nullptr;
78 }
79
80 if (!dex_file->DisableWrite()) {
81 ScopedObjectAccess soa(env);
82 ThrowWrappedIOException("Failed to make dex file read-only");
83 return nullptr;
84 }
85
86 return dex_file.release();
87}
88
89static jlong InMemoryDexClassLoader_DexData_initializeWithDirectBuffer(
90 JNIEnv* env, jclass, jobject buffer, jint start, jint end) {
91 uint8_t* base_address = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
92 if (base_address == nullptr) {
93 ScopedObjectAccess soa(env);
94 ThrowWrappedIOException("dexFileBuffer not direct");
95 return 0;
96 }
97
98 std::unique_ptr<MemMap> dex_mem_map(AllocateDexMemoryMap(env, start, end));
99 if (dex_mem_map == nullptr) {
100 DCHECK(Thread::Current()->IsExceptionPending());
101 return 0;
102 }
103
104 size_t length = static_cast<size_t>(end - start);
105 memcpy(dex_mem_map->Begin(), base_address, length);
106 return DexFileToCookie(CreateDexFile(env, std::move(dex_mem_map)));
107}
108
109static jlong InMemoryDexClassLoader_DexData_initializeWithArray(
110 JNIEnv* env, jclass, jbyteArray buffer, jint start, jint end) {
111 std::unique_ptr<MemMap> dex_mem_map(AllocateDexMemoryMap(env, start, end));
112 if (dex_mem_map == nullptr) {
113 DCHECK(Thread::Current()->IsExceptionPending());
114 return 0;
115 }
116
117 auto destination = reinterpret_cast<jbyte*>(dex_mem_map.get()->Begin());
118 env->GetByteArrayRegion(buffer, start, end - start, destination);
119 return DexFileToCookie(CreateDexFile(env, std::move(dex_mem_map)));
120}
121
122static void InMemoryDexClassLoader_DexData_uninitialize(JNIEnv* env, jclass, jlong cookie) {
123 const DexFile* dex_file = CookieToDexFile(cookie);
124 if (kIsDebugBuild) {
125 ScopedObjectAccess soa(env);
126 ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
127 CHECK(class_linker->FindDexCache(soa.Self(), *dex_file, true) == nullptr);
128 }
129 delete dex_file;
130}
131
132static jclass InMemoryDexClassLoader_DexData_findClass(
133 JNIEnv* env, jobject dexData, jstring name, jobject loader, jlong cookie) {
134 ScopedUtfChars scoped_class_name(env, name);
135 if (env->ExceptionCheck()) {
136 return nullptr;
137 }
138
139 const char* class_name = scoped_class_name.c_str();
140 const std::string descriptor(DotToDescriptor(class_name));
141 const char* class_descriptor = descriptor.c_str();
142 const size_t hash = ComputeModifiedUtf8Hash(class_descriptor);
143 const DexFile* dex_file = CookieToDexFile(cookie);
David Sehr9aa352e2016-09-15 18:13:52 -0700144 const DexFile::ClassDef* dex_class_def =
145 OatDexFile::FindClassDef(*dex_file, class_descriptor, hash);
Orion Hodsona4c2a052016-08-17 10:51:42 +0100146 if (dex_class_def != nullptr) {
147 ScopedObjectAccess soa(env);
148 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
149 StackHandleScope<1> handle_scope(soa.Self());
150 Handle<mirror::ClassLoader> class_loader(
Mathieu Chartier0795f232016-09-27 18:43:30 -0700151 handle_scope.NewHandle(soa.Decode<mirror::ClassLoader>(loader)));
Orion Hodsona4c2a052016-08-17 10:51:42 +0100152 class_linker->RegisterDexFile(*dex_file, class_loader.Get());
153 mirror::Class* result = class_linker->DefineClass(
154 soa.Self(), class_descriptor, hash, class_loader, *dex_file, *dex_class_def);
155 if (result != nullptr) {
156 // Ensure the class table has a strong reference to the
157 // InMemoryClassLoader/DexData instance now that a class has
158 // been loaded.
159 class_linker->InsertDexFileInToClassLoader(
Mathieu Chartier1cc62e42016-10-03 18:01:28 -0700160 soa.Decode<mirror::Object>(dexData).Ptr(), class_loader.Get());
Orion Hodsona4c2a052016-08-17 10:51:42 +0100161 return soa.AddLocalReference<jclass>(result);
162 }
163 }
164
165 VLOG(class_linker) << "Failed to find dex_class_def " << class_name;
166 return nullptr;
167}
168
169static JNINativeMethod gMethods[] = {
170 NATIVE_METHOD(InMemoryDexClassLoader_DexData,
171 initializeWithDirectBuffer,
172 "(Ljava/nio/ByteBuffer;II)J"),
173 NATIVE_METHOD(InMemoryDexClassLoader_DexData, initializeWithArray, "([BII)J"),
174 NATIVE_METHOD(InMemoryDexClassLoader_DexData, uninitialize, "(J)V"),
175 NATIVE_METHOD(InMemoryDexClassLoader_DexData,
176 findClass,
177 "(Ljava/lang/String;Ljava/lang/ClassLoader;J)Ljava/lang/Class;"),
178};
179
180void register_dalvik_system_InMemoryDexClassLoader_DexData(JNIEnv* env) {
181 REGISTER_NATIVE_METHODS("dalvik/system/InMemoryDexClassLoader$DexData");
182}
183
184} // namespace art