diff options
Diffstat (limited to 'widget/android/jni')
-rw-r--r-- | widget/android/jni/Accessors.h | 274 | ||||
-rw-r--r-- | widget/android/jni/Natives.h | 707 | ||||
-rw-r--r-- | widget/android/jni/Refs.h | 953 | ||||
-rw-r--r-- | widget/android/jni/Types.h | 140 | ||||
-rw-r--r-- | widget/android/jni/Utils.cpp | 291 | ||||
-rw-r--r-- | widget/android/jni/Utils.h | 147 | ||||
-rw-r--r-- | widget/android/jni/moz.build | 24 |
7 files changed, 0 insertions, 2536 deletions
diff --git a/widget/android/jni/Accessors.h b/widget/android/jni/Accessors.h deleted file mode 100644 index fe2cbc9d4..000000000 --- a/widget/android/jni/Accessors.h +++ /dev/null @@ -1,274 +0,0 @@ -#ifndef mozilla_jni_Accessors_h__ -#define mozilla_jni_Accessors_h__ - -#include <jni.h> - -#include "mozilla/jni/Refs.h" -#include "mozilla/jni/Types.h" -#include "mozilla/jni/Utils.h" -#include "AndroidBridge.h" - -namespace mozilla { -namespace jni { - -namespace detail { - -// Helper class to convert an arbitrary type to a jvalue, e.g. Value(123).val. -struct Value -{ - Value(jboolean z) { val.z = z; } - Value(jbyte b) { val.b = b; } - Value(jchar c) { val.c = c; } - Value(jshort s) { val.s = s; } - Value(jint i) { val.i = i; } - Value(jlong j) { val.j = j; } - Value(jfloat f) { val.f = f; } - Value(jdouble d) { val.d = d; } - Value(jobject l) { val.l = l; } - - jvalue val; -}; - -} // namespace detail - -using namespace detail; - -// Base class for Method<>, Field<>, and Constructor<>. -class Accessor -{ - static void GetNsresult(JNIEnv* env, nsresult* rv) - { - if (env->ExceptionCheck()) { -#ifdef MOZ_CHECK_JNI - env->ExceptionDescribe(); -#endif - env->ExceptionClear(); - *rv = NS_ERROR_FAILURE; - } else { - *rv = NS_OK; - } - } - -protected: - // Called after making a JNIEnv call. - template<class Traits> - static void EndAccess(const typename Traits::Owner::Context& ctx, - nsresult* rv) - { - if (Traits::exceptionMode == ExceptionMode::ABORT) { - MOZ_CATCH_JNI_EXCEPTION(ctx.Env()); - - } else if (Traits::exceptionMode == ExceptionMode::NSRESULT) { - GetNsresult(ctx.Env(), rv); - } - } -}; - - -// Member<> is used to call a JNI method given a traits class. -template<class Traits, typename ReturnType = typename Traits::ReturnType> -class Method : public Accessor -{ - typedef Accessor Base; - typedef typename Traits::Owner::Context Context; - -protected: - static jmethodID sID; - - static void BeginAccess(const Context& ctx) - { - MOZ_ASSERT_JNI_THREAD(Traits::callingThread); - static_assert(Traits::dispatchTarget == DispatchTarget::CURRENT, - "Dispatching not supported for method call"); - - if (sID) { - return; - } - - if (Traits::isStatic) { - MOZ_ALWAYS_TRUE(sID = AndroidBridge::GetStaticMethodID( - ctx.Env(), ctx.ClassRef(), Traits::name, Traits::signature)); - } else { - MOZ_ALWAYS_TRUE(sID = AndroidBridge::GetMethodID( - ctx.Env(), ctx.ClassRef(), Traits::name, Traits::signature)); - } - } - - static void EndAccess(const Context& ctx, nsresult* rv) - { - return Base::EndAccess<Traits>(ctx, rv); - } - -public: - template<typename... Args> - static ReturnType Call(const Context& ctx, nsresult* rv, const Args&... args) - { - JNIEnv* const env = ctx.Env(); - BeginAccess(ctx); - - jvalue jargs[] = { - Value(TypeAdapter<Args>::FromNative(env, args)).val ... - }; - - auto result = TypeAdapter<ReturnType>::ToNative(env, - Traits::isStatic ? - (env->*TypeAdapter<ReturnType>::StaticCall)( - ctx.RawClassRef(), sID, jargs) : - (env->*TypeAdapter<ReturnType>::Call)( - ctx.Get(), sID, jargs)); - - EndAccess(ctx, rv); - return result; - } -}; - -// Define sID member. -template<class T, typename R> jmethodID Method<T, R>::sID; - - -// Specialize void because C++ forbids us from -// using a "void" temporary result variable. -template<class Traits> -class Method<Traits, void> : public Method<Traits, bool> -{ - typedef Method<Traits, bool> Base; - typedef typename Traits::Owner::Context Context; - -public: - template<typename... Args> - static void Call(const Context& ctx, nsresult* rv, - const Args&... args) - { - JNIEnv* const env = ctx.Env(); - Base::BeginAccess(ctx); - - jvalue jargs[] = { - Value(TypeAdapter<Args>::FromNative(env, args)).val ... - }; - - if (Traits::isStatic) { - env->CallStaticVoidMethodA(ctx.RawClassRef(), Base::sID, jargs); - } else { - env->CallVoidMethodA(ctx.Get(), Base::sID, jargs); - } - - Base::EndAccess(ctx, rv); - } -}; - - -// Constructor<> is used to construct a JNI instance given a traits class. -template<class Traits> -class Constructor : protected Method<Traits, typename Traits::ReturnType> { - typedef typename Traits::Owner::Context Context; - typedef typename Traits::ReturnType ReturnType; - typedef Method<Traits, ReturnType> Base; - -public: - template<typename... Args> - static ReturnType Call(const Context& ctx, nsresult* rv, - const Args&... args) - { - JNIEnv* const env = ctx.Env(); - Base::BeginAccess(ctx); - - jvalue jargs[] = { - Value(TypeAdapter<Args>::FromNative(env, args)).val ... - }; - - auto result = TypeAdapter<ReturnType>::ToNative( - env, env->NewObjectA(ctx.RawClassRef(), Base::sID, jargs)); - - Base::EndAccess(ctx, rv); - return result; - } -}; - - -// Field<> is used to access a JNI field given a traits class. -template<class Traits> -class Field : public Accessor -{ - typedef Accessor Base; - typedef typename Traits::Owner::Context Context; - typedef typename Traits::ReturnType GetterType; - typedef typename Traits::SetterType SetterType; - -private: - - static jfieldID sID; - - static void BeginAccess(const Context& ctx) - { - MOZ_ASSERT_JNI_THREAD(Traits::callingThread); - static_assert(Traits::dispatchTarget == DispatchTarget::CURRENT, - "Dispatching not supported for field access"); - - if (sID) { - return; - } - - if (Traits::isStatic) { - MOZ_ALWAYS_TRUE(sID = AndroidBridge::GetStaticFieldID( - ctx.Env(), ctx.ClassRef(), Traits::name, Traits::signature)); - } else { - MOZ_ALWAYS_TRUE(sID = AndroidBridge::GetFieldID( - ctx.Env(), ctx.ClassRef(), Traits::name, Traits::signature)); - } - } - - static void EndAccess(const Context& ctx, nsresult* rv) - { - return Base::EndAccess<Traits>(ctx, rv); - } - -public: - static GetterType Get(const Context& ctx, nsresult* rv) - { - JNIEnv* const env = ctx.Env(); - BeginAccess(ctx); - - auto result = TypeAdapter<GetterType>::ToNative( - env, Traits::isStatic ? - - (env->*TypeAdapter<GetterType>::StaticGet) - (ctx.RawClassRef(), sID) : - - (env->*TypeAdapter<GetterType>::Get) - (ctx.Get(), sID)); - - EndAccess(ctx, rv); - return result; - } - - static void Set(const Context& ctx, nsresult* rv, SetterType val) - { - JNIEnv* const env = ctx.Env(); - BeginAccess(ctx); - - if (Traits::isStatic) { - (env->*TypeAdapter<SetterType>::StaticSet)( - ctx.RawClassRef(), sID, - TypeAdapter<SetterType>::FromNative(env, val)); - } else { - (env->*TypeAdapter<SetterType>::Set)( - ctx.Get(), sID, - TypeAdapter<SetterType>::FromNative(env, val)); - } - - EndAccess(ctx, rv); - } -}; - -// Define sID member. -template<class T> jfieldID Field<T>::sID; - - -// Define the sClassRef member declared in Refs.h and -// used by Method and Field above. -template<class C, typename T> jclass Context<C, T>::sClassRef; - -} // namespace jni -} // namespace mozilla - -#endif // mozilla_jni_Accessors_h__ diff --git a/widget/android/jni/Natives.h b/widget/android/jni/Natives.h deleted file mode 100644 index 511d96a87..000000000 --- a/widget/android/jni/Natives.h +++ /dev/null @@ -1,707 +0,0 @@ -#ifndef mozilla_jni_Natives_h__ -#define mozilla_jni_Natives_h__ - -#include <jni.h> - -#include "mozilla/IndexSequence.h" -#include "mozilla/Move.h" -#include "mozilla/Tuple.h" -#include "mozilla/TypeTraits.h" -#include "mozilla/UniquePtr.h" -#include "mozilla/WeakPtr.h" -#include "mozilla/Unused.h" -#include "mozilla/jni/Accessors.h" -#include "mozilla/jni/Refs.h" -#include "mozilla/jni/Types.h" -#include "mozilla/jni/Utils.h" - -namespace mozilla { -namespace jni { - -/** - * C++ classes implementing instance (non-static) native methods can choose - * from one of two ownership models, when associating a C++ object with a Java - * instance. - * - * * If the C++ class inherits from mozilla::SupportsWeakPtr, weak pointers - * will be used. The Java instance will store and own the pointer to a - * WeakPtr object. The C++ class itself is otherwise not owned or directly - * referenced. To attach a Java instance to a C++ instance, pass in a pointer - * to the C++ class (i.e. MyClass*). - * - * class MyClass : public SupportsWeakPtr<MyClass> - * , public MyJavaClass::Natives<MyClass> - * { - * // ... - * - * public: - * MOZ_DECLARE_WEAKREFERENCE_TYPENAME(MyClass) - * using MyJavaClass::Natives<MyClass>::Dispose; - * - * void AttachTo(const MyJavaClass::LocalRef& instance) - * { - * MyJavaClass::Natives<MyClass>::AttachInstance(instance, this); - * - * // "instance" does NOT own "this", so the C++ object - * // lifetime is separate from the Java object lifetime. - * } - * }; - * - * * If the C++ class doesn't inherit from mozilla::SupportsWeakPtr, the Java - * instance will store and own a pointer to the C++ object itself. This - * pointer must not be stored or deleted elsewhere. To attach a Java instance - * to a C++ instance, pass in a reference to a UniquePtr of the C++ class - * (i.e. UniquePtr<MyClass>). - * - * class MyClass : public MyJavaClass::Natives<MyClass> - * { - * // ... - * - * public: - * using MyJavaClass::Natives<MyClass>::Dispose; - * - * static void AttachTo(const MyJavaClass::LocalRef& instance) - * { - * MyJavaClass::Natives<MyClass>::AttachInstance( - * instance, mozilla::MakeUnique<MyClass>()); - * - * // "instance" owns the newly created C++ object, so the C++ - * // object is destroyed as soon as instance.dispose() is called. - * } - * }; - */ - -namespace detail { - -inline uintptr_t CheckNativeHandle(JNIEnv* env, uintptr_t handle) -{ - if (!handle) { - if (!env->ExceptionCheck()) { - ThrowException(env, "java/lang/NullPointerException", - "Null native pointer"); - } - return 0; - } - return handle; -} - -template<class Impl, bool UseWeakPtr = mozilla::IsBaseOf< - SupportsWeakPtr<Impl>, Impl>::value /* = false */> -struct NativePtr -{ - static Impl* Get(JNIEnv* env, jobject instance) - { - return reinterpret_cast<Impl*>(CheckNativeHandle( - env, GetNativeHandle(env, instance))); - } - - template<class LocalRef> - static Impl* Get(const LocalRef& instance) - { - return Get(instance.Env(), instance.Get()); - } - - template<class LocalRef> - static void Set(const LocalRef& instance, UniquePtr<Impl>&& ptr) - { - Clear(instance); - SetNativeHandle(instance.Env(), instance.Get(), - reinterpret_cast<uintptr_t>(ptr.release())); - MOZ_CATCH_JNI_EXCEPTION(instance.Env()); - } - - template<class LocalRef> - static void Clear(const LocalRef& instance) - { - UniquePtr<Impl> ptr(reinterpret_cast<Impl*>( - GetNativeHandle(instance.Env(), instance.Get()))); - MOZ_CATCH_JNI_EXCEPTION(instance.Env()); - - if (ptr) { - SetNativeHandle(instance.Env(), instance.Get(), 0); - MOZ_CATCH_JNI_EXCEPTION(instance.Env()); - } - } -}; - -template<class Impl> -struct NativePtr<Impl, /* UseWeakPtr = */ true> -{ - static Impl* Get(JNIEnv* env, jobject instance) - { - const auto ptr = reinterpret_cast<WeakPtr<Impl>*>( - CheckNativeHandle(env, GetNativeHandle(env, instance))); - if (!ptr) { - return nullptr; - } - - Impl* const impl = *ptr; - if (!impl) { - ThrowException(env, "java/lang/NullPointerException", - "Native object already released"); - } - return impl; - } - - template<class LocalRef> - static Impl* Get(const LocalRef& instance) - { - return Get(instance.Env(), instance.Get()); - } - - template<class LocalRef> - static void Set(const LocalRef& instance, Impl* ptr) - { - Clear(instance); - SetNativeHandle(instance.Env(), instance.Get(), - reinterpret_cast<uintptr_t>(new WeakPtr<Impl>(ptr))); - MOZ_CATCH_JNI_EXCEPTION(instance.Env()); - } - - template<class LocalRef> - static void Clear(const LocalRef& instance) - { - const auto ptr = reinterpret_cast<WeakPtr<Impl>*>( - GetNativeHandle(instance.Env(), instance.Get())); - MOZ_CATCH_JNI_EXCEPTION(instance.Env()); - - if (ptr) { - SetNativeHandle(instance.Env(), instance.Get(), 0); - MOZ_CATCH_JNI_EXCEPTION(instance.Env()); - delete ptr; - } - } -}; - -} // namespace detail - -using namespace detail; - -/** - * For JNI native methods that are dispatched to a proxy, i.e. using - * @WrapForJNI(dispatchTo = "proxy"), the implementing C++ class must provide a - * OnNativeCall member. Subsequently, every native call is automatically - * wrapped in a functor object, and the object is passed to OnNativeCall. The - * OnNativeCall implementation can choose to invoke the call, save it, dispatch - * it to a different thread, etc. Each copy of functor may only be invoked - * once. - * - * class MyClass : public MyJavaClass::Natives<MyClass> - * { - * // ... - * - * template<class Functor> - * class ProxyRunnable final : public Runnable - * { - * Functor mCall; - * public: - * ProxyRunnable(Functor&& call) : mCall(mozilla::Move(call)) {} - * virtual void run() override { mCall(); } - * }; - * - * public: - * template<class Functor> - * static void OnNativeCall(Functor&& call) - * { - * RunOnAnotherThread(new ProxyRunnable(mozilla::Move(call))); - * } - * }; - */ - -namespace detail { - -// ProxyArg is used to handle JNI ref arguments for proxies. Because a proxied -// call may happen outside of the original JNI native call, we must save all -// JNI ref arguments as global refs to avoid the arguments going out of scope. -template<typename T> -struct ProxyArg -{ - static_assert(mozilla::IsPod<T>::value, "T must be primitive type"); - - // Primitive types can be saved by value. - typedef T Type; - typedef typename TypeAdapter<T>::JNIType JNIType; - - static void Clear(JNIEnv* env, Type&) {} - - static Type From(JNIEnv* env, JNIType val) - { - return TypeAdapter<T>::ToNative(env, val); - } -}; - -template<class C, typename T> -struct ProxyArg<Ref<C, T>> -{ - // Ref types need to be saved by global ref. - typedef typename C::GlobalRef Type; - typedef typename TypeAdapter<Ref<C, T>>::JNIType JNIType; - - static void Clear(JNIEnv* env, Type& ref) { ref.Clear(env); } - - static Type From(JNIEnv* env, JNIType val) - { - return Type(env, C::Ref::From(val)); - } -}; - -template<typename C> struct ProxyArg<const C&> : ProxyArg<C> {}; -template<> struct ProxyArg<StringParam> : ProxyArg<String::Ref> {}; -template<class C> struct ProxyArg<LocalRef<C>> : ProxyArg<typename C::Ref> {}; - -// ProxyNativeCall implements the functor object that is passed to OnNativeCall -template<class Impl, class Owner, bool IsStatic, - bool HasThisArg /* has instance/class local ref in the call */, - typename... Args> -class ProxyNativeCall : public AbstractCall -{ - // "this arg" refers to the Class::LocalRef (for static methods) or - // Owner::LocalRef (for instance methods) that we optionally (as indicated - // by HasThisArg) pass into the destination C++ function. - typedef typename mozilla::Conditional<IsStatic, - Class, Owner>::Type ThisArgClass; - typedef typename mozilla::Conditional<IsStatic, - jclass, jobject>::Type ThisArgJNIType; - - // Type signature of the destination C++ function, which matches the - // Method template parameter in NativeStubImpl::Wrap. - typedef typename mozilla::Conditional<IsStatic, - typename mozilla::Conditional<HasThisArg, - void (*) (const Class::LocalRef&, Args...), - void (*) (Args...)>::Type, - typename mozilla::Conditional<HasThisArg, - void (Impl::*) (const typename Owner::LocalRef&, Args...), - void (Impl::*) (Args...)>::Type>::Type NativeCallType; - - // Destination C++ function. - NativeCallType mNativeCall; - // Saved this arg. - typename ThisArgClass::GlobalRef mThisArg; - // Saved arguments. - mozilla::Tuple<typename ProxyArg<Args>::Type...> mArgs; - - // We cannot use IsStatic and HasThisArg directly (without going through - // extra hoops) because GCC complains about invalid overloads, so we use - // another pair of template parameters, Static and ThisArg. - - template<bool Static, bool ThisArg, size_t... Indices> - typename mozilla::EnableIf<Static && ThisArg, void>::Type - Call(const Class::LocalRef& cls, - mozilla::IndexSequence<Indices...>) const - { - (*mNativeCall)(cls, mozilla::Get<Indices>(mArgs)...); - } - - template<bool Static, bool ThisArg, size_t... Indices> - typename mozilla::EnableIf<Static && !ThisArg, void>::Type - Call(const Class::LocalRef& cls, - mozilla::IndexSequence<Indices...>) const - { - (*mNativeCall)(mozilla::Get<Indices>(mArgs)...); - } - - template<bool Static, bool ThisArg, size_t... Indices> - typename mozilla::EnableIf<!Static && ThisArg, void>::Type - Call(const typename Owner::LocalRef& inst, - mozilla::IndexSequence<Indices...>) const - { - Impl* const impl = NativePtr<Impl>::Get(inst); - MOZ_CATCH_JNI_EXCEPTION(inst.Env()); - (impl->*mNativeCall)(inst, mozilla::Get<Indices>(mArgs)...); - } - - template<bool Static, bool ThisArg, size_t... Indices> - typename mozilla::EnableIf<!Static && !ThisArg, void>::Type - Call(const typename Owner::LocalRef& inst, - mozilla::IndexSequence<Indices...>) const - { - Impl* const impl = NativePtr<Impl>::Get(inst); - MOZ_CATCH_JNI_EXCEPTION(inst.Env()); - (impl->*mNativeCall)(mozilla::Get<Indices>(mArgs)...); - } - - template<size_t... Indices> - void Clear(JNIEnv* env, mozilla::IndexSequence<Indices...>) - { - int dummy[] = { - (ProxyArg<Args>::Clear(env, Get<Indices>(mArgs)), 0)... - }; - mozilla::Unused << dummy; - } - -public: - // The class that implements the call target. - typedef Impl TargetClass; - typedef typename ThisArgClass::Param ThisArgType; - - static const bool isStatic = IsStatic; - - ProxyNativeCall(ThisArgJNIType thisArg, - NativeCallType nativeCall, - JNIEnv* env, - typename ProxyArg<Args>::JNIType... args) - : mNativeCall(nativeCall) - , mThisArg(env, ThisArgClass::Ref::From(thisArg)) - , mArgs(ProxyArg<Args>::From(env, args)...) - {} - - ProxyNativeCall(ProxyNativeCall&&) = default; - ProxyNativeCall(const ProxyNativeCall&) = default; - - // Get class ref for static calls or object ref for instance calls. - typename ThisArgClass::Param GetThisArg() const { return mThisArg; } - - // Return if target is the given function pointer / pointer-to-member. - // Because we can only compare pointers of the same type, we use a - // templated overload that is chosen only if given a different type of - // pointer than our target pointer type. - bool IsTarget(NativeCallType call) const { return call == mNativeCall; } - template<typename T> bool IsTarget(T&&) const { return false; } - - // Redirect the call to another function / class member with the same - // signature as the original target. Crash if given a wrong signature. - void SetTarget(NativeCallType call) { mNativeCall = call; } - template<typename T> void SetTarget(T&&) const { MOZ_CRASH(); } - - void operator()() override - { - JNIEnv* const env = GetEnvForThread(); - typename ThisArgClass::LocalRef thisArg(env, mThisArg); - Call<IsStatic, HasThisArg>( - thisArg, typename IndexSequenceFor<Args...>::Type()); - - // Clear all saved global refs. We do this after the call is invoked, - // and not inside the destructor because we already have a JNIEnv here, - // so it's more efficient to clear out the saved args here. The - // downside is that the call can only be invoked once. - Clear(env, typename IndexSequenceFor<Args...>::Type()); - mThisArg.Clear(env); - } -}; - -template<class Impl, bool HasThisArg, typename... Args> -struct Dispatcher -{ - template<class Traits, bool IsStatic = Traits::isStatic, - typename... ProxyArgs> - static typename EnableIf< - Traits::dispatchTarget == DispatchTarget::PROXY, void>::Type - Run(ProxyArgs&&... args) - { - Impl::OnNativeCall(ProxyNativeCall< - Impl, typename Traits::Owner, IsStatic, - HasThisArg, Args...>(Forward<ProxyArgs>(args)...)); - } - - template<class Traits, bool IsStatic = Traits::isStatic, - typename ThisArg, typename... ProxyArgs> - static typename EnableIf< - Traits::dispatchTarget == DispatchTarget::GECKO, void>::Type - Run(ThisArg thisArg, ProxyArgs&&... args) - { - // For a static method, do not forward the "this arg" (i.e. the class - // local ref) if the implementation does not request it. This saves us - // a pair of calls to add/delete global ref. - DispatchToGeckoThread(MakeUnique<ProxyNativeCall< - Impl, typename Traits::Owner, IsStatic, HasThisArg, - Args...>>(HasThisArg || !IsStatic ? thisArg : nullptr, - Forward<ProxyArgs>(args)...)); - } - - template<class Traits, bool IsStatic = false, typename... ProxyArgs> - static typename EnableIf< - Traits::dispatchTarget == DispatchTarget::CURRENT, void>::Type - Run(ProxyArgs&&... args) {} -}; - -} // namespace detail - -// Wrapper methods that convert arguments from the JNI types to the native -// types, e.g. from jobject to jni::Object::Ref. For instance methods, the -// wrapper methods also convert calls to calls on objects. -// -// We need specialization for static/non-static because the two have different -// signatures (jobject vs jclass and Impl::*Method vs *Method). -// We need specialization for return type, because void return type requires -// us to not deal with the return value. - -// Bug 1207642 - Work around Dalvik bug by realigning stack on JNI entry -#ifdef __i386__ -#define MOZ_JNICALL JNICALL __attribute__((force_align_arg_pointer)) -#else -#define MOZ_JNICALL JNICALL -#endif - -template<class Traits, class Impl, class Args = typename Traits::Args> -class NativeStub; - -template<class Traits, class Impl, typename... Args> -class NativeStub<Traits, Impl, jni::Args<Args...>> -{ - using Owner = typename Traits::Owner; - using ReturnType = typename Traits::ReturnType; - - static constexpr bool isStatic = Traits::isStatic; - static constexpr bool isVoid = mozilla::IsVoid<ReturnType>::value; - - struct VoidType { using JNIType = void; }; - using ReturnJNIType = typename Conditional< - isVoid, VoidType, TypeAdapter<ReturnType>>::Type::JNIType; - - using ReturnTypeForNonVoidInstance = typename Conditional< - !isStatic && !isVoid, ReturnType, VoidType>::Type; - using ReturnTypeForVoidInstance = typename Conditional< - !isStatic && isVoid, ReturnType, VoidType&>::Type; - using ReturnTypeForNonVoidStatic = typename Conditional< - isStatic && !isVoid, ReturnType, VoidType>::Type; - using ReturnTypeForVoidStatic = typename Conditional< - isStatic && isVoid, ReturnType, VoidType&>::Type; - - static_assert(Traits::dispatchTarget == DispatchTarget::CURRENT || isVoid, - "Dispatched calls must have void return type"); - -public: - // Non-void instance method - template<ReturnTypeForNonVoidInstance (Impl::*Method) (Args...)> - static MOZ_JNICALL ReturnJNIType - Wrap(JNIEnv* env, jobject instance, - typename TypeAdapter<Args>::JNIType... args) - { - MOZ_ASSERT_JNI_THREAD(Traits::callingThread); - - Impl* const impl = NativePtr<Impl>::Get(env, instance); - if (!impl) { - // There is a pending JNI exception at this point. - return ReturnJNIType(); - } - return TypeAdapter<ReturnType>::FromNative(env, - (impl->*Method)(TypeAdapter<Args>::ToNative(env, args)...)); - } - - // Non-void instance method with instance reference - template<ReturnTypeForNonVoidInstance (Impl::*Method) - (const typename Owner::LocalRef&, Args...)> - static MOZ_JNICALL ReturnJNIType - Wrap(JNIEnv* env, jobject instance, - typename TypeAdapter<Args>::JNIType... args) - { - MOZ_ASSERT_JNI_THREAD(Traits::callingThread); - - Impl* const impl = NativePtr<Impl>::Get(env, instance); - if (!impl) { - // There is a pending JNI exception at this point. - return ReturnJNIType(); - } - auto self = Owner::LocalRef::Adopt(env, instance); - const auto res = TypeAdapter<ReturnType>::FromNative(env, - (impl->*Method)(self, TypeAdapter<Args>::ToNative(env, args)...)); - self.Forget(); - return res; - } - - // Void instance method - template<ReturnTypeForVoidInstance (Impl::*Method) (Args...)> - static MOZ_JNICALL void - Wrap(JNIEnv* env, jobject instance, - typename TypeAdapter<Args>::JNIType... args) - { - MOZ_ASSERT_JNI_THREAD(Traits::callingThread); - - if (Traits::dispatchTarget != DispatchTarget::CURRENT) { - Dispatcher<Impl, /* HasThisArg */ false, Args...>:: - template Run<Traits>(instance, Method, env, args...); - return; - } - - Impl* const impl = NativePtr<Impl>::Get(env, instance); - if (!impl) { - // There is a pending JNI exception at this point. - return; - } - (impl->*Method)(TypeAdapter<Args>::ToNative(env, args)...); - } - - // Void instance method with instance reference - template<ReturnTypeForVoidInstance (Impl::*Method) - (const typename Owner::LocalRef&, Args...)> - static MOZ_JNICALL void - Wrap(JNIEnv* env, jobject instance, - typename TypeAdapter<Args>::JNIType... args) - { - MOZ_ASSERT_JNI_THREAD(Traits::callingThread); - - if (Traits::dispatchTarget != DispatchTarget::CURRENT) { - Dispatcher<Impl, /* HasThisArg */ true, Args...>:: - template Run<Traits>(instance, Method, env, args...); - return; - } - - Impl* const impl = NativePtr<Impl>::Get(env, instance); - if (!impl) { - // There is a pending JNI exception at this point. - return; - } - auto self = Owner::LocalRef::Adopt(env, instance); - (impl->*Method)(self, TypeAdapter<Args>::ToNative(env, args)...); - self.Forget(); - } - - // Overload for DisposeNative - template<ReturnTypeForVoidInstance (*DisposeNative) - (const typename Owner::LocalRef&)> - static MOZ_JNICALL void - Wrap(JNIEnv* env, jobject instance) - { - MOZ_ASSERT_JNI_THREAD(Traits::callingThread); - - if (Traits::dispatchTarget != DispatchTarget::CURRENT) { - using LocalRef = typename Owner::LocalRef; - Dispatcher<Impl, /* HasThisArg */ false, const LocalRef&>:: - template Run<Traits, /* IsStatic */ true>( - /* ThisArg */ nullptr, DisposeNative, env, instance); - return; - } - - auto self = Owner::LocalRef::Adopt(env, instance); - (Impl::DisposeNative)(self); - self.Forget(); - } - - // Non-void static method - template<ReturnTypeForNonVoidStatic (*Method) (Args...)> - static MOZ_JNICALL ReturnJNIType - Wrap(JNIEnv* env, jclass, typename TypeAdapter<Args>::JNIType... args) - { - MOZ_ASSERT_JNI_THREAD(Traits::callingThread); - - return TypeAdapter<ReturnType>::FromNative(env, - (*Method)(TypeAdapter<Args>::ToNative(env, args)...)); - } - - // Non-void static method with class reference - template<ReturnTypeForNonVoidStatic (*Method) - (const Class::LocalRef&, Args...)> - static MOZ_JNICALL ReturnJNIType - Wrap(JNIEnv* env, jclass cls, typename TypeAdapter<Args>::JNIType... args) - { - MOZ_ASSERT_JNI_THREAD(Traits::callingThread); - - auto clazz = Class::LocalRef::Adopt(env, cls); - const auto res = TypeAdapter<ReturnType>::FromNative(env, - (*Method)(clazz, TypeAdapter<Args>::ToNative(env, args)...)); - clazz.Forget(); - return res; - } - - // Void static method - template<ReturnTypeForVoidStatic (*Method) (Args...)> - static MOZ_JNICALL void - Wrap(JNIEnv* env, jclass cls, typename TypeAdapter<Args>::JNIType... args) - { - MOZ_ASSERT_JNI_THREAD(Traits::callingThread); - - if (Traits::dispatchTarget != DispatchTarget::CURRENT) { - Dispatcher<Impl, /* HasThisArg */ false, Args...>:: - template Run<Traits>(cls, Method, env, args...); - return; - } - - (*Method)(TypeAdapter<Args>::ToNative(env, args)...); - } - - // Void static method with class reference - template<ReturnTypeForVoidStatic (*Method) - (const Class::LocalRef&, Args...)> - static MOZ_JNICALL void - Wrap(JNIEnv* env, jclass cls, typename TypeAdapter<Args>::JNIType... args) - { - MOZ_ASSERT_JNI_THREAD(Traits::callingThread); - - if (Traits::dispatchTarget != DispatchTarget::CURRENT) { - Dispatcher<Impl, /* HasThisArg */ true, Args...>:: - template Run<Traits>(cls, Method, env, args...); - return; - } - - auto clazz = Class::LocalRef::Adopt(env, cls); - (*Method)(clazz, TypeAdapter<Args>::ToNative(env, args)...); - clazz.Forget(); - } -}; - -// Generate a JNINativeMethod from a native -// method's traits class and a wrapped stub. -template<class Traits, typename Ret, typename... Args> -constexpr JNINativeMethod MakeNativeMethod(MOZ_JNICALL Ret (*stub)(JNIEnv*, Args...)) -{ - return { - Traits::name, - Traits::signature, - reinterpret_cast<void*>(stub) - }; -} - -// Class inherited by implementing class. -template<class Cls, class Impl> -class NativeImpl -{ - typedef typename Cls::template Natives<Impl> Natives; - - static bool sInited; - -public: - static void Init() { - if (sInited) { - return; - } - const auto& ctx = typename Cls::Context(); - ctx.Env()->RegisterNatives( - ctx.ClassRef(), Natives::methods, - sizeof(Natives::methods) / sizeof(Natives::methods[0])); - MOZ_CATCH_JNI_EXCEPTION(ctx.Env()); - sInited = true; - } - -protected: - - // Associate a C++ instance with a Java instance. - static void AttachNative(const typename Cls::LocalRef& instance, - SupportsWeakPtr<Impl>* ptr) - { - static_assert(mozilla::IsBaseOf<SupportsWeakPtr<Impl>, Impl>::value, - "Attach with UniquePtr&& when not using WeakPtr"); - return NativePtr<Impl>::Set(instance, static_cast<Impl*>(ptr)); - } - - static void AttachNative(const typename Cls::LocalRef& instance, - UniquePtr<Impl>&& ptr) - { - static_assert(!mozilla::IsBaseOf<SupportsWeakPtr<Impl>, Impl>::value, - "Attach with SupportsWeakPtr* when using WeakPtr"); - return NativePtr<Impl>::Set(instance, mozilla::Move(ptr)); - } - - // Get the C++ instance associated with a Java instance. - // There is always a pending exception if the return value is nullptr. - static Impl* GetNative(const typename Cls::LocalRef& instance) { - return NativePtr<Impl>::Get(instance); - } - - static void DisposeNative(const typename Cls::LocalRef& instance) { - NativePtr<Impl>::Clear(instance); - } - - NativeImpl() { - // Initialize on creation if not already initialized. - Init(); - } -}; - -// Define static member. -template<class C, class I> -bool NativeImpl<C, I>::sInited; - -} // namespace jni -} // namespace mozilla - -#endif // mozilla_jni_Natives_h__ diff --git a/widget/android/jni/Refs.h b/widget/android/jni/Refs.h deleted file mode 100644 index 9f54ee5cd..000000000 --- a/widget/android/jni/Refs.h +++ /dev/null @@ -1,953 +0,0 @@ -#ifndef mozilla_jni_Refs_h__ -#define mozilla_jni_Refs_h__ - -#include <jni.h> - -#include "mozilla/Move.h" -#include "mozilla/jni/Utils.h" - -#include "nsError.h" // for nsresult -#include "nsString.h" -#include "nsTArray.h" - -namespace mozilla { -namespace jni { - -// Wrapped object reference (e.g. jobject, jclass, etc...) -template<class Cls, typename JNIType> class Ref; -// Represents a calling context for JNI methods. -template<class Cls, typename JNIType> class Context; -// Wrapped local reference that inherits from Ref. -template<class Cls> class LocalRef; -// Wrapped global reference that inherits from Ref. -template<class Cls> class GlobalRef; -// Wrapped dangling reference that's owned by someone else. -template<class Cls> class DependentRef; - - -// Class to hold the native types of a method's arguments. -// For example, if a method has signature (ILjava/lang/String;)V, -// its arguments class would be jni::Args<int32_t, jni::String::Param> -template<typename...> -struct Args {}; - - -class Object; - -// Base class for Ref and its specializations. -template<class Cls, typename Type> -class Ref -{ - template<class C, typename T> friend class Ref; - - using Self = Ref<Cls, Type>; - using bool_type = void (Self::*)() const; - void non_null_reference() const {} - - // A Cls-derivative that allows copying - // (e.g. when acting as a return value). - struct CopyableCtx : public Context<Cls, Type> - { - CopyableCtx(JNIEnv* env, Type instance) - : Context<Cls, Type>(env, instance) - {} - - CopyableCtx(const CopyableCtx& cls) - : Context<Cls, Type>(cls.Env(), cls.Get()) - {} - }; - - // Private copy constructor so that there's no danger of assigning a - // temporary LocalRef/GlobalRef to a Ref, and potentially use the Ref - // after the source had been freed. - Ref(const Ref&) = default; - -protected: - static JNIEnv* FindEnv() - { - return Cls::callingThread == CallingThread::GECKO ? - GetGeckoThreadEnv() : GetEnvForThread(); - } - - Type mInstance; - - // Protected jobject constructor because outside code should be using - // Ref::From. Using Ref::From makes it very easy to see which code is using - // raw JNI types for future refactoring. - explicit Ref(Type instance) : mInstance(instance) {} - -public: - using JNIType = Type; - - // Construct a Ref form a raw JNI reference. - static Ref<Cls, Type> From(JNIType obj) - { - return Ref<Cls, Type>(obj); - } - - // Construct a Ref form a generic object reference. - static Ref<Cls, Type> From(const Ref<Object, jobject>& obj) - { - return Ref<Cls, Type>(JNIType(obj.Get())); - } - - MOZ_IMPLICIT Ref(decltype(nullptr)) : mInstance(nullptr) {} - - // Get the raw JNI reference. - JNIType Get() const - { - return mInstance; - } - - bool operator==(const Ref& other) const - { - // Treat two references of the same object as being the same. - return mInstance == other.mInstance || JNI_FALSE != - FindEnv()->IsSameObject(mInstance, other.mInstance); - } - - bool operator!=(const Ref& other) const - { - return !operator==(other); - } - - bool operator==(decltype(nullptr)) const - { - return !mInstance; - } - - bool operator!=(decltype(nullptr)) const - { - return !!mInstance; - } - - CopyableCtx operator->() const - { - return CopyableCtx(FindEnv(), mInstance); - } - - // Any ref can be cast to an object ref. - operator Ref<Object, jobject>() const - { - return Ref<Object, jobject>(mInstance); - } - - // Null checking (e.g. !!ref) using the safe-bool idiom. - operator bool_type() const - { - return mInstance ? &Self::non_null_reference : nullptr; - } - - // We don't allow implicit conversion to jobject because that can lead - // to easy mistakes such as assigning a temporary LocalRef to a jobject, - // and using the jobject after the LocalRef has been freed. - - // We don't allow explicit conversion, to make outside code use Ref::Get. - // Using Ref::Get makes it very easy to see which code is using raw JNI - // types to make future refactoring easier. - - // operator JNIType() const = delete; -}; - - -// Represents a calling context for JNI methods. -template<class Cls, typename Type> -class Context : public Ref<Cls, Type> -{ - using Ref = jni::Ref<Cls, Type>; - - static jclass sClassRef; // global reference - -protected: - JNIEnv* const mEnv; - -public: - static jclass RawClassRef() - { - return sClassRef; - } - - Context() - : Ref(nullptr) - , mEnv(Ref::FindEnv()) - {} - - Context(JNIEnv* env, Type instance) - : Ref(instance) - , mEnv(env) - {} - - jclass ClassRef() const - { - if (!sClassRef) { - const jclass cls = GetClassRef(mEnv, Cls::name); - sClassRef = jclass(mEnv->NewGlobalRef(cls)); - mEnv->DeleteLocalRef(cls); - } - return sClassRef; - } - - JNIEnv* Env() const - { - return mEnv; - } - - bool operator==(const Ref& other) const - { - // Treat two references of the same object as being the same. - return Ref::mInstance == other.mInstance || JNI_FALSE != - mEnv->IsSameObject(Ref::mInstance, other.mInstance); - } - - bool operator!=(const Ref& other) const - { - return !operator==(other); - } - - bool operator==(decltype(nullptr)) const - { - return !Ref::mInstance; - } - - bool operator!=(decltype(nullptr)) const - { - return !!Ref::mInstance; - } - - Cls operator->() const - { - MOZ_ASSERT(Ref::mInstance, "Null jobject"); - return Cls(*this); - } -}; - - -template<class Cls, typename Type = jobject> -class ObjectBase -{ -protected: - const jni::Context<Cls, Type>& mCtx; - - jclass ClassRef() const { return mCtx.ClassRef(); } - JNIEnv* Env() const { return mCtx.Env(); } - Type Instance() const { return mCtx.Get(); } - -public: - using Ref = jni::Ref<Cls, Type>; - using Context = jni::Context<Cls, Type>; - using LocalRef = jni::LocalRef<Cls>; - using GlobalRef = jni::GlobalRef<Cls>; - using Param = const Ref&; - - static const CallingThread callingThread = CallingThread::ANY; - static const char name[]; - - explicit ObjectBase(const Context& ctx) : mCtx(ctx) {} - - Cls* operator->() - { - return static_cast<Cls*>(this); - } -}; - -// Binding for a plain jobject. -class Object : public ObjectBase<Object, jobject> -{ -public: - explicit Object(const Context& ctx) : ObjectBase<Object, jobject>(ctx) {} -}; - -// Binding for a built-in object reference other than jobject. -template<typename T> -class TypedObject : public ObjectBase<TypedObject<T>, T> -{ -public: - explicit TypedObject(const Context<TypedObject<T>, T>& ctx) - : ObjectBase<TypedObject<T>, T>(ctx) - {} -}; - - -// Define bindings for built-in types. -using String = TypedObject<jstring>; -using Class = TypedObject<jclass>; -using Throwable = TypedObject<jthrowable>; - -using BooleanArray = TypedObject<jbooleanArray>; -using ByteArray = TypedObject<jbyteArray>; -using CharArray = TypedObject<jcharArray>; -using ShortArray = TypedObject<jshortArray>; -using IntArray = TypedObject<jintArray>; -using LongArray = TypedObject<jlongArray>; -using FloatArray = TypedObject<jfloatArray>; -using DoubleArray = TypedObject<jdoubleArray>; -using ObjectArray = TypedObject<jobjectArray>; - - -namespace detail { - -// See explanation in LocalRef. -template<class Cls> struct GenericObject { using Type = Object; }; -template<> struct GenericObject<Object> -{ - struct Type { - using Ref = jni::Ref<Type, jobject>; - using Context = jni::Context<Type, jobject>; - }; -}; -template<class Cls> struct GenericLocalRef -{ - template<class C> struct Type : jni::Object {}; -}; -template<> struct GenericLocalRef<Object> -{ - template<class C> using Type = jni::LocalRef<C>; -}; - -} // namespace - -template<class Cls> -class LocalRef : public Cls::Context -{ - template<class C> friend class LocalRef; - - using Ctx = typename Cls::Context; - using Ref = typename Cls::Ref; - using JNIType = typename Ref::JNIType; - - // In order to be able to convert LocalRef<Object> to LocalRef<Cls>, we - // need constructors and copy assignment operators that take in a - // LocalRef<Object> argument. However, if Cls *is* Object, we would have - // duplicated constructors and operators with LocalRef<Object> arguments. To - // avoid this conflict, we use GenericObject, which is defined as Object for - // LocalRef<non-Object> and defined as a dummy class for LocalRef<Object>. - using GenericObject = typename detail::GenericObject<Cls>::Type; - - // Similarly, GenericLocalRef is useed to convert LocalRef<Cls> to, - // LocalRef<Object>. It's defined as LocalRef<C> for Cls == Object, - // and defined as a dummy template class for Cls != Object. - template<class C> using GenericLocalRef - = typename detail::GenericLocalRef<Cls>::template Type<C>; - - static JNIType NewLocalRef(JNIEnv* env, JNIType obj) - { - return JNIType(obj ? env->NewLocalRef(obj) : nullptr); - } - - LocalRef(JNIEnv* env, JNIType instance) : Ctx(env, instance) {} - - LocalRef& swap(LocalRef& other) - { - auto instance = other.mInstance; - other.mInstance = Ctx::mInstance; - Ctx::mInstance = instance; - return *this; - } - -public: - // Construct a LocalRef from a raw JNI local reference. Unlike Ref::From, - // LocalRef::Adopt returns a LocalRef that will delete the local reference - // when going out of scope. - static LocalRef Adopt(JNIType instance) - { - return LocalRef(Ref::FindEnv(), instance); - } - - static LocalRef Adopt(JNIEnv* env, JNIType instance) - { - return LocalRef(env, instance); - } - - // Copy constructor. - LocalRef(const LocalRef<Cls>& ref) - : Ctx(ref.mEnv, NewLocalRef(ref.mEnv, ref.mInstance)) - {} - - // Move constructor. - LocalRef(LocalRef<Cls>&& ref) - : Ctx(ref.mEnv, ref.mInstance) - { - ref.mInstance = nullptr; - } - - explicit LocalRef(JNIEnv* env = Ref::FindEnv()) - : Ctx(env, nullptr) - {} - - // Construct a LocalRef from any Ref, - // which means creating a new local reference. - MOZ_IMPLICIT LocalRef(const Ref& ref) - : Ctx(Ref::FindEnv(), nullptr) - { - Ctx::mInstance = NewLocalRef(Ctx::mEnv, ref.Get()); - } - - LocalRef(JNIEnv* env, const Ref& ref) - : Ctx(env, NewLocalRef(env, ref.Get())) - {} - - // Move a LocalRef<Object> into a LocalRef<Cls> without - // creating/deleting local references. - MOZ_IMPLICIT LocalRef(LocalRef<GenericObject>&& ref) - : Ctx(ref.mEnv, JNIType(ref.mInstance)) - { - ref.mInstance = nullptr; - } - - template<class C> - MOZ_IMPLICIT LocalRef(GenericLocalRef<C>&& ref) - : Ctx(ref.mEnv, ref.mInstance) - { - ref.mInstance = nullptr; - } - - // Implicitly converts nullptr to LocalRef. - MOZ_IMPLICIT LocalRef(decltype(nullptr)) - : Ctx(Ref::FindEnv(), nullptr) - {} - - ~LocalRef() - { - if (Ctx::mInstance) { - Ctx::mEnv->DeleteLocalRef(Ctx::mInstance); - Ctx::mInstance = nullptr; - } - } - - // Get the raw JNI reference that can be used as a return value. - // Returns the same JNI type (jobject, jstring, etc.) as the underlying Ref. - typename Ref::JNIType Forget() - { - const auto obj = Ctx::Get(); - Ctx::mInstance = nullptr; - return obj; - } - - LocalRef<Cls>& operator=(LocalRef<Cls> ref) - { - return swap(ref); - } - - LocalRef<Cls>& operator=(const Ref& ref) - { - LocalRef<Cls> newRef(Ctx::mEnv, ref); - return swap(newRef); - } - - LocalRef<Cls>& operator=(LocalRef<GenericObject>&& ref) - { - LocalRef<Cls> newRef(mozilla::Move(ref)); - return swap(newRef); - } - - template<class C> - LocalRef<Cls>& operator=(GenericLocalRef<C>&& ref) - { - LocalRef<Cls> newRef(mozilla::Move(ref)); - return swap(newRef); - } - - LocalRef<Cls>& operator=(decltype(nullptr)) - { - LocalRef<Cls> newRef(Ctx::mEnv, nullptr); - return swap(newRef); - } -}; - - -template<class Cls> -class GlobalRef : public Cls::Ref -{ - using Ref = typename Cls::Ref; - using JNIType = typename Ref::JNIType; - - static JNIType NewGlobalRef(JNIEnv* env, JNIType instance) - { - return JNIType(instance ? env->NewGlobalRef(instance) : nullptr); - } - - GlobalRef& swap(GlobalRef& other) - { - auto instance = other.mInstance; - other.mInstance = Ref::mInstance; - Ref::mInstance = instance; - return *this; - } - -public: - GlobalRef() - : Ref(nullptr) - {} - - // Copy constructor - GlobalRef(const GlobalRef& ref) - : Ref(NewGlobalRef(GetEnvForThread(), ref.mInstance)) - {} - - // Move constructor - GlobalRef(GlobalRef&& ref) - : Ref(ref.mInstance) - { - ref.mInstance = nullptr; - } - - MOZ_IMPLICIT GlobalRef(const Ref& ref) - : Ref(NewGlobalRef(GetEnvForThread(), ref.Get())) - {} - - GlobalRef(JNIEnv* env, const Ref& ref) - : Ref(NewGlobalRef(env, ref.Get())) - {} - - MOZ_IMPLICIT GlobalRef(const LocalRef<Cls>& ref) - : Ref(NewGlobalRef(ref.Env(), ref.Get())) - {} - - // Implicitly converts nullptr to GlobalRef. - MOZ_IMPLICIT GlobalRef(decltype(nullptr)) - : Ref(nullptr) - {} - - ~GlobalRef() - { - if (Ref::mInstance) { - Clear(GetEnvForThread()); - } - } - - // Get the raw JNI reference that can be used as a return value. - // Returns the same JNI type (jobject, jstring, etc.) as the underlying Ref. - typename Ref::JNIType Forget() - { - const auto obj = Ref::Get(); - Ref::mInstance = nullptr; - return obj; - } - - void Clear(JNIEnv* env) - { - if (Ref::mInstance) { - env->DeleteGlobalRef(Ref::mInstance); - Ref::mInstance = nullptr; - } - } - - GlobalRef<Cls>& operator=(GlobalRef<Cls> ref) - { - return swap(ref); - } - - GlobalRef<Cls>& operator=(const Ref& ref) - { - GlobalRef<Cls> newRef(ref); - return swap(newRef); - } - - GlobalRef<Cls>& operator=(const LocalRef<Cls>& ref) - { - GlobalRef<Cls> newRef(ref); - return swap(newRef); - } - - GlobalRef<Cls>& operator=(decltype(nullptr)) - { - GlobalRef<Cls> newRef(nullptr); - return swap(newRef); - } -}; - - -template<class Cls> -class DependentRef : public Cls::Ref -{ - using Ref = typename Cls::Ref; - -public: - DependentRef(typename Ref::JNIType instance) - : Ref(instance) - {} - - DependentRef(const DependentRef& ref) - : Ref(ref.Get()) - {} -}; - - -class StringParam; - -template<> -class TypedObject<jstring> : public ObjectBase<TypedObject<jstring>, jstring> -{ - using Base = ObjectBase<TypedObject<jstring>, jstring>; - -public: - using Param = const StringParam&; - - explicit TypedObject(const Context& ctx) : Base(ctx) {} - - size_t Length() const - { - const size_t ret = Base::Env()->GetStringLength(Base::Instance()); - MOZ_CATCH_JNI_EXCEPTION(Base::Env()); - return ret; - } - - nsString ToString() const - { - const jchar* const str = Base::Env()->GetStringChars( - Base::Instance(), nullptr); - const jsize len = Base::Env()->GetStringLength(Base::Instance()); - - nsString result(reinterpret_cast<const char16_t*>(str), len); - Base::Env()->ReleaseStringChars(Base::Instance(), str); - return result; - } - - nsCString ToCString() const - { - return NS_ConvertUTF16toUTF8(ToString()); - } - - // Convert jstring to a nsString. - operator nsString() const - { - return ToString(); - } - - // Convert jstring to a nsCString. - operator nsCString() const - { - return ToCString(); - } -}; - -// Define a custom parameter type for String, -// which accepts both String::Ref and nsAString/nsACString -class StringParam : public String::Ref -{ - using Ref = String::Ref; - -private: - // Not null if we should delete ref on destruction. - JNIEnv* const mEnv; - - static jstring GetString(JNIEnv* env, const nsAString& str) - { - const jstring result = env->NewString( - reinterpret_cast<const jchar*>(str.BeginReading()), - str.Length()); - MOZ_CATCH_JNI_EXCEPTION(env); - return result; - } - -public: - MOZ_IMPLICIT StringParam(decltype(nullptr)) - : Ref(nullptr) - , mEnv(nullptr) - {} - - MOZ_IMPLICIT StringParam(const Ref& ref) - : Ref(ref.Get()) - , mEnv(nullptr) - {} - - MOZ_IMPLICIT StringParam(const nsAString& str, JNIEnv* env = Ref::FindEnv()) - : Ref(GetString(env, str)) - , mEnv(env) - {} - - MOZ_IMPLICIT StringParam(const char16_t* str, JNIEnv* env = Ref::FindEnv()) - : Ref(GetString(env, nsDependentString(str))) - , mEnv(env) - {} - - MOZ_IMPLICIT StringParam(const nsACString& str, JNIEnv* env = Ref::FindEnv()) - : Ref(GetString(env, NS_ConvertUTF8toUTF16(str))) - , mEnv(env) - {} - - MOZ_IMPLICIT StringParam(const char* str, JNIEnv* env = Ref::FindEnv()) - : Ref(GetString(env, NS_ConvertUTF8toUTF16(str))) - , mEnv(env) - {} - - StringParam(StringParam&& other) - : Ref(other.Get()) - , mEnv(other.mEnv) - { - other.mInstance = nullptr; - } - - ~StringParam() - { - if (mEnv && Get()) { - mEnv->DeleteLocalRef(Get()); - } - } - - operator String::LocalRef() const - { - // We can't return our existing ref because the returned - // LocalRef could be freed first, so we need a new local ref. - return String::LocalRef(mEnv ? mEnv : Ref::FindEnv(), *this); - } -}; - - -namespace detail { - template<typename T> struct TypeAdapter; -} - -// Ref specialization for arrays. -template<typename JNIType, class ElementType> -class ArrayRefBase : public ObjectBase<TypedObject<JNIType>, JNIType> -{ - using Base = ObjectBase<TypedObject<JNIType>, JNIType>; - -public: - explicit ArrayRefBase(const Context<TypedObject<JNIType>, JNIType>& ctx) - : Base(ctx) - {} - - static typename Base::LocalRef New(const ElementType* data, size_t length) { - using JNIElemType = typename detail::TypeAdapter<ElementType>::JNIType; - static_assert(sizeof(ElementType) == sizeof(JNIElemType), - "Size of native type must match size of JNI type"); - JNIEnv* const jenv = mozilla::jni::GetEnvForThread(); - auto result = - (jenv->*detail::TypeAdapter<ElementType>::NewArray)(length); - MOZ_CATCH_JNI_EXCEPTION(jenv); - (jenv->*detail::TypeAdapter<ElementType>::SetArray)( - result, jsize(0), length, - reinterpret_cast<const JNIElemType*>(data)); - MOZ_CATCH_JNI_EXCEPTION(jenv); - return Base::LocalRef::Adopt(jenv, result); - } - - size_t Length() const - { - const size_t ret = Base::Env()->GetArrayLength(Base::Instance()); - MOZ_CATCH_JNI_EXCEPTION(Base::Env()); - return ret; - } - - ElementType GetElement(size_t index) const - { - using JNIElemType = typename detail::TypeAdapter<ElementType>::JNIType; - static_assert(sizeof(ElementType) == sizeof(JNIElemType), - "Size of native type must match size of JNI type"); - - ElementType ret; - (Base::Env()->*detail::TypeAdapter<ElementType>::GetArray)( - Base::Instance(), jsize(index), 1, - reinterpret_cast<JNIElemType*>(&ret)); - MOZ_CATCH_JNI_EXCEPTION(Base::Env()); - return ret; - } - - nsTArray<ElementType> GetElements() const - { - using JNIElemType = typename detail::TypeAdapter<ElementType>::JNIType; - static_assert(sizeof(ElementType) == sizeof(JNIElemType), - "Size of native type must match size of JNI type"); - - const jsize len = size_t(Base::Env()->GetArrayLength(Base::Instance())); - - nsTArray<ElementType> array((size_t(len))); - array.SetLength(size_t(len)); - (Base::Env()->*detail::TypeAdapter<ElementType>::GetArray)( - Base::Instance(), 0, len, - reinterpret_cast<JNIElemType*>(array.Elements())); - return array; - } - - ElementType operator[](size_t index) const - { - return GetElement(index); - } - - operator nsTArray<ElementType>() const - { - return GetElements(); - } -}; - -#define DEFINE_PRIMITIVE_ARRAY_REF(JNIType, ElementType) \ - template<> \ - class TypedObject<JNIType> : public ArrayRefBase<JNIType, ElementType> \ - { \ - public: \ - explicit TypedObject(const Context& ctx) \ - : ArrayRefBase<JNIType, ElementType>(ctx) \ - {} \ - } - -DEFINE_PRIMITIVE_ARRAY_REF(jbooleanArray, bool); -DEFINE_PRIMITIVE_ARRAY_REF(jbyteArray, int8_t); -DEFINE_PRIMITIVE_ARRAY_REF(jcharArray, char16_t); -DEFINE_PRIMITIVE_ARRAY_REF(jshortArray, int16_t); -DEFINE_PRIMITIVE_ARRAY_REF(jintArray, int32_t); -DEFINE_PRIMITIVE_ARRAY_REF(jlongArray, int64_t); -DEFINE_PRIMITIVE_ARRAY_REF(jfloatArray, float); -DEFINE_PRIMITIVE_ARRAY_REF(jdoubleArray, double); - -#undef DEFINE_PRIMITIVE_ARRAY_REF - - -class ByteBuffer : public ObjectBase<ByteBuffer, jobject> -{ -public: - explicit ByteBuffer(const Context& ctx) - : ObjectBase<ByteBuffer, jobject>(ctx) - {} - - static LocalRef New(void* data, size_t capacity) - { - JNIEnv* const env = GetEnvForThread(); - const auto ret = LocalRef::Adopt( - env, env->NewDirectByteBuffer(data, jlong(capacity))); - MOZ_CATCH_JNI_EXCEPTION(env); - return ret; - } - - void* Address() - { - void* const ret = Env()->GetDirectBufferAddress(Instance()); - MOZ_CATCH_JNI_EXCEPTION(Env()); - return ret; - } - - size_t Capacity() - { - const size_t ret = size_t(Env()->GetDirectBufferCapacity(Instance())); - MOZ_CATCH_JNI_EXCEPTION(Env()); - return ret; - } -}; - - -template<> -class TypedObject<jobjectArray> - : public ObjectBase<TypedObject<jobjectArray>, jobjectArray> -{ - using Base = ObjectBase<TypedObject<jobjectArray>, jobjectArray>; - -public: - explicit TypedObject(const Context& ctx) : Base(ctx) {} - - size_t Length() const - { - const size_t ret = Base::Env()->GetArrayLength(Base::Instance()); - MOZ_CATCH_JNI_EXCEPTION(Base::Env()); - return ret; - } - - Object::LocalRef GetElement(size_t index) const - { - auto ret = Object::LocalRef::Adopt( - Base::Env(), Base::Env()->GetObjectArrayElement( - Base::Instance(), jsize(index))); - MOZ_CATCH_JNI_EXCEPTION(Base::Env()); - return ret; - } - - nsTArray<Object::LocalRef> GetElements() const - { - const jsize len = size_t(Base::Env()->GetArrayLength(Base::Instance())); - - nsTArray<Object::LocalRef> array((size_t(len))); - for (jsize i = 0; i < len; i++) { - array.AppendElement(Object::LocalRef::Adopt( - Base::Env(), Base::Env()->GetObjectArrayElement( - Base::Instance(), i))); - MOZ_CATCH_JNI_EXCEPTION(Base::Env()); - } - return array; - } - - Object::LocalRef operator[](size_t index) const - { - return GetElement(index); - } - - operator nsTArray<Object::LocalRef>() const - { - return GetElements(); - } - - void SetElement(size_t index, Object::Param element) const - { - Base::Env()->SetObjectArrayElement( - Base::Instance(), jsize(index), element.Get()); - MOZ_CATCH_JNI_EXCEPTION(Base::Env()); - } -}; - - -// Support conversion from LocalRef<T>* to LocalRef<Object>*: -// LocalRef<Foo> foo; -// Foo::GetFoo(&foo); // error because parameter type is LocalRef<Object>*. -// Foo::GetFoo(ReturnTo(&foo)); // OK because ReturnTo converts the argument. -template<class Cls> -class ReturnToLocal -{ -private: - LocalRef<Cls>* const localRef; - LocalRef<Object> objRef; - -public: - explicit ReturnToLocal(LocalRef<Cls>* ref) : localRef(ref) {} - operator LocalRef<Object>*() { return &objRef; } - - ~ReturnToLocal() - { - if (objRef) { - *localRef = mozilla::Move(objRef); - } - } -}; - -template<class Cls> -ReturnToLocal<Cls> ReturnTo(LocalRef<Cls>* ref) -{ - return ReturnToLocal<Cls>(ref); -} - - -// Support conversion from GlobalRef<T>* to LocalRef<Object/T>*: -// GlobalRef<Foo> foo; -// Foo::GetFoo(&foo); // error because parameter type is LocalRef<Foo>*. -// Foo::GetFoo(ReturnTo(&foo)); // OK because ReturnTo converts the argument. -template<class Cls> -class ReturnToGlobal -{ -private: - GlobalRef<Cls>* const globalRef; - LocalRef<Object> objRef; - LocalRef<Cls> clsRef; - -public: - explicit ReturnToGlobal(GlobalRef<Cls>* ref) : globalRef(ref) {} - operator LocalRef<Object>*() { return &objRef; } - operator LocalRef<Cls>*() { return &clsRef; } - - ~ReturnToGlobal() - { - if (objRef) { - *globalRef = (clsRef = mozilla::Move(objRef)); - } else if (clsRef) { - *globalRef = clsRef; - } - } -}; - -template<class Cls> -ReturnToGlobal<Cls> ReturnTo(GlobalRef<Cls>* ref) -{ - return ReturnToGlobal<Cls>(ref); -} - -} // namespace jni -} // namespace mozilla - -#endif // mozilla_jni_Refs_h__ diff --git a/widget/android/jni/Types.h b/widget/android/jni/Types.h deleted file mode 100644 index a083d3e50..000000000 --- a/widget/android/jni/Types.h +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef mozilla_jni_Types_h__ -#define mozilla_jni_Types_h__ - -#include <jni.h> - -#include "mozilla/jni/Refs.h" - -namespace mozilla { -namespace jni { -namespace detail { - -// TypeAdapter specializations are the interfaces between native/C++ types such -// as int32_t and JNI types such as jint. The template parameter T is the native -// type, and each TypeAdapter specialization can have the following members: -// -// * Call: JNIEnv member pointer for making a method call that returns T. -// * StaticCall: JNIEnv member pointer for making a static call that returns T. -// * Get: JNIEnv member pointer for getting a field of type T. -// * StaticGet: JNIEnv member pointer for getting a static field of type T. -// * Set: JNIEnv member pointer for setting a field of type T. -// * StaticGet: JNIEnv member pointer for setting a static field of type T. -// * ToNative: static function that converts the JNI type to the native type. -// * FromNative: static function that converts the native type to the JNI type. - -template<typename T> struct TypeAdapter; - - -// TypeAdapter<LocalRef<Cls>> applies when jobject is a return value. -template<class Cls> struct TypeAdapter<LocalRef<Cls>> { - using JNIType = typename Cls::Ref::JNIType; - - static constexpr auto Call = &JNIEnv::CallObjectMethodA; - static constexpr auto StaticCall = &JNIEnv::CallStaticObjectMethodA; - static constexpr auto Get = &JNIEnv::GetObjectField; - static constexpr auto StaticGet = &JNIEnv::GetStaticObjectField; - - // Declare instance as jobject because JNI methods return - // jobject even if the return value is really jstring, etc. - static LocalRef<Cls> ToNative(JNIEnv* env, jobject instance) { - return LocalRef<Cls>::Adopt(env, JNIType(instance)); - } - - static JNIType FromNative(JNIEnv*, LocalRef<Cls>&& instance) { - return instance.Forget(); - } -}; - -// clang is picky about function types, including attributes that modify the calling -// convention, lining up. GCC appears to be somewhat less so. -#ifdef __clang__ -#define MOZ_JNICALL_ABI JNICALL -#else -#define MOZ_JNICALL_ABI -#endif - -template<class Cls> constexpr jobject - (JNIEnv::*TypeAdapter<LocalRef<Cls>>::Call)(jobject, jmethodID, jvalue*) MOZ_JNICALL_ABI; -template<class Cls> constexpr jobject - (JNIEnv::*TypeAdapter<LocalRef<Cls>>::StaticCall)(jclass, jmethodID, jvalue*) MOZ_JNICALL_ABI; -template<class Cls> constexpr jobject - (JNIEnv::*TypeAdapter<LocalRef<Cls>>::Get)(jobject, jfieldID); -template<class Cls> constexpr jobject - (JNIEnv::*TypeAdapter<LocalRef<Cls>>::StaticGet)(jclass, jfieldID); - - -// TypeAdapter<Ref<Cls>> applies when jobject is a parameter value. -template<class Cls, typename T> struct TypeAdapter<Ref<Cls, T>> { - using JNIType = typename Ref<Cls, T>::JNIType; - - static constexpr auto Set = &JNIEnv::SetObjectField; - static constexpr auto StaticSet = &JNIEnv::SetStaticObjectField; - - static DependentRef<Cls> ToNative(JNIEnv* env, JNIType instance) { - return DependentRef<Cls>(instance); - } - - static JNIType FromNative(JNIEnv*, const Ref<Cls, T>& instance) { - return instance.Get(); - } -}; - -template<class Cls, typename T> constexpr void - (JNIEnv::*TypeAdapter<Ref<Cls, T>>::Set)(jobject, jfieldID, jobject); -template<class Cls, typename T> constexpr void - (JNIEnv::*TypeAdapter<Ref<Cls, T>>::StaticSet)(jclass, jfieldID, jobject); - - -// jstring has its own Param type. -template<> struct TypeAdapter<StringParam> - : public TypeAdapter<String::Ref> -{}; - -template<class Cls> struct TypeAdapter<const Cls&> - : public TypeAdapter<Cls> -{}; - - -#define DEFINE_PRIMITIVE_TYPE_ADAPTER(NativeType, JNIType, JNIName) \ - \ - template<> struct TypeAdapter<NativeType> { \ - using JNI##Type = JNIType; \ - \ - static constexpr auto Call = &JNIEnv::Call ## JNIName ## MethodA; \ - static constexpr auto StaticCall = &JNIEnv::CallStatic ## JNIName ## MethodA; \ - static constexpr auto Get = &JNIEnv::Get ## JNIName ## Field; \ - static constexpr auto StaticGet = &JNIEnv::GetStatic ## JNIName ## Field; \ - static constexpr auto Set = &JNIEnv::Set ## JNIName ## Field; \ - static constexpr auto StaticSet = &JNIEnv::SetStatic ## JNIName ## Field; \ - static constexpr auto GetArray = &JNIEnv::Get ## JNIName ## ArrayRegion; \ - static constexpr auto SetArray = &JNIEnv::Set ## JNIName ## ArrayRegion; \ - static constexpr auto NewArray = &JNIEnv::New ## JNIName ## Array; \ - \ - static JNIType FromNative(JNIEnv*, NativeType val) { \ - return static_cast<JNIType>(val); \ - } \ - static NativeType ToNative(JNIEnv*, JNIType val) { \ - return static_cast<NativeType>(val); \ - } \ - } - - -DEFINE_PRIMITIVE_TYPE_ADAPTER(bool, jboolean, Boolean); -DEFINE_PRIMITIVE_TYPE_ADAPTER(int8_t, jbyte, Byte); -DEFINE_PRIMITIVE_TYPE_ADAPTER(char16_t, jchar, Char); -DEFINE_PRIMITIVE_TYPE_ADAPTER(int16_t, jshort, Short); -DEFINE_PRIMITIVE_TYPE_ADAPTER(int32_t, jint, Int); -DEFINE_PRIMITIVE_TYPE_ADAPTER(int64_t, jlong, Long); -DEFINE_PRIMITIVE_TYPE_ADAPTER(float, jfloat, Float); -DEFINE_PRIMITIVE_TYPE_ADAPTER(double, jdouble, Double); - -#undef DEFINE_PRIMITIVE_TYPE_ADAPTER - -} // namespace detail - -using namespace detail; - -} // namespace jni -} // namespace mozilla - -#endif // mozilla_jni_Types_h__ diff --git a/widget/android/jni/Utils.cpp b/widget/android/jni/Utils.cpp deleted file mode 100644 index 919588851..000000000 --- a/widget/android/jni/Utils.cpp +++ /dev/null @@ -1,291 +0,0 @@ -#include "Utils.h" -#include "Types.h" - -#include <android/log.h> -#include <pthread.h> - -#include "mozilla/Assertions.h" - -#include "GeneratedJNIWrappers.h" -#include "nsAppShell.h" - -namespace mozilla { -namespace jni { - -namespace detail { - -#define DEFINE_PRIMITIVE_TYPE_ADAPTER(NativeType, JNIType, JNIName, ABIName) \ - \ - constexpr JNIType (JNIEnv::*TypeAdapter<NativeType>::Call) \ - (jobject, jmethodID, jvalue*) MOZ_JNICALL_ABI; \ - constexpr JNIType (JNIEnv::*TypeAdapter<NativeType>::StaticCall) \ - (jclass, jmethodID, jvalue*) MOZ_JNICALL_ABI; \ - constexpr JNIType (JNIEnv::*TypeAdapter<NativeType>::Get) \ - (jobject, jfieldID) ABIName; \ - constexpr JNIType (JNIEnv::*TypeAdapter<NativeType>::StaticGet) \ - (jclass, jfieldID) ABIName; \ - constexpr void (JNIEnv::*TypeAdapter<NativeType>::Set) \ - (jobject, jfieldID, JNIType) ABIName; \ - constexpr void (JNIEnv::*TypeAdapter<NativeType>::StaticSet) \ - (jclass, jfieldID, JNIType) ABIName; \ - constexpr void (JNIEnv::*TypeAdapter<NativeType>::GetArray) \ - (JNIType ## Array, jsize, jsize, JNIType*) - -DEFINE_PRIMITIVE_TYPE_ADAPTER(bool, jboolean, Boolean, /*nothing*/); -DEFINE_PRIMITIVE_TYPE_ADAPTER(int8_t, jbyte, Byte, /*nothing*/); -DEFINE_PRIMITIVE_TYPE_ADAPTER(char16_t, jchar, Char, /*nothing*/); -DEFINE_PRIMITIVE_TYPE_ADAPTER(int16_t, jshort, Short, /*nothing*/); -DEFINE_PRIMITIVE_TYPE_ADAPTER(int32_t, jint, Int, /*nothing*/); -DEFINE_PRIMITIVE_TYPE_ADAPTER(int64_t, jlong, Long, /*nothing*/); -DEFINE_PRIMITIVE_TYPE_ADAPTER(float, jfloat, Float, MOZ_JNICALL_ABI); -DEFINE_PRIMITIVE_TYPE_ADAPTER(double, jdouble, Double, MOZ_JNICALL_ABI); - -#undef DEFINE_PRIMITIVE_TYPE_ADAPTER - -} // namespace detail - -template<> const char ObjectBase<Object, jobject>::name[] = "java/lang/Object"; -template<> const char ObjectBase<TypedObject<jstring>, jstring>::name[] = "java/lang/String"; -template<> const char ObjectBase<TypedObject<jclass>, jclass>::name[] = "java/lang/Class"; -template<> const char ObjectBase<TypedObject<jthrowable>, jthrowable>::name[] = "java/lang/Throwable"; -template<> const char ObjectBase<TypedObject<jbooleanArray>, jbooleanArray>::name[] = "[Z"; -template<> const char ObjectBase<TypedObject<jbyteArray>, jbyteArray>::name[] = "[B"; -template<> const char ObjectBase<TypedObject<jcharArray>, jcharArray>::name[] = "[C"; -template<> const char ObjectBase<TypedObject<jshortArray>, jshortArray>::name[] = "[S"; -template<> const char ObjectBase<TypedObject<jintArray>, jintArray>::name[] = "[I"; -template<> const char ObjectBase<TypedObject<jlongArray>, jlongArray>::name[] = "[J"; -template<> const char ObjectBase<TypedObject<jfloatArray>, jfloatArray>::name[] = "[F"; -template<> const char ObjectBase<TypedObject<jdoubleArray>, jdoubleArray>::name[] = "[D"; -template<> const char ObjectBase<TypedObject<jobjectArray>, jobjectArray>::name[] = "[Ljava/lang/Object;"; -template<> const char ObjectBase<ByteBuffer, jobject>::name[] = "java/nio/ByteBuffer"; - - -JNIEnv* sGeckoThreadEnv; - -namespace { - -JavaVM* sJavaVM; -pthread_key_t sThreadEnvKey; -jclass sOOMErrorClass; -jobject sClassLoader; -jmethodID sClassLoaderLoadClass; -bool sIsFennec; - -void UnregisterThreadEnv(void* env) -{ - if (!env) { - // We were never attached. - return; - } - // The thread may have already been detached. In that case, it's still - // okay to call DetachCurrentThread(); it'll simply return an error. - // However, we must not access | env | because it may be invalid. - MOZ_ASSERT(sJavaVM); - sJavaVM->DetachCurrentThread(); -} - -} // namespace - -void SetGeckoThreadEnv(JNIEnv* aEnv) -{ - MOZ_ASSERT(aEnv); - MOZ_ASSERT(!sGeckoThreadEnv || sGeckoThreadEnv == aEnv); - - if (!sGeckoThreadEnv - && pthread_key_create(&sThreadEnvKey, UnregisterThreadEnv)) { - MOZ_CRASH("Failed to initialize required TLS"); - } - - sGeckoThreadEnv = aEnv; - MOZ_ALWAYS_TRUE(!pthread_setspecific(sThreadEnvKey, aEnv)); - - MOZ_ALWAYS_TRUE(!aEnv->GetJavaVM(&sJavaVM)); - MOZ_ASSERT(sJavaVM); - - sOOMErrorClass = Class::GlobalRef(Class::LocalRef::Adopt( - aEnv->FindClass("java/lang/OutOfMemoryError"))).Forget(); - aEnv->ExceptionClear(); - - sClassLoader = Object::GlobalRef(java::GeckoThread::ClsLoader()).Forget(); - sClassLoaderLoadClass = aEnv->GetMethodID( - Class::LocalRef::Adopt(aEnv->GetObjectClass(sClassLoader)).Get(), - "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;"); - MOZ_ASSERT(sClassLoader && sClassLoaderLoadClass); - - auto geckoAppClass = Class::LocalRef::Adopt( - aEnv->FindClass("org/mozilla/gecko/GeckoApp")); - aEnv->ExceptionClear(); - sIsFennec = !!geckoAppClass; -} - -JNIEnv* GetEnvForThread() -{ - MOZ_ASSERT(sGeckoThreadEnv); - - JNIEnv* env = static_cast<JNIEnv*>(pthread_getspecific(sThreadEnvKey)); - if (env) { - return env; - } - - // We don't have a saved JNIEnv, so try to get one. - // AttachCurrentThread() does the same thing as GetEnv() when a thread is - // already attached, so we don't have to call GetEnv() at all. - if (!sJavaVM->AttachCurrentThread(&env, nullptr)) { - MOZ_ASSERT(env); - MOZ_ALWAYS_TRUE(!pthread_setspecific(sThreadEnvKey, env)); - return env; - } - - MOZ_CRASH("Failed to get JNIEnv for thread"); - return nullptr; // unreachable -} - -bool ThrowException(JNIEnv *aEnv, const char *aClass, - const char *aMessage) -{ - MOZ_ASSERT(aEnv, "Invalid thread JNI env"); - - Class::LocalRef cls = Class::LocalRef::Adopt(aEnv->FindClass(aClass)); - MOZ_ASSERT(cls, "Cannot find exception class"); - - return !aEnv->ThrowNew(cls.Get(), aMessage); -} - -bool HandleUncaughtException(JNIEnv* aEnv) -{ - MOZ_ASSERT(aEnv, "Invalid thread JNI env"); - - if (!aEnv->ExceptionCheck()) { - return false; - } - -#ifdef MOZ_CHECK_JNI - aEnv->ExceptionDescribe(); -#endif - - Throwable::LocalRef e = - Throwable::LocalRef::Adopt(aEnv, aEnv->ExceptionOccurred()); - MOZ_ASSERT(e); - aEnv->ExceptionClear(); - - String::LocalRef stack = java::GeckoAppShell::GetExceptionStackTrace(e); - if (stack && ReportException(aEnv, e.Get(), stack.Get())) { - return true; - } - - aEnv->ExceptionClear(); - java::GeckoAppShell::HandleUncaughtException(e); - - if (NS_WARN_IF(aEnv->ExceptionCheck())) { - aEnv->ExceptionDescribe(); - aEnv->ExceptionClear(); - } - - return true; -} - -bool ReportException(JNIEnv* aEnv, jthrowable aExc, jstring aStack) -{ - bool result = true; - - if (sOOMErrorClass && aEnv->IsInstanceOf(aExc, sOOMErrorClass)) { - NS_ABORT_OOM(0); // Unknown OOM size - } - return result; -} - -namespace { - -jclass sJNIObjectClass; -jfieldID sJNIObjectHandleField; - -bool EnsureJNIObject(JNIEnv* env, jobject instance) { - if (!sJNIObjectClass) { - sJNIObjectClass = Class::GlobalRef(Class::LocalRef::Adopt(GetClassRef( - env, "org/mozilla/gecko/mozglue/JNIObject"))).Forget(); - - sJNIObjectHandleField = env->GetFieldID( - sJNIObjectClass, "mHandle", "J"); - } - - MOZ_ASSERT(env->IsInstanceOf(instance, sJNIObjectClass)); - return true; -} - -} // namespace - -uintptr_t GetNativeHandle(JNIEnv* env, jobject instance) -{ - if (!EnsureJNIObject(env, instance)) { - return 0; - } - - return static_cast<uintptr_t>( - env->GetLongField(instance, sJNIObjectHandleField)); -} - -void SetNativeHandle(JNIEnv* env, jobject instance, uintptr_t handle) -{ - if (!EnsureJNIObject(env, instance)) { - return; - } - - env->SetLongField(instance, sJNIObjectHandleField, - static_cast<jlong>(handle)); -} - -jclass GetClassRef(JNIEnv* aEnv, const char* aClassName) -{ - // First try the default class loader. - auto classRef = Class::LocalRef::Adopt(aEnv, aEnv->FindClass(aClassName)); - - if (!classRef && sClassLoader) { - // If the default class loader failed but we have an app class loader, try that. - // Clear the pending exception from failed FindClass call above. - aEnv->ExceptionClear(); - classRef = Class::LocalRef::Adopt(aEnv, jclass( - aEnv->CallObjectMethod(sClassLoader, sClassLoaderLoadClass, - StringParam(aClassName, aEnv).Get()))); - } - - if (classRef) { - return classRef.Forget(); - } - - __android_log_print( - ANDROID_LOG_ERROR, "Gecko", - ">>> FATAL JNI ERROR! FindClass(className=\"%s\") failed. " - "Did ProGuard optimize away something it shouldn't have?", - aClassName); - aEnv->ExceptionDescribe(); - MOZ_CRASH("Cannot find JNI class"); - return nullptr; -} - -void DispatchToGeckoThread(UniquePtr<AbstractCall>&& aCall) -{ - class AbstractCallEvent : public nsAppShell::Event - { - UniquePtr<AbstractCall> mCall; - - public: - AbstractCallEvent(UniquePtr<AbstractCall>&& aCall) - : mCall(Move(aCall)) - {} - - void Run() override - { - (*mCall)(); - } - }; - - nsAppShell::PostEvent(MakeUnique<AbstractCallEvent>(Move(aCall))); -} - -bool IsFennec() -{ - return sIsFennec; -} - -} // jni -} // mozilla diff --git a/widget/android/jni/Utils.h b/widget/android/jni/Utils.h deleted file mode 100644 index 38e0b6b0c..000000000 --- a/widget/android/jni/Utils.h +++ /dev/null @@ -1,147 +0,0 @@ -#ifndef mozilla_jni_Utils_h__ -#define mozilla_jni_Utils_h__ - -#include <jni.h> - -#include "mozilla/UniquePtr.h" - -#if defined(DEBUG) || !defined(RELEASE_OR_BETA) -#define MOZ_CHECK_JNI -#endif - -#ifdef MOZ_CHECK_JNI -#include <pthread.h> -#include "mozilla/Assertions.h" -#include "APKOpen.h" -#include "MainThreadUtils.h" -#endif - -namespace mozilla { -namespace jni { - -// How exception during a JNI call should be treated. -enum class ExceptionMode -{ - // Abort on unhandled excepion (default). - ABORT, - // Ignore the exception and return to caller. - IGNORE, - // Catch any exception and return a nsresult. - NSRESULT, -}; - -// Thread that a particular JNI call is allowed on. -enum class CallingThread -{ - // Can be called from any thread (default). - ANY, - // Can be called from the Gecko thread. - GECKO, - // Can be called from the Java UI thread. - UI, -}; - -// If and where a JNI call will be dispatched. -enum class DispatchTarget -{ - // Call happens synchronously on the calling thread (default). - CURRENT, - // Call happens synchronously on the calling thread, but the call is - // wrapped in a function object and is passed thru UsesNativeCallProxy. - // Method must return void. - PROXY, - // Call is dispatched asynchronously on the Gecko thread. Method must - // return void. - GECKO, -}; - - -extern JNIEnv* sGeckoThreadEnv; - -inline bool IsAvailable() -{ - return !!sGeckoThreadEnv; -} - -inline JNIEnv* GetGeckoThreadEnv() -{ -#ifdef MOZ_CHECK_JNI - MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Must be on Gecko thread"); - MOZ_RELEASE_ASSERT(sGeckoThreadEnv, "Must have a JNIEnv"); -#endif - return sGeckoThreadEnv; -} - -void SetGeckoThreadEnv(JNIEnv* aEnv); - -JNIEnv* GetEnvForThread(); - -#ifdef MOZ_CHECK_JNI -#define MOZ_ASSERT_JNI_THREAD(thread) \ - do { \ - if ((thread) == mozilla::jni::CallingThread::GECKO) { \ - MOZ_RELEASE_ASSERT(::NS_IsMainThread()); \ - } else if ((thread) == mozilla::jni::CallingThread::UI) { \ - const bool isOnUiThread = ::pthread_equal(::pthread_self(), \ - ::getJavaUiThread()); \ - MOZ_RELEASE_ASSERT(isOnUiThread); \ - } \ - } while (0) -#else -#define MOZ_ASSERT_JNI_THREAD(thread) do {} while (0) -#endif - -bool ThrowException(JNIEnv *aEnv, const char *aClass, - const char *aMessage); - -inline bool ThrowException(JNIEnv *aEnv, const char *aMessage) -{ - return ThrowException(aEnv, "java/lang/Exception", aMessage); -} - -inline bool ThrowException(const char *aClass, const char *aMessage) -{ - return ThrowException(GetEnvForThread(), aClass, aMessage); -} - -inline bool ThrowException(const char *aMessage) -{ - return ThrowException(GetEnvForThread(), aMessage); -} - -bool HandleUncaughtException(JNIEnv* aEnv); - -bool ReportException(JNIEnv* aEnv, jthrowable aExc, jstring aStack); - -#define MOZ_CATCH_JNI_EXCEPTION(env) \ - do { \ - if (mozilla::jni::HandleUncaughtException((env))) { \ - MOZ_CRASH("JNI exception"); \ - } \ - } while (0) - - -uintptr_t GetNativeHandle(JNIEnv* env, jobject instance); - -void SetNativeHandle(JNIEnv* env, jobject instance, uintptr_t handle); - -jclass GetClassRef(JNIEnv* aEnv, const char* aClassName); - -struct AbstractCall -{ - virtual ~AbstractCall() {} - virtual void operator()() = 0; -}; - -void DispatchToGeckoThread(UniquePtr<AbstractCall>&& aCall); - -/** - * Returns whether Gecko is running in a Fennec environment, as determined by - * the presence of the GeckoApp class. - */ -bool IsFennec(); - -} // jni -} // mozilla - -#endif // mozilla_jni_Utils_h__ diff --git a/widget/android/jni/moz.build b/widget/android/jni/moz.build deleted file mode 100644 index 31d7d32e6..000000000 --- a/widget/android/jni/moz.build +++ /dev/null @@ -1,24 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -EXPORTS.mozilla.jni += [ - 'Accessors.h', - 'Natives.h', - 'Refs.h', - 'Types.h', - 'Utils.h', -] - -UNIFIED_SOURCES += [ - 'Utils.cpp', -] - -FINAL_LIBRARY = 'xul' - -LOCAL_INCLUDES += [ - '/widget', - '/widget/android', -] |