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.
5 #include "base/android/scoped_java_ref.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "testing/gtest/include/gtest/gtest.h"
16 int g_global_refs
= 0;
18 const JNINativeInterface
* g_previous_functions
;
20 jobject
NewGlobalRef(JNIEnv
* env
, jobject obj
) {
22 return g_previous_functions
->NewGlobalRef(env
, obj
);
25 void DeleteGlobalRef(JNIEnv
* env
, jobject obj
) {
27 return g_previous_functions
->DeleteGlobalRef(env
, obj
);
30 jobject
NewLocalRef(JNIEnv
* env
, jobject obj
) {
32 return g_previous_functions
->NewLocalRef(env
, obj
);
35 void DeleteLocalRef(JNIEnv
* env
, jobject obj
) {
37 return g_previous_functions
->DeleteLocalRef(env
, obj
);
41 class ScopedJavaRefTest
: public testing::Test
{
43 void SetUp() override
{
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
;
58 void TearDown() override
{
59 JNIEnv
* env
= AttachCurrentThread();
60 env
->functions
= g_previous_functions
;
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
;
67 // The main purpose of this is testing the various conversions compile.
68 TEST_F(ScopedJavaRefTest
, Conversions
) {
69 JNIEnv
* env
= AttachCurrentThread();
70 ScopedJavaLocalRef
<jstring
> str
= ConvertUTF8ToJavaString(env
, "string");
71 ScopedJavaGlobalRef
<jstring
> global(str
);
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()));
81 const JavaRef
<jstring
>& str_ref
= str
;
82 EXPECT_EQ("string", ConvertJavaStringToUTF8(str_ref
));
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
93 str
.Reset(ConvertUTF8ToJavaString(env
, "string"));
94 EXPECT_EQ(1, g_local_refs
);
95 EXPECT_EQ(0, g_global_refs
);
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
);
102 ScopedJavaLocalRef
<jstring
> str2(env
, str
.Release());
103 EXPECT_EQ(1, g_local_refs
);
105 ScopedJavaLocalRef
<jstring
> str3(str2
);
106 EXPECT_EQ(2, g_local_refs
);
108 EXPECT_EQ(1, g_local_refs
);
110 EXPECT_EQ(0, g_local_refs
);
112 EXPECT_EQ(1, g_global_refs
);
113 ScopedJavaGlobalRef
<jobject
> global_obj2(global_obj
);
114 EXPECT_EQ(2, g_global_refs
);
117 EXPECT_EQ(0, g_local_refs
);
118 EXPECT_EQ(0, g_global_refs
);
121 } // namespace android