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 #include "base/android/scoped_java_ref.h"
6
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10
11 namespace base {
12 namespace android {
13
14 namespace {
15 int g_local_refs = 0;
16 int g_global_refs = 0;
17
18 const JNINativeInterface* g_previous_functions;
19
NewGlobalRef(JNIEnv * env,jobject obj)20 jobject NewGlobalRef(JNIEnv* env, jobject obj) {
21 ++g_global_refs;
22 return g_previous_functions->NewGlobalRef(env, obj);
23 }
24
DeleteGlobalRef(JNIEnv * env,jobject obj)25 void DeleteGlobalRef(JNIEnv* env, jobject obj) {
26 --g_global_refs;
27 return g_previous_functions->DeleteGlobalRef(env, obj);
28 }
29
NewLocalRef(JNIEnv * env,jobject obj)30 jobject NewLocalRef(JNIEnv* env, jobject obj) {
31 ++g_local_refs;
32 return g_previous_functions->NewLocalRef(env, obj);
33 }
34
DeleteLocalRef(JNIEnv * env,jobject obj)35 void DeleteLocalRef(JNIEnv* env, jobject obj) {
36 --g_local_refs;
37 return g_previous_functions->DeleteLocalRef(env, obj);
38 }
39 } // namespace
40
41 class ScopedJavaRefTest : public testing::Test {
42 protected:
SetUp()43 void SetUp() override {
44 g_local_refs = 0;
45 g_global_refs = 0;
46 JNIEnv* env = AttachCurrentThread();
47 g_previous_functions = env->functions;
48 hooked_functions = *g_previous_functions;
49 env->functions = &hooked_functions;
50 // We inject our own functions in JNINativeInterface so we can keep track
51 // of the reference counting ourselves.
52 hooked_functions.NewGlobalRef = &NewGlobalRef;
53 hooked_functions.DeleteGlobalRef = &DeleteGlobalRef;
54 hooked_functions.NewLocalRef = &NewLocalRef;
55 hooked_functions.DeleteLocalRef = &DeleteLocalRef;
56 }
57
TearDown()58 void TearDown() override {
59 JNIEnv* env = AttachCurrentThread();
60 env->functions = g_previous_functions;
61 }
62 // From JellyBean release, the instance of this struct provided in JNIEnv is
63 // read-only, so we deep copy it to allow individual functions to be hooked.
64 JNINativeInterface hooked_functions;
65 };
66
67 // The main purpose of this is testing the various conversions compile.
TEST_F(ScopedJavaRefTest,Conversions)68 TEST_F(ScopedJavaRefTest, Conversions) {
69 JNIEnv* env = AttachCurrentThread();
70 ScopedJavaLocalRef<jstring> str = ConvertUTF8ToJavaString(env, "string");
71 ScopedJavaGlobalRef<jstring> global(str);
72 {
73 ScopedJavaGlobalRef<jobject> global_obj(str);
74 ScopedJavaLocalRef<jobject> local_obj(global);
75 const JavaRef<jobject>& obj_ref1(str);
76 const JavaRef<jobject>& obj_ref2(global);
77 EXPECT_TRUE(env->IsSameObject(obj_ref1.obj(), obj_ref2.obj()));
78 EXPECT_TRUE(env->IsSameObject(global_obj.obj(), obj_ref2.obj()));
79 }
80 global.Reset(str);
81 const JavaRef<jstring>& str_ref = str;
82 EXPECT_EQ("string", ConvertJavaStringToUTF8(str_ref));
83 str.Reset();
84 }
85
TEST_F(ScopedJavaRefTest,RefCounts)86 TEST_F(ScopedJavaRefTest, RefCounts) {
87 JNIEnv* env = AttachCurrentThread();
88 ScopedJavaLocalRef<jstring> str;
89 // The ConvertJavaStringToUTF8 below creates a new string that would normally
90 // return a local ref. We simulate that by starting the g_local_refs count at
91 // 1.
92 g_local_refs = 1;
93 str.Reset(ConvertUTF8ToJavaString(env, "string"));
94 EXPECT_EQ(1, g_local_refs);
95 EXPECT_EQ(0, g_global_refs);
96 {
97 ScopedJavaGlobalRef<jstring> global_str(str);
98 ScopedJavaGlobalRef<jobject> global_obj(global_str);
99 EXPECT_EQ(1, g_local_refs);
100 EXPECT_EQ(2, g_global_refs);
101
102 ScopedJavaLocalRef<jstring> str2(env, str.Release());
103 EXPECT_EQ(1, g_local_refs);
104 {
105 ScopedJavaLocalRef<jstring> str3(str2);
106 EXPECT_EQ(2, g_local_refs);
107 }
108 EXPECT_EQ(1, g_local_refs);
109 {
110 ScopedJavaLocalRef<jstring> str4((ScopedJavaLocalRef<jstring>(str2)));
111 EXPECT_EQ(2, g_local_refs);
112 }
113 EXPECT_EQ(1, g_local_refs);
114 {
115 ScopedJavaLocalRef<jstring> str5;
116 str5 = ScopedJavaLocalRef<jstring>(str2);
117 EXPECT_EQ(2, g_local_refs);
118 }
119 EXPECT_EQ(1, g_local_refs);
120 str2.Reset();
121 EXPECT_EQ(0, g_local_refs);
122 global_str.Reset();
123 EXPECT_EQ(1, g_global_refs);
124 ScopedJavaGlobalRef<jobject> global_obj2(global_obj);
125 EXPECT_EQ(2, g_global_refs);
126 }
127
128 EXPECT_EQ(0, g_local_refs);
129 EXPECT_EQ(0, g_global_refs);
130 }
131
132 } // namespace android
133 } // namespace base
134