blob: 7dd26f49aeda79775e557d139161b7452e6793d7 [file] [log] [blame]
// 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()