1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_jni_Utils_h__
8 #define mozilla_jni_Utils_h__
9 
10 #include <jni.h>
11 
12 #include "nsIRunnable.h"
13 
14 #include "mozilla/UniquePtr.h"
15 
16 #if defined(DEBUG) || !defined(RELEASE_OR_BETA)
17 #  define MOZ_CHECK_JNI
18 #endif
19 
20 #ifdef MOZ_CHECK_JNI
21 #  include <unistd.h>
22 #  include "mozilla/Assertions.h"
23 #  include "APKOpen.h"
24 #  include "MainThreadUtils.h"
25 #endif
26 
27 namespace mozilla {
28 namespace jni {
29 
30 // How exception during a JNI call should be treated.
31 enum class ExceptionMode {
32   // Abort on unhandled excepion (default).
33   ABORT,
34   // Ignore the exception and return to caller.
35   IGNORE,
36   // Catch any exception and return a nsresult.
37   NSRESULT,
38 };
39 
40 // Thread that a particular JNI call is allowed on.
41 enum class CallingThread {
42   // Can be called from any thread (default).
43   ANY,
44   // Can be called from the Gecko thread.
45   GECKO,
46   // Can be called from the Java UI thread.
47   UI,
48 };
49 
50 // If and where a JNI call will be dispatched.
51 enum class DispatchTarget {
52   // Call happens synchronously on the calling thread (default).
53   CURRENT,
54   // Call happens synchronously on the calling thread, but the call is
55   // wrapped in a function object and is passed thru UsesNativeCallProxy.
56   // Method must return void.
57   PROXY,
58   // Call is dispatched asynchronously on the Gecko thread to the XPCOM
59   // (nsThread) event queue. Method must return void.
60   GECKO,
61   // Call is dispatched asynchronously on the Gecko thread to the widget
62   // (nsAppShell) event queue. In most cases, events in the widget event
63   // queue (aka native event queue) are favored over events in the XPCOM
64   // event queue. Method must return void.
65   GECKO_PRIORITY,
66 };
67 
68 extern JavaVM* sJavaVM;
69 extern JNIEnv* sGeckoThreadEnv;
70 
IsAvailable()71 inline bool IsAvailable() { return !!sGeckoThreadEnv; }
72 
GetVM()73 inline JavaVM* GetVM() {
74 #ifdef MOZ_CHECK_JNI
75   MOZ_ASSERT(sJavaVM);
76 #endif
77   return sJavaVM;
78 }
79 
GetGeckoThreadEnv()80 inline JNIEnv* GetGeckoThreadEnv() {
81 #ifdef MOZ_CHECK_JNI
82   MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Must be on Gecko thread");
83   MOZ_RELEASE_ASSERT(sGeckoThreadEnv, "Must have a JNIEnv");
84 #endif
85   return sGeckoThreadEnv;
86 }
87 
88 void SetGeckoThreadEnv(JNIEnv* aEnv);
89 
90 JNIEnv* GetEnvForThread();
91 
92 #ifdef MOZ_CHECK_JNI
93 #  define MOZ_ASSERT_JNI_THREAD(thread)                            \
94     do {                                                           \
95       if ((thread) == mozilla::jni::CallingThread::GECKO) {        \
96         MOZ_RELEASE_ASSERT(::NS_IsMainThread());                   \
97       } else if ((thread) == mozilla::jni::CallingThread::UI) {    \
98         const bool isOnUiThread = (GetUIThreadId() == ::gettid()); \
99         MOZ_RELEASE_ASSERT(isOnUiThread);                          \
100       }                                                            \
101     } while (0)
102 #else
103 #  define MOZ_ASSERT_JNI_THREAD(thread) \
104     do {                                \
105     } while (0)
106 #endif
107 
108 bool ThrowException(JNIEnv* aEnv, const char* aClass, const char* aMessage);
109 
ThrowException(JNIEnv * aEnv,const char * aMessage)110 inline bool ThrowException(JNIEnv* aEnv, const char* aMessage) {
111   return ThrowException(aEnv, "java/lang/Exception", aMessage);
112 }
113 
ThrowException(const char * aClass,const char * aMessage)114 inline bool ThrowException(const char* aClass, const char* aMessage) {
115   return ThrowException(GetEnvForThread(), aClass, aMessage);
116 }
117 
ThrowException(const char * aMessage)118 inline bool ThrowException(const char* aMessage) {
119   return ThrowException(GetEnvForThread(), aMessage);
120 }
121 
122 bool HandleUncaughtException(JNIEnv* aEnv);
123 
124 bool ReportException(JNIEnv* aEnv, jthrowable aExc, jstring aStack);
125 
126 #define MOZ_CATCH_JNI_EXCEPTION(env)                    \
127   do {                                                  \
128     if (mozilla::jni::HandleUncaughtException((env))) { \
129       MOZ_CRASH("JNI exception");                       \
130     }                                                   \
131   } while (0)
132 
133 uintptr_t GetNativeHandle(JNIEnv* env, jobject instance);
134 
135 void SetNativeHandle(JNIEnv* env, jobject instance, uintptr_t handle);
136 
137 jclass GetClassRef(JNIEnv* aEnv, const char* aClassName);
138 
139 void DispatchToGeckoPriorityQueue(already_AddRefed<nsIRunnable> aCall);
140 
141 int GetAPIVersion();
142 
143 pid_t GetUIThreadId();
144 
145 }  // namespace jni
146 }  // namespace mozilla
147 
148 #endif  // mozilla_jni_Utils_h__
149