OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/android/scoped_java_ref.h" | 5 #include "base/android/scoped_java_ref.h" |
6 | 6 |
7 #include "base/android/jni_android.h" | 7 #include "base/android/jni_android.h" |
8 #include "base/android/jni_string.h" | 8 #include "base/android/jni_string.h" |
9 #include "testing/gtest/include/gtest/gtest.h" | 9 #include "testing/gtest/include/gtest/gtest.h" |
10 | 10 |
11 namespace base { | 11 namespace base { |
12 namespace android { | 12 namespace android { |
13 | 13 |
14 namespace { | 14 namespace { |
15 int g_local_refs = 0; | 15 int g_local_refs = 0; |
16 int g_global_refs = 0; | 16 int g_global_refs = 0; |
17 | 17 |
| 18 JNINativeInterface g_previous_functions = {0}; |
| 19 |
18 jobject NewGlobalRef(JNIEnv* env, jobject obj) { | 20 jobject NewGlobalRef(JNIEnv* env, jobject obj) { |
19 ++g_global_refs; | 21 ++g_global_refs; |
20 return AttachCurrentThread()->NewGlobalRef(obj); | 22 return g_previous_functions.NewGlobalRef(env, obj); |
21 } | 23 } |
22 | 24 |
23 void DeleteGlobalRef(JNIEnv* env, jobject obj) { | 25 void DeleteGlobalRef(JNIEnv* env, jobject obj) { |
24 --g_global_refs; | 26 --g_global_refs; |
25 return AttachCurrentThread()->DeleteGlobalRef(obj); | 27 return g_previous_functions.DeleteGlobalRef(env, obj); |
26 } | 28 } |
27 | 29 |
28 jobject NewLocalRef(JNIEnv* env, jobject obj) { | 30 jobject NewLocalRef(JNIEnv* env, jobject obj) { |
29 ++g_local_refs; | 31 ++g_local_refs; |
30 return AttachCurrentThread()->NewLocalRef(obj); | 32 return g_previous_functions.NewLocalRef(env, obj); |
31 } | 33 } |
32 | 34 |
33 void DeleteLocalRef(JNIEnv* env, jobject obj) { | 35 void DeleteLocalRef(JNIEnv* env, jobject obj) { |
34 --g_local_refs; | 36 --g_local_refs; |
35 return AttachCurrentThread()->DeleteLocalRef(obj); | 37 return g_previous_functions.DeleteLocalRef(env, obj); |
36 } | 38 } |
37 } // namespace | 39 } // namespace |
38 | 40 |
39 class ScopedJavaRefTest : public testing::Test { | 41 class ScopedJavaRefTest : public testing::Test { |
40 protected: | 42 protected: |
41 virtual void SetUp() { | 43 virtual void SetUp() { |
42 g_local_refs = 0; | 44 g_local_refs = 0; |
43 g_global_refs = 0; | 45 g_global_refs = 0; |
44 JNIEnv* env = AttachCurrentThread(); | 46 JNIEnv* env = AttachCurrentThread(); |
45 counting_env = *env; | 47 g_previous_functions = *env->functions; |
46 counting_functions = *counting_env.functions; | 48 // We inject our own functions in JNINativeInterface so we can keep track |
47 counting_functions.NewGlobalRef = &NewGlobalRef; | 49 // of the reference counting ourselves. |
48 counting_functions.DeleteGlobalRef = &DeleteGlobalRef; | 50 JNINativeInterface* native_interface = |
49 counting_functions.NewLocalRef = &NewLocalRef; | 51 const_cast<JNINativeInterface*>(env->functions); |
50 counting_functions.DeleteLocalRef = &DeleteLocalRef; | 52 native_interface->NewGlobalRef = &NewGlobalRef; |
51 counting_env.functions = &counting_functions; | 53 native_interface->DeleteGlobalRef = &DeleteGlobalRef; |
| 54 native_interface->NewLocalRef = &NewLocalRef; |
| 55 native_interface->DeleteLocalRef = &DeleteLocalRef; |
52 } | 56 } |
53 | 57 |
54 // Special JNI env configured in SetUp to count in and out all local & global | 58 virtual void TearDown() { |
55 // reference instances. Be careful to only use this with the ScopedJavaRef | 59 JNIEnv* env = AttachCurrentThread(); |
56 // classes under test, else it's easy to get system references counted in | 60 *(const_cast<JNINativeInterface*>(env->functions)) = g_previous_functions; |
57 // here too. | 61 } |
58 JNIEnv counting_env; | |
59 JNINativeInterface counting_functions; | |
60 }; | 62 }; |
61 | 63 |
62 // The main purpose of this is testing the various conversions compile. | 64 // The main purpose of this is testing the various conversions compile. |
63 TEST_F(ScopedJavaRefTest, Conversions) { | 65 TEST_F(ScopedJavaRefTest, Conversions) { |
64 JNIEnv* env = AttachCurrentThread(); | 66 JNIEnv* env = AttachCurrentThread(); |
65 ScopedJavaLocalRef<jstring> str(env, ConvertUTF8ToJavaString(env, "string")); | 67 ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(env, "string"); |
66 ScopedJavaGlobalRef<jstring> global(str); | 68 ScopedJavaGlobalRef<jstring> global(str); |
67 { | 69 { |
68 ScopedJavaGlobalRef<jobject> global_obj(str); | 70 ScopedJavaGlobalRef<jobject> global_obj(str); |
69 ScopedJavaLocalRef<jobject> local_obj(global); | 71 ScopedJavaLocalRef<jobject> local_obj(global); |
70 const JavaRef<jobject>& obj_ref1(str); | 72 const JavaRef<jobject>& obj_ref1(str); |
71 const JavaRef<jobject>& obj_ref2(global); | 73 const JavaRef<jobject>& obj_ref2(global); |
72 EXPECT_TRUE(env->IsSameObject(obj_ref1.obj(), obj_ref2.obj())); | 74 EXPECT_TRUE(env->IsSameObject(obj_ref1.obj(), obj_ref2.obj())); |
73 EXPECT_TRUE(env->IsSameObject(global_obj.obj(), obj_ref2.obj())); | 75 EXPECT_TRUE(env->IsSameObject(global_obj.obj(), obj_ref2.obj())); |
74 } | 76 } |
75 global.Reset(str); | 77 global.Reset(str); |
76 const JavaRef<jstring>& str_ref = str; | 78 const JavaRef<jstring>& str_ref = str; |
77 EXPECT_EQ("string", ConvertJavaStringToUTF8(env, str_ref.obj())); | 79 EXPECT_EQ("string", ConvertJavaStringToUTF8(str_ref)); |
78 str.Reset(); | 80 str.Reset(); |
79 } | 81 } |
80 | 82 |
81 TEST_F(ScopedJavaRefTest, RefCounts) { | 83 TEST_F(ScopedJavaRefTest, RefCounts) { |
| 84 JNIEnv* env = AttachCurrentThread(); |
82 ScopedJavaLocalRef<jstring> str; | 85 ScopedJavaLocalRef<jstring> str; |
83 str.Reset(&counting_env, ConvertUTF8ToJavaString(AttachCurrentThread(), | 86 // The ConvertJavaStringToUTF8 below creates a new string that would normally |
84 "string")); | 87 // return a local ref. We simulate that by starting the g_local_refs count at |
| 88 // 1. |
| 89 g_local_refs = 1; |
| 90 str.Reset(ConvertUTF8ToJavaString(env, "string")); |
85 EXPECT_EQ(1, g_local_refs); | 91 EXPECT_EQ(1, g_local_refs); |
86 EXPECT_EQ(0, g_global_refs); | 92 EXPECT_EQ(0, g_global_refs); |
87 | |
88 { | 93 { |
89 ScopedJavaGlobalRef<jstring> global_str(str); | 94 ScopedJavaGlobalRef<jstring> global_str(str); |
90 ScopedJavaGlobalRef<jobject> global_obj(global_str); | 95 ScopedJavaGlobalRef<jobject> global_obj(global_str); |
91 EXPECT_EQ(1, g_local_refs); | 96 EXPECT_EQ(1, g_local_refs); |
92 EXPECT_EQ(2, g_global_refs); | 97 EXPECT_EQ(2, g_global_refs); |
93 | 98 |
94 ScopedJavaLocalRef<jstring> str2(&counting_env, str.Release()); | 99 ScopedJavaLocalRef<jstring> str2(env, str.Release()); |
95 EXPECT_EQ(1, g_local_refs); | 100 EXPECT_EQ(1, g_local_refs); |
96 { | 101 { |
97 ScopedJavaLocalRef<jstring> str3(str2); | 102 ScopedJavaLocalRef<jstring> str3(str2); |
98 EXPECT_EQ(2, g_local_refs); | 103 EXPECT_EQ(2, g_local_refs); |
99 } | 104 } |
100 EXPECT_EQ(1, g_local_refs); | 105 EXPECT_EQ(1, g_local_refs); |
101 str2.Reset(); | 106 str2.Reset(); |
102 EXPECT_EQ(0, g_local_refs); | 107 EXPECT_EQ(0, g_local_refs); |
103 global_str.Reset(); | 108 global_str.Reset(); |
104 EXPECT_EQ(1, g_global_refs); | 109 EXPECT_EQ(1, g_global_refs); |
105 ScopedJavaGlobalRef<jobject> global_obj2(global_obj); | 110 ScopedJavaGlobalRef<jobject> global_obj2(global_obj); |
106 EXPECT_EQ(2, g_global_refs); | 111 EXPECT_EQ(2, g_global_refs); |
107 } | 112 } |
108 | 113 |
109 EXPECT_EQ(0, g_local_refs); | 114 EXPECT_EQ(0, g_local_refs); |
110 EXPECT_EQ(0, g_global_refs); | 115 EXPECT_EQ(0, g_global_refs); |
111 } | 116 } |
112 | 117 |
113 } // namespace android | 118 } // namespace android |
114 } // namespace base | 119 } // namespace base |
OLD | NEW |