mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
Bug 1157908 - Optimize pumpMessageLoop call to use less JNI; r=snorp
This commit is contained in:
parent
5864b21201
commit
d34c3d89e6
@ -254,7 +254,7 @@ public class GeckoAppShell
|
||||
|
||||
// Initialization methods
|
||||
public static native void registerJavaUiThread();
|
||||
public static native void nativeInit(ClassLoader clsLoader);
|
||||
public static native void nativeInit(ClassLoader clsLoader, MessageQueue msgQueue);
|
||||
|
||||
// helper methods
|
||||
public static native void onResume();
|
||||
@ -264,7 +264,6 @@ public class GeckoAppShell
|
||||
public static void removeObserver(String observerKey) {
|
||||
sendEventToGecko(GeckoEvent.createRemoveObserverEvent(observerKey));
|
||||
}
|
||||
public static native Message getNextMessageFromQueue(MessageQueue queue);
|
||||
public static native void onSurfaceTextureFrameAvailable(Object surfaceTexture, int id);
|
||||
public static native void dispatchMemoryPressure();
|
||||
|
||||
@ -351,7 +350,7 @@ public class GeckoAppShell
|
||||
Looper.myQueue().addIdleHandler(idleHandler);
|
||||
|
||||
// Initialize AndroidBridge.
|
||||
nativeInit(GeckoAppShell.class.getClassLoader());
|
||||
nativeInit(GeckoAppShell.class.getClassLoader(), Looper.myQueue());
|
||||
|
||||
// First argument is the .apk path
|
||||
String combinedArgs = apkPath + " -greomni " + apkPath;
|
||||
@ -2432,13 +2431,8 @@ public class GeckoAppShell
|
||||
}
|
||||
|
||||
@WrapElementForJNI
|
||||
public static boolean pumpMessageLoop() {
|
||||
Handler geckoHandler = ThreadUtils.sGeckoHandler;
|
||||
Message msg = getNextMessageFromQueue(ThreadUtils.sGeckoQueue);
|
||||
|
||||
if (msg == null) {
|
||||
return false;
|
||||
}
|
||||
public static boolean pumpMessageLoop(final Message msg) {
|
||||
final Handler geckoHandler = ThreadUtils.sGeckoHandler;
|
||||
|
||||
if (msg.obj == geckoHandler && msg.getTarget() == geckoHandler) {
|
||||
// Our "queue is empty" message; see runGecko()
|
||||
|
@ -156,7 +156,6 @@ public class GeckoThread extends Thread implements GeckoEventListener {
|
||||
Looper.prepare();
|
||||
ThreadUtils.sGeckoThread = this;
|
||||
ThreadUtils.sGeckoHandler = new Handler();
|
||||
ThreadUtils.sGeckoQueue = Looper.myQueue();
|
||||
|
||||
if (mDebugging) {
|
||||
try {
|
||||
|
@ -36,7 +36,6 @@ public final class ThreadUtils {
|
||||
// Once Bug 709230 is resolved we should reconsider this as ProGuard should be able to optimise
|
||||
// this out at compile time.
|
||||
public static Handler sGeckoHandler;
|
||||
public static MessageQueue sGeckoQueue;
|
||||
public static volatile Thread sGeckoThread;
|
||||
|
||||
// Delayed Runnable that resets the Gecko thread priority.
|
||||
|
@ -77,16 +77,16 @@ Java_org_mozilla_gecko_GeckoAppShell_registerJavaUiThread(JNIEnv * arg0, jclass
|
||||
|
||||
#ifdef JNI_STUBS
|
||||
|
||||
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_nativeInit_t)(JNIEnv *, jclass, jobject);
|
||||
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_nativeInit_t)(JNIEnv *, jclass, jobject, jobject);
|
||||
static Java_org_mozilla_gecko_GeckoAppShell_nativeInit_t f_Java_org_mozilla_gecko_GeckoAppShell_nativeInit;
|
||||
extern "C" NS_EXPORT void JNICALL
|
||||
Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv * arg0, jclass arg1, jobject arg2) {
|
||||
Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv * arg0, jclass arg1, jobject arg2, jobject arg3) {
|
||||
if (!f_Java_org_mozilla_gecko_GeckoAppShell_nativeInit) {
|
||||
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
|
||||
"JNI Function called before it was loaded");
|
||||
return ;
|
||||
}
|
||||
f_Java_org_mozilla_gecko_GeckoAppShell_nativeInit(arg0, arg1, arg2);
|
||||
f_Java_org_mozilla_gecko_GeckoAppShell_nativeInit(arg0, arg1, arg2, arg3);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -115,25 +115,6 @@ Java_org_mozilla_gecko_GeckoAppShell_onResume(JNIEnv * arg0, jclass arg1) {
|
||||
|
||||
#ifdef JNI_STUBS
|
||||
|
||||
typedef jobject (*Java_org_mozilla_gecko_GeckoAppShell_getNextMessageFromQueue_t)(JNIEnv *, jclass, jobject);
|
||||
static Java_org_mozilla_gecko_GeckoAppShell_getNextMessageFromQueue_t f_Java_org_mozilla_gecko_GeckoAppShell_getNextMessageFromQueue;
|
||||
extern "C" NS_EXPORT jobject JNICALL
|
||||
Java_org_mozilla_gecko_GeckoAppShell_getNextMessageFromQueue(JNIEnv * arg0, jclass arg1, jobject arg2) {
|
||||
if (!f_Java_org_mozilla_gecko_GeckoAppShell_getNextMessageFromQueue) {
|
||||
arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
|
||||
"JNI Function called before it was loaded");
|
||||
return nullptr;
|
||||
}
|
||||
return f_Java_org_mozilla_gecko_GeckoAppShell_getNextMessageFromQueue(arg0, arg1, arg2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef JNI_BINDINGS
|
||||
xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_getNextMessageFromQueue", &f_Java_org_mozilla_gecko_GeckoAppShell_getNextMessageFromQueue);
|
||||
#endif
|
||||
|
||||
#ifdef JNI_STUBS
|
||||
|
||||
typedef void (*Java_org_mozilla_gecko_GeckoAppShell_onSurfaceTextureFrameAvailable_t)(JNIEnv *, jclass, jobject, jint);
|
||||
static Java_org_mozilla_gecko_GeckoAppShell_onSurfaceTextureFrameAvailable_t f_Java_org_mozilla_gecko_GeckoAppShell_onSurfaceTextureFrameAvailable;
|
||||
extern "C" NS_EXPORT void JNICALL
|
||||
|
@ -150,7 +150,7 @@ jfieldID AndroidBridge::GetStaticFieldID(JNIEnv* env, jclass jClass,
|
||||
}
|
||||
|
||||
void
|
||||
AndroidBridge::ConstructBridge(JNIEnv *jEnv, Object::Param clsLoader)
|
||||
AndroidBridge::ConstructBridge(JNIEnv *jEnv, Object::Param clsLoader, Object::Param msgQueue)
|
||||
{
|
||||
/* NSS hack -- bionic doesn't handle recursive unloads correctly,
|
||||
* because library finalizer functions are called with the dynamic
|
||||
@ -165,6 +165,16 @@ AndroidBridge::ConstructBridge(JNIEnv *jEnv, Object::Param clsLoader)
|
||||
MOZ_ASSERT(!sBridge);
|
||||
sBridge = new AndroidBridge;
|
||||
sBridge->Init(jEnv, clsLoader); // Success or crash
|
||||
|
||||
auto msgQueueClass = ClassObject::LocalRef::Adopt(
|
||||
jEnv, jEnv->GetObjectClass(msgQueue.Get()));
|
||||
sBridge->mMessageQueue = msgQueue;
|
||||
// mMessageQueueNext must not be null
|
||||
sBridge->mMessageQueueNext = GetMethodID(
|
||||
jEnv, msgQueueClass.Get(), "next", "()Landroid/os/Message;");
|
||||
// mMessageQueueMessages may be null (e.g. due to proguard optimization)
|
||||
sBridge->mMessageQueueMessages = jEnv->GetFieldID(
|
||||
msgQueueClass.Get(), "mMessages", "Landroid/os/Message;");
|
||||
}
|
||||
|
||||
void
|
||||
@ -1666,6 +1676,32 @@ AndroidBridge::GetProxyForURI(const nsACString & aSpec,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
AndroidBridge::PumpMessageLoop()
|
||||
{
|
||||
JNIEnv* const env = GetJNIEnv();
|
||||
|
||||
if (mMessageQueueMessages) {
|
||||
auto msg = Object::LocalRef::Adopt(env,
|
||||
env->GetObjectField(mMessageQueue.Get(),
|
||||
mMessageQueueMessages));
|
||||
// if queue.mMessages is null, queue.next() will block, which we don't
|
||||
// want. It turns out to be an order of magnitude more performant to do
|
||||
// this extra check here and block less vs. one fewer checks here and
|
||||
// more blocking.
|
||||
if (!msg) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
auto msg = Object::LocalRef::Adopt(
|
||||
env, env->CallObjectMethod(mMessageQueue.Get(), mMessageQueueNext));
|
||||
if (!msg) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return GeckoAppShell::PumpMessageLoop(msg);
|
||||
}
|
||||
|
||||
/* attribute nsIAndroidBrowserApp browserApp; */
|
||||
NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp)
|
||||
|
@ -133,7 +133,9 @@ public:
|
||||
return pthread_equal(pthread_self(), sJavaUiThread);
|
||||
}
|
||||
|
||||
static void ConstructBridge(JNIEnv *jEnv, jni::Object::Param clsLoader);
|
||||
static void ConstructBridge(JNIEnv *jEnv,
|
||||
jni::Object::Param clsLoader,
|
||||
jni::Object::Param msgQueue);
|
||||
|
||||
static AndroidBridge *Bridge() {
|
||||
return sBridge;
|
||||
@ -314,6 +316,8 @@ public:
|
||||
const int32_t aPort,
|
||||
nsACString & aResult);
|
||||
|
||||
bool PumpMessageLoop();
|
||||
|
||||
// Utility methods.
|
||||
static jstring NewJavaString(JNIEnv* env, const char16_t* string, uint32_t len);
|
||||
static jstring NewJavaString(JNIEnv* env, const nsAString& string);
|
||||
@ -410,6 +414,10 @@ protected:
|
||||
jni::Object::GlobalRef mClassLoader;
|
||||
jmethodID mClassLoaderLoadClass;
|
||||
|
||||
jni::Object::GlobalRef mMessageQueue;
|
||||
jfieldID mMessageQueueMessages;
|
||||
jmethodID mMessageQueueNext;
|
||||
|
||||
// calls we've dlopened from libjnigraphics.so
|
||||
int (* AndroidBitmap_getInfo)(JNIEnv *env, jobject bitmap, void *info);
|
||||
int (* AndroidBitmap_lockPixels)(JNIEnv *env, jobject bitmap, void **buffer);
|
||||
|
@ -65,9 +65,10 @@ Java_org_mozilla_gecko_GeckoAppShell_registerJavaUiThread(JNIEnv *jenv, jclass j
|
||||
}
|
||||
|
||||
NS_EXPORT void JNICALL
|
||||
Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv *jenv, jclass, jobject clsLoader)
|
||||
Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv *jenv, jclass, jobject clsLoader, jobject msgQueue)
|
||||
{
|
||||
AndroidBridge::ConstructBridge(jenv, jni::Object::Ref::From(clsLoader));
|
||||
AndroidBridge::ConstructBridge(
|
||||
jenv, jni::Object::Ref::From(clsLoader), jni::Object::Ref::From(msgQueue));
|
||||
}
|
||||
|
||||
NS_EXPORT void JNICALL
|
||||
@ -854,33 +855,6 @@ Java_org_mozilla_gecko_GeckoAppShell_onFullScreenPluginHidden(JNIEnv* jenv, jcla
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
NS_EXPORT jobject JNICALL
|
||||
Java_org_mozilla_gecko_GeckoAppShell_getNextMessageFromQueue(JNIEnv* jenv, jclass, jobject queue)
|
||||
{
|
||||
static jclass jMessageQueueCls = nullptr;
|
||||
static jfieldID jMessagesField;
|
||||
static jmethodID jNextMethod;
|
||||
if (!jMessageQueueCls) {
|
||||
jMessageQueueCls = (jclass) jenv->NewGlobalRef(jenv->FindClass("android/os/MessageQueue"));
|
||||
jNextMethod = jenv->GetMethodID(jMessageQueueCls, "next", "()Landroid/os/Message;");
|
||||
jMessagesField = jenv->GetFieldID(jMessageQueueCls, "mMessages", "Landroid/os/Message;");
|
||||
}
|
||||
|
||||
if (!jMessageQueueCls || !jNextMethod)
|
||||
return nullptr;
|
||||
|
||||
if (jMessagesField) {
|
||||
jobject msg = jenv->GetObjectField(queue, jMessagesField);
|
||||
// if queue.mMessages is null, queue.next() will block, which we don't want
|
||||
// It turns out to be an order of magnitude more performant to do this extra check here and
|
||||
// block less vs. one fewer checks here and more blocking.
|
||||
if (!msg) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return jenv->CallObjectMethod(queue, jNextMethod);
|
||||
}
|
||||
|
||||
NS_EXPORT void JNICALL
|
||||
Java_org_mozilla_gecko_GeckoAppShell_onSurfaceTextureFrameAvailable(JNIEnv* jenv, jclass, jobject surfaceTexture, jint id)
|
||||
{
|
||||
|
@ -529,9 +529,9 @@ void GeckoAppShell::PerformHapticFeedback(bool a0)
|
||||
constexpr char GeckoAppShell::PumpMessageLoop_t::name[];
|
||||
constexpr char GeckoAppShell::PumpMessageLoop_t::signature[];
|
||||
|
||||
bool GeckoAppShell::PumpMessageLoop()
|
||||
bool GeckoAppShell::PumpMessageLoop(mozilla::jni::Object::Param a0)
|
||||
{
|
||||
return mozilla::jni::Method<PumpMessageLoop_t>::Call(nullptr, nullptr);
|
||||
return mozilla::jni::Method<PumpMessageLoop_t>::Call(nullptr, nullptr, a0);
|
||||
}
|
||||
|
||||
constexpr char GeckoAppShell::RegisterSurfaceTextureFrameListener_t::name[];
|
||||
|
@ -1009,13 +1009,13 @@ public:
|
||||
typedef bool SetterType;
|
||||
static constexpr char name[] = "pumpMessageLoop";
|
||||
static constexpr char signature[] =
|
||||
"()Z";
|
||||
"(Landroid/os/Message;)Z";
|
||||
static const bool isStatic = true;
|
||||
static const bool isMultithreaded = false;
|
||||
static const mozilla::jni::ExceptionMode exceptionMode = mozilla::jni::ExceptionMode::ABORT;
|
||||
};
|
||||
|
||||
static bool PumpMessageLoop();
|
||||
static bool PumpMessageLoop(mozilla::jni::Object::Param);
|
||||
|
||||
public:
|
||||
struct RegisterSurfaceTextureFrameListener_t {
|
||||
|
@ -248,7 +248,7 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
|
||||
// (bug 750713). Looper messages effectively have the lowest
|
||||
// priority because we only process them before we're about to
|
||||
// wait for new events.
|
||||
if (widget::GeckoAppShell::PumpMessageLoop()) {
|
||||
if (AndroidBridge::Bridge()->PumpMessageLoop()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user