Bug 786419 - Part 8 - Several improvements to per-app-offline behaviour r=jduell
authorValentin Gosu <valentin.gosu@gmail.com>
Fri, 22 Aug 2014 20:15:00 +0300
changeset 232390 c748712cd1ee62af9ea485449b278af08288b29a
parent 232389 9653d9285cca794827cd6fa55b8ac8dbe1a3354b
child 232391 6898b53b3c11d04f422af9d90a5b9bca378d5ad4
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell
bugs786419
milestone35.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 786419 - Part 8 - Several improvements to per-app-offline behaviour r=jduell Make GetAppId() pure-virtual and add implementation for TCPSocketParent, UDPSocketParent, and one for Necko parent that returns UNKNOWN_APP_ID Change nsIOService to use IsNeckoChild instead of XRE_ method. Include nsThreadUtils.h (for nsRunnable and dispatchToMainThread) and NeckoCommon for IsNeckoChild. Make HttpChannelParent set LOAD_ONLY_FROM_CACHE, LOAD_FROM_CACHE and LOAD_NO_NETWORK_IO when offline.
dom/network/TCPSocketParent.cpp
dom/network/TCPSocketParent.h
dom/network/UDPSocketParent.cpp
dom/network/UDPSocketParent.h
netwerk/base/src/OfflineObserver.cpp
netwerk/base/src/OfflineObserver.h
netwerk/base/src/nsIOService.cpp
netwerk/ipc/NeckoParent.h
netwerk/protocol/http/HttpChannelParent.cpp
--- a/dom/network/TCPSocketParent.cpp
+++ b/dom/network/TCPSocketParent.cpp
@@ -75,36 +75,42 @@ TCPSocketParentBase::TCPSocketParentBase
 TCPSocketParentBase::~TCPSocketParentBase()
 {
   if (mObserver) {
     mObserver->RemoveObserver();
   }
   mozilla::DropJSObjects(this);
 }
 
