aboutsummaryrefslogtreecommitdiff
path: root/header_only_include/nativehelper/utils.h
diff options
context:
space:
mode:
Diffstat (limited to 'header_only_include/nativehelper/utils.h')
-rw-r--r--header_only_include/nativehelper/utils.h154
1 files changed, 154 insertions, 0 deletions
diff --git a/header_only_include/nativehelper/utils.h b/header_only_include/nativehelper/utils.h
new file mode 100644
index 0000000..30f239e
--- /dev/null
+++ b/header_only_include/nativehelper/utils.h
@@ -0,0 +1,154 @@
+/*
+ * 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...
+// }
+//
+// 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 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