|  | /* | 
|  | *  Copyright 2017 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include "sdk/android/native_api/jni/class_loader.h" | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <string> | 
|  |  | 
|  | #include "rtc_base/checks.h" | 
|  | #include "sdk/android/generated_native_api_jni/WebRtcClassLoader_jni.h" | 
|  | #include "sdk/android/native_api/jni/java_types.h" | 
|  | #include "third_party/jni_zero/jni_zero.h" | 
|  |  | 
|  | // Abort the process if `jni` has a Java exception pending. This macros uses the | 
|  | // comma operator to execute ExceptionDescribe and ExceptionClear ignoring their | 
|  | // return values and sending "" to the error stream. | 
|  | #define CHECK_EXCEPTION(jni)        \ | 
|  | RTC_CHECK(!jni->ExceptionCheck()) \ | 
|  | << (jni->ExceptionDescribe(), jni->ExceptionClear(), "") | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class ClassLoader { | 
|  | public: | 
|  | explicit ClassLoader(JNIEnv* env) | 
|  | : class_loader_(jni::Java_WebRtcClassLoader_getClassLoader(env)) { | 
|  | class_loader_class_ = reinterpret_cast<jclass>( | 
|  | env->NewGlobalRef(env->FindClass("java/lang/ClassLoader"))); | 
|  | CHECK_EXCEPTION(env); | 
|  | load_class_method_ = | 
|  | env->GetMethodID(class_loader_class_, "loadClass", | 
|  | "(Ljava/lang/String;)Ljava/lang/Class;"); | 
|  | CHECK_EXCEPTION(env); | 
|  | } | 
|  |  | 
|  | ScopedJavaLocalRef<jclass> FindClass(JNIEnv* env, const char* c_name) { | 
|  | // ClassLoader.loadClass expects a classname with components separated by | 
|  | // dots instead of the slashes that JNIEnv::FindClass expects. | 
|  | std::string name(c_name); | 
|  | std::replace(name.begin(), name.end(), '/', '.'); | 
|  | ScopedJavaLocalRef<jstring> j_name = NativeToJavaString(env, name); | 
|  | const jclass clazz = static_cast<jclass>(env->CallObjectMethod( | 
|  | class_loader_.obj(), load_class_method_, j_name.obj())); | 
|  | CHECK_EXCEPTION(env); | 
|  | return ScopedJavaLocalRef<jclass>(env, clazz); | 
|  | } | 
|  |  | 
|  | private: | 
|  | ScopedJavaGlobalRef<jobject> class_loader_; | 
|  | jclass class_loader_class_; | 
|  | jmethodID load_class_method_; | 
|  | }; | 
|  |  | 
|  | static ClassLoader* g_class_loader = nullptr; | 
|  |  | 
|  | jclass GetClass(JNIEnv* env, const char* class_name, const char* unused) { | 
|  | RTC_CHECK(g_class_loader); | 
|  | return static_cast<jclass>( | 
|  | g_class_loader->FindClass(env, class_name).Release()); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | void InitClassLoader(JNIEnv* env) { | 
|  | RTC_CHECK(g_class_loader == nullptr); | 
|  | g_class_loader = new ClassLoader(env); | 
|  | jni_zero::SetClassResolver(&GetClass); | 
|  | } | 
|  |  | 
|  | ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* c_name) { | 
|  | if (g_class_loader != nullptr) { | 
|  | // The class loader will be null in the JNI code called from the ClassLoader | 
|  | // ctor when we are bootstrapping ourself. | 
|  | return g_class_loader->FindClass(env, c_name); | 
|  | } | 
|  | // jni_zero generated code uses dots instead of slashes. | 
|  | // Convert to use slashes since that's what JNI's FindClass expects. | 
|  | // See | 
|  | // https://cs.android.com/android/platform/superproject/main/+/main:art/runtime/jni/check_jni.cc;l=349;drc=0f62043c1670cd365aba1894ad8046cdfc1c905d | 
|  |  | 
|  | std::string name(c_name); | 
|  | std::replace(name.begin(), name.end(), '.', '/'); | 
|  | return ScopedJavaLocalRef<jclass>(env, env->FindClass(name.c_str())); | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |