summaryrefslogtreecommitdiffstats
path: root/base/android
diff options
context:
space:
mode:
authorpeter@chromium.org <peter@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-09 21:02:27 +0000
committerpeter@chromium.org <peter@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-09 21:02:27 +0000
commitfe0f1aba6584072a969924656771becb71589fec (patch)
treef74019055cf4b2193f4b05e247b0e42c3d676c0b /base/android
parent1153596a4543e779244f410b2ecf804d9c8c54e9 (diff)
downloadchromium_src-fe0f1aba6584072a969924656771becb71589fec.zip
chromium_src-fe0f1aba6584072a969924656771becb71589fec.tar.gz
chromium_src-fe0f1aba6584072a969924656771becb71589fec.tar.bz2
Upstream Android JNI code, allowing us to use more ScopedJava references.
BUG= TEST= Review URL: http://codereview.chromium.org/9358028 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@121284 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/android')
-rw-r--r--base/android/jni_android.cc154
-rw-r--r--base/android/jni_android.h86
-rw-r--r--base/android/jni_array.cc54
-rw-r--r--base/android/jni_array.h26
-rw-r--r--base/android/jni_array_unittest.cc31
-rw-r--r--base/android/jni_string.cc36
-rw-r--r--base/android/jni_string.h11
-rw-r--r--base/android/scoped_java_ref.cc23
-rw-r--r--base/android/scoped_java_ref.h12
-rw-r--r--base/android/scoped_java_ref_unittest.cc53
10 files changed, 358 insertions, 128 deletions
diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc
index f99f1ab..69399ad 100644
--- a/base/android/jni_android.cc
+++ b/base/android/jni_android.cc
@@ -12,8 +12,11 @@
#include "base/threading/platform_thread.h"
namespace {
-JavaVM* g_jvm = 0;
-jobject g_application_context = NULL;
+
+JavaVM* g_jvm = NULL;
+
+base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >
+ g_application_context = LAZY_INSTANCE_INITIALIZER;
struct MethodIdentifier {
const char* class_name;
@@ -73,13 +76,106 @@ void InitVM(JavaVM* vm) {
}
void InitApplicationContext(const JavaRef<jobject>& context) {
- DCHECK(!g_application_context);
- g_application_context = context.env()->NewGlobalRef(context.obj());
+ DCHECK(g_application_context.Get().is_null());
+ g_application_context.Get().Reset(context);
+}
+
+const jobject GetApplicationContext() {
+ DCHECK(!g_application_context.Get().is_null());
+ return g_application_context.Get().obj();
+}
+
+ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name) {
+ jclass clazz = env->FindClass(class_name);
+ CHECK(clazz && !ClearException(env)) << "Failed to find class " << class_name;
+ return ScopedJavaLocalRef<jclass>(env, clazz);
+}
+
+bool HasClass(JNIEnv* env, const char* class_name) {
+ ScopedJavaLocalRef<jclass> clazz(env, env->FindClass(class_name));
+ if (!clazz.obj()) {
+ ClearException(env);
+ return false;
+ }
+ bool error = ClearException(env);
+ DCHECK(!error);
+ return true;
+}
+
+jmethodID GetMethodID(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* method_name,
+ const char* jni_signature) {
+ jmethodID method_id =
+ env->GetMethodID(clazz.obj(), method_name, jni_signature);
+ CHECK(method_id && !ClearException(env)) << "Failed to find method " <<
+ method_name << " " << jni_signature;
+ return method_id;
+}
+
+jmethodID GetStaticMethodID(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* method_name,
+ const char* jni_signature) {
+ jmethodID method_id =
+ env->GetStaticMethodID(clazz.obj(), method_name, jni_signature);
+ CHECK(method_id && !ClearException(env)) << "Failed to find static method " <<
+ method_name << " " << jni_signature;
+ return method_id;
+}
+
+bool HasMethod(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* method_name,
+ const char* jni_signature) {
+ jmethodID method_id =
+ env->GetMethodID(clazz.obj(), method_name, jni_signature);
+ if (!method_id) {
+ ClearException(env);
+ return false;
+ }
+ bool error = ClearException(env);
+ DCHECK(!error);
+ return true;
}
-jobject GetApplicationContext() {
- DCHECK(g_application_context);
- return g_application_context;
+jfieldID GetFieldID(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* field_name,
+ const char* jni_signature) {
+ jfieldID field_id = env->GetFieldID(clazz.obj(), field_name, jni_signature);
+ CHECK(field_id && !ClearException(env)) << "Failed to find field " <<
+ field_name << " " << jni_signature;
+ bool error = ClearException(env);
+ DCHECK(!error);
+ return field_id;
+}
+
+bool HasField(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* field_name,
+ const char* jni_signature) {
+ jfieldID field_id = env->GetFieldID(clazz.obj(), field_name, jni_signature);
+ if (!field_id) {
+ ClearException(env);
+ return false;
+ }
+ bool error = ClearException(env);
+ DCHECK(!error);
+ return true;
+}
+
+jfieldID GetStaticFieldID(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* field_name,
+ const char* jni_signature) {
+ jfieldID field_id =
+ env->GetStaticFieldID(clazz.obj(), field_name, jni_signature);
+ CHECK(field_id && !ClearException(env)) << "Failed to find static field " <<
+ field_name << " " << jni_signature;
+ bool error = ClearException(env);
+ DCHECK(!error);
+ return field_id;
}
jmethodID GetMethodIDFromClassName(JNIEnv* env,
@@ -111,7 +207,7 @@ jmethodID GetMethodIDFromClassName(JNIEnv* env,
}
ScopedJavaLocalRef<jclass> clazz(env, env->FindClass(class_name));
- jmethodID id = GetMethodID(env, clazz.obj(), method, jni_signature);
+ jmethodID id = GetMethodID(env, clazz, method, jni_signature);
while (base::subtle::Acquire_CompareAndSwap(&g_method_id_map_lock,
kUnlocked,
@@ -127,43 +223,23 @@ jmethodID GetMethodIDFromClassName(JNIEnv* env,
return id;
}
-jmethodID GetMethodID(JNIEnv* env,
- jclass clazz,
- const char* const method,
- const char* const jni_signature) {
- jmethodID id = env->GetMethodID(clazz, method, jni_signature);
- DCHECK(id) << method;
- CheckException(env);
- return id;
+bool HasException(JNIEnv* env) {
+ return env->ExceptionCheck() != JNI_FALSE;
}
-jmethodID GetStaticMethodID(JNIEnv* env,
- jclass clazz,
- const char* const method,
- const char* const jni_signature) {
- jmethodID id = env->GetStaticMethodID(clazz, method, jni_signature);
- DCHECK(id) << method;
- CheckException(env);
- return id;
-}
-
-jfieldID GetFieldID(JNIEnv* env,
- jclass clazz,
- const char* field,
- const char* jni_signature) {
- jfieldID id = env->GetFieldID(clazz, field, jni_signature);
- DCHECK(id) << field;
- CheckException(env);
- return id;
-}
-
-bool CheckException(JNIEnv* env) {
- if (env->ExceptionCheck() == JNI_FALSE)
+bool ClearException(JNIEnv* env) {
+ if (!HasException(env))
return false;
- env->ExceptionDescribe();
env->ExceptionClear();
return true;
}
+void CheckException(JNIEnv* env) {
+ if (HasException(env)) {
+ env->ExceptionDescribe();
+ CHECK(false);
+ }
+}
+
} // namespace android
} // namespace base
diff --git a/base/android/jni_android.h b/base/android/jni_android.h
index a5571e0..0e7b557 100644
--- a/base/android/jni_android.h
+++ b/base/android/jni_android.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -26,13 +26,45 @@ void InitVM(JavaVM* vm);
// Initializes the global application context object. The |context| can be any
// valid reference to the application context. Internally holds a global ref to
// the context. InitVM and InitApplicationContext maybe called in either order.
-// TODO: We might combine InitVM() and InitApplicationContext() into one method.
void InitApplicationContext(const JavaRef<jobject>& context);
// Gets a global ref to the application context set with
// InitApplicationContext(). Ownership is retained by the function - the caller
// must NOT release it.
-jobject GetApplicationContext();
+const jobject GetApplicationContext();
+
+// Finds the class named |class_name| and returns it.
+// Use this method instead of invoking directly the JNI FindClass method (to
+// prevent leaking local references).
+// This method triggers a fatal assertion if the class could not be found.
+// Use HasClass if you need to check whether the class exists.
+ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* class_name);
+
+// Returns true iff the class |class_name| could be found.
+bool HasClass(JNIEnv* env, const char* class_name);
+
+// Returns the method ID for the method with the specified name and signature.
+// This method triggers a fatal assertion if the method could not be found.
+// Use HasMethod if you need to check whether a method exists.
+jmethodID GetMethodID(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* method_name,
+ const char* jni_signature);
+
+// Returns the method ID for the static method with the specified name and
+// signature.
+// This method triggers a fatal assertion if the method could not be found.
+// Use HasMethod if you need to check whether a method exists.
+jmethodID GetStaticMethodID(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* method_name,
+ const char* jni_signature);
+
+// Returns true iff |clazz| has a method with the specified name and signature.
+bool HasMethod(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* method_name,
+ const char* jni_signature);
// Gets the method ID from the class name. Clears the pending Java exception
// and returns NULL if the method is not found. Caches results. Note that
@@ -46,30 +78,36 @@ jmethodID GetMethodIDFromClassName(JNIEnv* env,
const char* method,
const char* jni_signature);
-// Get the method ID for a method. Will clear the pending Java
-// exception and return 0 if the method is not found.
-jmethodID GetMethodID(JNIEnv* env,
- jclass clazz,
- const char* const method,
- const char* const jni_signature);
-
-// Get the method ID for a class static method. Will clear the pending Java
-// exception and return 0 if the method is not found.
-jmethodID GetStaticMethodID(JNIEnv* env,
- jclass clazz,
- const char* const method,
- const char* const jni_signature);
-
-// Gets the field ID for a class field. Clears the pending Java exception and
-// returns NULL if the field is not found.
+// Gets the field ID for a class field.
+// This method triggers a fatal assertion if the field could not be found.
jfieldID GetFieldID(JNIEnv* env,
- jclass clazz,
- const char* field,
+ const JavaRef<jclass>& clazz,
+ const char* field_name,
const char* jni_signature);
-// Returns true if an exception is pending in the provided JNIEnv*. If an
-// exception is pending, this function prints and then clears it.
-bool CheckException(JNIEnv* env);
+// Returns true if |clazz| as a field with the given name and signature.
+// TODO(jcivelli): Determine whether we explicitly have to pass the environment.
+bool HasField(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* field_name,
+ const char* jni_signature);
+
+// Gets the field ID for a static class field.
+// This method triggers a fatal assertion if the field could not be found.
+jfieldID GetStaticFieldID(JNIEnv* env,
+ const JavaRef<jclass>& clazz,
+ const char* field_name,
+ const char* jni_signature);
+
+// Returns true if an exception is pending in the provided JNIEnv*.
+bool HasException(JNIEnv* env);
+
+// If an exception is pending in the provided JNIEnv*, this function clears it
+// and returns true.
+bool ClearException(JNIEnv* env);
+
+// This function will call CHECK() macro if there's any pending exception.
+void CheckException(JNIEnv* env);
} // namespace android
} // namespace base
diff --git a/base/android/jni_array.cc b/base/android/jni_array.cc
index ae2f185..8e0547c 100644
--- a/base/android/jni_array.cc
+++ b/base/android/jni_array.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,15 +6,13 @@
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
-#include "base/android/scoped_java_ref.h"
#include "base/logging.h"
namespace base {
namespace android {
-jbyteArray ToJavaByteArray(JNIEnv* env,
- const unsigned char* bytes,
- size_t len) {
+ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
+ JNIEnv* env, const uint8* bytes, size_t len) {
jbyteArray byte_array = env->NewByteArray(len);
CheckException(env);
DCHECK(byte_array);
@@ -24,37 +22,55 @@ jbyteArray ToJavaByteArray(JNIEnv* env,
env->ReleaseByteArrayElements(byte_array, elements, 0);
CheckException(env);
- return byte_array;
+ return ScopedJavaLocalRef<jbyteArray>(env, byte_array);
}
-jobjectArray ToJavaArrayOfByteArray(JNIEnv* env,
- const std::vector<std::string>& v) {
- ScopedJavaLocalRef<jclass> byte_array_clazz(env, env->FindClass("[B"));
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
+ JNIEnv* env, const std::vector<std::string>& v) {
+ ScopedJavaLocalRef<jclass> byte_array_clazz = GetClass(env, "[B");
jobjectArray joa = env->NewObjectArray(v.size(),
byte_array_clazz.obj(), NULL);
CheckException(env);
for (size_t i = 0; i < v.size(); ++i) {
- ScopedJavaLocalRef<jobject> byte_array(env, ToJavaByteArray(env,
- reinterpret_cast<const uint8*>(v[i].data()), v[i].length()));
+ ScopedJavaLocalRef<jbyteArray> byte_array = ToJavaByteArray(env,
+ reinterpret_cast<const uint8*>(v[i].data()), v[i].length());
env->SetObjectArrayElement(joa, i, byte_array.obj());
}
- return joa;
+ return ScopedJavaLocalRef<jobjectArray>(env, joa);
}
-jobjectArray ToJavaArrayOfStrings(JNIEnv* env,
- const std::vector<std::string>& v) {
- ScopedJavaLocalRef<jclass> string_clazz(env,
- env->FindClass("java/lang/String"));
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+ JNIEnv* env, const std::vector<std::string>& v) {
+ ScopedJavaLocalRef<jclass> string_clazz = GetClass(env, "java/lang/String");
jobjectArray joa = env->NewObjectArray(v.size(), string_clazz.obj(), NULL);
CheckException(env);
for (size_t i = 0; i < v.size(); ++i) {
- ScopedJavaLocalRef<jstring> item(env,
- ConvertUTF8ToJavaString(env, v[i]));
+ ScopedJavaLocalRef<jstring> item = ConvertUTF8ToJavaString(env, v[i]);
env->SetObjectArrayElement(joa, i, item.obj());
}
- return joa;
+ return ScopedJavaLocalRef<jobjectArray>(env, joa);
+}
+
+void AppendJavaByteArrayToByteVector(JNIEnv* env,
+ jbyteArray byte_array,
+ std::vector<uint8>* out) {
+ DCHECK(out);
+ if (!byte_array)
+ return;
+ jsize len = env->GetArrayLength(byte_array);
+ jbyte* bytes = env->GetByteArrayElements(byte_array, NULL);
+ out->insert(out->end(), bytes, bytes + len);
+ env->ReleaseByteArrayElements(byte_array, bytes, JNI_ABORT);
+}
+
+void JavaByteArrayToByteVector(JNIEnv* env,
+ jbyteArray byte_array,
+ std::vector<uint8>* out) {
+ DCHECK(out);
+ out->clear();
+ AppendJavaByteArrayToByteVector(env, byte_array, out);
}
} // namespace android
diff --git a/base/android/jni_array.h b/base/android/jni_array.h
index edf05c6..fea5548 100644
--- a/base/android/jni_array.h
+++ b/base/android/jni_array.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,18 +9,32 @@
#include <string>
#include <vector>
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+
namespace base {
namespace android {
// Returns a new Java byte array converted from the given bytes array.
-jbyteArray ToJavaByteArray(JNIEnv* env, const unsigned char* bytes, size_t len);
+ScopedJavaLocalRef<jbyteArray> ToJavaByteArray(
+ JNIEnv* env, const uint8* bytes, size_t len);
// Returns a array of Java byte array converted from |v|.
-jobjectArray ToJavaArrayOfByteArray(JNIEnv* env,
- const std::vector<std::string>& v);
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfByteArray(
+ JNIEnv* env, const std::vector<std::string>& v);
+
+ScopedJavaLocalRef<jobjectArray> ToJavaArrayOfStrings(
+ JNIEnv* env, const std::vector<std::string>& v);
+
+// Appends the Java bytes in |bytes_array| onto the end of |out|.
+void AppendJavaByteArrayToByteVector(JNIEnv* env,
+ jbyteArray byte_array,
+ std::vector<uint8>* out);
-jobjectArray ToJavaArrayOfStrings(JNIEnv* env,
- const std::vector<std::string>& v);
+// Replaces the content of |out| with the Java bytes in |bytes_array|.
+void JavaByteArrayToByteVector(JNIEnv* env,
+ jbyteArray byte_array,
+ std::vector<uint8>* out);
} // namespace android
} // namespace base
diff --git a/base/android/jni_array_unittest.cc b/base/android/jni_array_unittest.cc
new file mode 100644
index 0000000..7529335
--- /dev/null
+++ b/base/android/jni_array_unittest.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/android/jni_array.h"
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace android {
+
+TEST(JniArray, BasicConversions) {
+ const uint8 kBytes[] = { 0, 1, 2, 3 };
+ const size_t kLen = arraysize(kBytes);
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jbyteArray> bytes = ToJavaByteArray(env, kBytes, kLen);
+ ASSERT_TRUE(bytes.obj());
+
+ std::vector<uint8> vec(5);
+ JavaByteArrayToByteVector(env, bytes.obj(), &vec);
+ EXPECT_EQ(4U, vec.size());
+ EXPECT_EQ(std::vector<uint8>(kBytes, kBytes + kLen), vec);
+
+ AppendJavaByteArrayToByteVector(env, bytes.obj(), &vec);
+ EXPECT_EQ(8U, vec.size());
+}
+
+} // namespace android
+} // namespace base
diff --git a/base/android/jni_string.cc b/base/android/jni_string.cc
index 26e7114..94ec0df 100644
--- a/base/android/jni_string.cc
+++ b/base/android/jni_string.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,6 +8,17 @@
#include "base/logging.h"
#include "base/utf_string_conversions.h"
+namespace {
+
+// Internal version that does not use a scoped local pointer.
+jstring ConvertUTF16ToJavaStringImpl(JNIEnv* env, const string16& str) {
+ jstring result = env->NewString(str.data(), str.length());
+ base::android::CheckException(env);
+ return result;
+}
+
+}
+
namespace base {
namespace android {
@@ -17,7 +28,12 @@ std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str) {
return UTF16ToUTF8(ConvertJavaStringToUTF16(env, str));
}
-jstring ConvertUTF8ToJavaString(JNIEnv* env, const base::StringPiece& str) {
+std::string ConvertJavaStringToUTF8(const JavaRef<jstring>& str) {
+ return ConvertJavaStringToUTF8(str.env(), str.obj());
+}
+
+ScopedJavaLocalRef<jstring> ConvertUTF8ToJavaString(
+ JNIEnv* env, const base::StringPiece& str) {
// JNI's NewStringUTF expects "modified" UTF8 so instead create the string
// via our own UTF16 conversion utility.
// Further, Dalvik requires the string passed into NewStringUTF() to come from
@@ -25,7 +41,8 @@ jstring ConvertUTF8ToJavaString(JNIEnv* env, const base::StringPiece& str) {
// it gets here, so constructing via UTF16 side-steps this issue.
// (Dalvik stores strings internally as UTF16 anyway, so there shouldn't be
// a significant performance hit by doing it this way).
- return ConvertUTF16ToJavaString(env, UTF8ToUTF16(str));
+ return ScopedJavaLocalRef<jstring>(env, ConvertUTF16ToJavaStringImpl(
+ env, UTF8ToUTF16(str)));
}
string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str) {
@@ -39,10 +56,15 @@ string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str) {
return result;
}
-jstring ConvertUTF16ToJavaString(JNIEnv* env, const string16& str) {
- jstring result = env->NewString(str.data(), str.length());
- CheckException(env);
- return result;
+string16 ConvertJavaStringToUTF16(const JavaRef<jstring>& str) {
+ return ConvertJavaStringToUTF16(str.env(), str.obj());
+}
+
+// TODO(joth): change this to accept const StringPiece16&.
+ScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(JNIEnv* env,
+ const string16& str) {
+ return ScopedJavaLocalRef<jstring>(env,
+ ConvertUTF16ToJavaStringImpl(env, str));
}
} // namespace android
diff --git a/base/android/jni_string.h b/base/android/jni_string.h
index bb902d1..1987f04 100644
--- a/base/android/jni_string.h
+++ b/base/android/jni_string.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,6 +8,7 @@
#include <jni.h>
#include <string>
+#include "base/android/scoped_java_ref.h"
#include "base/string16.h"
#include "base/string_piece.h"
@@ -16,15 +17,19 @@ namespace android {
// Convert a Java string to UTF8. Returns a std string.
std::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str);
+std::string ConvertJavaStringToUTF8(const JavaRef<jstring>& str);
// Convert a std string to Java string.
-jstring ConvertUTF8ToJavaString(JNIEnv* env, const base::StringPiece& str);
+ScopedJavaLocalRef<jstring> ConvertUTF8ToJavaString(
+ JNIEnv* env, const base::StringPiece& str);
// Convert a Java string to UTF16. Returns a string16.
string16 ConvertJavaStringToUTF16(JNIEnv* env, jstring str);
+string16 ConvertJavaStringToUTF16(const JavaRef<jstring>& str);
// Convert a string16 to a Java string.
-jstring ConvertUTF16ToJavaString(JNIEnv* env, const string16& str);
+ScopedJavaLocalRef<jstring> ConvertUTF16ToJavaString(
+ JNIEnv* env, const string16& str);
} // namespace android
} // namespace base
diff --git a/base/android/scoped_java_ref.cc b/base/android/scoped_java_ref.cc
index da932f8..2cbcc75 100644
--- a/base/android/scoped_java_ref.cc
+++ b/base/android/scoped_java_ref.cc
@@ -1,9 +1,11 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/android/scoped_java_ref.h"
+#include "base/logging.h"
+
namespace base {
namespace android {
@@ -12,7 +14,10 @@ JavaRef<jobject>::JavaRef() : env_(NULL), obj_(NULL) {}
JavaRef<jobject>::JavaRef(JNIEnv* env, jobject obj)
: env_(env),
obj_(obj) {
- DCHECK_EQ(JNILocalRefType, env->GetObjectRefType(obj));
+ if (obj) {
+ DCHECK(env);
+ DCHECK_EQ(JNILocalRefType, env->GetObjectRefType(obj));
+ }
}
JavaRef<jobject>::~JavaRef() {
@@ -36,6 +41,20 @@ void JavaRef<jobject>::SetNewGlobalRef(JNIEnv* env, jobject obj) {
obj_ = obj;
}
+void JavaRef<jobject>::ResetLocalRef() {
+ if (obj_)
+ env_->DeleteLocalRef(obj_);
+ env_ = NULL;
+ obj_ = NULL;
+}
+
+void JavaRef<jobject>::ResetGlobalRef() {
+ if (obj_)
+ env_->DeleteGlobalRef(obj_);
+ env_ = NULL;
+ obj_ = NULL;
+}
+
jobject JavaRef<jobject>::ReleaseInternal() {
jobject obj = obj_;
env_ = NULL;
diff --git a/base/android/scoped_java_ref.h b/base/android/scoped_java_ref.h
index a74cef7..dd93b25 100644
--- a/base/android/scoped_java_ref.h
+++ b/base/android/scoped_java_ref.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,7 +8,7 @@
#include <jni.h>
#include <stddef.h>
-#include "base/logging.h"
+#include "base/basictypes.h"
namespace base {
namespace android {
@@ -25,6 +25,8 @@ class JavaRef<jobject> {
JNIEnv* env() const { return env_; }
jobject obj() const { return obj_; }
+ bool is_null() const { return obj_ == NULL; }
+
protected:
// Initializes a NULL reference.
JavaRef();
@@ -39,6 +41,8 @@ class JavaRef<jobject> {
// use by the sub-classes.
void SetNewLocalRef(JNIEnv* env, jobject obj);
void SetNewGlobalRef(JNIEnv* env, jobject obj);
+ void ResetLocalRef();
+ void ResetGlobalRef();
jobject ReleaseInternal();
private:
@@ -104,7 +108,7 @@ class ScopedJavaLocalRef : public JavaRef<T> {
}
void Reset() {
- this->SetNewLocalRef(NULL, NULL);
+ this->ResetLocalRef();
}
template<typename U>
@@ -148,7 +152,7 @@ class ScopedJavaGlobalRef : public JavaRef<T> {
}
void Reset() {
- this->SetNewGlobalRef(NULL, NULL);
+ this->ResetGlobalRef();
}
template<typename U>
diff --git a/base/android/scoped_java_ref_unittest.cc b/base/android/scoped_java_ref_unittest.cc
index a6dfc7a..f8bc675 100644
--- a/base/android/scoped_java_ref_unittest.cc
+++ b/base/android/scoped_java_ref_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -15,24 +15,26 @@ namespace {
int g_local_refs = 0;
int g_global_refs = 0;
+JNINativeInterface g_previous_functions = {0};
+
jobject NewGlobalRef(JNIEnv* env, jobject obj) {
++g_global_refs;
- return AttachCurrentThread()->NewGlobalRef(obj);
+ return g_previous_functions.NewGlobalRef(env, obj);
}
void DeleteGlobalRef(JNIEnv* env, jobject obj) {
--g_global_refs;
- return AttachCurrentThread()->DeleteGlobalRef(obj);
+ return g_previous_functions.DeleteGlobalRef(env, obj);
}
jobject NewLocalRef(JNIEnv* env, jobject obj) {
++g_local_refs;
- return AttachCurrentThread()->NewLocalRef(obj);
+ return g_previous_functions.NewLocalRef(env, obj);
}
void DeleteLocalRef(JNIEnv* env, jobject obj) {
--g_local_refs;
- return AttachCurrentThread()->DeleteLocalRef(obj);
+ return g_previous_functions.DeleteLocalRef(env, obj);
}
} // namespace
@@ -42,27 +44,27 @@ class ScopedJavaRefTest : public testing::Test {
g_local_refs = 0;
g_global_refs = 0;
JNIEnv* env = AttachCurrentThread();
- counting_env = *env;
- counting_functions = *counting_env.functions;
- counting_functions.NewGlobalRef = &NewGlobalRef;
- counting_functions.DeleteGlobalRef = &DeleteGlobalRef;
- counting_functions.NewLocalRef = &NewLocalRef;
- counting_functions.DeleteLocalRef = &DeleteLocalRef;
- counting_env.functions = &counting_functions;
+ g_previous_functions = *env->functions;
+ // We inject our own functions in JNINativeInterface so we can keep track
+ // of the reference counting ourselves.
+ JNINativeInterface* native_interface =
+ const_cast<JNINativeInterface*>(env->functions);
+ native_interface->NewGlobalRef = &NewGlobalRef;
+ native_interface->DeleteGlobalRef = &DeleteGlobalRef;
+ native_interface->NewLocalRef = &NewLocalRef;
+ native_interface->DeleteLocalRef = &DeleteLocalRef;
}
- // Special JNI env configured in SetUp to count in and out all local & global
- // reference instances. Be careful to only use this with the ScopedJavaRef
- // classes under test, else it's easy to get system references counted in
- // here too.
- JNIEnv counting_env;
- JNINativeInterface counting_functions;
+ virtual void TearDown() {
+ JNIEnv* env = AttachCurrentThread();
+ *(const_cast<JNINativeInterface*>(env->functions)) = g_previous_functions;
+ }
};
// The main purpose of this is testing the various conversions compile.
TEST_F(ScopedJavaRefTest, Conversions) {
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jstring> str(env, ConvertUTF8ToJavaString(env, "string"));
+ ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(env, "string");
ScopedJavaGlobalRef<jstring> global(str);
{
ScopedJavaGlobalRef<jobject> global_obj(str);
@@ -74,24 +76,27 @@ TEST_F(ScopedJavaRefTest, Conversions) {
}
global.Reset(str);
const JavaRef<jstring>& str_ref = str;
- EXPECT_EQ("string", ConvertJavaStringToUTF8(env, str_ref.obj()));
+ EXPECT_EQ("string", ConvertJavaStringToUTF8(str_ref));
str.Reset();
}
TEST_F(ScopedJavaRefTest, RefCounts) {
+ JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jstring> str;
- str.Reset(&counting_env, ConvertUTF8ToJavaString(AttachCurrentThread(),
- "string"));
+ // The ConvertJavaStringToUTF8 below creates a new string that would normally
+ // return a local ref. We simulate that by starting the g_local_refs count at
+ // 1.
+ g_local_refs = 1;
+ str.Reset(ConvertUTF8ToJavaString(env, "string"));
EXPECT_EQ(1, g_local_refs);
EXPECT_EQ(0, g_global_refs);
-
{
ScopedJavaGlobalRef<jstring> global_str(str);
ScopedJavaGlobalRef<jobject> global_obj(global_str);
EXPECT_EQ(1, g_local_refs);
EXPECT_EQ(2, g_global_refs);
- ScopedJavaLocalRef<jstring> str2(&counting_env, str.Release());
+ ScopedJavaLocalRef<jstring> str2(env, str.Release());
EXPECT_EQ(1, g_local_refs);
{
ScopedJavaLocalRef<jstring> str3(str2);