Home | History | Annotate | Download | only in android
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_ANDROID_SCOPED_JAVA_REF_H_
      6 #define BASE_ANDROID_SCOPED_JAVA_REF_H_
      7 
      8 #include <jni.h>
      9 #include <stddef.h>
     10 
     11 #include "base/base_export.h"
     12 #include "base/basictypes.h"
     13 
     14 namespace base {
     15 namespace android {
     16 
     17 // Creates a new local reference frame, in which at least a given number of
     18 // local references can be created. Note that local references already created
     19 // in previous local frames are still valid in the current local frame.
     20 class BASE_EXPORT ScopedJavaLocalFrame {
     21  public:
     22   explicit ScopedJavaLocalFrame(JNIEnv* env);
     23   ScopedJavaLocalFrame(JNIEnv* env, int capacity);
     24   ~ScopedJavaLocalFrame();
     25 
     26  private:
     27   // This class is only good for use on the thread it was created on so
     28   // it's safe to cache the non-threadsafe JNIEnv* inside this object.
     29   JNIEnv* env_;
     30 
     31   DISALLOW_COPY_AND_ASSIGN(ScopedJavaLocalFrame);
     32 };
     33 
     34 // Forward declare the generic java reference template class.
     35 template<typename T> class JavaRef;
     36 
     37 // Template specialization of JavaRef, which acts as the base class for all
     38 // other JavaRef<> template types. This allows you to e.g. pass
     39 // ScopedJavaLocalRef<jstring> into a function taking const JavaRef<jobject>&
     40 template<>
     41 class BASE_EXPORT JavaRef<jobject> {
     42  public:
     43   jobject obj() const { return obj_; }
     44 
     45   bool is_null() const { return obj_ == NULL; }
     46 
     47  protected:
     48   // Initializes a NULL reference.
     49   JavaRef();
     50 
     51   // Takes ownership of the |obj| reference passed; requires it to be a local
     52   // reference type.
     53   JavaRef(JNIEnv* env, jobject obj);
     54 
     55   ~JavaRef();
     56 
     57   // The following are implementation detail convenience methods, for
     58   // use by the sub-classes.
     59   JNIEnv* SetNewLocalRef(JNIEnv* env, jobject obj);
     60   void SetNewGlobalRef(JNIEnv* env, jobject obj);
     61   void ResetLocalRef(JNIEnv* env);
     62   void ResetGlobalRef();
     63   jobject ReleaseInternal();
     64 
     65  private:
     66   jobject obj_;
     67 
     68   DISALLOW_COPY_AND_ASSIGN(JavaRef);
     69 };
     70 
     71 // Generic base class for ScopedJavaLocalRef and ScopedJavaGlobalRef. Useful
     72 // for allowing functions to accept a reference without having to mandate
     73 // whether it is a local or global type.
     74 template<typename T>
     75 class JavaRef : public JavaRef<jobject> {
     76  public:
     77   T obj() const { return static_cast<T>(JavaRef<jobject>::obj()); }
     78 
     79  protected:
     80   JavaRef() {}
     81   ~JavaRef() {}
     82 
     83   JavaRef(JNIEnv* env, T obj) : JavaRef<jobject>(env, obj) {}
     84 
     85  private:
     86   DISALLOW_COPY_AND_ASSIGN(JavaRef);
     87 };
     88 
     89 // Holds a local reference to a Java object. The local reference is scoped
     90 // to the lifetime of this object.
     91 // Instances of this class may hold onto any JNIEnv passed into it until
     92 // destroyed. Therefore, since a JNIEnv is only suitable for use on a single
     93 // thread, objects of this class must be created, used, and destroyed, on a
     94 // single thread.
     95 // Therefore, this class should only be used as a stack-based object and from a
     96 // single thread. If you wish to have the reference outlive the current
     97 // callstack (e.g. as a class member) or you wish to pass it across threads,
     98 // use a ScopedJavaGlobalRef instead.
     99 template<typename T>
    100 class ScopedJavaLocalRef : public JavaRef<T> {
    101  public:
    102   ScopedJavaLocalRef() : env_(NULL) {}
    103 
    104   // Non-explicit copy constructor, to allow ScopedJavaLocalRef to be returned
    105   // by value as this is the normal usage pattern.
    106   ScopedJavaLocalRef(const ScopedJavaLocalRef<T>& other)
    107       : env_(other.env_) {
    108     this->SetNewLocalRef(env_, other.obj());
    109   }
    110 
    111   template<typename U>
    112   explicit ScopedJavaLocalRef(const U& other)
    113       : env_(NULL) {
    114     this->Reset(other);
    115   }
    116 
    117   // Assumes that |obj| is a local reference to a Java object and takes
    118   // ownership  of this local reference.
    119   ScopedJavaLocalRef(JNIEnv* env, T obj) : JavaRef<T>(env, obj), env_(env) {}
    120 
    121   ~ScopedJavaLocalRef() {
    122     this->Reset();
    123   }
    124 
    125   // Overloaded assignment operator defined for consistency with the implicit
    126   // copy constructor.
    127   void operator=(const ScopedJavaLocalRef<T>& other) {
    128     this->Reset(other);
    129   }
    130 
    131   void Reset() {
    132     this->ResetLocalRef(env_);
    133   }
    134 
    135   template<typename U>
    136   void Reset(const ScopedJavaLocalRef<U>& other) {
    137     // We can copy over env_ here as |other| instance must be from the same
    138     // thread as |this| local ref. (See class comment for multi-threading
    139     // limitations, and alternatives).
    140     this->Reset(other.env_, other.obj());
    141   }
    142 
    143   template<typename U>
    144   void Reset(const U& other) {
    145     // If |env_| was not yet set (is still NULL) it will be attached to the
    146     // current thread in SetNewLocalRef().
    147     this->Reset(env_, other.obj());
    148   }
    149 
    150   template<typename U>
    151   void Reset(JNIEnv* env, U obj) {
    152     implicit_cast<T>(obj);  // Ensure U is assignable to T
    153     env_ = this->SetNewLocalRef(env, obj);
    154   }
    155 
    156   // Releases the local reference to the caller. The caller *must* delete the
    157   // local reference when it is done with it.
    158   T Release() {
    159     return static_cast<T>(this->ReleaseInternal());
    160   }
    161 
    162  private:
    163   // This class is only good for use on the thread it was created on so
    164   // it's safe to cache the non-threadsafe JNIEnv* inside this object.
    165   JNIEnv* env_;
    166 };
    167 
    168 // Holds a global reference to a Java object. The global reference is scoped
    169 // to the lifetime of this object. This class does not hold onto any JNIEnv*
    170 // passed to it, hence it is safe to use across threads (within the constraints
    171 // imposed by the underlying Java object that it references).
    172 template<typename T>
    173 class ScopedJavaGlobalRef : public JavaRef<T> {
    174  public:
    175   ScopedJavaGlobalRef() {}
    176 
    177   explicit ScopedJavaGlobalRef(const ScopedJavaGlobalRef<T>& other) {
    178     this->Reset(other);
    179   }
    180 
    181   template<typename U>
    182   explicit ScopedJavaGlobalRef(const U& other) {
    183     this->Reset(other);
    184   }
    185 
    186   ~ScopedJavaGlobalRef() {
    187     this->Reset();
    188   }
    189 
    190   void Reset() {
    191     this->ResetGlobalRef();
    192   }
    193 
    194   template<typename U>
    195   void Reset(const U& other) {
    196     this->Reset(NULL, other.obj());
    197   }
    198 
    199   template<typename U>
    200   void Reset(JNIEnv* env, U obj) {
    201     implicit_cast<T>(obj);  // Ensure U is assignable to T
    202     this->SetNewGlobalRef(env, obj);
    203   }
    204 
    205   // Releases the global reference to the caller. The caller *must* delete the
    206   // global reference when it is done with it.
    207   T Release() {
    208     return static_cast<T>(this->ReleaseInternal());
    209   }
    210 };
    211 
    212 }  // namespace android
    213 }  // namespace base
    214 
    215 #endif  // BASE_ANDROID_SCOPED_JAVA_REF_H_
    216