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.
--- 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)
{