Migrate webrtc to stop using its own JniZero mirror classes

Bug: chromium:325408567
Change-Id: I2eb33b077148bf89223f1f69b07339fc9f2d948e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/347921
Reviewed-by: Jeremy Leconte <jleconte@google.com>
Commit-Queue: Jeremy Leconte <jleconte@google.com>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#42151}
This commit is contained in:
Mohamed 2024-04-18 22:43:45 +00:00 committed by WebRTC LUCI CQ
parent 454d65196e
commit bc5c5e9d66
21 changed files with 75 additions and 492 deletions

View file

@ -185,7 +185,8 @@ void AndroidVoipClient::GetSupportedCodecs(JNIEnv* env) {
webrtc::ScopedJavaLocalRef<jstring> (*convert_function)(
JNIEnv*, const std::string&) = &webrtc::NativeToJavaString;
Java_VoipClient_onGetSupportedCodecsCompleted(
env_, j_voip_client_, NativeToJavaList(env_, names, convert_function));
env_, j_voip_client_,
webrtc::NativeToJavaList(env_, names, convert_function));
}
void AndroidVoipClient::GetLocalIPAddress(JNIEnv* env) {

View file

@ -141,6 +141,7 @@ if (is_android) {
":video_egl_jni",
"../../pc:libjingle_peerconnection",
"../../rtc_base:ssl",
"//third_party/jni_zero",
]
output_extension = "so"
}
@ -936,7 +937,6 @@ if (current_os == "linux" || is_android) {
"native_api/jni/class_loader.cc",
"native_api/jni/java_types.cc",
"native_api/jni/jvm.cc",
"src/jni/jni_generator_helper.cc",
"src/jni/jni_generator_helper.h",
]
@ -956,6 +956,7 @@ if (current_os == "linux" || is_android) {
"../../api:sequence_checker",
"//api:array_view",
"//rtc_base:checks",
"//third_party/jni_zero",
]
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
}
@ -1116,7 +1117,10 @@ if (current_os == "linux" || is_android) {
"src/jni/jvm.h",
]
deps = [ "../../rtc_base:checks" ]
deps = [
"../../rtc_base:checks",
"//third_party/jni_zero",
]
}
rtc_library("videoframe_jni") {

View file

@ -23,7 +23,7 @@ JNI_FUNCTION_DECLARATION(void,
jclass,
jstring j_message) {
std::string message =
JavaToNativeString(jni, JavaParamRef<jstring>(j_message));
JavaToNativeString(jni, JavaParamRef<jstring>(jni, j_message));
RTC_LOG(LS_INFO) << message;
}

View file

@ -21,7 +21,7 @@ JNI_FUNCTION_DECLARATION(jint,
JNIEnv* jni,
jclass,
jobject video_frame_buffer) {
const JavaParamRef<jobject> j_video_frame_buffer(video_frame_buffer);
const JavaParamRef<jobject> j_video_frame_buffer(jni, video_frame_buffer);
rtc::scoped_refptr<VideoFrameBuffer> buffer =
JavaToNativeFrameBuffer(jni, j_video_frame_buffer);
return static_cast<jint>(buffer->type());
@ -32,7 +32,7 @@ JNI_FUNCTION_DECLARATION(jobject,
JNIEnv* jni,
jclass,
jobject i420_buffer) {
const JavaParamRef<jobject> j_i420_buffer(i420_buffer);
const JavaParamRef<jobject> j_i420_buffer(jni, i420_buffer);
rtc::scoped_refptr<VideoFrameBuffer> buffer =
JavaToNativeFrameBuffer(jni, j_i420_buffer);
const I420BufferInterface* inputBuffer = buffer->GetI420();

View file

@ -2,4 +2,5 @@ include_rules = [
"+modules/audio_device/include/audio_device.h",
"+modules/utility/include/jvm_android.h",
"+system_wrappers/include",
"+third_party/jni_zero",
]

View file

@ -40,7 +40,7 @@ void GetDefaultAudioParameters(JNIEnv* env,
jobject application_context,
AudioParameters* input_parameters,
AudioParameters* output_parameters) {
const JavaParamRef<jobject> j_context(application_context);
const JavaParamRef<jobject> j_context(env, application_context);
const ScopedJavaLocalRef<jobject> j_audio_manager =
jni::GetAudioManager(env, j_context);
const int input_sample_rate = jni::GetDefaultSampleRate(env, j_audio_manager);
@ -78,7 +78,7 @@ CreateJavaInputAndAAudioOutputAudioDeviceModule(JNIEnv* env,
jobject application_context) {
RTC_DLOG(LS_INFO) << __FUNCTION__;
// Get default audio input/output parameters.
const JavaParamRef<jobject> j_context(application_context);
const JavaParamRef<jobject> j_context(env, application_context);
const ScopedJavaLocalRef<jobject> j_audio_manager =
jni::GetAudioManager(env, j_context);
AudioParameters input_parameters;
@ -104,7 +104,7 @@ rtc::scoped_refptr<AudioDeviceModule> CreateJavaAudioDeviceModule(
jobject application_context) {
RTC_DLOG(LS_INFO) << __FUNCTION__;
// Get default audio input/output parameters.
const JavaParamRef<jobject> j_context(application_context);
const JavaParamRef<jobject> j_context(env, application_context);
const ScopedJavaLocalRef<jobject> j_audio_manager =
jni::GetAudioManager(env, j_context);
AudioParameters input_parameters;
@ -155,7 +155,7 @@ CreateJavaInputAndOpenSLESOutputAudioDeviceModule(JNIEnv* env,
jobject application_context) {
RTC_DLOG(LS_INFO) << __FUNCTION__;
// Get default audio input/output parameters.
const JavaParamRef<jobject> j_context(application_context);
const JavaParamRef<jobject> j_context(env, application_context);
const ScopedJavaLocalRef<jobject> j_audio_manager =
jni::GetAudioManager(env, j_context);
AudioParameters input_parameters;

View file

@ -21,29 +21,29 @@
namespace webrtc {
SdpVideoFormat JavaToNativeVideoCodecInfo(JNIEnv* jni, jobject codec_info) {
return jni::VideoCodecInfoToSdpVideoFormat(jni,
JavaParamRef<jobject>(codec_info));
return jni::VideoCodecInfoToSdpVideoFormat(
jni, JavaParamRef<jobject>(jni, codec_info));
}
std::unique_ptr<VideoDecoderFactory> JavaToNativeVideoDecoderFactory(
JNIEnv* jni,
jobject decoder_factory) {
return std::make_unique<jni::VideoDecoderFactoryWrapper>(
jni, JavaParamRef<jobject>(decoder_factory));
jni, JavaParamRef<jobject>(jni, decoder_factory));
}
std::unique_ptr<VideoEncoderFactory> JavaToNativeVideoEncoderFactory(
JNIEnv* jni,
jobject encoder_factory) {
return std::make_unique<jni::VideoEncoderFactoryWrapper>(
jni, JavaParamRef<jobject>(encoder_factory));
jni, JavaParamRef<jobject>(jni, encoder_factory));
}
std::vector<VideoEncoder::ResolutionBitrateLimits>
JavaToNativeResolutionBitrateLimits(JNIEnv* jni,
const jobjectArray j_bitrate_limits_array) {
return jni::JavaToNativeResolutionBitrateLimits(
jni, JavaParamRef<jobjectArray>(j_bitrate_limits_array));
jni, JavaParamRef<jobjectArray>(jni, j_bitrate_limits_array));
}
} // namespace webrtc

View file

@ -16,7 +16,7 @@
#include "rtc_base/checks.h"
#include "sdk/android/generated_native_api_jni/WebRtcClassLoader_jni.h"
#include "sdk/android/native_api/jni/java_types.h"
#include "sdk/android/native_api/jni/scoped_java_ref.h"
#include "third_party/jni_zero/jni_zero.h"
// Abort the process if `jni` has a Java exception pending. This macros uses the
// comma operator to execute ExceptionDescribe and ExceptionClear ignoring their
@ -62,11 +62,18 @@ class ClassLoader {
static ClassLoader* g_class_loader = nullptr;
jclass GetClass(JNIEnv* env, const char* class_name, const char* unused) {
RTC_CHECK(g_class_loader);
return static_cast<jclass>(
g_class_loader->FindClass(env, class_name).Release());
}
} // namespace
void InitClassLoader(JNIEnv* env) {
RTC_CHECK(g_class_loader == nullptr);
g_class_loader = new ClassLoader(env);
jni_zero::SetClassResolver(&GetClass);
}
ScopedJavaLocalRef<jclass> GetClass(JNIEnv* env, const char* c_name) {

View file

@ -393,7 +393,7 @@ std::vector<std::string> JavaToStdVectorStrings(JNIEnv* jni,
if (!list.is_null()) {
for (const JavaRef<jobject>& str : Iterable(jni, list)) {
converted_list.push_back(JavaToStdString(
jni, JavaParamRef<jstring>(static_cast<jstring>(str.obj()))));
jni, JavaParamRef<jstring>(jni, static_cast<jstring>(str.obj()))));
}
}
return converted_list;

View file

@ -340,7 +340,7 @@ inline std::string JavaToStdString(JNIEnv* jni,
// Deprecated. Use scoped jobjects instead.
inline std::string JavaToStdString(JNIEnv* jni, jstring j_string) {
return JavaToStdString(jni, JavaParamRef<jstring>(j_string));
return JavaToStdString(jni, JavaParamRef<jstring>(jni, j_string));
}
// Deprecated. Use JavaListToNativeVector<std::string, jstring> instead.
@ -360,7 +360,7 @@ inline std::map<std::string, std::string> JavaToStdMapStrings(
// Deprecated. Use scoped jobjects instead.
inline std::map<std::string, std::string> JavaToStdMapStrings(JNIEnv* jni,
jobject j_map) {
return JavaToStdMapStrings(jni, JavaParamRef<jobject>(j_map));
return JavaToStdMapStrings(jni, JavaParamRef<jobject>(jni, j_map));
}
} // namespace webrtc

View file

@ -8,56 +8,10 @@
* be found in the AUTHORS file in the root of the source tree.
*/
// Originally this class is from Chromium.
// https://cs.chromium.org/chromium/src/base/android/jni_int_wrapper.h.
#ifndef SDK_ANDROID_NATIVE_API_JNI_JNI_INT_WRAPPER_H_
#define SDK_ANDROID_NATIVE_API_JNI_JNI_INT_WRAPPER_H_
#include <jni.h>
#include <cstdint>
// Wrapper used to receive int when calling Java from native. The wrapper
// disallows automatic conversion of anything besides int32_t to a jint.
// Checking is only done in debugging builds.
#ifdef NDEBUG
typedef jint JniIntWrapper;
// This inline is sufficiently trivial that it does not change the
// final code generated by g++.
inline jint as_jint(JniIntWrapper wrapper) {
return wrapper;
}
#else
class JniIntWrapper {
public:
JniIntWrapper() : i_(0) {}
JniIntWrapper(int32_t i) : i_(i) {} // NOLINT(runtime/explicit)
explicit JniIntWrapper(const JniIntWrapper& ji) : i_(ji.i_) {}
jint as_jint() const { return i_; }
// If you get an "invokes a deleted function" error at the lines below it is
// because you used an implicit conversion to convert e.g. a long to an
// int32_t when calling Java. We disallow this. If you want a lossy
// conversion, please use an explicit conversion in your C++ code.
JniIntWrapper(uint32_t) = delete; // NOLINT(runtime/explicit)
JniIntWrapper(uint64_t) = delete; // NOLINT(runtime/explicit)
JniIntWrapper(int64_t) = delete; // NOLINT(runtime/explicit)
private:
const jint i_;
};
inline jint as_jint(const JniIntWrapper& wrapper) {
return wrapper.as_jint();
}
#endif // NDEBUG
#include "third_party/jni_zero/jni_zero.h"
#endif // SDK_ANDROID_NATIVE_API_JNI_JNI_INT_WRAPPER_H_

View file

@ -19,200 +19,13 @@
#include <utility>
#include "sdk/android/native_api/jni/jvm.h"
#include "third_party/jni_zero/jni_zero.h"
namespace webrtc {
// Generic base class for ScopedJavaLocalRef and ScopedJavaGlobalRef. Useful
// for allowing functions to accept a reference without having to mandate
// whether it is a local or global type.
template <typename T>
class JavaRef;
// Template specialization of JavaRef, which acts as the base class for all
// other JavaRef<> template types. This allows you to e.g. pass JavaRef<jstring>
// into a function taking const JavaRef<jobject>&.
template <>
class JavaRef<jobject> {
public:
JavaRef(const JavaRef&) = delete;
JavaRef& operator=(const JavaRef&) = delete;
jobject obj() const { return obj_; }
bool is_null() const {
// This is not valid for weak references. For weak references you need to
// use env->IsSameObject(objc_, nullptr), but that should be avoided anyway
// since it does not prevent the object from being freed immediately
// thereafter. Consequently, programmers should not use this check on weak
// references anyway and should first make a ScopedJavaLocalRef or
// ScopedJavaGlobalRef before checking if it is null.
return obj_ == nullptr;
}
protected:
constexpr JavaRef() : obj_(nullptr) {}
explicit JavaRef(jobject obj) : obj_(obj) {}
jobject obj_;
};
template <typename T>
class JavaRef : public JavaRef<jobject> {
public:
JavaRef(const JavaRef&) = delete;
JavaRef& operator=(const JavaRef&) = delete;
T obj() const { return static_cast<T>(obj_); }
protected:
JavaRef() : JavaRef<jobject>(nullptr) {}
explicit JavaRef(T obj) : JavaRef<jobject>(obj) {}
};
// Holds a local reference to a JNI method parameter.
// Method parameters should not be deleted, and so this class exists purely to
// wrap them as a JavaRef<T> in the JNI binding generator. Do not create
// instances manually.
template <typename T>
class JavaParamRef : public JavaRef<T> {
public:
// Assumes that `obj` is a parameter passed to a JNI method from Java.
// Does not assume ownership as parameters should not be deleted.
explicit JavaParamRef(T obj) : JavaRef<T>(obj) {}
JavaParamRef(JNIEnv*, T obj) : JavaRef<T>(obj) {}
JavaParamRef(const JavaParamRef&) = delete;
JavaParamRef& operator=(const JavaParamRef&) = delete;
};
// Holds a local reference to a Java object. The local reference is scoped
// to the lifetime of this object.
// Instances of this class may hold onto any JNIEnv passed into it until
// destroyed. Therefore, since a JNIEnv is only suitable for use on a single
// thread, objects of this class must be created, used, and destroyed, on a
// single thread.
// Therefore, this class should only be used as a stack-based object and from a
// single thread. If you wish to have the reference outlive the current
// callstack (e.g. as a class member) or you wish to pass it across threads,
// use a ScopedJavaGlobalRef instead.
template <typename T>
class ScopedJavaLocalRef : public JavaRef<T> {
public:
ScopedJavaLocalRef() = default;
ScopedJavaLocalRef(std::nullptr_t) {} // NOLINT(runtime/explicit)
ScopedJavaLocalRef(JNIEnv* env, const JavaRef<T>& other) : env_(env) {
Reset(other.obj(), OwnershipPolicy::RETAIN);
}
// Allow constructing e.g. ScopedJavaLocalRef<jobject> from
// ScopedJavaLocalRef<jstring>.
template <typename G>
ScopedJavaLocalRef(ScopedJavaLocalRef<G>&& other) : env_(other.env()) {
Reset(other.Release(), OwnershipPolicy::ADOPT);
}
ScopedJavaLocalRef(const ScopedJavaLocalRef& other) : env_(other.env_) {
Reset(other.obj(), OwnershipPolicy::RETAIN);
}
// Assumes that `obj` is a reference to a Java object and takes
// ownership of this reference. This should preferably not be used
// outside of JNI helper functions.
ScopedJavaLocalRef(JNIEnv* env, T obj) : JavaRef<T>(obj), env_(env) {}
~ScopedJavaLocalRef() {
if (obj_ != nullptr)
env_->DeleteLocalRef(obj_);
}
void operator=(const ScopedJavaLocalRef& other) {
Reset(other.obj(), OwnershipPolicy::RETAIN);
}
void operator=(ScopedJavaLocalRef&& other) {
Reset(other.Release(), OwnershipPolicy::ADOPT);
}
// Releases the reference to the caller. The caller *must* delete the
// reference when it is done with it. Note that calling a Java method
// is *not* a transfer of ownership and Release() should not be used.
T Release() {
T obj = static_cast<T>(obj_);
obj_ = nullptr;
return obj;
}
JNIEnv* env() const { return env_; }
private:
using JavaRef<T>::obj_;
enum OwnershipPolicy {
// The scoped object takes ownership of an object by taking over an existing
// ownership claim.
ADOPT,
// The scoped object will retain the the object and any initial ownership is
// not changed.
RETAIN
};
void Reset(T obj, OwnershipPolicy policy) {
if (obj_ != nullptr)
env_->DeleteLocalRef(obj_);
obj_ = (obj != nullptr && policy == OwnershipPolicy::RETAIN)
? env_->NewLocalRef(obj)
: obj;
}
JNIEnv* const env_ = AttachCurrentThreadIfNeeded();
};
// Holds a global reference to a Java object. The global reference is scoped
// to the lifetime of this object. This class does not hold onto any JNIEnv*
// passed to it, hence it is safe to use across threads (within the constraints
// imposed by the underlying Java object that it references).
template <typename T>
class ScopedJavaGlobalRef : public JavaRef<T> {
public:
using JavaRef<T>::obj_;
ScopedJavaGlobalRef() = default;
explicit constexpr ScopedJavaGlobalRef(std::nullptr_t) {}
ScopedJavaGlobalRef(JNIEnv* env, const JavaRef<T>& other)
: JavaRef<T>(static_cast<T>(env->NewGlobalRef(other.obj()))) {}
explicit ScopedJavaGlobalRef(const ScopedJavaLocalRef<T>& other)
: ScopedJavaGlobalRef(other.env(), other) {}
ScopedJavaGlobalRef(ScopedJavaGlobalRef&& other)
: JavaRef<T>(other.Release()) {}
~ScopedJavaGlobalRef() {
if (obj_ != nullptr)
AttachCurrentThreadIfNeeded()->DeleteGlobalRef(obj_);
}
ScopedJavaGlobalRef(const ScopedJavaGlobalRef&) = delete;
ScopedJavaGlobalRef& operator=(const ScopedJavaGlobalRef&) = delete;
void operator=(const JavaRef<T>& other) {
JNIEnv* env = AttachCurrentThreadIfNeeded();
if (obj_ != nullptr) {
env->DeleteGlobalRef(obj_);
}
obj_ = other.is_null() ? nullptr : env->NewGlobalRef(other.obj());
}
void operator=(std::nullptr_t) {
if (obj_ != nullptr) {
AttachCurrentThreadIfNeeded()->DeleteGlobalRef(obj_);
}
obj_ = nullptr;
}
// Releases the reference to the caller. The caller *must* delete the
// reference when it is done with it. Note that calling a Java method
// is *not* a transfer of ownership and Release() should not be used.
T Release() {
T obj = static_cast<T>(obj_);
obj_ = nullptr;
return obj;
}
};
using jni_zero::JavaParamRef;
using jni_zero::JavaRef;
using jni_zero::ScopedJavaGlobalRef;
using jni_zero::ScopedJavaLocalRef;
template <typename T>
inline ScopedJavaLocalRef<T> static_java_ref_cast(JNIEnv* env,

View file

@ -20,7 +20,7 @@ std::unique_ptr<rtc::NetworkMonitorFactory> CreateAndroidNetworkMonitorFactory(
JNIEnv* env,
jobject application_context) {
return std::make_unique<jni::AndroidNetworkMonitorFactory>(
env, JavaParamRef<jobject>(application_context));
env, JavaParamRef<jobject>(env, application_context));
}
std::unique_ptr<rtc::NetworkMonitorFactory>

View file

@ -22,7 +22,7 @@ std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> JavaToNativeVideoSink(
JNIEnv* jni,
jobject video_sink) {
return std::make_unique<jni::VideoSinkWrapper>(
jni, JavaParamRef<jobject>(video_sink));
jni, JavaParamRef<jobject>(jni, video_sink));
}
ScopedJavaLocalRef<jobject> NativeToJavaVideoFrame(JNIEnv* jni,

View file

@ -1,5 +1,6 @@
include_rules = [
"+third_party/libyuv",
"+third_party/jni_zero",
"+call/callfactoryinterface.h",
"+common_video",
"+logging/rtc_event_log/rtc_event_log_factory.h",

View file

@ -8,6 +8,7 @@
* be found in the AUTHORS file in the root of the source tree.
*/
#include "rtc_base/checks.h"
#include "sdk/android/generated_video_jni/JavaI420Buffer_jni.h"
#include "third_party/libyuv/include/libyuv/scale.h"

View file

@ -1,80 +0,0 @@
/*
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "sdk/android/src/jni/jni_generator_helper.h"
#include "sdk/android/native_api/jni/class_loader.h"
namespace webrtc {
// If `atomic_class_id` set, it'll return immediately. Otherwise, it will look
// up the class and store it. If there's a race, we take care to only store one
// global reference (and the duplicated effort will happen only once).
jclass LazyGetClass(JNIEnv* env,
const char* class_name,
std::atomic<jclass>* atomic_class_id) {
const jclass value = std::atomic_load(atomic_class_id);
if (value)
return value;
webrtc::ScopedJavaGlobalRef<jclass> clazz(webrtc::GetClass(env, class_name));
RTC_CHECK(!clazz.is_null()) << class_name;
jclass cas_result = nullptr;
if (std::atomic_compare_exchange_strong(atomic_class_id, &cas_result,
clazz.obj())) {
// We sucessfully stored `clazz` in `atomic_class_id`, so we are
// intentionally leaking the global ref since it's now stored there.
return clazz.Release();
} else {
// Some other thread came before us and stored a global pointer in
// `atomic_class_id`. Relase our global ref and return the ref from the
// other thread.
return cas_result;
}
}
// If `atomic_method_id` set, it'll return immediately. Otherwise, it will look
// up the method id and store it. If there's a race, it's ok since the values
// are the same (and the duplicated effort will happen only once).
template <MethodID::Type type>
jmethodID MethodID::LazyGet(JNIEnv* env,
jclass clazz,
const char* method_name,
const char* jni_signature,
std::atomic<jmethodID>* atomic_method_id) {
const jmethodID value = std::atomic_load(atomic_method_id);
if (value)
return value;
auto get_method_ptr = type == MethodID::TYPE_STATIC
? &JNIEnv::GetStaticMethodID
: &JNIEnv::GetMethodID;
jmethodID id = (env->*get_method_ptr)(clazz, method_name, jni_signature);
CHECK_EXCEPTION(env) << "error during GetMethodID: " << method_name << ", "
<< jni_signature;
RTC_CHECK(id) << method_name << ", " << jni_signature;
std::atomic_store(atomic_method_id, id);
return id;
}
// Various template instantiations.
template jmethodID MethodID::LazyGet<MethodID::TYPE_STATIC>(
JNIEnv* env,
jclass clazz,
const char* method_name,
const char* jni_signature,
std::atomic<jmethodID>* atomic_method_id);
template jmethodID MethodID::LazyGet<MethodID::TYPE_INSTANCE>(
JNIEnv* env,
jclass clazz,
const char* method_name,
const char* jni_signature,
std::atomic<jmethodID>* atomic_method_id);
} // namespace webrtc

View file

@ -18,15 +18,8 @@
#include <atomic>
#include "rtc_base/checks.h"
#include "sdk/android/native_api/jni/jni_int_wrapper.h"
#include "sdk/android/native_api/jni/scoped_java_ref.h"
#include "third_party/jni_zero/jni_zero_internal.h"
#define CHECK_CLAZZ(env, jcaller, clazz, ...) RTC_DCHECK(clazz);
#define CHECK_NATIVE_PTR(env, jcaller, native_ptr, method_name, ...) \
RTC_DCHECK(native_ptr) << method_name;
#define BASE_EXPORT
#define JNI_REGISTRATION_EXPORT __attribute__((visibility("default")))
#if defined(WEBRTC_ARCH_X86)
@ -39,130 +32,22 @@
#define JNI_GENERATOR_EXPORT extern "C" JNIEXPORT JNICALL
#endif
#if defined(WEBRTC_ARCH_X86)
// Dalvik JIT generated code doesn't guarantee 16-byte stack alignment on
// x86 - use force_align_arg_pointer to realign the stack at the JNI
// boundary. crbug.com/655248
#define JNI_BOUNDARY_EXPORT \
extern "C" __attribute__((visibility("default"), force_align_arg_pointer))
#else
#define JNI_BOUNDARY_EXPORT extern "C" __attribute__((visibility("default")))
#endif
#if defined(COMPONENT_BUILD)
#define JNI_ZERO_COMPONENT_BUILD_EXPORT __attribute__((visibility("default")))
#else
#define JNI_ZERO_COMPONENT_BUILD_EXPORT
#endif
#define CHECK_EXCEPTION(jni) \
RTC_CHECK(!jni->ExceptionCheck()) \
<< (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
namespace webrtc {
// This function will initialize `atomic_class_id` to contain a global ref to
// the given class, and will return that ref on subsequent calls. The caller is
// responsible to zero-initialize `atomic_class_id`. It's fine to
// simultaneously call this on multiple threads referencing the same
// `atomic_method_id`.
jclass LazyGetClass(JNIEnv* env,
const char* class_name,
std::atomic<jclass>* atomic_class_id);
// This class is a wrapper for JNIEnv Get(Static)MethodID.
class MethodID {
public:
enum Type {
TYPE_STATIC,
TYPE_INSTANCE,
};
// This function will initialize `atomic_method_id` to contain a ref to
// the given method, and will return that ref on subsequent calls. The caller
// is responsible to zero-initialize `atomic_method_id`. It's fine to
// simultaneously call this on multiple threads referencing the same
// `atomic_method_id`.
template <Type type>
static jmethodID LazyGet(JNIEnv* env,
jclass clazz,
const char* method_name,
const char* jni_signature,
std::atomic<jmethodID>* atomic_method_id);
};
using jni_zero::JavaParamRef;
using jni_zero::JavaRef;
using jni_zero::ScopedJavaGlobalRef;
using jni_zero::ScopedJavaLocalRef;
} // namespace webrtc
namespace jni_zero {
// Re-export relevant classes into the namespaces the script expects.
using webrtc::JavaParamRef;
using webrtc::JavaRef;
using webrtc::LazyGetClass;
using webrtc::MethodID;
using webrtc::ScopedJavaLocalRef;
inline void CheckException(JNIEnv* env) {
CHECK_EXCEPTION(env);
}
// A 32 bit number could be an address on stack. Random 64 bit marker on the
// stack is much less likely to be present on stack.
constexpr uint64_t kJniStackMarkerValue = 0xbdbdef1bebcade1b;
// Context about the JNI call with exception checked to be stored in stack.
template <bool checked>
struct BASE_EXPORT JniJavaCallContext {
public:
inline JniJavaCallContext() {
// TODO(ssid): Implement for other architectures.
#if defined(__arm__) || defined(__aarch64__)
// This assumes that this method does not increment the stack pointer.
asm volatile("mov %0, sp" : "=r"(sp));
#else
sp = 0;
#endif
}
// Force no inline to reduce code size.
template <jni_zero::MethodID::Type type>
void Init(JNIEnv* env,
jclass clazz,
const char* method_name,
const char* jni_signature,
std::atomic<jmethodID>* atomic_method_id) {
env_ = env;
// Make sure compiler doesn't optimize out the assignment.
memcpy(&marker, &kJniStackMarkerValue, sizeof(kJniStackMarkerValue));
// Gets PC of the calling function.
pc = reinterpret_cast<uintptr_t>(__builtin_return_address(0));
method_id_ = jni_zero::MethodID::LazyGet<type>(
env, clazz, method_name, jni_signature, atomic_method_id);
}
~JniJavaCallContext() {
// Reset so that spurious marker finds are avoided.
memset(&marker, 0, sizeof(marker));
if (checked) {
jni_zero::CheckException(env_);
}
}
jmethodID method_id() { return method_id_; }
private:
uint64_t marker;
uintptr_t sp;
uintptr_t pc;
JNIEnv* env_;
jmethodID method_id_;
};
// Re-export helpers in the old jni_generator namespace.
// TODO(b/319078685): Remove once all uses of the jni_generator has been
// updated.
namespace jni_generator {
using jni_zero::internal::kJniStackMarkerValue;
// TODO(b/319078685): Remove JniJavaCallContextUnchecked once all uses of the
// jni_generator has been updated.
struct BASE_EXPORT JniJavaCallContextUnchecked {
struct JniJavaCallContextUnchecked {
inline JniJavaCallContextUnchecked() {
// TODO(ssid): Implement for other architectures.
#if defined(__arm__) || defined(__aarch64__)
@ -207,7 +92,7 @@ struct BASE_EXPORT JniJavaCallContextUnchecked {
// TODO(b/319078685): Remove JniJavaCallContextChecked once all uses of the
// jni_generator has been updated.
// Context about the JNI call with exception unchecked to be stored in stack.
struct BASE_EXPORT JniJavaCallContextChecked {
struct JniJavaCallContextChecked {
// Force no inline to reduce code size.
template <jni_zero::MethodID::Type type>
void Init(JNIEnv* env,
@ -229,24 +114,6 @@ static_assert(sizeof(JniJavaCallContextChecked) ==
sizeof(JniJavaCallContextUnchecked),
"Stack unwinder cannot work with structs of different sizes.");
} // namespace jni_zero
namespace jni_zero {
namespace internal {
using jni_zero::JniJavaCallContext;
using jni_zero::JniJavaCallContextChecked;
using jni_zero::JniJavaCallContextUnchecked;
using webrtc::LazyGetClass;
} // namespace internal
} // namespace jni_zero
// Re-export helpers in the old jni_generator namespace.
// TODO(b/319078685): Remove once all uses of the jni_generator has been
// updated.
namespace jni_generator {
using jni_zero::JniJavaCallContext;
using jni_zero::JniJavaCallContextChecked;
using jni_zero::JniJavaCallContextUnchecked;
} // namespace jni_generator
// Re-export helpers in the namespaces that the old jni_generator script
@ -255,11 +122,11 @@ using jni_zero::JniJavaCallContextUnchecked;
// updated.
namespace base {
namespace android {
using webrtc::JavaParamRef;
using webrtc::JavaRef;
using webrtc::LazyGetClass;
using webrtc::MethodID;
using webrtc::ScopedJavaLocalRef;
using jni_zero::JavaParamRef;
using jni_zero::JavaRef;
using jni_zero::MethodID;
using jni_zero::ScopedJavaLocalRef;
using jni_zero::internal::LazyGetClass;
} // namespace android
} // namespace base
#endif // SDK_ANDROID_SRC_JNI_JNI_GENERATOR_HELPER_H_

View file

@ -19,6 +19,7 @@
#include <string>
#include "rtc_base/checks.h"
#include "third_party/jni_zero/jni_zero.h"
namespace webrtc {
namespace jni {
@ -70,11 +71,18 @@ static void CreateJNIPtrKey() {
<< "pthread_key_create";
}
void HandleException(JNIEnv* env) {
RTC_CHECK(false) << (env->ExceptionDescribe(), env->ExceptionClear(), "");
}
jint InitGlobalJniVariables(JavaVM* jvm) {
RTC_CHECK(!g_jvm) << "InitGlobalJniVariables!";
g_jvm = jvm;
RTC_CHECK(g_jvm) << "InitGlobalJniVariables handed NULL?";
jni_zero::SetExceptionHandler(&HandleException);
jni_zero::InitVM(jvm);
RTC_CHECK(!pthread_once(&g_jni_ptr_once, &CreateJNIPtrKey)) << "pthread_once";
JNIEnv* jni = nullptr;

View file

@ -50,8 +50,9 @@ JNI_FUNCTION_DECLARATION(void,
jint j_severity,
jstring j_tag,
jstring j_message) {
std::string message = JavaToStdString(jni, JavaParamRef<jstring>(j_message));
std::string tag = JavaToStdString(jni, JavaParamRef<jstring>(j_tag));
std::string message =
JavaToStdString(jni, JavaParamRef<jstring>(jni, j_message));
std::string tag = JavaToStdString(jni, JavaParamRef<jstring>(jni, j_tag));
RTC_LOG_TAG(static_cast<rtc::LoggingSeverity>(j_severity), tag.c_str())
<< message;
}

View file

@ -10,8 +10,13 @@
#include "sdk/android/src/jni/scoped_java_ref_counted.h"
#include "rtc_base/checks.h"
#include "sdk/android/generated_base_jni/RefCounted_jni.h"
#define CHECK_EXCEPTION(jni) \
RTC_CHECK(!jni->ExceptionCheck()) \
<< (jni->ExceptionDescribe(), jni->ExceptionClear(), "")
namespace webrtc {
namespace jni {