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