in agdk/game_controller/common/JNIUtil.h [101:224]
static jclass loadClass(JNIEnv *env,
jobject activity,
const char *name,
JNINativeMethod *nativeMethods,
size_t nativeMethodsSize) {
/*
* 1. Get a classloder from actvity
* 2. Try to create the requested class from the activty classloader
* 3. If step 2 not successful then get a classloder for dex bytes (in memory or file)
* 4. If step 3 is successful then register native methods
*/
if (!env || !activity || !name) {
return nullptr;
}
jclass activityClass = env->GetObjectClass(activity);
jclass classLoaderClass = env->FindClass("java/lang/ClassLoader");
jmethodID getClassLoader = env->GetMethodID(activityClass,
"getClassLoader",
"()Ljava/lang/ClassLoader;");
jobject classLoaderObj = env->CallObjectMethod(activity, getClassLoader);
jmethodID loadClass = env->GetMethodID(classLoaderClass,
"loadClass",
"(Ljava/lang/String;)Ljava/lang/Class;");
jstring className = env->NewStringUTF(name);
jclass targetClass = static_cast<jclass>(
env->CallObjectMethod(classLoaderObj, loadClass, className));
if (env->ExceptionCheck()) {
env->ExceptionClear();
jstring dexLoaderClassName = env->NewStringUTF("dalvik/system/InMemoryDexClassLoader");
jclass imclassloaderClass = static_cast<jclass>(env->CallObjectMethod(classLoaderObj,
loadClass,
dexLoaderClassName));
env->DeleteLocalRef(dexLoaderClassName);
if (env->ExceptionCheck() || !imclassloaderClass) {
env->ExceptionClear();
// For older SDK versions <26, where InMemoryDexClassLoader is not available
dexLoaderClassName = env->NewStringUTF("dalvik/system/PathClassLoader");
imclassloaderClass = static_cast<jclass>(env->CallObjectMethod(classLoaderObj,
loadClass,
dexLoaderClassName));
env->DeleteLocalRef(dexLoaderClassName);
if (env->ExceptionCheck() || !imclassloaderClass) {
env->ExceptionDescribe();
env->ExceptionClear();
ALOGE("Unable to find dalvik/system/PathClassLoader.");
targetClass = nullptr;
} else {
jmethodID constructor
= env->GetMethodID(imclassloaderClass,
"<init>",
"(Ljava/lang/String;Ljava/lang/ClassLoader;)V");
std::string tempPath;
if (!createTempFile(env, activity, ".dex", tempPath)) {
ALOGE("Unable to create a temporary file to store DEX with Java classes.");
} else {
size_t dex_file_size =
(size_t)(&_binary_classes_dex_end - &_binary_classes_dex_start);
if (!saveBytesToFile(tempPath, &_binary_classes_dex_start,
dex_file_size)) {
ALOGE("Unable to write to %s file.", tempPath.c_str());
} else {
jstring dexPathString = env->NewStringUTF(tempPath.c_str());
jobject imclassloaderObj = env->NewObject(imclassloaderClass,
constructor,
dexPathString,
classLoaderObj);
env->DeleteLocalRef(dexPathString);
targetClass = static_cast<jclass>(
env->CallObjectMethod(imclassloaderObj, loadClass, className));
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
ALOGE("Unable to find %s class", name);
} else {
env->RegisterNatives(targetClass,
nativeMethods, nativeMethodsSize);
ALOGI("Using internal %s class from dex bytes.", name);
}
if (imclassloaderObj) {
env->DeleteLocalRef(imclassloaderObj);
}
}
deleteFile(tempPath);
}
}
} else {
jmethodID constructor =
env->GetMethodID(imclassloaderClass,
"<init>",
"(Ljava/nio/ByteBuffer;Ljava/lang/ClassLoader;)V");
size_t dex_file_size =
(size_t)(&_binary_classes_dex_end - &_binary_classes_dex_start);
auto byteBuffer = env->NewDirectByteBuffer((void *) &_binary_classes_dex_start,
dex_file_size);
jobject imclassloaderObj = env->NewObject(imclassloaderClass,
constructor,
byteBuffer,
classLoaderObj);
targetClass = static_cast<jclass>(
env->CallObjectMethod(imclassloaderObj, loadClass, className));
if (env->ExceptionCheck()) {
env->ExceptionDescribe();
env->ExceptionClear();
ALOGE("Unable to find %s class", name);
} else {
env->RegisterNatives(targetClass, nativeMethods, nativeMethodsSize);
ALOGI("Using internal %s class from dex bytes.", name);
}
if (imclassloaderObj) {
env->DeleteLocalRef(imclassloaderObj);
}
}
if (imclassloaderClass) {
env->DeleteLocalRef(imclassloaderClass);
}
}
env->DeleteLocalRef(className);
return targetClass;
}