Bug 1195496 - Implement speculative connection method in GeckoThread; r=snorp
authorJim Chen <nchen@mozilla.com>
Wed, 19 Aug 2015 18:14:47 -0400
changeset 259075 2d89db567a589c0290d89b16e785690e505db27b
parent 259074 6242c04623f1fc5ae7b8aace3e7240ecd7e746db
child 259076 6d5b38d75c5e25b8f667b42402250359969fda9c
push id29268
push userryanvm@gmail.com
push dateTue, 25 Aug 2015 00:37:23 +0000
treeherdermozilla-central@08015770c9d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp
bugs1195496
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 1195496 - Implement speculative connection method in GeckoThread; r=snorp One thing we do in the Fennec CLH is to make a speculative connection based on the URI that's passed in. However, by the time the CLH runs, we're far along into startup, and the advantage of a speculative connection is reduced. This patch implements making speculative connection as a method in GeckoThread, so that Fennec can make a speculative connection without relying on the Fennec CLH.
mobile/android/base/GeckoThread.java
widget/android/GeneratedJNINatives.h
widget/android/GeneratedJNIWrappers.cpp
widget/android/GeneratedJNIWrappers.h
widget/android/nsAppShell.cpp
--- a/mobile/android/base/GeckoThread.java
+++ b/mobile/android/base/GeckoThread.java
@@ -541,9 +541,21 @@ public class GeckoThread extends Thread 
 
     private static boolean checkAndSetState(final State currentState, final State newState) {
         if (!sState.compareAndSet(currentState, newState)) {
             return false;
         }
         flushQueuedNativeCalls(newState);
         return true;
     }
+
+    @WrapForJNI(stubName = "SpeculativeConnect")
+    private static native void speculativeConnectNative(String uri);
+
+    public static void speculativeConnect(final String uri) {
+        // This is almost always called before Gecko loads, so we don't
+        // bother checking here if Gecko is actually loaded or not.
+        // Speculative connection depends on proxy settings,
+        // so the earliest it can happen is after profile is ready.
+        queueNativeCallUntil(State.PROFILE_READY, GeckoThread.class,
+                             "speculativeConnectNative", uri);
+    }
 }
--- a/widget/android/GeneratedJNINatives.h
+++ b/widget/android/GeneratedJNINatives.h
@@ -32,16 +32,31 @@ public:
                 ::template Wrap<&Impl::RequestNativeStack>)
     };
 };
 
 template<class Impl>
 constexpr JNINativeMethod ANRReporter::Natives<Impl>::methods[];
 
 template<class Impl>
+class GeckoThread::Natives : public mozilla::jni::NativeImpl<GeckoThread, Impl>
+{
+public:
+    static constexpr JNINativeMethod methods[] = {
+
+        mozilla::jni::MakeNativeMethod<GeckoThread::SpeculativeConnect_t>(
+                mozilla::jni::NativeStub<GeckoThread::SpeculativeConnect_t, Impl>
+                ::template Wrap<&Impl::SpeculativeConnect>)
+    };
+};
+
+template<class Impl>
+constexpr JNINativeMethod GeckoThread::Natives<Impl>::methods[];
+
+template<class Impl>
 class NativeJSContainer::Natives : public mozilla::jni::NativeImpl<NativeJSContainer, Impl>
 {
 public:
     static constexpr JNINativeMethod methods[] = {
 
         mozilla::jni::MakeNativeMethod<NativeJSContainer::Clone2_t>(
                 mozilla::jni::NativeStub<NativeJSContainer::Clone2_t, Impl>
                 ::template Wrap<&Impl::Clone>),
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -776,16 +776,19 @@ auto GeckoThread::PumpMessageLoop(mozill
 constexpr char GeckoThread::SetState_t::name[];
 constexpr char GeckoThread::SetState_t::signature[];
 
 auto GeckoThread::SetState(mozilla::jni::Object::Param a0) -> void
 {
     return mozilla::jni::Method<SetState_t>::Call(nullptr, nullptr, a0);
 }
 
+constexpr char GeckoThread::SpeculativeConnect_t::name[];
+constexpr char GeckoThread::SpeculativeConnect_t::signature[];
+
 constexpr char GeckoThread::ClsLoader_t::name[];
 constexpr char GeckoThread::ClsLoader_t::signature[];
 
 auto GeckoThread::ClsLoader() -> mozilla::jni::Object::LocalRef
 {
     return mozilla::jni::Field<ClsLoader_t>::Get(nullptr, nullptr);
 }
 
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -1852,16 +1852,32 @@ public:
         static const bool isMultithreaded = false;
         static const mozilla::jni::ExceptionMode exceptionMode =
                 mozilla::jni::ExceptionMode::ABORT;
     };
 
     static auto SetState(mozilla::jni::Object::Param) -> void;
 
 public:
+    struct SpeculativeConnect_t {
+        typedef GeckoThread Owner;
+        typedef void ReturnType;
+        typedef void SetterType;
+        typedef mozilla::jni::Args<
+                mozilla::jni::String::Param> Args;
+        static constexpr char name[] = "speculativeConnectNative";
+        static constexpr char signature[] =
+                "(Ljava/lang/String;)V";
+        static const bool isStatic = true;
+        static const bool isMultithreaded = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+    };
+
+public:
     struct ClsLoader_t {
         typedef GeckoThread Owner;
         typedef mozilla::jni::Object::LocalRef ReturnType;
         typedef mozilla::jni::Object::Param SetterType;
         typedef mozilla::jni::Args<> Args;
         static constexpr char name[] = "clsLoader";
         static constexpr char signature[] =
                 "Ljava/lang/ClassLoader;";
@@ -1887,16 +1903,18 @@ public:
         static const mozilla::jni::ExceptionMode exceptionMode =
                 mozilla::jni::ExceptionMode::ABORT;
     };
 
     static auto MsgQueue() -> mozilla::jni::Object::LocalRef;
 
     static auto MsgQueue(mozilla::jni::Object::Param) -> void;
 
+public:
+    template<class Impl> class Natives;
 };
 
 class GeckoThread::State : public mozilla::jni::Class<State>
 {
 public:
     typedef mozilla::jni::Ref<State> Ref;
     typedef mozilla::jni::LocalRef<State> LocalRef;
     typedef mozilla::jni::GlobalRef<State> GlobalRef;
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -19,27 +19,31 @@
 #include "nsIGeolocationProvider.h"
 #include "nsCacheService.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDOMClientRectList.h"
 #include "nsIDOMClientRect.h"
 #include "nsIDOMWakeLockListener.h"
 #include "nsIPowerManagerService.h"
 #include "nsINetworkLinkService.h"
+#include "nsISpeculativeConnect.h"
+#include "nsIURIFixup.h"
 #include "nsCategoryManagerUtils.h"
+#include "nsCDefaultURIFixup.h"
 
 #include "mozilla/HangMonitor.h"
 #include "mozilla/Services.h"
 #include "mozilla/unused.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Hal.h"
 #include "prenv.h"
 
 #include "AndroidBridge.h"
 #include "AndroidBridgeUtilities.h"
+#include "GeneratedJNINatives.h"
 #include <android/log.h>
 #include <pthread.h>
 #include <wchar.h>
 
 #include "mozilla/dom/ScreenOrientation.h"
 #ifdef MOZ_GAMEPAD
 #include "mozilla/dom/GamepadFunctions.h"
 #include "mozilla/dom/Gamepad.h"
@@ -123,31 +127,83 @@ public:
     return NS_OK;
   }
 };
 
 NS_IMPL_ISUPPORTS(WakeLockListener, nsIDOMMozWakeLockListener)
 nsCOMPtr<nsIPowerManagerService> sPowerManagerService = nullptr;
 StaticRefPtr<WakeLockListener> sWakeLockListener;
 
