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