blob: 2c06460f9eb8058e25f220a360c8029e180bfa62 [file] [log] [blame]
Magnus Jedvert3111e5f2017-11-07 12:33:43 +01001/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Sami Kalliomäki82f96e62018-01-29 13:18:57 +010011#include "sdk/android/native_api/jni/class_loader.h"
Magnus Jedvert3111e5f2017-11-07 12:33:43 +010012
13#include <algorithm>
14#include <string>
15
16#include "rtc_base/checks.h"
Sami Kalliomäki82f96e62018-01-29 13:18:57 +010017#include "sdk/android/generated_native_api_jni/jni/WebRtcClassLoader_jni.h"
18#include "sdk/android/native_api/jni/java_types.h"
19#include "sdk/android/native_api/jni/scoped_java_ref.h"
Magnus Jedvert3111e5f2017-11-07 12:33:43 +010020
21// Abort the process if |jni| has a Java exception pending. This macros uses the
22// comma operator to execute ExceptionDescribe and ExceptionClear ignoring their
23// return values and sending "" to the error stream.
24#define CHECK_EXCEPTION(jni) \
25 RTC_CHECK(!jni->ExceptionCheck()) \
26 << (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
27
28namespace webrtc {
Magnus Jedvert3111e5f2017-11-07 12:33:43 +010029
30namespace {
31
32class ClassLoader {
33 public:
Magnus Jedvert84d8ae52017-12-20 15:12:10 +010034 explicit ClassLoader(JNIEnv* env)
Magnus Jedvertc7da2662018-05-18 12:13:56 +020035 : class_loader_(jni::Java_WebRtcClassLoader_getClassLoader(env)) {
Magnus Jedvert3111e5f2017-11-07 12:33:43 +010036 class_loader_class_ = reinterpret_cast<jclass>(
37 env->NewGlobalRef(env->FindClass("java/lang/ClassLoader")));
38 CHECK_EXCEPTION(env);
39 load_class_method_ =
40 env->GetMethodID(class_loader_class_, "loadClass",
41 "(Ljava/lang/String;)Ljava/lang/Class;");
42 CHECK_EXCEPTION(env);
Magnus Jedvert3111e5f2017-11-07 12:33:43 +010043 }
44
Magnus Jedvert84d8ae52017-12-20 15:12:10 +010045 ScopedJavaLocalRef<jclass> FindClass(JNIEnv* env, const char* c_name) {
Magnus Jedvert3111e5f2017-11-07 12:33:43 +010046 // ClassLoader.loadClass expects a classname with components separated by
47 // dots instead of the slashes that JNIEnv::FindClass expects.
48 std::string name(c_name);
49 std::replace(name.begin(), name.end(), '/', '.');
Magnus Jedvert84d8ae52017-12-20 15:12:10 +010050 ScopedJavaLocalRef<jstring> j_name = NativeToJavaString(env, name);
51 const jclass clazz = static_cast<jclass>(env->CallObjectMethod(
52 class_loader_.obj(), load_class_method_, j_name.obj()));
Magnus Jedvert3111e5f2017-11-07 12:33:43 +010053 CHECK_EXCEPTION(env);
Magnus Jedvert84d8ae52017-12-20 15:12:10 +010054 return ScopedJavaLocalRef<jclass>(env, clazz);
Magnus Jedvert3111e5f2017-11-07 12:33:43 +010055 }
56
57 private:
Magnus Jedvert84d8ae52017-12-20 15:12:10 +010058 ScopedJavaGlobalRef<jobject> class_loader_;
Magnus Jedvert3111e5f2017-11-07 12:33:43 +010059 jclass class_loader_class_;
60 jmethodID load_class_method_;
Magnus Jedvert3111e5f2017-11-07 12:33:43 +010061};
62
63static ClassLoader* g_class_loader = nullptr;
64
65} // namespace
66
67void InitClassLoader(JNIEnv* env) {
68 RTC_CHECK(g_class_loader == nullptr);
69 g_class_loader = new ClassLoader(env);
70}
71
Magnus Jedvert84d8ae52017-12-20 15:12:10 +010072ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* name) {
Magnus Jedvert3111e5f2017-11-07 12:33:43 +010073 // The class loader will be null in the JNI code called from the ClassLoader
74 // ctor when we are bootstrapping ourself.
Magnus Jedvert84d8ae52017-12-20 15:12:10 +010075 return (g_class_loader == nullptr)
76 ? ScopedJavaLocalRef<jclass>(env, env->FindClass(name))
77 : g_class_loader->FindClass(env, name);
Magnus Jedvert3111e5f2017-11-07 12:33:43 +010078}
79
Magnus Jedvert3111e5f2017-11-07 12:33:43 +010080} // namespace webrtc