blob: db245aa0d8c38eb88aea507d36b2b5afb754b065 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "dalvik_system_InMemoryDexClassLoader_DexData.h"
#include "class_linker.h"
#include "common_throws.h"
#include "dex_file.h"
#include "jni_internal.h"
#include "mem_map.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
#include "oat_file.h"
#include "scoped_thread_state_change-inl.h"
#include "ScopedUtfChars.h"
namespace art {
static std::unique_ptr<MemMap> AllocateDexMemoryMap(JNIEnv* env, jint start, jint end) {
if (end <= start) {
ScopedObjectAccess soa(env);
ThrowWrappedIOException("Bad range");
return nullptr;
}
std::string error_message;
size_t length = static_cast<size_t>(end - start);
std::unique_ptr<MemMap> dex_mem_map(MemMap::MapAnonymous("DEX data",
nullptr,
length,
PROT_READ | PROT_WRITE,
/* low_4gb */ false,
/* reuse */ false,
&error_message));
if (dex_mem_map == nullptr) {
ScopedObjectAccess soa(env);
ThrowWrappedIOException("%s", error_message.c_str());
}
return dex_mem_map;
}
static jlong DexFileToCookie(const DexFile* dex_file) {
return reinterpret_cast<jlong>(dex_file);
}
static const DexFile* CookieToDexFile(jlong cookie) {
return reinterpret_cast<const DexFile*>(cookie);
}
static const DexFile* CreateDexFile(JNIEnv* env, std::unique_ptr<MemMap> dex_mem_map) {
std::string location = StringPrintf("InMemoryDexClassLoader_DexData@%p-%p",
dex_mem_map->Begin(),
dex_mem_map->End());
std::string error_message;
std::unique_ptr<const DexFile> dex_file(DexFile::Open(location,
0,
std::move(dex_mem_map),
/* verify */ true,
/* verify_location */ true,
&error_message));
if (dex_file == nullptr) {
ScopedObjectAccess soa(env);
ThrowWrappedIOException("%s", error_message.c_str());
return nullptr;
}
if (!dex_file->DisableWrite()) {
ScopedObjectAccess soa(env);
ThrowWrappedIOException("Failed to make dex file read-only");
return nullptr;
}
return dex_file.release();
}
static jlong InMemoryDexClassLoader_DexData_initializeWithDirectBuffer(
JNIEnv* env, jclass, jobject buffer, jint start, jint end) {
uint8_t* base_address = reinterpret_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
if (base_address == nullptr) {
ScopedObjectAccess soa(env);
ThrowWrappedIOException("dexFileBuffer not direct");
return 0;
}
std::unique_ptr<MemMap> dex_mem_map(AllocateDexMemoryMap(env, start, end));
if (dex_mem_map == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
return 0;
}
size_t length = static_cast<size_t>(end - start);
memcpy(dex_mem_map->Begin(), base_address, length);
return DexFileToCookie(CreateDexFile(env, std::move(dex_mem_map)));
}
static jlong InMemoryDexClassLoader_DexData_initializeWithArray(
JNIEnv* env, jclass, jbyteArray buffer, jint start, jint end) {
std::unique_ptr<MemMap> dex_mem_map(AllocateDexMemoryMap(env, start, end));
if (dex_mem_map == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
return 0;
}
auto destination = reinterpret_cast<jbyte*>(dex_mem_map.get()->Begin());
env->GetByteArrayRegion(buffer, start, end - start, destination);
return DexFileToCookie(CreateDexFile(env, std::move(dex_mem_map)));
}
static void InMemoryDexClassLoader_DexData_uninitialize(JNIEnv* env, jclass, jlong cookie) {
const DexFile* dex_file = CookieToDexFile(cookie);
if (kIsDebugBuild) {
ScopedObjectAccess soa(env);
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
CHECK(class_linker->FindDexCache(soa.Self(), *dex_file, true) == nullptr);
}
delete dex_file;
}
static jclass InMemoryDexClassLoader_DexData_findClass(
JNIEnv* env, jobject dexData, jstring name, jobject loader, jlong cookie) {
ScopedUtfChars scoped_class_name(env, name);
if (env->ExceptionCheck()) {
return nullptr;
}
const char* class_name = scoped_class_name.c_str();
const std::string descriptor(DotToDescriptor(class_name));
const char* class_descriptor = descriptor.c_str();
const size_t hash = ComputeModifiedUtf8Hash(class_descriptor);
const DexFile* dex_file = CookieToDexFile(cookie);
const DexFile::ClassDef* dex_class_def =
OatDexFile::FindClassDef(*dex_file, class_descriptor, hash);
if (dex_class_def != nullptr) {
ScopedObjectAccess soa(env);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
StackHandleScope<1> handle_scope(soa.Self());
Handle<mirror::ClassLoader> class_loader(
handle_scope.NewHandle(soa.Decode<mirror::ClassLoader>(loader)));
class_linker->RegisterDexFile(*dex_file, class_loader.Get());
ObjPtr<mirror::Class> result = class_linker->DefineClass(
soa.Self(),
class_descriptor,
hash, class_loader,
*dex_file,
*dex_class_def);
if (result != nullptr) {
// Ensure the class table has a strong reference to the
// InMemoryClassLoader/DexData instance now that a class has
// been loaded.
class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object>(dexData),
class_loader.Get());
return soa.AddLocalReference<jclass>(result);
}
}
VLOG(class_linker) << "Failed to find dex_class_def " << class_name;
return nullptr;
}
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(InMemoryDexClassLoader_DexData,
initializeWithDirectBuffer,
"(Ljava/nio/ByteBuffer;II)J"),
NATIVE_METHOD(InMemoryDexClassLoader_DexData, initializeWithArray, "([BII)J"),
NATIVE_METHOD(InMemoryDexClassLoader_DexData, uninitialize, "(J)V"),
NATIVE_METHOD(InMemoryDexClassLoader_DexData,
findClass,
"(Ljava/lang/String;Ljava/lang/ClassLoader;J)Ljava/lang/Class;"),
};
void register_dalvik_system_InMemoryDexClassLoader_DexData(JNIEnv* env) {
REGISTER_NATIVE_METHODS("dalvik/system/InMemoryDexClassLoader$DexData");
}
} // namespace art