1 /*
2 * Copyright 2015 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 #include "examples/unityplugin/class_reference_holder.h"
11
12 #include <utility>
13
14 #include "sdk/android/src/jni/jni_helpers.h"
15
16 namespace unity_plugin {
17
18 // ClassReferenceHolder holds global reference to Java classes in app/webrtc.
19 class ClassReferenceHolder {
20 public:
21 explicit ClassReferenceHolder(JNIEnv* jni);
22 ~ClassReferenceHolder();
23
24 void FreeReferences(JNIEnv* jni);
25 jclass GetClass(const std::string& name);
26
27 void LoadClass(JNIEnv* jni, const std::string& name);
28
29 private:
30 std::map<std::string, jclass> classes_;
31 };
32
33 // Allocated in LoadGlobalClassReferenceHolder(),
34 // freed in FreeGlobalClassReferenceHolder().
35 static ClassReferenceHolder* g_class_reference_holder = nullptr;
36
LoadGlobalClassReferenceHolder()37 void LoadGlobalClassReferenceHolder() {
38 RTC_CHECK(g_class_reference_holder == nullptr);
39 g_class_reference_holder = new ClassReferenceHolder(webrtc::jni::GetEnv());
40 }
41
FreeGlobalClassReferenceHolder()42 void FreeGlobalClassReferenceHolder() {
43 g_class_reference_holder->FreeReferences(
44 webrtc::jni::AttachCurrentThreadIfNeeded());
45 delete g_class_reference_holder;
46 g_class_reference_holder = nullptr;
47 }
48
ClassReferenceHolder(JNIEnv * jni)49 ClassReferenceHolder::ClassReferenceHolder(JNIEnv* jni) {
50 LoadClass(jni, "org/webrtc/UnityUtility");
51 }
52
~ClassReferenceHolder()53 ClassReferenceHolder::~ClassReferenceHolder() {
54 RTC_CHECK(classes_.empty()) << "Must call FreeReferences() before dtor!";
55 }
56
FreeReferences(JNIEnv * jni)57 void ClassReferenceHolder::FreeReferences(JNIEnv* jni) {
58 for (std::map<std::string, jclass>::const_iterator it = classes_.begin();
59 it != classes_.end(); ++it) {
60 jni->DeleteGlobalRef(it->second);
61 }
62 classes_.clear();
63 }
64
GetClass(const std::string & name)65 jclass ClassReferenceHolder::GetClass(const std::string& name) {
66 std::map<std::string, jclass>::iterator it = classes_.find(name);
67 RTC_CHECK(it != classes_.end()) << "Unexpected GetClass() call for: " << name;
68 return it->second;
69 }
70
LoadClass(JNIEnv * jni,const std::string & name)71 void ClassReferenceHolder::LoadClass(JNIEnv* jni, const std::string& name) {
72 jclass localRef = jni->FindClass(name.c_str());
73 CHECK_EXCEPTION(jni) << "error during FindClass: " << name;
74 RTC_CHECK(localRef) << name;
75 jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
76 CHECK_EXCEPTION(jni) << "error during NewGlobalRef: " << name;
77 RTC_CHECK(globalRef) << name;
78 bool inserted = classes_.insert(std::make_pair(name, globalRef)).second;
79 RTC_CHECK(inserted) << "Duplicate class name: " << name;
80 }
81
82 // Returns a global reference guaranteed to be valid for the lifetime of the
83 // process.
FindClass(JNIEnv * jni,const char * name)84 jclass FindClass(JNIEnv* jni, const char* name) {
85 return g_class_reference_holder->GetClass(name);
86 }
87
88 } // namespace unity_plugin
89