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