Home | History | Annotate | Download | only in android
      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 
     20 jobject NewGlobalRef(JNIEnv* env, jobject obj) {
     21   ++g_global_refs;
     22   return g_previous_functions->NewGlobalRef(env, obj);
     23 }
     24 
     25 void DeleteGlobalRef(JNIEnv* env, jobject obj) {
     26   --g_global_refs;
     27   return g_previous_functions->DeleteGlobalRef(env, obj);
     28 }
     29 
     30 jobject NewLocalRef(JNIEnv* env, jobject obj) {
     31   ++g_local_refs;
     32   return g_previous_functions->NewLocalRef(env, obj);
     33 }
     34 
     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:
     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 
     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.
     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 
     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