diff --git a/netwerk/base/nsIOService.cpp b/netwerk/base/nsIOService.cpp index 27268e47e396..7cfdee26a781 100644 --- a/netwerk/base/nsIOService.cpp +++ b/netwerk/base/nsIOService.cpp @@ -1530,7 +1530,7 @@ nsIOService::GetManageOfflineStatus(bool *aManage) { // input argument 'data' is already UTF8'ed nsresult nsIOService::OnNetworkLinkEvent(const char *data) { - if (IsNeckoChild()) { + if (IsNeckoChild() || IsSocketProcessChild()) { // There is nothing IO service could do on the child process // with this at the moment. Feel free to add functionality // here at will, though. diff --git a/netwerk/ipc/NeckoCommon.h b/netwerk/ipc/NeckoCommon.h index 95a652fe81fe..18c3c86af59e 100644 --- a/netwerk/ipc/NeckoCommon.h +++ b/netwerk/ipc/NeckoCommon.h @@ -95,6 +95,11 @@ inline bool IsNeckoChild() { return amChild; } +inline bool IsSocketProcessChild() { + static bool amChild = (XRE_GetProcessType() == GeckoProcessType_Socket); + return amChild; +} + namespace NeckoCommonInternal { extern bool gSecurityDisabled; extern bool gRegisteredBool; diff --git a/netwerk/ipc/PSocketProcess.ipdl b/netwerk/ipc/PSocketProcess.ipdl index 0a39b52598e1..8fad922152ad 100644 --- a/netwerk/ipc/PSocketProcess.ipdl +++ b/netwerk/ipc/PSocketProcess.ipdl @@ -24,6 +24,7 @@ child: bool anonymize, bool minimizeMemoryUsage, MaybeFileDesc DMDFile); + async SetOffline(bool offline); }; } // namespace net diff --git a/netwerk/ipc/SocketProcessChild.cpp b/netwerk/ipc/SocketProcessChild.cpp index e086d1e6df17..ce374cb7e485 100644 --- a/netwerk/ipc/SocketProcessChild.cpp +++ b/netwerk/ipc/SocketProcessChild.cpp @@ -106,5 +106,17 @@ mozilla::ipc::IPCResult SocketProcessChild::RecvRequestMemoryReport( return IPC_OK(); } +mozilla::ipc::IPCResult SocketProcessChild::RecvSetOffline( + const bool& aOffline) { + LOG(("SocketProcessChild::RecvSetOffline aOffline=%d\n", aOffline)); + + nsCOMPtr io(do_GetIOService()); + NS_ASSERTION(io, "IO Service can not be null"); + + io->SetOffline(aOffline); + + return IPC_OK(); +} + } // namespace net } // namespace mozilla diff --git a/netwerk/ipc/SocketProcessChild.h b/netwerk/ipc/SocketProcessChild.h index e4526c954d42..c26abe939b2f 100644 --- a/netwerk/ipc/SocketProcessChild.h +++ b/netwerk/ipc/SocketProcessChild.h @@ -29,6 +29,7 @@ class SocketProcessChild final : public PSocketProcessChild { mozilla::ipc::IPCResult RecvRequestMemoryReport( const uint32_t& generation, const bool& anonymize, const bool& minimizeMemoryUsage, const MaybeFileDesc& DMDFile) override; + mozilla::ipc::IPCResult RecvSetOffline(const bool& aOffline) override; void CleanUp(); diff --git a/netwerk/ipc/SocketProcessHost.cpp b/netwerk/ipc/SocketProcessHost.cpp index e8492d4b5d9c..2f976b51dda9 100644 --- a/netwerk/ipc/SocketProcessHost.cpp +++ b/netwerk/ipc/SocketProcessHost.cpp @@ -4,12 +4,67 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "SocketProcessHost.h" -#include "SocketProcessParent.h" + #include "nsAppRunner.h" +#include "nsIObserverService.h" +#include "SocketProcessParent.h" namespace mozilla { namespace net { +#define NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC "ipc:network:set-offline" + +class OfflineObserver final : public nsIObserver { + public: + NS_DECL_THREADSAFE_ISUPPORTS + explicit OfflineObserver(SocketProcessHost* aProcessHost) + : mProcessHost(aProcessHost) { + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (obs) { + obs->AddObserver(this, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC, false); + } + } + + void Destroy() { + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr obs = mozilla::services::GetObserverService(); + if (obs) { + obs->RemoveObserver(this, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC); + } + mProcessHost = nullptr; + } + + private: + // nsIObserver implementation. + NS_IMETHOD + Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* aData) override { + if (!mProcessHost) { + return NS_OK; + } + + if (!strcmp(aTopic, NS_IPC_IOSERVICE_SET_OFFLINE_TOPIC)) { + NS_ConvertUTF16toUTF8 dataStr(aData); + const char* offline = dataStr.get(); + if (!mProcessHost->IsConnected() || + mProcessHost->GetActor()->SendSetOffline( + !strcmp(offline, "true") ? true : false)) { + return NS_ERROR_NOT_AVAILABLE; + } + } + + return NS_OK; + } + virtual ~OfflineObserver() = default; + + SocketProcessHost* mProcessHost; +}; + +NS_IMPL_ISUPPORTS(OfflineObserver, nsIObserver) + SocketProcessHost::SocketProcessHost(Listener* aListener) : GeckoChildProcessHost(GeckoProcessType_Socket), mListener(aListener), @@ -21,7 +76,15 @@ SocketProcessHost::SocketProcessHost(Listener* aListener) MOZ_COUNT_CTOR(SocketProcessHost); } -SocketProcessHost::~SocketProcessHost() { MOZ_COUNT_DTOR(SocketProcessHost); } +SocketProcessHost::~SocketProcessHost() { + MOZ_COUNT_DTOR(SocketProcessHost); + if (mOfflineObserver) { + RefPtr observer = mOfflineObserver; + NS_DispatchToMainThread( + NS_NewRunnableFunction("SocketProcessHost::DestroyOfflineObserver", + [observer]() { observer->Destroy(); })); + } +} bool SocketProcessHost::Launch() { MOZ_ASSERT(mLaunchPhase == LaunchPhase::Unlaunched); @@ -143,6 +206,16 @@ void SocketProcessHost::InitAfterConnect(bool aSucceeded) { DebugOnly rv = mSocketProcessParent->Open( GetChannel(), base::GetProcId(GetChildProcessHandle())); MOZ_ASSERT(rv); + + nsCOMPtr ioService(do_GetIOService()); + MOZ_ASSERT(ioService, "No IO service?"); + bool offline = false; + DebugOnly result = ioService->GetOffline(&offline); + MOZ_ASSERT(NS_SUCCEEDED(result), "Failed getting offline?"); + + Unused << GetActor()->SendSetOffline(offline); + + mOfflineObserver = new OfflineObserver(this); } if (mListener) { @@ -155,6 +228,10 @@ void SocketProcessHost::Shutdown() { MOZ_ASSERT(NS_IsMainThread()); mListener = nullptr; + if (mOfflineObserver) { + mOfflineObserver->Destroy(); + mOfflineObserver = nullptr; + } if (mSocketProcessParent) { // OnChannelClosed uses this to check if the shutdown was expected or diff --git a/netwerk/ipc/SocketProcessHost.h b/netwerk/ipc/SocketProcessHost.h index 59b1c2f7fddf..59d8e2ee5910 100644 --- a/netwerk/ipc/SocketProcessHost.h +++ b/netwerk/ipc/SocketProcessHost.h @@ -14,6 +14,7 @@ namespace mozilla { namespace net { +class OfflineObserver; class SocketProcessParent; // SocketProcessHost is the "parent process" container for a subprocess handle @@ -101,6 +102,8 @@ class SocketProcessHost final : public mozilla::ipc::GeckoChildProcessHost { // OnProcessUnexpectedShutdown will be invoked. bool mShutdownRequested; bool mChannelClosed; + + RefPtr mOfflineObserver; }; class SocketProcessMemoryReporter : public MemoryReportingProcess {