Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright (c) 2013 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 "webrtc/base/checks.h"
     12 #include "webrtc/modules/utility/include/helpers_android.h"
     13 
     14 #include <android/log.h>
     15 #include <assert.h>
     16 #include <pthread.h>
     17 #include <stddef.h>
     18 #include <unistd.h>
     19 
     20 #define TAG "HelpersAndroid"
     21 #define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
     22 
     23 namespace webrtc {
     24 
     25 JNIEnv* GetEnv(JavaVM* jvm) {
     26   void* env = NULL;
     27   jint status = jvm->GetEnv(&env, JNI_VERSION_1_6);
     28   RTC_CHECK(((env != NULL) && (status == JNI_OK)) ||
     29             ((env == NULL) && (status == JNI_EDETACHED)))
     30       << "Unexpected GetEnv return: " << status << ":" << env;
     31   return reinterpret_cast<JNIEnv*>(env);
     32 }
     33 
     34 // Return a |jlong| that will correctly convert back to |ptr|.  This is needed
     35 // because the alternative (of silently passing a 32-bit pointer to a vararg
     36 // function expecting a 64-bit param) picks up garbage in the high 32 bits.
     37 jlong PointerTojlong(void* ptr) {
     38   static_assert(sizeof(intptr_t) <= sizeof(jlong),
     39                 "Time to rethink the use of jlongs");
     40   // Going through intptr_t to be obvious about the definedness of the
     41   // conversion from pointer to integral type.  intptr_t to jlong is a standard
     42   // widening by the static_assert above.
     43   jlong ret = reinterpret_cast<intptr_t>(ptr);
     44   RTC_DCHECK(reinterpret_cast<void*>(ret) == ptr);
     45   return ret;
     46 }
     47 
     48 jmethodID GetMethodID (
     49     JNIEnv* jni, jclass c, const char* name, const char* signature) {
     50   jmethodID m = jni->GetMethodID(c, name, signature);
     51   CHECK_EXCEPTION(jni) << "Error during GetMethodID: " << name << ", "
     52                        << signature;
     53   RTC_CHECK(m) << name << ", " << signature;
     54   return m;
     55 }
     56 
     57 jmethodID GetStaticMethodID (
     58     JNIEnv* jni, jclass c, const char* name, const char* signature) {
     59   jmethodID m = jni->GetStaticMethodID(c, name, signature);
     60   CHECK_EXCEPTION(jni) << "Error during GetStaticMethodID: " << name << ", "
     61                        << signature;
     62   RTC_CHECK(m) << name << ", " << signature;
     63   return m;
     64 }
     65 
     66 jclass FindClass(JNIEnv* jni, const char* name) {
     67   jclass c = jni->FindClass(name);
     68   CHECK_EXCEPTION(jni) << "Error during FindClass: " << name;
     69   RTC_CHECK(c) << name;
     70   return c;
     71 }
     72 
     73 jobject NewGlobalRef(JNIEnv* jni, jobject o) {
     74   jobject ret = jni->NewGlobalRef(o);
     75   CHECK_EXCEPTION(jni) << "Error during NewGlobalRef";
     76   RTC_CHECK(ret);
     77   return ret;
     78 }
     79 
     80 void DeleteGlobalRef(JNIEnv* jni, jobject o) {
     81   jni->DeleteGlobalRef(o);
     82   CHECK_EXCEPTION(jni) << "Error during DeleteGlobalRef";
     83 }
     84 
     85 std::string GetThreadId() {
     86   char buf[21];  // Big enough to hold a kuint64max plus terminating NULL.
     87   int thread_id = gettid();
     88   RTC_CHECK_LT(snprintf(buf, sizeof(buf), "%i", thread_id),
     89                static_cast<int>(sizeof(buf)))
     90       << "Thread id is bigger than uint64??";
     91   return std::string(buf);
     92 }
     93 
     94 std::string GetThreadInfo() {
     95   return "@[tid=" + GetThreadId() + "]";
     96 }
     97 
     98 AttachThreadScoped::AttachThreadScoped(JavaVM* jvm)
     99     : attached_(false), jvm_(jvm), env_(NULL) {
    100   env_ = GetEnv(jvm);
    101   if (!env_) {
    102     // Adding debug log here so we can track down potential leaks and figure
    103     // out why we sometimes see "Native thread exiting without having called
    104     // DetachCurrentThread" in logcat outputs.
    105     ALOGD("Attaching thread to JVM%s", GetThreadInfo().c_str());
    106     jint res = jvm->AttachCurrentThread(&env_, NULL);
    107     attached_ = (res == JNI_OK);
    108     RTC_CHECK(attached_) << "AttachCurrentThread failed: " << res;
    109   }
    110 }
    111 
    112 AttachThreadScoped::~AttachThreadScoped() {
    113   if (attached_) {
    114     ALOGD("Detaching thread from JVM%s", GetThreadInfo().c_str());
    115     jint res = jvm_->DetachCurrentThread();
    116     RTC_CHECK(res == JNI_OK) << "DetachCurrentThread failed: " << res;
    117     RTC_CHECK(!GetEnv(jvm_));
    118   }
    119 }
    120 
    121 JNIEnv* AttachThreadScoped::env() { return env_; }
    122 
    123 }  // namespace webrtc
    124