Bug 1192082 - Iniialize/deinitialize JNI in nsAppShell; r=snorp
authorJim Chen <nchen@mozilla.com>
Thu, 13 Aug 2015 00:53:40 -0400
changeset 290151 2302cc77b4005936917e0295c07921a257ff038d
parent 290150 250e5f0da2477da1abb19ebb38a7fbdd11e95427
child 290152 ba4f1b9b7c0151570a5c6ab0f079d245920917cb
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp
bugs1192082
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1192082 - Iniialize/deinitialize JNI in nsAppShell; r=snorp First we need to set the Gecko thread JNIEnv* in nsAndroidStartup, but after that we can initialize and deinitialize the rest of JNI, including AndroidBridge, in GeckoAppShell. This makes nsAppShell control the AndroidBridge lifetime. Over time, parts of the AndroidBridge functionality will be migrated to nsAppShell.
mobile/android/base/GeckoThread.java
mozglue/android/APKOpen.cpp
toolkit/xre/nsAndroidStartup.cpp
widget/android/AndroidBridge.cpp
widget/android/GeneratedJNIWrappers.cpp
widget/android/GeneratedJNIWrappers.h
widget/android/nsAppShell.cpp
--- a/mobile/android/base/GeckoThread.java
+++ b/mobile/android/base/GeckoThread.java
@@ -42,16 +42,18 @@ public class GeckoThread extends Thread 
         // After being loaded by class loader.
         INITIAL,
         // After launching Gecko thread
         LAUNCHED,
         // After loading the mozglue library.
         MOZGLUE_READY,
         // After loading the libxul library.
         LIBS_READY,
+        // After initializing nsAppShell and JNI calls.
+        JNI_READY,
         // After initializing frontend JS (corresponding to "Gecko:Ready" event)
         RUNNING,
         // After leaving Gecko event loop
         EXITING,
         // After exiting GeckoThread (corresponding to "Gecko:Exited" event)
         EXITED;
 
         public boolean is(final State other) {
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -365,34 +365,34 @@ Java_org_mozilla_gecko_mozglue_GeckoLoad
   mozglueresult rv = loadNSSLibs(str);
   if (rv != SUCCESS) {
     JNI_Throw(jenv, "java/lang/Exception", "Error loading nss libraries");
   }
   __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load nss done\n");
   jenv->ReleaseStringUTFChars(jApkName, str);
 }
 
-typedef void (*GeckoStart_t)(void *, const nsXREAppData *);
+typedef void (*GeckoStart_t)(JNIEnv*, char*, const nsXREAppData*);
 
 extern "C" NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jstring jargs)
 {
   GeckoStart_t GeckoStart;
   xul_dlsym("GeckoStart", &GeckoStart);
   if (GeckoStart == nullptr)
     return;
   // XXX: java doesn't give us true UTF8, we should figure out something
   // better to do here
   int len = jenv->GetStringUTFLength(jargs);
   // GeckoStart needs to write in the args buffer, so we need a copy.
   char *args = (char *) malloc(len + 1);
   jenv->GetStringUTFRegion(jargs, 0, len, args);
   args[len] = '\0';
   ElfLoader::Singleton.ExpectShutdown(false);
-  GeckoStart(args, &sAppData);
+  GeckoStart(jenv, args, &sAppData);
   ElfLoader::Singleton.ExpectShutdown(true);
   free(args);
 }
 
 typedef int GeckoProcessType;
 
 extern "C" NS_EXPORT mozglueresult
 ChildProcessInit(int argc, char* argv[])
--- a/toolkit/xre/nsAndroidStartup.cpp
+++ b/toolkit/xre/nsAndroidStartup.cpp
@@ -6,44 +6,47 @@
 #include <android/log.h>
 
 #include <jni.h>
 
 #include <stdlib.h>
 #include <string.h>
 #include <pthread.h>
 
+#include "mozilla/jni/Utils.h"
 #include "nsTArray.h"
 #include "nsString.h"
 #include "nsIFile.h"
 #include "nsAppRunner.h"
 #include "APKOpen.h"
 #include "nsExceptionHandler.h"
 
 #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, MOZ_APP_NAME, args)
 
 extern "C" NS_EXPORT void
