tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

jvm_android.cc (8837B)


      1 /*
      2 *  Copyright (c) 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 
     11 #include "modules/utility/include/jvm_android.h"
     12 
     13 #include <jni.h>
     14 
     15 #include <cstdarg>
     16 #include <cstring>
     17 #include <memory>
     18 #include <string>
     19 
     20 #include "modules/utility/include/helpers_android.h"
     21 #include "rtc_base/checks.h"
     22 #include "rtc_base/logging.h"
     23 
     24 namespace webrtc {
     25 
     26 JVM* g_jvm;
     27 
     28 // TODO(henrika): add more clases here if needed.
     29 struct {
     30  const char* name;
     31  jclass clazz;
     32 } loaded_classes[] = {};
     33 
     34 // Android's FindClass() is trickier than usual because the app-specific
     35 // ClassLoader is not consulted when there is no app-specific frame on the
     36 // stack.  Consequently, we only look up all classes once in native WebRTC.
     37 // http://developer.android.com/training/articles/perf-jni.html#faq_FindClass
     38 void LoadClasses(JNIEnv* jni) {
     39  RTC_LOG(LS_INFO) << "LoadClasses:";
     40  for (auto& c : loaded_classes) {
     41    jclass localRef = FindClass(jni, c.name);
     42    RTC_LOG(LS_INFO) << "name: " << c.name;
     43    CHECK_EXCEPTION(jni) << "Error during FindClass: " << c.name;
     44    RTC_CHECK(localRef) << c.name;
     45    jclass globalRef = reinterpret_cast<jclass>(jni->NewGlobalRef(localRef));
     46    CHECK_EXCEPTION(jni) << "Error during NewGlobalRef: " << c.name;
     47    RTC_CHECK(globalRef) << c.name;
     48    c.clazz = globalRef;
     49  }
     50 }
     51 
     52 void FreeClassReferences(JNIEnv* jni) {
     53  for (auto& c : loaded_classes) {
     54    jni->DeleteGlobalRef(c.clazz);
     55    c.clazz = nullptr;
     56  }
     57 }
     58 
     59 jclass LookUpClass(const char* name) {
     60  for (auto& c : loaded_classes) {
     61    if (strcmp(c.name, name) == 0)
     62      return c.clazz;
     63  }
     64  RTC_CHECK(false) << "Unable to find class in lookup table";
     65  return 0;
     66 }
     67 
     68 // JvmThreadConnector implementation.
     69 JvmThreadConnector::JvmThreadConnector() : attached_(false) {
     70  RTC_LOG(LS_INFO) << "JvmThreadConnector::ctor";
     71  JavaVM* jvm = JVM::GetInstance()->jvm();
     72  RTC_CHECK(jvm);
     73  JNIEnv* jni = GetEnv(jvm);
     74  if (!jni) {
     75    RTC_LOG(LS_INFO) << "Attaching thread to JVM";
     76    JNIEnv* env = nullptr;
     77    jint ret = jvm->AttachCurrentThread(&env, nullptr);
     78    attached_ = (ret == JNI_OK);
     79  }
     80 }
     81 
     82 JvmThreadConnector::~JvmThreadConnector() {
     83  RTC_LOG(LS_INFO) << "JvmThreadConnector::dtor";
     84  RTC_DCHECK(thread_checker_.IsCurrent());
     85  if (attached_) {
     86    RTC_LOG(LS_INFO) << "Detaching thread from JVM";
     87    jint res = JVM::GetInstance()->jvm()->DetachCurrentThread();
     88    RTC_CHECK(res == JNI_OK) << "DetachCurrentThread failed: " << res;
     89  }
     90 }
     91 
     92 // GlobalRef implementation.
     93 GlobalRef::GlobalRef(JNIEnv* jni, jobject object)
     94    : jni_(jni), j_object_(NewGlobalRef(jni, object)) {
     95  RTC_LOG(LS_INFO) << "GlobalRef::ctor";
     96 }
     97 
     98 GlobalRef::~GlobalRef() {
     99  RTC_LOG(LS_INFO) << "GlobalRef::dtor";
    100  DeleteGlobalRef(jni_, j_object_);
    101 }
    102 
    103 jboolean GlobalRef::CallBooleanMethod(jmethodID methodID, ...) {
    104  va_list args;
    105  va_start(args, methodID);
    106  jboolean res = jni_->CallBooleanMethodV(j_object_, methodID, args);
    107  CHECK_EXCEPTION(jni_) << "Error during CallBooleanMethod";
    108  va_end(args);
    109  return res;
    110 }
    111 
    112 jint GlobalRef::CallIntMethod(jmethodID methodID, ...) {
    113  va_list args;
    114  va_start(args, methodID);
    115  jint res = jni_->CallIntMethodV(j_object_, methodID, args);
    116  CHECK_EXCEPTION(jni_) << "Error during CallIntMethod";
    117  va_end(args);
    118  return res;
    119 }
    120 
    121 void GlobalRef::CallVoidMethod(jmethodID methodID, ...) {
    122  va_list args;
    123  va_start(args, methodID);
    124  jni_->CallVoidMethodV(j_object_, methodID, args);
    125  CHECK_EXCEPTION(jni_) << "Error during CallVoidMethod";
    126  va_end(args);
    127 }
    128 
    129 // NativeRegistration implementation.
    130 NativeRegistration::NativeRegistration(JNIEnv* jni, jclass clazz)
    131    : JavaClass(jni, clazz), jni_(jni) {
    132  RTC_LOG(LS_INFO) << "NativeRegistration::ctor";
    133 }
    134 
    135 NativeRegistration::~NativeRegistration() {
    136  RTC_LOG(LS_INFO) << "NativeRegistration::dtor";
    137  jni_->UnregisterNatives(j_class_);
    138  CHECK_EXCEPTION(jni_) << "Error during UnregisterNatives";
    139 }
    140 
    141 std::unique_ptr<GlobalRef> NativeRegistration::NewObject(const char* name,
    142                                                         const char* signature,
    143                                                         ...) {
    144  RTC_LOG(LS_INFO) << "NativeRegistration::NewObject";
    145  va_list args;
    146  va_start(args, signature);
    147  jobject obj = jni_->NewObjectV(
    148      j_class_, GetMethodID(jni_, j_class_, name, signature), args);
    149  CHECK_EXCEPTION(jni_) << "Error during NewObjectV";
    150  va_end(args);
    151  return std::unique_ptr<GlobalRef>(new GlobalRef(jni_, obj));
    152 }
    153 
    154 // JavaClass implementation.
    155 jmethodID JavaClass::GetMethodId(const char* name, const char* signature) {
    156  return GetMethodID(jni_, j_class_, name, signature);
    157 }
    158 
    159 jmethodID JavaClass::GetStaticMethodId(const char* name,
    160                                       const char* signature) {
    161  return GetStaticMethodID(jni_, j_class_, name, signature);
    162 }
    163 
    164 jobject JavaClass::CallStaticObjectMethod(jmethodID methodID, ...) {
    165  va_list args;
    166  va_start(args, methodID);
    167  jobject res = jni_->CallStaticObjectMethodV(j_class_, methodID, args);
    168  CHECK_EXCEPTION(jni_) << "Error during CallStaticObjectMethod";
    169  return res;
    170 }
    171 
    172 jint JavaClass::CallStaticIntMethod(jmethodID methodID, ...) {
    173  va_list args;
    174  va_start(args, methodID);
    175  jint res = jni_->CallStaticIntMethodV(j_class_, methodID, args);
    176  CHECK_EXCEPTION(jni_) << "Error during CallStaticIntMethod";
    177  return res;
    178 }
    179 
    180 // JNIEnvironment implementation.
    181 JNIEnvironment::JNIEnvironment(JNIEnv* jni) : jni_(jni) {
    182  RTC_LOG(LS_INFO) << "JNIEnvironment::ctor";
    183 }
    184 
    185 JNIEnvironment::~JNIEnvironment() {
    186  RTC_LOG(LS_INFO) << "JNIEnvironment::dtor";
    187  RTC_DCHECK(thread_checker_.IsCurrent());
    188 }
    189 
    190 std::unique_ptr<NativeRegistration> JNIEnvironment::RegisterNatives(
    191    const char* name,
    192    const JNINativeMethod* methods,
    193    int num_methods) {
    194  RTC_LOG(LS_INFO) << "JNIEnvironment::RegisterNatives: " << name;
    195  RTC_DCHECK(thread_checker_.IsCurrent());
    196  jclass clazz = LookUpClass(name);
    197  jni_->RegisterNatives(clazz, methods, num_methods);
    198  CHECK_EXCEPTION(jni_) << "Error during RegisterNatives";
    199  return std::unique_ptr<NativeRegistration>(
    200      new NativeRegistration(jni_, clazz));
    201 }
    202 
    203 std::string JNIEnvironment::JavaToStdString(const jstring& j_string) {
    204  RTC_DCHECK(thread_checker_.IsCurrent());
    205  const char* jchars = jni_->GetStringUTFChars(j_string, nullptr);
    206  CHECK_EXCEPTION(jni_);
    207  const int size = jni_->GetStringUTFLength(j_string);
    208  CHECK_EXCEPTION(jni_);
    209  std::string ret(jchars, size);
    210  jni_->ReleaseStringUTFChars(j_string, jchars);
    211  CHECK_EXCEPTION(jni_);
    212  return ret;
    213 }
    214 
    215 // static
    216 void JVM::Initialize(JavaVM* jvm) {
    217  RTC_LOG(LS_INFO) << "JVM::Initialize";
    218  RTC_CHECK(!g_jvm);
    219  g_jvm = new JVM(jvm);
    220 }
    221 
    222 void JVM::Initialize(JavaVM* jvm, jobject context) {
    223  Initialize(jvm);
    224 
    225  // Pass in the context to the new ContextUtils class.
    226  JNIEnv* jni = g_jvm->jni();
    227  jclass context_utils = FindClass(jni, "org/webrtc/ContextUtils");
    228  jmethodID initialize_method = jni->GetStaticMethodID(
    229      context_utils, "initialize", "(Landroid/content/Context;)V");
    230  jni->CallStaticVoidMethod(context_utils, initialize_method, context);
    231 }
    232 
    233 // static
    234 void JVM::Uninitialize() {
    235  RTC_LOG(LS_INFO) << "JVM::Uninitialize";
    236  RTC_DCHECK(g_jvm);
    237  delete g_jvm;
    238  g_jvm = nullptr;
    239 }
    240 
    241 // static
    242 JVM* JVM::GetInstance() {
    243  RTC_DCHECK(g_jvm);
    244  return g_jvm;
    245 }
    246 
    247 JVM::JVM(JavaVM* jvm) : jvm_(jvm) {
    248  RTC_LOG(LS_INFO) << "JVM::JVM";
    249  RTC_CHECK(jni()) << "AttachCurrentThread() must be called on this thread.";
    250  LoadClasses(jni());
    251 }
    252 
    253 JVM::~JVM() {
    254  RTC_LOG(LS_INFO) << "JVM::~JVM";
    255  RTC_DCHECK(thread_checker_.IsCurrent());
    256  FreeClassReferences(jni());
    257 }
    258 
    259 std::unique_ptr<JNIEnvironment> JVM::environment() {
    260  RTC_LOG(LS_INFO) << "JVM::environment";
    261  ;
    262  // The JNIEnv is used for thread-local storage. For this reason, we cannot
    263  // share a JNIEnv between threads. If a piece of code has no other way to get
    264  // its JNIEnv, we should share the JavaVM, and use GetEnv to discover the
    265  // thread's JNIEnv. (Assuming it has one, if not, use AttachCurrentThread).
    266  // See // http://developer.android.com/training/articles/perf-jni.html.
    267  JNIEnv* jni = GetEnv(jvm_);
    268  if (!jni) {
    269    RTC_LOG(LS_ERROR)
    270        << "AttachCurrentThread() has not been called on this thread";
    271    return std::unique_ptr<JNIEnvironment>();
    272  }
    273  return std::unique_ptr<JNIEnvironment>(new JNIEnvironment(jni));
    274 }
    275 
    276 JavaClass JVM::GetClass(const char* name) {
    277  RTC_LOG(LS_INFO) << "JVM::GetClass: " << name;
    278  RTC_DCHECK(thread_checker_.IsCurrent());
    279  return JavaClass(jni(), LookUpClass(name));
    280 }
    281 
    282 }  // namespace webrtc