| // Copyright 2025 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/android/jni_callback.h" |
| |
| // Must come after all headers that specialize FromJniType() / ToJniType(). |
| #include "base/base_minimal_jni/JniCallbackImpl_jni.h" |
| |
| namespace base::android { |
| |
| namespace { |
| class JniOnceCallback { |
| public: |
| explicit JniOnceCallback(JniOnceWrappedCallbackType&& on_complete) |
| : wrapped_callback_(std::make_unique<JniOnceWrappedCallbackType>( |
| std::move(on_complete))) {} |
| ~JniOnceCallback() = default; |
| |
| JniOnceCallback(const JniOnceCallback&) = delete; |
| const JniOnceCallback& operator=(const JniOnceCallback&) = delete; |
| |
| jni_zero::ScopedJavaLocalRef<jobject> TransferToJava(JNIEnv* env) && { |
| CHECK(wrapped_callback_); |
| CHECK(!wrapped_callback_->is_null()); |
| bool is_repeating = false; |
| return Java_JniCallbackImpl_Constructor( |
| env, is_repeating, |
| reinterpret_cast<jlong>(wrapped_callback_.release())); |
| } |
| |
| private: |
| std::unique_ptr<JniOnceWrappedCallbackType> wrapped_callback_; |
| }; |
| |
| class JniRepeatingCallback { |
| public: |
| explicit JniRepeatingCallback( |
| const JniRepeatingWrappedCallbackType& on_complete) |
| : wrapped_callback_( |
| std::make_unique<JniRepeatingWrappedCallbackType>(on_complete)) {} |
| explicit JniRepeatingCallback(JniRepeatingWrappedCallbackType&& on_complete) |
| : wrapped_callback_(std::make_unique<JniRepeatingWrappedCallbackType>( |
| std::move(on_complete))) {} |
| ~JniRepeatingCallback() = default; |
| |
| jni_zero::ScopedJavaLocalRef<jobject> TransferToJava(JNIEnv* env) && { |
| CHECK(wrapped_callback_); |
| CHECK(!wrapped_callback_->is_null()); |
| bool is_repeating = true; |
| return Java_JniCallbackImpl_Constructor( |
| env, is_repeating, |
| reinterpret_cast<jlong>(wrapped_callback_.release())); |
| } |
| JniRepeatingCallback(const JniRepeatingCallback&) = delete; |
| const JniRepeatingCallback& operator=(const JniRepeatingCallback&) = delete; |
| |
| private: |
| std::unique_ptr<JniRepeatingWrappedCallbackType> wrapped_callback_; |
| }; |
| } // namespace |
| |
| ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| JniOnceWrappedCallbackType&& callback) { |
| return JniOnceCallback(std::move(callback)).TransferToJava(env); |
| } |
| |
| ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| JniRepeatingWrappedCallbackType&& callback) { |
| return JniRepeatingCallback(std::move(callback)).TransferToJava(env); |
| } |
| |
| ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| const JniRepeatingWrappedCallbackType& callback) { |
| return JniRepeatingCallback(callback).TransferToJava(env); |
| } |
| |
| ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| base::OnceCallback<void()>&& callback) { |
| return ToJniCallback(env, base::BindOnce( |
| [](base::OnceCallback<void()> captured_callback, |
| const jni_zero::JavaRef<jobject>& j_null) { |
| // For callbacks with no parameters, the |
| // parameter from Java should be null. |
| CHECK(!j_null); |
| std::move(captured_callback).Run(); |
| }, |
| std::move(callback))); |
| } |
| |
| ScopedJavaLocalRef<jobject> ToJniCallback( |
| JNIEnv* env, |
| const base::RepeatingCallback<void()>& callback) { |
| return ToJniCallback( |
| env, base::BindRepeating( |
| [](const base::RepeatingCallback<void()>& captured_callback, |
| const jni_zero::JavaRef<jobject>& j_null) { |
| // For callbacks with no parameters, the parameter from Java |
| // should be null. |
| CHECK(!j_null); |
| captured_callback.Run(); |
| }, |
| std::move(callback))); |
| } |
| |
| void JNI_JniCallbackImpl_OnResult( |
| JNIEnv* env, |
| jboolean isRepeating, |
| jlong callbackPtr, |
| const jni_zero::JavaParamRef<jobject>& j_result) { |
| if (isRepeating) { |
| auto* callback = |
| reinterpret_cast<JniRepeatingWrappedCallbackType*>(callbackPtr); |
| callback->Run(j_result); |
| } else { |
| auto* callback = reinterpret_cast<JniOnceWrappedCallbackType*>(callbackPtr); |
| std::move(*callback).Run(j_result); |
| delete callback; |
| } |
| } |
| |
| void JNI_JniCallbackImpl_Destroy(JNIEnv* env, |
| jboolean isRepeating, |
| jlong callbackPtr) { |
| if (isRepeating) { |
| auto* callback = |
| reinterpret_cast<JniRepeatingWrappedCallbackType*>(callbackPtr); |
| // Call Reset to ensure all accidental use-after-frees fail loudly. |
| callback->Reset(); |
| delete callback; |
| } else { |
| auto* callback = reinterpret_cast<JniOnceWrappedCallbackType*>(callbackPtr); |
| // Call Reset to ensure all accidental use-after-frees fail loudly. |
| callback->Reset(); |
| delete callback; |
| } |
| } |
| |
| } // namespace base::android |
| |
| DEFINE_JNI_FOR_JniCallbackImpl() |