blob: b01c060d16dd0e08ca972d77a085969a469bb919 [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* get_c_str(const char* str) { return str; }
[[maybe_unused]] static const char* get_c_str(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...
// }
#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 tmp_scoped_utf_chars_(env, expr); \
if (tmp_scoped_utf_chars_.c_str() == nullptr) { \
/* Return with a pending exception from `ScopedUtfChars`. */ \
return __VA_ARGS__; \
} \
std::move(tmp_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* tmp_c_str_ = android::jnihelp::internal::get_c_str(expr); \
ScopedLocalRef<jstring> tmp_local_ref_(env, env->NewStringUTF(tmp_c_str_)); \
/* `NewStringUTF` returns nullptr when OOM or the input is nullptr, but only throws an \
* exception when OOM. */ \
if (tmp_local_ref_ == nullptr && tmp_c_str_ != nullptr) { \
/* Return with a pending exception from `NewStringUTF`. */ \
return __VA_ARGS__; \
} \
std::move(tmp_local_ref_); \
})
} // namespace jnihelp
} // namespace android