+uint32_t
+TCPSocketParent::GetAppId()
+{
+  uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
+  const PContentParent *content = Manager()->Manager();
+  const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
+  if (browsers.Length() > 0) {
+    TabParent *tab = static_cast<TabParent*>(browsers[0]);
+    appId = tab->OwnAppId();
+  }
+  return appId;
+};
+
 nsresult
 TCPSocketParent::OfflineNotification(nsISupports *aSubject)
 {
   nsCOMPtr<nsIAppOfflineInfo> info(do_QueryInterface(aSubject));
   if (!info) {
     return NS_OK;
   }
 
   uint32_t targetAppId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
   info->GetAppId(&targetAppId);
 
   // Obtain App ID
-  uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
-  const PContentParent *content = Manager()->Manager();
-  const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
-  if (browsers.Length() > 0) {
-    TabParent *tab = static_cast<TabParent*>(browsers[0]);
-    appId = tab->OwnAppId();
-  }
-
+  uint32_t appId = GetAppId();
   if (appId != targetAppId) {
     return NS_OK;
   }
 
   // If the app is offline, close the socket
   if (mSocket && NS_IsAppOffline(appId)) {
     mSocket->Close();
     mSocket = nullptr;
@@ -150,23 +156,17 @@ TCPSocketParent::RecvOpen(const nsString
   // tests without this loophole.
   if (net::UsingNeckoIPCSecurity() &&
       !AssertAppProcessPermission(Manager()->Manager(), "tcp-socket")) {
     FireInteralError(this, __LINE__);
     return true;
   }
 
   // Obtain App ID
-  uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
-  const PContentParent *content = Manager()->Manager();
-  const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
-  if (browsers.Length() > 0) {
-    TabParent *tab = static_cast<TabParent*>(browsers[0]);
-    appId = tab->OwnAppId();
-  }
+  uint32_t appId = GetAppId();
 
   if (NS_IsAppOffline(appId)) {
     NS_ERROR("Can't open socket because app is offline");
     FireInteralError(this, __LINE__);
     return true;
   }
 
   nsresult rv;
--- a/dom/network/TCPSocketParent.h
+++ b/dom/network/TCPSocketParent.h
@@ -57,16 +57,17 @@ public:
   virtual bool RecvStartTLS() MOZ_OVERRIDE;
   virtual bool RecvSuspend() MOZ_OVERRIDE;
   virtual bool RecvResume() MOZ_OVERRIDE;
   virtual bool RecvClose() MOZ_OVERRIDE;
   virtual bool RecvData(const SendableData& aData,
                         const uint32_t& aTrackingNumber) MOZ_OVERRIDE;
   virtual bool RecvRequestDelete() MOZ_OVERRIDE;
   virtual nsresult OfflineNotification(nsISupports *) MOZ_OVERRIDE;
+  virtual uint32_t GetAppId() MOZ_OVERRIDE;
 
 private:
   virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/network/UDPSocketParent.cpp
+++ b/dom/network/UDPSocketParent.cpp
@@ -44,36 +44,42 @@ UDPSocketParent::OfflineNotification(nsI
   if (!info) {
     return NS_OK;
   }
 
   uint32_t targetAppId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
   info->GetAppId(&targetAppId);
 
   // Obtain App ID
-  uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
-  const PContentParent *content = Manager()->Manager();
-  const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
-  if (browsers.Length() > 0) {
-    TabParent *tab = static_cast<TabParent*>(browsers[0]);
-    appId = tab->OwnAppId();
-  }
-
+  uint32_t appId = GetAppId();
   if (appId != targetAppId) {
     return NS_OK;
   }
 
   // If the app is offline, close the socket
   if (mSocket && NS_IsAppOffline(appId)) {
     mSocket->Close();
   }
 
   return NS_OK;
 }
 
+uint32_t
+UDPSocketParent::GetAppId()
+{
+  uint32_t appId = nsIScriptSecurityManager::UNKNOWN_APP_ID;
+  const PContentParent *content = Manager()->Manager();
+  const InfallibleTArray<PBrowserParent*>& browsers = content->ManagedPBrowserParent();
+  if (browsers.Length() > 0) {
+    TabParent *tab = static_cast<TabParent*>(browsers[0]);
+    appId = tab->OwnAppId();
+  }
+  return appId;
+}
+
 bool
 UDPSocketParent::Init(const nsACString& aFilter)
 {
   if (!aFilter.IsEmpty()) {
     nsAutoCString contractId(NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX);
     contractId.Append(aFilter);
     nsCOMPtr<nsIUDPSocketFilterHandler> filterHandler =
       do_GetService(contractId.get());
--- a/dom/network/UDPSocketParent.h
+++ b/dom/network/UDPSocketParent.h
@@ -36,16 +36,17 @@ public:
   virtual bool RecvClose() MOZ_OVERRIDE;
 
   virtual bool RecvRequestDelete() MOZ_OVERRIDE;
   virtual bool RecvJoinMulticast(const nsCString& aMulticastAddress,
                                  const nsCString& aInterface) MOZ_OVERRIDE;
   virtual bool RecvLeaveMulticast(const nsCString& aMulticastAddress,
                                   const nsCString& aInterface) MOZ_OVERRIDE;
   virtual nsresult OfflineNotification(nsISupports *) MOZ_OVERRIDE;
+  virtual uint32_t GetAppId() MOZ_OVERRIDE;
 
 private:
   virtual ~UDPSocketParent();
 
   virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
   void Send(const InfallibleTArray<uint8_t>& aData, const UDPSocketAddr& aAddr);
   void Send(const InputStreamParams& aStream, const UDPSocketAddr& aAddr);
   nsresult BindInternal(const nsCString& aHost, const uint16_t& aPort,
--- a/netwerk/base/src/OfflineObserver.cpp
+++ b/netwerk/base/src/OfflineObserver.cpp
@@ -84,22 +84,16 @@ OfflineObserver::Observe(nsISupports *aS
 {
   if (mParent &&
       !strcmp(aTopic, NS_IOSERVICE_APP_OFFLINE_STATUS_TOPIC)) {
     mParent->OfflineNotification(aSubject);
   }
   return NS_OK;
 }
 
-uint32_t
-DisconnectableParent::GetAppId()
-{
-  return NECKO_UNKNOWN_APP_ID;
-}
-
 nsresult
 DisconnectableParent::OfflineNotification(nsISupports *aSubject)
 {
   nsCOMPtr<nsIAppOfflineInfo> info(do_QueryInterface(aSubject));
   if (!info) {
     return NS_ERROR_NOT_INITIALIZED;
   }
 
--- a/netwerk/base/src/OfflineObserver.h
+++ b/netwerk/base/src/OfflineObserver.h
@@ -24,17 +24,17 @@ namespace net {
 class DisconnectableParent
 {
 public:
   // This is called on the main thread, by the OfflineObserver.
   // aSubject is of type nsAppOfflineInfo and contains appId and offline mode.
   virtual nsresult OfflineNotification(nsISupports *aSubject);
 
   // GetAppId returns the appId for the app associated with the parent
-  virtual uint32_t GetAppId();
+  virtual uint32_t GetAppId() = 0;
 
   // OfflineDisconnect cancels all existing connections in the parent when
   // the app becomes offline.
   virtual void     OfflineDisconnect() { }
 };
 
 /**
  * This class observes the "network:app-offline-status-changed" topic and calls
--- a/netwerk/base/src/nsIOService.cpp
+++ b/netwerk/base/src/nsIOService.cpp
@@ -34,26 +34,29 @@
 #include "nsINetworkLinkService.h"
 #include "nsPISocketTransportService.h"
 #include "nsAsyncRedirectVerifyHelper.h"
 #include "nsURLHelper.h"
 #include "nsPIDNSService.h"
 #include "nsIProtocolProxyService2.h"
 #include "MainThreadUtils.h"
 #include "nsIWidget.h"
+#include "nsThreadUtils.h"
+#include "mozilla/net/NeckoCommon.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsINetworkManager.h"
 #endif
 
 #if defined(XP_WIN)
 #include "nsNativeConnectionHelper.h"
 #endif
 
 using namespace mozilla;
+using mozilla::net::IsNeckoChild;
 
 #define PORT_PREF_PREFIX           "network.security.ports."
 #define PORT_PREF(x)               PORT_PREF_PREFIX x
 #define AUTODIAL_PREF              "network.autodial-helper.enabled"
 #define MANAGE_OFFLINE_STATUS_PREF "network.manage-offline-status"
 
 // Nb: these have been misnomers since bug 715770 removed the buffer cache.
 // "network.segment.count" and "network.segment.size" would be better names,
@@ -920,21 +923,22 @@ nsIOService::ParsePortList(nsIPrefBranch
 void
 nsIOService::GetPrefBranch(nsIPrefBranch **result)
 {
     *result = nullptr;
     CallGetService(NS_PREFSERVICE_CONTRACTID, result);
 }
 
 // This returns true if wifi-only apps should have connectivity.
+// Always returns false in the child process (should not depend on this method)
 static bool
 IsWifiActive()
 {
     // We don't need to do this check inside the child process
-    if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    if (IsNeckoChild()) {
         return false;
     }
 #ifdef MOZ_WIDGET_GONK
     // On B2G we query the network manager for the active interface
     nsCOMPtr<nsINetworkManager> networkManager =
         do_GetService("@mozilla.org/network/manager;1");
     if (!networkManager) {
         return false;
@@ -1424,17 +1428,17 @@ private:
     int32_t mState;
 };
 
 }
 
 NS_IMETHODIMP
 nsIOService::SetAppOffline(uint32_t aAppId, int32_t aState)
 {
-    NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default,
+    NS_ENSURE_TRUE(!IsNeckoChild(),
                    NS_ERROR_FAILURE);
     NS_ENSURE_TRUE(aAppId != nsIScriptSecurityManager::NO_APP_ID,
                    NS_ERROR_INVALID_ARG);
     NS_ENSURE_TRUE(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
                    NS_ERROR_INVALID_ARG);
 
     if (!NS_IsMainThread()) {
         NS_DispatchToMainThread(new SetAppOfflineMainThread(aAppId, aState));
@@ -1465,16 +1469,17 @@ nsIOService::SetAppOfflineInternal(uint3
     switch (aState) {
     case nsIAppOfflineInfo::OFFLINE:
         mAppsOfflineStatus.Put(aAppId, nsIAppOfflineInfo::OFFLINE);
         if (!offline) {
             NotifyAppOfflineStatus(aAppId, nsIAppOfflineInfo::OFFLINE);
         }
         break;
     case nsIAppOfflineInfo::WIFI_ONLY:
+        MOZ_RELEASE_ASSERT(!IsNeckoChild());
         mAppsOfflineStatus.Put(aAppId, nsIAppOfflineInfo::WIFI_ONLY);
         if (offline && wifiActive) {
             NotifyAppOfflineStatus(aAppId, nsIAppOfflineInfo::ONLINE);
         } else if (!offline && !wifiActive) {
             NotifyAppOfflineStatus(aAppId, nsIAppOfflineInfo::OFFLINE);
         }
         break;
     case nsIAppOfflineInfo::ONLINE:
@@ -1507,16 +1512,17 @@ nsIOService::IsAppOffline(uint32_t aAppI
 
     int32_t state;
     if (mAppsOfflineStatus.Get(aAppId, &state)) {
         switch (state) {
         case nsIAppOfflineInfo::OFFLINE:
             *aResult = true;
             break;
         case nsIAppOfflineInfo::WIFI_ONLY:
+            MOZ_RELEASE_ASSERT(!IsNeckoChild());
             *aResult = !IsWifiActive();
             break;
         default:
             // The app is online by default
             break;
         }
     }
 
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -49,16 +49,17 @@ public:
   static const char*
   CreateChannelLoadContext(const PBrowserOrId& aBrowser,
                            PContentParent* aContent,
                            const SerializedLoadContext& aSerialized,
                            nsCOMPtr<nsILoadContext> &aResult);
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
   virtual nsresult OfflineNotification(nsISupports *) MOZ_OVERRIDE;
+  virtual uint32_t GetAppId() MOZ_OVERRIDE { return NECKO_UNKNOWN_APP_ID; }
   virtual void
   CloneManagees(ProtocolBase* aSource,
               mozilla::ipc::ProtocolCloneContext* aCtx) MOZ_OVERRIDE;
   virtual PCookieServiceParent* AllocPCookieServiceParent() MOZ_OVERRIDE;
   virtual bool
   RecvPCookieServiceConstructor(PCookieServiceParent* aActor) MOZ_OVERRIDE
   {
     return PNeckoParent::RecvPCookieServiceConstructor(aActor);
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -226,16 +226,18 @@ HttpChannelParent::DoAsyncOpen(  const U
   if (appId != NECKO_UNKNOWN_APP_ID &&
       appId != NECKO_NO_APP_ID) {
     gIOService->IsAppOffline(appId, &appOffline);
   }
 
   uint32_t loadFlags = aLoadFlags;
   if (appOffline) {
     loadFlags |= nsICachingChannel::LOAD_ONLY_FROM_CACHE;
+    loadFlags |= nsIRequest::LOAD_FROM_CACHE;
+    loadFlags |= nsICachingChannel::LOAD_NO_NETWORK_IO;
   }
 
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewChannel(getter_AddRefs(channel),
                      uri,
                      requestingPrincipal,
                      aSecurityFlags,
                      aContentPolicyType,
@@ -378,18 +380,22 @@ HttpChannelParent::ConnectChannel(const 
   bool appOffline = false;
   uint32_t appId = GetAppId();
   if (appId != NECKO_UNKNOWN_APP_ID &&
       appId != NECKO_NO_APP_ID) {
     gIOService->IsAppOffline(appId, &appOffline);
   }
 
   if (appOffline) {
-    mChannel->Cancel(NS_ERROR_OFFLINE);
-    mStatus = NS_ERROR_OFFLINE;
+    uint32_t loadFlags;
+    mChannel->GetLoadFlags(&loadFlags);
+    loadFlags |= nsICachingChannel::LOAD_ONLY_FROM_CACHE;
+    loadFlags |= nsIRequest::LOAD_FROM_CACHE;
+    loadFlags |= nsICachingChannel::LOAD_NO_NETWORK_IO;
+    mChannel->SetLoadFlags(loadFlags);
   }
 
   return true;
 }
 
 bool
 HttpChannelParent::RecvSetPriority(const uint16_t& priority)
 {