-GeckoStart(void *data, const nsXREAppData *appData)
+GeckoStart(JNIEnv* env, char* data, const nsXREAppData* appData)
 {
+    mozilla::jni::SetGeckoThreadEnv(env);
+
 #ifdef MOZ_CRASHREPORTER
     const struct mapping_info *info = getLibraryMapping();
     while (info->name) {
       CrashReporter::AddLibraryMapping(info->name, info->base,
                                        info->len, info->offset);
       info++;
     }
 #endif
 
     if (!data) {
         LOG("Failed to get arguments for GeckoStart\n");
         return;
     }
 
     nsTArray<char *> targs;
-    char *arg = strtok(static_cast<char *>(data), " ");
+    char *arg = strtok(data, " ");
     while (arg) {
         targs.AppendElement(arg);
         arg = strtok(nullptr, " ");
     }
     targs.AppendElement(static_cast<char *>(nullptr));
 
     int result = XRE_main(targs.Length() - 1, targs.Elements(), appData, 0);
 
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -42,18 +42,16 @@
 #include "nsContentUtils.h"
 #include "nsIScriptError.h"
 #include "nsIHttpChannel.h"
 
 #include "MediaCodec.h"
 #include "SurfaceTexture.h"
 #include "GLContextProvider.h"
 
-#include "ANRReporter.h"
-
 using namespace mozilla;
 using namespace mozilla::gfx;
 using namespace mozilla::jni;
 using namespace mozilla::widget;
 
 AndroidBridge* AndroidBridge::sBridge = nullptr;
 pthread_t AndroidBridge::sJavaUiThread;
 static jobject sGlobalContext = nullptr;
@@ -255,17 +253,16 @@ AndroidBridge::AndroidBridge()
     jByteBufferRead = readableByteChannel.getMethod("read", "(Ljava/nio/ByteBuffer;)I");
 
     AutoJNIClass inputStream(jEnv, "java/io/InputStream");
     jInputStream = inputStream.getGlobalRef();
     jClose = inputStream.getMethod("close", "()V");
     jAvailable = inputStream.getMethod("available", "()I");
 
     InitAndroidJavaWrappers(jEnv);
-    ANRReporter::Init();
 }
 
 // Raw JNIEnv variants.
 jstring AndroidBridge::NewJavaString(JNIEnv* env, const char16_t* string, uint32_t len) {
    jstring ret = env->NewString(reinterpret_cast<const jchar*>(string), len);
    if (env->ExceptionCheck()) {
        ALOG_BRIDGE("Exceptional exit of: %s", __PRETTY_FUNCTION__);
        env->ExceptionDescribe();
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -871,16 +871,24 @@ auto GeckoThread::State::EXITING() -> St
 constexpr char GeckoThread::State::INITIAL_t::name[];
 constexpr char GeckoThread::State::INITIAL_t::signature[];
 
 auto GeckoThread::State::INITIAL() -> State::LocalRef
 {
     return mozilla::jni::Field<INITIAL_t>::Get(nullptr, nullptr);
 }
 
+constexpr char GeckoThread::State::JNI_READY_t::name[];
+constexpr char GeckoThread::State::JNI_READY_t::signature[];
+
+auto GeckoThread::State::JNI_READY() -> State::LocalRef
+{
+    return mozilla::jni::Field<JNI_READY_t>::Get(nullptr, nullptr);
+}
+
 constexpr char GeckoThread::State::LAUNCHED_t::name[];
 constexpr char GeckoThread::State::LAUNCHED_t::signature[];
 
 auto GeckoThread::State::LAUNCHED() -> State::LocalRef
 {
     return mozilla::jni::Field<LAUNCHED_t>::Get(nullptr, nullptr);
 }
 
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -2065,16 +2065,33 @@ public:
         static const bool isMultithreaded = true;
         static const mozilla::jni::ExceptionMode exceptionMode =
                 mozilla::jni::ExceptionMode::ABORT;
     };
 
     static auto INITIAL() -> State::LocalRef;
 
 public:
+    struct JNI_READY_t {
+        typedef State Owner;
+        typedef State::LocalRef ReturnType;
+        typedef State::Param SetterType;
+        typedef mozilla::jni::Args<> Args;
+        static constexpr char name[] = "JNI_READY";
+        static constexpr char signature[] =
+                "Lorg/mozilla/gecko/GeckoThread$State;";
+        static const bool isStatic = true;
+        static const bool isMultithreaded = true;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+    };
+
+    static auto JNI_READY() -> State::LocalRef;
+
+public:
     struct LAUNCHED_t {
         typedef State Owner;
         typedef State::LocalRef ReturnType;
         typedef State::Param SetterType;
         typedef mozilla::jni::Args<> Args;
         static constexpr char name[] = "LAUNCHED";
         static constexpr char signature[] =
                 "Lorg/mozilla/gecko/GeckoThread$State;";
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -51,16 +51,18 @@
 #include "nsIURI.h"
 #include "IHistory.h"
 #endif
 
 #ifdef MOZ_LOGGING
 #include "mozilla/Logging.h"
 #endif
 
+#include "ANRReporter.h"
+
 #ifdef DEBUG_ANDROID_EVENTS
 #define EVLOG(args...)  ALOG(args)
 #else
 #define EVLOG(args...) do { } while (0)
 #endif
 
 using namespace mozilla;
 
@@ -141,28 +143,39 @@ nsAppShell::nsAppShell()
     sPowerManagerService = do_GetService(POWERMANAGERSERVICE_CONTRACTID);
 
     if (sPowerManagerService) {
         sWakeLockListener = new WakeLockListener();
     } else {
         NS_WARNING("Failed to retrieve PowerManagerService, wakelocks will be broken!");
     }
 
+    // Initialize JNI and Set the corresponding state in GeckoThread.
+
+    if (!jni::IsAvailable()) {
+        return;
+    }
+    AndroidBridge::ConstructBridge();
+    mozilla::ANRReporter::Init();
+
+    widget::GeckoThread::SetState(widget::GeckoThread::State::JNI_READY());
 }
 
 nsAppShell::~nsAppShell()
 {
     gAppShell = nullptr;
 
     if (sPowerManagerService) {
         sPowerManagerService->RemoveWakeLockListener(sWakeLockListener);
 
         sPowerManagerService = nullptr;
         sWakeLockListener = nullptr;
     }
+
+    AndroidBridge::DeconstructBridge();
 }
 
 void
 nsAppShell::NotifyNativeEvent()
 {
     MutexAutoLock lock(mCondLock);
     mQueueCond.Notify();
 }