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/jni_android.h"
7 #include "base/at_exit.h"
8 #include "base/logging.h"
9 #include "testing/gtest/include/gtest/gtest.h"
16 const char kJavaLangObject
[] = "java/lang/Object";
17 const char kGetClass
[] = "getClass";
18 const char kToString
[] = "toString";
19 const char kReturningJavaLangClass
[] = "()Ljava/lang/Class;";
20 const char kReturningJavaLangString
[] = "()Ljava/lang/String;";
22 const char* g_last_method
;
23 const char* g_last_jni_signature
;
24 jmethodID g_last_method_id
;
26 const JNINativeInterface
* g_previous_functions
;
28 jmethodID
GetMethodIDWrapper(JNIEnv
* env
, jclass clazz
, const char* method
,
29 const char* jni_signature
) {
30 g_last_method
= method
;
31 g_last_jni_signature
= jni_signature
;
32 g_last_method_id
= g_previous_functions
->GetMethodID(env
, clazz
, method
,
34 return g_last_method_id
;
39 class JNIAndroidTest
: public testing::Test
{
41 virtual void SetUp() {
42 JNIEnv
* env
= AttachCurrentThread();
43 g_previous_functions
= env
->functions
;
44 hooked_functions
= *g_previous_functions
;
45 env
->functions
= &hooked_functions
;
46 hooked_functions
.GetMethodID
= &GetMethodIDWrapper
;
49 virtual void TearDown() {
50 JNIEnv
* env
= AttachCurrentThread();
51 env
->functions
= g_previous_functions
;
57 g_last_jni_signature
= 0;
58 g_last_method_id
= NULL
;
60 // Needed to cleanup the cached method map in the implementation between
61 // runs (e.g. if using --gtest_repeat)
62 base::ShadowingAtExitManager exit_manager
;
63 // From JellyBean release, the instance of this struct provided in JNIEnv is
64 // read-only, so we deep copy it to allow individual functions to be hooked.
65 JNINativeInterface hooked_functions
;
68 TEST_F(JNIAndroidTest
, GetMethodIDFromClassNameCaching
) {
69 JNIEnv
* env
= AttachCurrentThread();
72 jmethodID id1
= GetMethodIDFromClassName(env
, kJavaLangObject
, kGetClass
,
73 kReturningJavaLangClass
);
74 EXPECT_STREQ(kGetClass
, g_last_method
);
75 EXPECT_STREQ(kReturningJavaLangClass
, g_last_jni_signature
);
76 EXPECT_EQ(g_last_method_id
, id1
);
79 jmethodID id2
= GetMethodIDFromClassName(env
, kJavaLangObject
, kGetClass
,
80 kReturningJavaLangClass
);
81 EXPECT_STREQ(0, g_last_method
);
82 EXPECT_STREQ(0, g_last_jni_signature
);
83 EXPECT_EQ(NULL
, g_last_method_id
);
87 jmethodID id3
= GetMethodIDFromClassName(env
, kJavaLangObject
, kToString
,
88 kReturningJavaLangString
);
89 EXPECT_STREQ(kToString
, g_last_method
);
90 EXPECT_STREQ(kReturningJavaLangString
, g_last_jni_signature
);
91 EXPECT_EQ(g_last_method_id
, id3
);
96 base::subtle::AtomicWord g_atomic_id
= 0;
97 int LazyMethodIDCall(JNIEnv
* env
, jclass clazz
, int p
) {
98 jmethodID id
= base::android::MethodID::LazyGet
<
99 base::android::MethodID::TYPE_STATIC
>(
105 return env
->CallStaticIntMethod(clazz
, id
, p
);
108 int MethodIDCall(JNIEnv
* env
, jclass clazz
, jmethodID id
, int p
) {
109 return env
->CallStaticIntMethod(clazz
, id
, p
);
114 TEST(JNIAndroidMicrobenchmark
, MethodId
) {
115 JNIEnv
* env
= AttachCurrentThread();
116 ScopedJavaLocalRef
<jclass
> clazz(GetClass(env
, "java/lang/Math"));
117 base::Time start_lazy
= base::Time::Now();
119 for (int i
= 0; i
< 1024; ++i
)
120 o
+= LazyMethodIDCall(env
, clazz
.obj(), i
);
121 base::Time end_lazy
= base::Time::Now();
123 jmethodID id
= reinterpret_cast<jmethodID
>(g_atomic_id
);
124 base::Time start
= base::Time::Now();
125 for (int i
= 0; i
< 1024; ++i
)
126 o
+= MethodIDCall(env
, clazz
.obj(), id
, i
);
127 base::Time end
= base::Time::Now();
129 // On a Galaxy Nexus, results were in the range of:
130 // JNI LazyMethodIDCall (us) 1984
131 // JNI MethodIDCall (us) 1861
132 LOG(ERROR
) << "JNI LazyMethodIDCall (us) " <<
133 base::TimeDelta(end_lazy
- start_lazy
).InMicroseconds();
134 LOG(ERROR
) << "JNI MethodIDCall (us) " <<
135 base::TimeDelta(end
- start
).InMicroseconds();
136 LOG(ERROR
) << "JNI " << o
;
140 } // namespace android