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