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