xref: /aosp_15_r20/libnativehelper/header_only_include/nativehelper/utils.h (revision 0797b24ee566c78eb48500180cb4bf71f81c8aab)
1*0797b24eSAndroid Build Coastguard Worker /*
2*0797b24eSAndroid Build Coastguard Worker  * Copyright (C) 2023 The Android Open Source Project
3*0797b24eSAndroid Build Coastguard Worker  *
4*0797b24eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*0797b24eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*0797b24eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*0797b24eSAndroid Build Coastguard Worker  *
8*0797b24eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*0797b24eSAndroid Build Coastguard Worker  *
10*0797b24eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*0797b24eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*0797b24eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*0797b24eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*0797b24eSAndroid Build Coastguard Worker  * limitations under the License.
15*0797b24eSAndroid Build Coastguard Worker  */
16*0797b24eSAndroid Build Coastguard Worker 
17*0797b24eSAndroid Build Coastguard Worker /**
18*0797b24eSAndroid Build Coastguard Worker  * JNI utils for external use.
19*0797b24eSAndroid Build Coastguard Worker  *
20*0797b24eSAndroid Build Coastguard Worker  * This file may only be included by C++ code.
21*0797b24eSAndroid Build Coastguard Worker  */
22*0797b24eSAndroid Build Coastguard Worker 
23*0797b24eSAndroid Build Coastguard Worker #pragma once
24*0797b24eSAndroid Build Coastguard Worker 
25*0797b24eSAndroid Build Coastguard Worker #include <jni.h>
26*0797b24eSAndroid Build Coastguard Worker 
27*0797b24eSAndroid Build Coastguard Worker #include <string>
28*0797b24eSAndroid Build Coastguard Worker 
29*0797b24eSAndroid Build Coastguard Worker #include "nativehelper/scoped_local_ref.h"
30*0797b24eSAndroid Build Coastguard Worker #include "nativehelper/scoped_utf_chars.h"
31*0797b24eSAndroid Build Coastguard Worker 
32*0797b24eSAndroid Build Coastguard Worker namespace android {
33*0797b24eSAndroid Build Coastguard Worker namespace jnihelp {
34*0797b24eSAndroid Build Coastguard Worker 
35*0797b24eSAndroid Build Coastguard Worker // Implementation details. DO NOT use directly.
36*0797b24eSAndroid Build Coastguard Worker namespace internal {
37*0797b24eSAndroid Build Coastguard Worker 
GetCStr(const char * str)38*0797b24eSAndroid Build Coastguard Worker [[maybe_unused]] static const char* GetCStr(const char* str) { return str; }
GetCStr(const std::string & str)39*0797b24eSAndroid Build Coastguard Worker [[maybe_unused]] static const char* GetCStr(const std::string& str) { return str.c_str(); }
40*0797b24eSAndroid Build Coastguard Worker 
41*0797b24eSAndroid Build Coastguard Worker }  // namespace internal
42*0797b24eSAndroid Build Coastguard Worker 
43*0797b24eSAndroid Build Coastguard Worker // A class that implicitly casts to the default values of various JNI types.
44*0797b24eSAndroid Build Coastguard Worker // Used for returning from a JNI method when an exception occurs, where we don't care about the
45*0797b24eSAndroid Build Coastguard Worker // return value.
46*0797b24eSAndroid Build Coastguard Worker class JniDefaultValue {
47*0797b24eSAndroid Build Coastguard Worker    public:
jboolean()48*0797b24eSAndroid Build Coastguard Worker     operator jboolean() const { return JNI_FALSE; }
jbyte()49*0797b24eSAndroid Build Coastguard Worker     operator jbyte() const { return 0; }
jchar()50*0797b24eSAndroid Build Coastguard Worker     operator jchar() const { return 0; }
jshort()51*0797b24eSAndroid Build Coastguard Worker     operator jshort() const { return 0; }
jint()52*0797b24eSAndroid Build Coastguard Worker     operator jint() const { return 0; }
jlong()53*0797b24eSAndroid Build Coastguard Worker     operator jlong() const { return 0; }
jfloat()54*0797b24eSAndroid Build Coastguard Worker     operator jfloat() const { return 0; }
jdouble()55*0797b24eSAndroid Build Coastguard Worker     operator jdouble() const { return 0; }
jobject()56*0797b24eSAndroid Build Coastguard Worker     operator jobject() const { return nullptr; }
jclass()57*0797b24eSAndroid Build Coastguard Worker     operator jclass() const { return nullptr; }
jstring()58*0797b24eSAndroid Build Coastguard Worker     operator jstring() const { return nullptr; }
jarray()59*0797b24eSAndroid Build Coastguard Worker     operator jarray() const { return nullptr; }
jobjectArray()60*0797b24eSAndroid Build Coastguard Worker     operator jobjectArray() const { return nullptr; }
jbooleanArray()61*0797b24eSAndroid Build Coastguard Worker     operator jbooleanArray() const { return nullptr; }
jbyteArray()62*0797b24eSAndroid Build Coastguard Worker     operator jbyteArray() const { return nullptr; }
jcharArray()63*0797b24eSAndroid Build Coastguard Worker     operator jcharArray() const { return nullptr; }
jshortArray()64*0797b24eSAndroid Build Coastguard Worker     operator jshortArray() const { return nullptr; }
jintArray()65*0797b24eSAndroid Build Coastguard Worker     operator jintArray() const { return nullptr; }
jlongArray()66*0797b24eSAndroid Build Coastguard Worker     operator jlongArray() const { return nullptr; }
jfloatArray()67*0797b24eSAndroid Build Coastguard Worker     operator jfloatArray() const { return nullptr; }
jdoubleArray()68*0797b24eSAndroid Build Coastguard Worker     operator jdoubleArray() const { return nullptr; }
jthrowable()69*0797b24eSAndroid Build Coastguard Worker     operator jthrowable() const { return nullptr; }
70*0797b24eSAndroid Build Coastguard Worker };
71*0797b24eSAndroid Build Coastguard Worker 
72*0797b24eSAndroid Build Coastguard Worker // Gets `ScopedUtfChars` from a `jstring` expression.
73*0797b24eSAndroid Build Coastguard Worker //
74*0797b24eSAndroid Build Coastguard Worker // Throws `NullPointerException` and returns the default value if the given `jstring` is a null
75*0797b24eSAndroid Build Coastguard Worker // pointer.
76*0797b24eSAndroid Build Coastguard Worker //
77*0797b24eSAndroid Build Coastguard Worker // Examples:
78*0797b24eSAndroid Build Coastguard Worker //
79*0797b24eSAndroid Build Coastguard Worker // - If the function returns a value:
80*0797b24eSAndroid Build Coastguard Worker //
81*0797b24eSAndroid Build Coastguard Worker // jobject MyJniMethod(JNIEnv* env, jstring j_str) {
82*0797b24eSAndroid Build Coastguard Worker //   ScopedUtfChars str = GET_UTF_OR_RETURN(env, j_str);
83*0797b24eSAndroid Build Coastguard Worker //   // Safely use `str` here...
84*0797b24eSAndroid Build Coastguard Worker // }
85*0797b24eSAndroid Build Coastguard Worker //
86*0797b24eSAndroid Build Coastguard Worker // - If the function returns void:
87*0797b24eSAndroid Build Coastguard Worker //
88*0797b24eSAndroid Build Coastguard Worker // void MyJniMethod(JNIEnv* env, jstring j_str) {
89*0797b24eSAndroid Build Coastguard Worker //   ScopedUtfChars str = GET_UTF_OR_RETURN_VOID(env, j_str);
90*0797b24eSAndroid Build Coastguard Worker //   // Safely use `str` here...
91*0797b24eSAndroid Build Coastguard Worker // }
92*0797b24eSAndroid Build Coastguard Worker //
93*0797b24eSAndroid Build Coastguard Worker // The idiomatic way to construct an `std::string` using this macro (an additional string copy is
94*0797b24eSAndroid Build Coastguard Worker // performed):
95*0797b24eSAndroid Build Coastguard Worker //
96*0797b24eSAndroid Build Coastguard Worker // jobject MyJniMethod(JNIEnv* env, jstring j_str) {
97*0797b24eSAndroid Build Coastguard Worker //   std::string str(GET_UTF_OR_RETURN(env, j_str));
98*0797b24eSAndroid Build Coastguard Worker //   // Safely use `str` here...
99*0797b24eSAndroid Build Coastguard Worker // }
100*0797b24eSAndroid Build Coastguard Worker #define GET_UTF_OR_RETURN(env, expr) \
101*0797b24eSAndroid Build Coastguard Worker     GET_UTF_OR_RETURN_IMPL_((env), (expr), android::jnihelp::JniDefaultValue())
102*0797b24eSAndroid Build Coastguard Worker #define GET_UTF_OR_RETURN_VOID(env, expr) GET_UTF_OR_RETURN_IMPL_((env), (expr))
103*0797b24eSAndroid Build Coastguard Worker 
104*0797b24eSAndroid Build Coastguard Worker #define GET_UTF_OR_RETURN_IMPL_(env, expr, ...)                          \
105*0797b24eSAndroid Build Coastguard Worker     ({                                                                   \
106*0797b24eSAndroid Build Coastguard Worker         ScopedUtfChars __or_return_scoped_utf_chars(env, expr);          \
107*0797b24eSAndroid Build Coastguard Worker         if (__or_return_scoped_utf_chars.c_str() == nullptr) {           \
108*0797b24eSAndroid Build Coastguard Worker             /* Return with a pending exception from `ScopedUtfChars`. */ \
109*0797b24eSAndroid Build Coastguard Worker             return __VA_ARGS__;                                          \
110*0797b24eSAndroid Build Coastguard Worker         }                                                                \
111*0797b24eSAndroid Build Coastguard Worker         std::move(__or_return_scoped_utf_chars);                         \
112*0797b24eSAndroid Build Coastguard Worker     })
113*0797b24eSAndroid Build Coastguard Worker 
114*0797b24eSAndroid Build Coastguard Worker // Creates `ScopedLocalRef<jstring>` from a `const char*` or `std::string` expression using
115*0797b24eSAndroid Build Coastguard Worker // NewStringUTF.
116*0797b24eSAndroid Build Coastguard Worker //
117*0797b24eSAndroid Build Coastguard Worker // Throws `OutOfMemoryError` and returns the default value if the system runs out of memory.
118*0797b24eSAndroid Build Coastguard Worker //
119*0797b24eSAndroid Build Coastguard Worker // Examples:
120*0797b24eSAndroid Build Coastguard Worker //
121*0797b24eSAndroid Build Coastguard Worker // - If the function returns a value:
122*0797b24eSAndroid Build Coastguard Worker //
123*0797b24eSAndroid Build Coastguard Worker // jobject MyJniMethod(JNIEnv* env) {
124*0797b24eSAndroid Build Coastguard Worker //   std::string str = "foo";
125*0797b24eSAndroid Build Coastguard Worker //   ScopedLocalRef<jstring> j_str = CREATE_UTF_OR_RETURN(env, str);
126*0797b24eSAndroid Build Coastguard Worker //   // Safely use `j_str` here...
127*0797b24eSAndroid Build Coastguard Worker // }
128*0797b24eSAndroid Build Coastguard Worker //
129*0797b24eSAndroid Build Coastguard Worker // - If the function returns void:
130*0797b24eSAndroid Build Coastguard Worker //
131*0797b24eSAndroid Build Coastguard Worker // void MyJniMethod(JNIEnv* env) {
132*0797b24eSAndroid Build Coastguard Worker //   std::string str = "foo";
133*0797b24eSAndroid Build Coastguard Worker //   ScopedLocalRef<jstring> j_str = CREATE_UTF_OR_RETURN_VOID(env, str);
134*0797b24eSAndroid Build Coastguard Worker //   // Safely use `j_str` here...
135*0797b24eSAndroid Build Coastguard Worker // }
136*0797b24eSAndroid Build Coastguard Worker #define CREATE_UTF_OR_RETURN(env, expr) \
137*0797b24eSAndroid Build Coastguard Worker     CREATE_UTF_OR_RETURN_IMPL_((env), (expr), android::jnihelp::JniDefaultValue())
138*0797b24eSAndroid Build Coastguard Worker #define CREATE_UTF_OR_RETURN_VOID(env, expr) CREATE_UTF_OR_RETURN_IMPL_((env), (expr))
139*0797b24eSAndroid Build Coastguard Worker 
140*0797b24eSAndroid Build Coastguard Worker #define CREATE_UTF_OR_RETURN_IMPL_(env, expr, ...)                                             \
141*0797b24eSAndroid Build Coastguard Worker     ({                                                                                         \
142*0797b24eSAndroid Build Coastguard Worker         const char* __or_return_c_str;                                                         \
143*0797b24eSAndroid Build Coastguard Worker         ScopedLocalRef<jstring> __or_return_local_ref(                                         \
144*0797b24eSAndroid Build Coastguard Worker             env,                                                                               \
145*0797b24eSAndroid Build Coastguard Worker             env->NewStringUTF(__or_return_c_str = android::jnihelp::internal::GetCStr(expr))); \
146*0797b24eSAndroid Build Coastguard Worker         /* `*__or_return_c_str` may be freed here, but we only compare the pointer against     \
147*0797b24eSAndroid Build Coastguard Worker          * nullptr. DO NOT DEREFERENCE `*__or_return_c_str` after this point. */               \
148*0797b24eSAndroid Build Coastguard Worker         /* `NewStringUTF` returns nullptr when OOM or the input is nullptr, but only throws an \
149*0797b24eSAndroid Build Coastguard Worker          * exception when OOM. */                                                              \
150*0797b24eSAndroid Build Coastguard Worker         if (__or_return_local_ref == nullptr && __or_return_c_str != nullptr) {                \
151*0797b24eSAndroid Build Coastguard Worker             /* Return with a pending exception from `NewStringUTF`. */                         \
152*0797b24eSAndroid Build Coastguard Worker             return __VA_ARGS__;                                                                \
153*0797b24eSAndroid Build Coastguard Worker         }                                                                                      \
154*0797b24eSAndroid Build Coastguard Worker         std::move(__or_return_local_ref);                                                      \
155*0797b24eSAndroid Build Coastguard Worker     })
156*0797b24eSAndroid Build Coastguard Worker 
157*0797b24eSAndroid Build Coastguard Worker }  // namespace jnihelp
158*0797b24eSAndroid Build Coastguard Worker }  // namespace android
159