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