scoped_java_ref.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  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. #ifndef BASE_ANDROID_SCOPED_JAVA_REF_H_
  5. #define BASE_ANDROID_SCOPED_JAVA_REF_H_
  6. #include <jni.h>
  7. #include <stddef.h>
  8. #include <type_traits>
  9. #include <utility>
  10. #include "base/base_export.h"
  11. #include "base/check_op.h"
  12. #include "base/memory/raw_ptr.h"
  13. namespace base {
  14. namespace android {
  15. // Creates a new local reference frame, in which at least a given number of
  16. // local references can be created. Note that local references already created
  17. // in previous local frames are still valid in the current local frame.
  18. class BASE_EXPORT ScopedJavaLocalFrame {
  19. public:
  20. explicit ScopedJavaLocalFrame(JNIEnv* env);
  21. ScopedJavaLocalFrame(JNIEnv* env, int capacity);
  22. ScopedJavaLocalFrame(const ScopedJavaLocalFrame&) = delete;
  23. ScopedJavaLocalFrame& operator=(const ScopedJavaLocalFrame&) = delete;
  24. ~ScopedJavaLocalFrame();
  25. private:
  26. // This class is only good for use on the thread it was created on so
  27. // it's safe to cache the non-threadsafe JNIEnv* inside this object.
  28. raw_ptr<JNIEnv> env_;
  29. };
  30. // Forward declare the generic java reference template class.
  31. template <typename T>
  32. class JavaRef;
  33. // Template specialization of JavaRef, which acts as the base class for all
  34. // other JavaRef<> template types. This allows you to e.g. pass
  35. // ScopedJavaLocalRef<jstring> into a function taking const JavaRef<jobject>&
  36. template <>
  37. class BASE_EXPORT JavaRef<jobject> {
  38. public:
  39. // Initializes a null reference.
  40. constexpr JavaRef() {}
  41. // Allow nullptr to be converted to JavaRef. This avoids having to declare an
  42. // empty JavaRef just to pass null to a function, and makes C++ "nullptr" and
  43. // Java "null" equivalent.
  44. constexpr JavaRef(std::nullptr_t) {}
  45. JavaRef(const JavaRef&) = delete;
  46. JavaRef& operator=(const JavaRef&) = delete;
  47. // Public to allow destruction of null JavaRef objects.
  48. ~JavaRef() {}
  49. // TODO(torne): maybe rename this to get() for consistency with unique_ptr
  50. // once there's fewer unnecessary uses of it in the codebase.
  51. jobject obj() const { return obj_; }
  52. explicit operator bool() const { return obj_ != nullptr; }
  53. // Deprecated. Just use bool conversion.
  54. // TODO(torne): replace usage and remove this.
  55. bool is_null() const { return obj_ == nullptr; }
  56. protected:
  57. // Takes ownership of the |obj| reference passed; requires it to be a local
  58. // reference type.
  59. #if DCHECK_IS_ON()
  60. // Implementation contains a DCHECK; implement out-of-line when DCHECK_IS_ON.
  61. JavaRef(JNIEnv* env, jobject obj);
  62. #else
  63. JavaRef(JNIEnv* env, jobject obj) : obj_(obj) {}
  64. #endif
  65. // Used for move semantics. obj_ must have been released first if non-null.
  66. void steal(JavaRef&& other) {
  67. obj_ = other.obj_;
  68. other.obj_ = nullptr;
  69. }
  70. // The following are implementation detail convenience methods, for
  71. // use by the sub-classes.
  72. JNIEnv* SetNewLocalRef(JNIEnv* env, jobject obj);
  73. void SetNewGlobalRef(JNIEnv* env, jobject obj);
  74. void ResetLocalRef(JNIEnv* env);
  75. void ResetGlobalRef();
  76. jobject ReleaseInternal();
  77. private:
  78. jobject obj_ = nullptr;
  79. };
  80. // Forward declare the object array reader for the convenience function.
  81. template <typename T>
  82. class JavaObjectArrayReader;
  83. // Generic base class for ScopedJavaLocalRef and ScopedJavaGlobalRef. Useful
  84. // for allowing functions to accept a reference without having to mandate
  85. // whether it is a local or global type.
  86. template <typename T>
  87. class JavaRef : public JavaRef<jobject> {
  88. public:
  89. constexpr JavaRef() {}
  90. constexpr JavaRef(std::nullptr_t) {}
  91. JavaRef(const JavaRef&) = delete;
  92. JavaRef& operator=(const JavaRef&) = delete;
  93. ~JavaRef() {}
  94. T obj() const { return static_cast<T>(JavaRef<jobject>::obj()); }
  95. // Get a JavaObjectArrayReader for the array pointed to by this reference.
  96. // Only defined for JavaRef<jobjectArray>.
  97. // You must pass the type of the array elements (usually jobject) as the
  98. // template parameter.
  99. template <typename ElementType,
  100. typename T_ = T,
  101. typename = std::enable_if_t<std::is_same<T_, jobjectArray>::value>>
  102. JavaObjectArrayReader<ElementType> ReadElements() const {
  103. return JavaObjectArrayReader<ElementType>(*this);
  104. }
  105. protected:
  106. JavaRef(JNIEnv* env, T obj) : JavaRef<jobject>(env, obj) {}
  107. };
  108. // Holds a local reference to a JNI method parameter.
  109. // Method parameters should not be deleted, and so this class exists purely to
  110. // wrap them as a JavaRef<T> in the JNI binding generator. Do not create
  111. // instances manually.
  112. template <typename T>
  113. class JavaParamRef : public JavaRef<T> {
  114. public:
  115. // Assumes that |obj| is a parameter passed to a JNI method from Java.
  116. // Does not assume ownership as parameters should not be deleted.
  117. JavaParamRef(JNIEnv* env, T obj) : JavaRef<T>(env, obj) {}
  118. // Allow nullptr to be converted to JavaParamRef. Some unit tests call JNI
  119. // methods directly from C++ and pass null for objects which are not actually
  120. // used by the implementation (e.g. the caller object); allow this to keep
  121. // working.
  122. JavaParamRef(std::nullptr_t) {}
  123. JavaParamRef(const JavaParamRef&) = delete;
  124. JavaParamRef& operator=(const JavaParamRef&) = delete;
  125. ~JavaParamRef() {}
  126. // TODO(torne): remove this cast once we're using JavaRef consistently.
  127. // http://crbug.com/506850
  128. operator T() const { return JavaRef<T>::obj(); }
  129. };
  130. // Holds a local reference to a Java object. The local reference is scoped
  131. // to the lifetime of this object.
  132. // Instances of this class may hold onto any JNIEnv passed into it until
  133. // destroyed. Therefore, since a JNIEnv is only suitable for use on a single
  134. // thread, objects of this class must be created, used, and destroyed, on a
  135. // single thread.
  136. // Therefore, this class should only be used as a stack-based object and from a
  137. // single thread. If you wish to have the reference outlive the current
  138. // callstack (e.g. as a class member) or you wish to pass it across threads,
  139. // use a ScopedJavaGlobalRef instead.
  140. template <typename T>
  141. class ScopedJavaLocalRef : public JavaRef<T> {
  142. public:
  143. // Take ownership of a bare jobject. This does not create a new reference.
  144. // This should only be used by JNI helper functions, or in cases where code
  145. // must call JNIEnv methods directly.
  146. static ScopedJavaLocalRef Adopt(JNIEnv* env, T obj) {
  147. return ScopedJavaLocalRef(env, obj);
  148. }
  149. constexpr ScopedJavaLocalRef() {}
  150. constexpr ScopedJavaLocalRef(std::nullptr_t) {}
  151. // Copy constructor. This is required in addition to the copy conversion
  152. // constructor below.
  153. ScopedJavaLocalRef(const ScopedJavaLocalRef& other) : env_(other.env_) {
  154. JavaRef<T>::SetNewLocalRef(env_, other.obj());
  155. }
  156. // Copy conversion constructor.
  157. template <typename U,
  158. typename = std::enable_if_t<std::is_convertible<U, T>::value>>
  159. ScopedJavaLocalRef(const ScopedJavaLocalRef<U>& other) : env_(other.env_) {
  160. JavaRef<T>::SetNewLocalRef(env_, other.obj());
  161. }
  162. // Move constructor. This is required in addition to the move conversion
  163. // constructor below.
  164. ScopedJavaLocalRef(ScopedJavaLocalRef&& other) : env_(other.env_) {
  165. JavaRef<T>::steal(std::move(other));
  166. }
  167. // Move conversion constructor.
  168. template <typename U,
  169. typename = std::enable_if_t<std::is_convertible<U, T>::value>>
  170. ScopedJavaLocalRef(ScopedJavaLocalRef<U>&& other) : env_(other.env_) {
  171. JavaRef<T>::steal(std::move(other));
  172. }
  173. // Constructor for other JavaRef types.
  174. explicit ScopedJavaLocalRef(const JavaRef<T>& other) { Reset(other); }
  175. // Assumes that |obj| is a local reference to a Java object and takes
  176. // ownership of this local reference.
  177. // TODO(torne): make legitimate uses call Adopt() instead, and make this
  178. // private.
  179. ScopedJavaLocalRef(JNIEnv* env, T obj) : JavaRef<T>(env, obj), env_(env) {}
  180. ~ScopedJavaLocalRef() { Reset(); }
  181. // Null assignment, for disambiguation.
  182. ScopedJavaLocalRef& operator=(std::nullptr_t) {
  183. Reset();
  184. return *this;
  185. }
  186. // Copy assignment.
  187. ScopedJavaLocalRef& operator=(const ScopedJavaLocalRef& other) {
  188. Reset(other);
  189. return *this;
  190. }
  191. // Copy conversion assignment.
  192. template <typename U,
  193. typename = std::enable_if_t<std::is_convertible<U, T>::value>>
  194. ScopedJavaLocalRef& operator=(const ScopedJavaLocalRef<U>& other) {
  195. Reset(other);
  196. return *this;
  197. }
  198. // Move assignment.
  199. template <typename U,
  200. typename = std::enable_if_t<std::is_convertible<U, T>::value>>
  201. ScopedJavaLocalRef& operator=(ScopedJavaLocalRef<U>&& other) {
  202. env_ = other.env_;
  203. Reset();
  204. JavaRef<T>::steal(std::move(other));
  205. return *this;
  206. }
  207. // Assignment for other JavaRef types.
  208. ScopedJavaLocalRef& operator=(const JavaRef<T>& other) {
  209. Reset(other);
  210. return *this;
  211. }
  212. void Reset() { JavaRef<T>::ResetLocalRef(env_); }
  213. template <typename U,
  214. typename = std::enable_if_t<std::is_convertible<U, T>::value>>
  215. void Reset(const ScopedJavaLocalRef<U>& other) {
  216. // We can copy over env_ here as |other| instance must be from the same
  217. // thread as |this| local ref. (See class comment for multi-threading
  218. // limitations, and alternatives).
  219. env_ = JavaRef<T>::SetNewLocalRef(other.env_, other.obj());
  220. }
  221. void Reset(const JavaRef<T>& other) {
  222. // If |env_| was not yet set (is still null) it will be attached to the
  223. // current thread in SetNewLocalRef().
  224. env_ = JavaRef<T>::SetNewLocalRef(env_, other.obj());
  225. }
  226. // Releases the local reference to the caller. The caller *must* delete the
  227. // local reference when it is done with it. Note that calling a Java method
  228. // is *not* a transfer of ownership and Release() should not be used.
  229. T Release() { return static_cast<T>(JavaRef<T>::ReleaseInternal()); }
  230. private:
  231. // This class is only good for use on the thread it was created on so
  232. // it's safe to cache the non-threadsafe JNIEnv* inside this object.
  233. raw_ptr<JNIEnv> env_ = nullptr;
  234. // Prevent ScopedJavaLocalRef(JNIEnv*, T obj) from being used to take
  235. // ownership of a JavaParamRef's underlying object - parameters are not
  236. // allowed to be deleted and so should not be owned by ScopedJavaLocalRef.
  237. // TODO(torne): this can be removed once JavaParamRef no longer has an
  238. // implicit conversion back to T.
  239. ScopedJavaLocalRef(JNIEnv* env, const JavaParamRef<T>& other);
  240. // Friend required to get env_ from conversions.
  241. template <typename U>
  242. friend class ScopedJavaLocalRef;
  243. // Avoids JavaObjectArrayReader having to accept and store its own env.
  244. template <typename U>
  245. friend class JavaObjectArrayReader;
  246. };
  247. // Holds a global reference to a Java object. The global reference is scoped
  248. // to the lifetime of this object. This class does not hold onto any JNIEnv*
  249. // passed to it, hence it is safe to use across threads (within the constraints
  250. // imposed by the underlying Java object that it references).
  251. template <typename T>
  252. class ScopedJavaGlobalRef : public JavaRef<T> {
  253. public:
  254. constexpr ScopedJavaGlobalRef() {}
  255. constexpr ScopedJavaGlobalRef(std::nullptr_t) {}
  256. // Copy constructor. This is required in addition to the copy conversion
  257. // constructor below.
  258. ScopedJavaGlobalRef(const ScopedJavaGlobalRef& other) { Reset(other); }
  259. // Copy conversion constructor.
  260. template <typename U,
  261. typename = std::enable_if_t<std::is_convertible<U, T>::value>>
  262. ScopedJavaGlobalRef(const ScopedJavaGlobalRef<U>& other) {
  263. Reset(other);
  264. }
  265. // Move constructor. This is required in addition to the move conversion
  266. // constructor below.
  267. ScopedJavaGlobalRef(ScopedJavaGlobalRef&& other) {
  268. JavaRef<T>::steal(std::move(other));
  269. }
  270. // Move conversion constructor.
  271. template <typename U,
  272. typename = std::enable_if_t<std::is_convertible<U, T>::value>>
  273. ScopedJavaGlobalRef(ScopedJavaGlobalRef<U>&& other) {
  274. JavaRef<T>::steal(std::move(other));
  275. }
  276. // Conversion constructor for other JavaRef types.
  277. explicit ScopedJavaGlobalRef(const JavaRef<T>& other) { Reset(other); }
  278. // Create a new global reference to the object.
  279. // Deprecated. Don't use bare jobjects; use a JavaRef as the input.
  280. ScopedJavaGlobalRef(JNIEnv* env, T obj) { Reset(env, obj); }
  281. ~ScopedJavaGlobalRef() { Reset(); }
  282. // Null assignment, for disambiguation.
  283. ScopedJavaGlobalRef& operator=(std::nullptr_t) {
  284. Reset();
  285. return *this;
  286. }
  287. // Copy assignment.
  288. ScopedJavaGlobalRef& operator=(const ScopedJavaGlobalRef& other) {
  289. Reset(other);
  290. return *this;
  291. }
  292. // Copy conversion assignment.
  293. template <typename U,
  294. typename = std::enable_if_t<std::is_convertible<U, T>::value>>
  295. ScopedJavaGlobalRef& operator=(const ScopedJavaGlobalRef<U>& other) {
  296. Reset(other);
  297. return *this;
  298. }
  299. // Move assignment.
  300. template <typename U,
  301. typename = std::enable_if_t<std::is_convertible<U, T>::value>>
  302. ScopedJavaGlobalRef& operator=(ScopedJavaGlobalRef<U>&& other) {
  303. Reset();
  304. JavaRef<T>::steal(std::move(other));
  305. return *this;
  306. }
  307. // Assignment for other JavaRef types.
  308. ScopedJavaGlobalRef& operator=(const JavaRef<T>& other) {
  309. Reset(other);
  310. return *this;
  311. }
  312. void Reset() { JavaRef<T>::ResetGlobalRef(); }
  313. template <typename U,
  314. typename = std::enable_if_t<std::is_convertible<U, T>::value>>
  315. void Reset(const ScopedJavaGlobalRef<U>& other) {
  316. Reset(nullptr, other.obj());
  317. }
  318. void Reset(const JavaRef<T>& other) { Reset(nullptr, other.obj()); }
  319. // Deprecated. You can just use Reset(const JavaRef&).
  320. void Reset(JNIEnv* env, const JavaParamRef<T>& other) {
  321. Reset(env, other.obj());
  322. }
  323. // Deprecated. Don't use bare jobjects; use a JavaRef as the input.
  324. void Reset(JNIEnv* env, T obj) { JavaRef<T>::SetNewGlobalRef(env, obj); }
  325. // Releases the global reference to the caller. The caller *must* delete the
  326. // global reference when it is done with it. Note that calling a Java method
  327. // is *not* a transfer of ownership and Release() should not be used.
  328. T Release() { return static_cast<T>(JavaRef<T>::ReleaseInternal()); }
  329. };
  330. // Wrapper for a jobjectArray which supports input iteration, allowing Java
  331. // arrays to be iterated over with a range-based for loop, or used with
  332. // <algorithm> functions that accept input iterators.
  333. //
  334. // The iterator returns each object in the array in turn, wrapped in a
  335. // ScopedJavaLocalRef<T>. T will usually be jobject, but if you know that the
  336. // array contains a more specific type (such as jstring) you can use that
  337. // instead. This does not check the type at runtime!
  338. //
  339. // The wrapper holds a local reference to the array and only queries the size of
  340. // the array once, so must only be used as a stack-based object from the current
  341. // thread.
  342. //
  343. // Note that this does *not* update the contents of the array if you mutate the
  344. // returned ScopedJavaLocalRef.
  345. template <typename T>
  346. class JavaObjectArrayReader {
  347. public:
  348. class iterator {
  349. public:
  350. // We can only be an input iterator, as all richer iterator types must
  351. // implement the multipass guarantee (always returning the same object for
  352. // the same iterator position), which is not practical when returning
  353. // temporary objects.
  354. using iterator_category = std::input_iterator_tag;
  355. using difference_type = ptrdiff_t;
  356. using value_type = ScopedJavaLocalRef<T>;
  357. // It doesn't make sense to return a reference type as the iterator creates
  358. // temporary wrapper objects when dereferenced. Fortunately, it's not
  359. // required that input iterators actually use references, and defining it
  360. // as value_type is valid.
  361. using reference = value_type;
  362. // This exists to make operator-> work as expected: its return value must
  363. // resolve to an actual pointer (otherwise the compiler just keeps calling
  364. // operator-> on the return value until it does), so we need an extra level
  365. // of indirection. This is sometimes called an "arrow proxy" or similar, and
  366. // this version is adapted from base/value_iterators.h.
  367. class pointer {
  368. public:
  369. explicit pointer(const reference& ref) : ref_(ref) {}
  370. pointer(const pointer& ptr) = default;
  371. pointer& operator=(const pointer& ptr) = delete;
  372. reference* operator->() { return &ref_; }
  373. private:
  374. reference ref_;
  375. };
  376. iterator(const iterator&) = default;
  377. ~iterator() = default;
  378. iterator& operator=(const iterator&) = default;
  379. bool operator==(const iterator& other) const {
  380. DCHECK(reader_ == other.reader_);
  381. return i_ == other.i_;
  382. }
  383. bool operator!=(const iterator& other) const {
  384. DCHECK(reader_ == other.reader_);
  385. return i_ != other.i_;
  386. }
  387. reference operator*() const {
  388. DCHECK(i_ < reader_->size_);
  389. // JNIEnv functions return unowned local references; take ownership with
  390. // Adopt so that ~ScopedJavaLocalRef will release it automatically later.
  391. return value_type::Adopt(
  392. reader_->array_.env_,
  393. static_cast<T>(reader_->array_.env_->GetObjectArrayElement(
  394. reader_->array_.obj(), i_)));
  395. }
  396. pointer operator->() const { return pointer(operator*()); }
  397. iterator& operator++() {
  398. DCHECK(i_ < reader_->size_);
  399. ++i_;
  400. return *this;
  401. }
  402. iterator operator++(int) {
  403. iterator old = *this;
  404. ++*this;
  405. return old;
  406. }
  407. private:
  408. iterator(const JavaObjectArrayReader* reader, jsize i)
  409. : reader_(reader), i_(i) {}
  410. raw_ptr<const JavaObjectArrayReader<T>> reader_;
  411. jsize i_;
  412. friend JavaObjectArrayReader;
  413. };
  414. JavaObjectArrayReader(const JavaRef<jobjectArray>& array) : array_(array) {
  415. size_ = array_.env_->GetArrayLength(array_.obj());
  416. }
  417. // Copy constructor to allow returning it from JavaRef::ReadElements().
  418. JavaObjectArrayReader(const JavaObjectArrayReader& other) = default;
  419. // Assignment operator for consistency with copy constructor.
  420. JavaObjectArrayReader& operator=(const JavaObjectArrayReader& other) =
  421. default;
  422. // Allow move constructor and assignment since this owns a local ref.
  423. JavaObjectArrayReader(JavaObjectArrayReader&& other) = default;
  424. JavaObjectArrayReader& operator=(JavaObjectArrayReader&& other) = default;
  425. bool empty() const { return size_ == 0; }
  426. jsize size() const { return size_; }
  427. iterator begin() const { return iterator(this, 0); }
  428. iterator end() const { return iterator(this, size_); }
  429. private:
  430. ScopedJavaLocalRef<jobjectArray> array_;
  431. jsize size_;
  432. friend iterator;
  433. };
  434. } // namespace android
  435. } // namespace base
  436. #endif // BASE_ANDROID_SCOPED_JAVA_REF_H_