• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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