static jclass loadClass()

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;
    }