xref: /aosp_15_r20/external/fbjni/cxx/fbjni/detail/References.cpp (revision 65c59e023c5336bbd4a23be7af78407e3d80e7e7)
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