• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
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 /**
18  * JNI utils for external use.
19  *
20  * This file may only be included by C++ code.
21  */
22 
23 #ifndef SRC_ANDROID_SDK_NATIVEHELPER_UTILS_H_
24 #define SRC_ANDROID_SDK_NATIVEHELPER_UTILS_H_
25 
26 // Copied from
27 // https://cs.android.com/android/platform/superproject/main/+/main:libnativehelper/header_only_include/nativehelper/utils.h;drc=4be05051ef76b2c24d8385732a892401eb45d911
28 
29 #include <jni.h>
30 
31 #include <string>
32 
33 #include "src/android_sdk/nativehelper/scoped_local_ref.h"
34 #include "src/android_sdk/nativehelper/scoped_utf_chars.h"
35 
36 namespace android {
37 namespace jnihelp {
38 
39 // Implementation details. DO NOT use directly.
40 namespace internal {
41 
GetCStr(const char * str)42 [[maybe_unused]] static const char* GetCStr(const char* str) {
43   return str;
44 }
GetCStr(const std::string & str)45 [[maybe_unused]] static const char* GetCStr(const std::string& str) {
46   return str.c_str();
47 }
48 
49 }  // namespace internal
50 
51 // A class that implicitly casts to the default values of various JNI types.
52 // Used for returning from a JNI method when an exception occurs, where we don't
53 // care about the return value.
54 class JniDefaultValue {
55  public:
jboolean()56   operator jboolean() const { return JNI_FALSE; }
jbyte()57   operator jbyte() const { return 0; }
jchar()58   operator jchar() const { return 0; }
jshort()59   operator jshort() const { return 0; }
jint()60   operator jint() const { return 0; }
jlong()61   operator jlong() const { return 0; }
jfloat()62   operator jfloat() const { return 0; }
jdouble()63   operator jdouble() const { return 0; }
jobject()64   operator jobject() const { return nullptr; }
jclass()65   operator jclass() const { return nullptr; }
jstring()66   operator jstring() const { return nullptr; }
jarray()67   operator jarray() const { return nullptr; }
jobjectArray()68   operator jobjectArray() const { return nullptr; }
jbooleanArray()69   operator jbooleanArray() const { return nullptr; }
jbyteArray()70   operator jbyteArray() const { return nullptr; }
jcharArray()71   operator jcharArray() const { return nullptr; }
jshortArray()72   operator jshortArray() const { return nullptr; }
jintArray()73   operator jintArray() const { return nullptr; }
jlongArray()74   operator jlongArray() const { return nullptr; }
jfloatArray()75   operator jfloatArray() const { return nullptr; }
jdoubleArray()76   operator jdoubleArray() const { return nullptr; }
jthrowable()77   operator jthrowable() const { return nullptr; }
78 };
79 
80 // Gets `ScopedUtfChars` from a `jstring` expression.
81 //
82 // Throws `NullPointerException` and returns the default value if the given
83 // `jstring` is a null pointer.
84 //
85 // Examples:
86 //
87 // - If the function returns a value:
88 //
89 // jobject MyJniMethod(JNIEnv* env, jstring j_str) {
90 //   ScopedUtfChars str = GET_UTF_OR_RETURN(env, j_str);
91 //   // Safely use `str` here...
92 // }
93 //
94 // - If the function returns void:
95 //
96 // void MyJniMethod(JNIEnv* env, jstring j_str) {
97 //   ScopedUtfChars str = GET_UTF_OR_RETURN_VOID(env, j_str);
98 //   // Safely use `str` here...
99 // }
100 //
101 // The idiomatic way to construct an `std::string` using this macro (an
102 // additional string copy is performed):
103 //
104 // jobject MyJniMethod(JNIEnv* env, jstring j_str) {
105 //   std::string str(GET_UTF_OR_RETURN(env, j_str));
106 //   // Safely use `str` here...
107 // }
108 #define GET_UTF_OR_RETURN(env, expr) \
109   GET_UTF_OR_RETURN_IMPL_((env), (expr), android::jnihelp::JniDefaultValue())
110 #define GET_UTF_OR_RETURN_VOID(env, expr) GET_UTF_OR_RETURN_IMPL_((env), (expr))
111 
112 #define GET_UTF_OR_RETURN_IMPL_(env, expr, ...)                    \
113   ({                                                               \
114     ScopedUtfChars __or_return_scoped_utf_chars(env, expr);        \
115     if (__or_return_scoped_utf_chars.c_str() == nullptr) {         \
116       /* Return with a pending exception from `ScopedUtfChars`. */ \
117       return __VA_ARGS__;                                          \
118     }                                                              \
119     std::move(__or_return_scoped_utf_chars);                       \
120   })
121 
122 // Creates `ScopedLocalRef<jstring>` from a `const char*` or `std::string`
123 // expression using NewStringUTF.
124 //
125 // Throws `OutOfMemoryError` and returns the default value if the system runs
126 // out of memory.
127 //
128 // Examples:
129 //
130 // - If the function returns a value:
131 //
132 // jobject MyJniMethod(JNIEnv* env) {
133 //   std::string str = "foo";
134 //   ScopedLocalRef<jstring> j_str = CREATE_UTF_OR_RETURN(env, str);
135 //   // Safely use `j_str` here...
136 // }
137 //
138 // - If the function returns void:
139 //
140 // void MyJniMethod(JNIEnv* env) {
141 //   std::string str = "foo";
142 //   ScopedLocalRef<jstring> j_str = CREATE_UTF_OR_RETURN_VOID(env, str);
143 //   // Safely use `j_str` here...
144 // }
145 #define CREATE_UTF_OR_RETURN(env, expr) \
146   CREATE_UTF_OR_RETURN_IMPL_((env), (expr), android::jnihelp::JniDefaultValue())
147 #define CREATE_UTF_OR_RETURN_VOID(env, expr) \
148   CREATE_UTF_OR_RETURN_IMPL_((env), (expr))
149 
150 #define CREATE_UTF_OR_RETURN_IMPL_(env, expr, ...)                             \
151   ({                                                                           \
152     const char* __or_return_c_str;                                             \
153     ScopedLocalRef<jstring> __or_return_local_ref(                             \
154         env,                                                                   \
155         env->NewStringUTF(__or_return_c_str =                                  \
156                               android::jnihelp::internal::GetCStr(expr)));     \
157     /* `*__or_return_c_str` may be freed here, but we only compare the pointer \
158      * against nullptr. DO NOT DEREFERENCE `*__or_return_c_str` after this     \
159      * point. */                                                               \
160     /* `NewStringUTF` returns nullptr when OOM or the input is nullptr, but    \
161      * only throws an exception when OOM. */                                   \
162     if (__or_return_local_ref == nullptr && __or_return_c_str != nullptr) {    \
163       /* Return with a pending exception from `NewStringUTF`. */               \
164       return __VA_ARGS__;                                                      \
165     }                                                                          \
166     std::move(__or_return_local_ref);                                          \
167   })
168 
169 }  // namespace jnihelp
170 }  // namespace android
171 
172 #endif  // SRC_ANDROID_SDK_NATIVEHELPER_UTILS_H_
173