blob: 12f591bb968b74b1f5d427c54578a49ecb859565 [file] [log] [blame]
/*
* 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