| /* |
| * 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 |