1 /*
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "References.h"
18
19 namespace facebook {
20 namespace jni {
21
JniLocalScope(JNIEnv * env,jint capacity)22 JniLocalScope::JniLocalScope(JNIEnv* env, jint capacity) : env_(env) {
23 hasFrame_ = false;
24 auto pushResult = env->PushLocalFrame(capacity);
25 FACEBOOK_JNI_THROW_EXCEPTION_IF(pushResult < 0);
26 hasFrame_ = true;
27 }
28
~JniLocalScope()29 JniLocalScope::~JniLocalScope() {
30 if (hasFrame_) {
31 env_->PopLocalFrame(nullptr);
32 }
33 }
34
35 namespace {
36
37 #ifdef __ANDROID__
38
getAndroidApiLevel()39 int32_t getAndroidApiLevel() {
40 // This is called from the static local initializer in
41 // isObjectRefType(), and creating fbjni references can call
42 // isObjectRefType(). So, to avoid recursively entering the block
43 // where the static is initialized (which is undefined behavior), we
44 // avoid using standard fbjni references here.
45
46 JNIEnv* env = Environment::current();
47 jclass cls = detail::findClass(env, "android/os/Build$VERSION");
48 jfieldID field = env->GetStaticFieldID(
49 cls, "SDK_INT", jtype_traits<jint>::kDescriptor.c_str());
50 if (!field) {
51 env->DeleteLocalRef(cls);
52 }
53 FACEBOOK_JNI_THROW_EXCEPTION_IF(!field);
54 int32_t ret = env->GetStaticIntField(cls, field);
55 env->DeleteLocalRef(cls);
56 return ret;
57 }
58
doesGetObjectRefTypeWork()59 bool doesGetObjectRefTypeWork() {
60 auto level = getAndroidApiLevel();
61 return level >= 14;
62 }
63
64 #else
65
66 bool doesGetObjectRefTypeWork() {
67 auto jni_version = Environment::current()->GetVersion();
68 return jni_version >= JNI_VERSION_1_6;
69 }
70
71 #endif
72
73 } // namespace
74
isObjectRefType(jobject reference,jobjectRefType refType)75 bool isObjectRefType(jobject reference, jobjectRefType refType) {
76 // null-check first so that we short-circuit during (safe) global
77 // constructors, where we won't have an Environment::current() yet
78 if (!reference) {
79 return true;
80 }
81
82 static bool getObjectRefTypeWorks = doesGetObjectRefTypeWork();
83
84 return !getObjectRefTypeWorks ||
85 Environment::current()->GetObjectRefType(reference) == refType;
86 }
87
88 } // namespace jni
89 } // namespace facebook
90