/* * 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 #include #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` 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 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 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 __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