+namespace {
+
+already_AddRefed<nsIURI>
+ResolveURI(const nsCString& uriStr)
+{
+    nsCOMPtr<nsIIOService> ioServ = do_GetIOService();
+    nsCOMPtr<nsIURI> uri;
+
+    if (NS_SUCCEEDED(ioServ->NewURI(uriStr, nullptr,
+                                    nullptr, getter_AddRefs(uri)))) {
+        return uri.forget();
+    }
+
+    nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID);
+    if (fixup && NS_SUCCEEDED(
+            fixup->CreateFixupURI(uriStr, 0, nullptr, getter_AddRefs(uri)))) {
+        return uri.forget();
+    }
+    return nullptr;
+}
+
+} // namespace
+
+class GeckoThreadNatives final
+    : public widget::GeckoThread::Natives<GeckoThreadNatives>
+{
+public:
+    static void SpeculativeConnect(jni::String::Param uriStr)
+    {
+        if (!NS_IsMainThread()) {
+            // We will be on the main thread if the call was queued on the Java
+            // side during startup. Otherwise, the call was not queued, which
+            // means Gecko is already sufficiently loaded, and we don't really
+            // care about speculative connections at this point.
+            return;
+        }
+
+        nsCOMPtr<nsIIOService> ioServ = do_GetIOService();
+        nsCOMPtr<nsISpeculativeConnect> specConn = do_QueryInterface(ioServ);
+        if (!specConn) {
+            return;
+        }
+
+        nsCOMPtr<nsIURI> uri = ResolveURI(nsCString(uriStr));
+        if (!uri) {
+            return;
+        }
+        specConn->SpeculativeConnect(uri, nullptr);
+    }
+};
+
 nsAppShell::nsAppShell()
     : mQueueLock("nsAppShell.mQueueLock"),
       mCondLock("nsAppShell.mCondLock"),
       mQueueCond(mCondLock, "nsAppShell.mQueueCond"),
       mQueuedViewportEvent(nullptr)
 {
     gAppShell = this;
 
     if (!XRE_IsParentProcess()) {
         return;
     }
 
     if (jni::IsAvailable()) {
         // Initialize JNI and Set the corresponding state in GeckoThread.
         AndroidBridge::ConstructBridge();
+        GeckoThreadNatives::Init();
         mozilla::ANRReporter::Init();
 
         widget::GeckoThread::SetState(widget::GeckoThread::State::JNI_READY());
     }
 
     sPowerManagerService = do_GetService(POWERMANAGERSERVICE_CONTRACTID);
 
     if (sPowerManagerService) {