diff options
Diffstat (limited to '')
-rw-r--r-- | netwerk/ipc/SocketProcessBridgeChild.cpp | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/netwerk/ipc/SocketProcessBridgeChild.cpp b/netwerk/ipc/SocketProcessBridgeChild.cpp new file mode 100644 index 0000000000..4fb5a0990c --- /dev/null +++ b/netwerk/ipc/SocketProcessBridgeChild.cpp @@ -0,0 +1,196 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SocketProcessBridgeChild.h" +#include "SocketProcessLogging.h" + +#include "mozilla/AppShutdown.h" +#include "mozilla/dom/ContentChild.h" +#include "mozilla/ipc/BackgroundChild.h" +#include "mozilla/ipc/Endpoint.h" +#include "mozilla/net/NeckoChild.h" +#include "nsIObserverService.h" +#include "nsThreadUtils.h" +#include "mozilla/Preferences.h" +#include "mozilla/StaticPrefs_network.h" + +namespace mozilla { + +using dom::ContentChild; + +namespace net { + +StaticRefPtr<SocketProcessBridgeChild> + SocketProcessBridgeChild::sSocketProcessBridgeChild; + +NS_IMPL_ISUPPORTS(SocketProcessBridgeChild, nsIObserver) + +// static +bool SocketProcessBridgeChild::Create( + Endpoint<PSocketProcessBridgeChild>&& aEndpoint) { + MOZ_ASSERT(NS_IsMainThread()); + + sSocketProcessBridgeChild = + new SocketProcessBridgeChild(std::move(aEndpoint)); + if (sSocketProcessBridgeChild->Inited()) { + mozilla::ipc::BackgroundChild::InitSocketBridgeStarter( + sSocketProcessBridgeChild); + return true; + } + + sSocketProcessBridgeChild = nullptr; + return false; +} + +// static +already_AddRefed<SocketProcessBridgeChild> +SocketProcessBridgeChild::GetSingleton() { + RefPtr<SocketProcessBridgeChild> child = sSocketProcessBridgeChild; + return child.forget(); +} + +// static +RefPtr<SocketProcessBridgeChild::GetPromise> +SocketProcessBridgeChild::GetSocketProcessBridge() { + MOZ_ASSERT(NS_IsMainThread()); + + if (!StaticPrefs::network_process_enabled()) { + return GetPromise::CreateAndReject(nsCString("Socket process disabled!"), + __func__); + } + + if (!gNeckoChild) { + return GetPromise::CreateAndReject(nsCString("No NeckoChild!"), __func__); + } + + // ContentChild is shutting down, we should not try to create + // SocketProcessBridgeChild. + ContentChild* content = ContentChild::GetSingleton(); + if (!content || content->IsShuttingDown()) { + return GetPromise::CreateAndReject( + nsCString("ContentChild is shutting down."), __func__); + } + + if (sSocketProcessBridgeChild) { + return GetPromise::CreateAndResolve(sSocketProcessBridgeChild, __func__); + } + + return gNeckoChild->SendInitSocketProcessBridge()->Then( + GetMainThreadSerialEventTarget(), __func__, + [](NeckoChild::InitSocketProcessBridgePromise::ResolveOrRejectValue&& + aResult) { + ContentChild* content = ContentChild::GetSingleton(); + if (!content || content->IsShuttingDown()) { + return GetPromise::CreateAndReject( + nsCString("ContentChild is shutting down."), __func__); + } + if (!sSocketProcessBridgeChild) { + if (aResult.IsReject()) { + return GetPromise::CreateAndReject( + nsCString("SendInitSocketProcessBridge failed"), __func__); + } + + if (!aResult.ResolveValue().IsValid()) { + return GetPromise::CreateAndReject( + nsCString( + "SendInitSocketProcessBridge resolved with an invalid " + "endpoint!"), + __func__); + } + + if (!SocketProcessBridgeChild::Create( + std::move(aResult.ResolveValue()))) { + return GetPromise::CreateAndReject( + nsCString("SendInitSocketProcessBridge resolved with a valid " + "endpoint, " + "but SocketProcessBridgeChild::Create failed!"), + __func__); + } + } + + return GetPromise::CreateAndResolve(sSocketProcessBridgeChild, + __func__); + }); +} + +SocketProcessBridgeChild::SocketProcessBridgeChild( + Endpoint<PSocketProcessBridgeChild>&& aEndpoint) + : mShuttingDown(false) { + LOG(("CONSTRUCT SocketProcessBridgeChild::SocketProcessBridgeChild\n")); + + mInited = aEndpoint.Bind(this); + if (!mInited) { + MOZ_ASSERT(false, "Bind failed!"); + return; + } + + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); + if (os) { + os->AddObserver(this, "content-child-shutdown", false); + } + + mSocketProcessPid = aEndpoint.OtherPid(); +} + +SocketProcessBridgeChild::~SocketProcessBridgeChild() { + LOG(("DESTRUCT SocketProcessBridgeChild::SocketProcessBridgeChild\n")); +} + +mozilla::ipc::IPCResult SocketProcessBridgeChild::RecvTest() { + LOG(("SocketProcessBridgeChild::RecvTest\n")); + return IPC_OK(); +} + +void SocketProcessBridgeChild::ActorDestroy(ActorDestroyReason aWhy) { + LOG(("SocketProcessBridgeChild::ActorDestroy\n")); + if (AbnormalShutdown == aWhy) { + if (gNeckoChild && + !AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) { + // Let NeckoParent know that the socket process connections must be + // rebuilt. + gNeckoChild->SendResetSocketProcessBridge(); + } + + nsresult res; + nsCOMPtr<nsISerialEventTarget> mSTSThread = + do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &res); + if (NS_SUCCEEDED(res) && mSTSThread) { + // This must be called off the main thread. If we don't make this call + // ipc::BackgroundChild::GetOrCreateSocketActorForCurrentThread() will + // return the previous actor that is no longer able to send. This causes + // rebuilding the socket process connections to fail. + MOZ_ALWAYS_SUCCEEDS(mSTSThread->Dispatch(NS_NewRunnableFunction( + "net::SocketProcessBridgeChild::ActorDestroy", + []() { ipc::BackgroundChild::CloseForCurrentThread(); }))); + } + } + + nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); + if (os) { + os->RemoveObserver(this, "content-child-shutdown"); + } + GetCurrentSerialEventTarget()->Dispatch( + NewRunnableMethod("net::SocketProcessBridgeChild::DeferredDestroy", this, + &SocketProcessBridgeChild::DeferredDestroy)); + mShuttingDown = true; +} + +NS_IMETHODIMP +SocketProcessBridgeChild::Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* aData) { + if (!strcmp(aTopic, "content-child-shutdown")) { + PSocketProcessBridgeChild::Close(); + } + return NS_OK; +} + +void SocketProcessBridgeChild::DeferredDestroy() { + MOZ_ASSERT(NS_IsMainThread()); + + sSocketProcessBridgeChild = nullptr; +} + +} // namespace net +} // namespace mozilla |