Bug 1677632 - pt1 - restart the socket process after a crash. r=kershaw,necko-reviewers

This will restart the socket process with a tab refresh or opening
a new tab.

Differential Revision: https://phabricator.services.mozilla.com/D102481
This commit is contained in:
Michael Froman 2021-01-28 16:42:53 +00:00
Родитель 2ff56dfe72
Коммит 98cf76a718
6 изменённых файлов: 65 добавлений и 27 удалений

Просмотреть файл

@ -28,7 +28,10 @@ MediaTransportHandlerIPC::MediaTransportHandlerIPC(
const RefPtr<net::SocketProcessBridgeChild>& aBridge) {
ipc::PBackgroundChild* actor =
ipc::BackgroundChild::GetOrCreateSocketActorForCurrentThread();
if (!actor) {
// An actor that can't send is possible if the socket process has
// crashed but hasn't been reconnected properly. See
// SocketProcessBridgeChild::ActorDestroy for more info.
if (!actor || !actor->CanSend()) {
NS_WARNING(
"MediaTransportHandlerIPC async init failed! Webrtc networking "
"will not work!");

Просмотреть файл

@ -71,7 +71,6 @@ void NeckoChild::InitNeckoChild() {
}
gNeckoChild = cpc->SendPNeckoConstructor();
NS_ASSERTION(gNeckoChild, "PNecko Protocol init failed!");
SocketProcessBridgeChild::GetSocketProcessBridge();
}
}

Просмотреть файл

@ -829,35 +829,50 @@ mozilla::ipc::IPCResult NeckoParent::RecvInitSocketProcessBridge(
InitSocketProcessBridgeResolver&& aResolver) {
MOZ_ASSERT(NS_IsMainThread());
Endpoint<PSocketProcessBridgeChild> invalidEndpoint;
if (NS_WARN_IF(mSocketProcessBridgeInited)) {
aResolver(std::move(invalidEndpoint));
return IPC_OK();
}
// Initing the socket process bridge must be async here in order to
// wait for the socket process launch before executing.
auto task = [self = this, resolver = std::move(aResolver)]() {
Endpoint<PSocketProcessBridgeChild> invalidEndpoint;
if (NS_WARN_IF(self->mSocketProcessBridgeInited)) {
resolver(std::move(invalidEndpoint));
return;
}
SocketProcessParent* parent = SocketProcessParent::GetSingleton();
if (NS_WARN_IF(!parent)) {
aResolver(std::move(invalidEndpoint));
return IPC_OK();
}
SocketProcessParent* parent = SocketProcessParent::GetSingleton();
if (NS_WARN_IF(!parent)) {
resolver(std::move(invalidEndpoint));
return;
}
Endpoint<PSocketProcessBridgeParent> parentEndpoint;
Endpoint<PSocketProcessBridgeChild> childEndpoint;
if (NS_WARN_IF(NS_FAILED(PSocketProcessBridge::CreateEndpoints(
parent->OtherPid(), Manager()->OtherPid(), &parentEndpoint,
&childEndpoint)))) {
aResolver(std::move(invalidEndpoint));
return IPC_OK();
}
Endpoint<PSocketProcessBridgeParent> parentEndpoint;
Endpoint<PSocketProcessBridgeChild> childEndpoint;
if (NS_WARN_IF(NS_FAILED(PSocketProcessBridge::CreateEndpoints(
parent->OtherPid(), self->Manager()->OtherPid(), &parentEndpoint,
&childEndpoint)))) {
resolver(std::move(invalidEndpoint));
return;
}
if (NS_WARN_IF(!parent->SendInitSocketProcessBridgeParent(
Manager()->OtherPid(), std::move(parentEndpoint)))) {
aResolver(std::move(invalidEndpoint));
return IPC_OK();
}
if (NS_WARN_IF(!parent->SendInitSocketProcessBridgeParent(
self->Manager()->OtherPid(), std::move(parentEndpoint)))) {
resolver(std::move(invalidEndpoint));
return;
}
aResolver(std::move(childEndpoint));
mSocketProcessBridgeInited = true;
resolver(std::move(childEndpoint));
self->mSocketProcessBridgeInited = true;
};
gIOService->CallOrWaitForSocketProcess(std::move(task));
return IPC_OK();
}
mozilla::ipc::IPCResult NeckoParent::RecvResetSocketProcessBridge() {
// SendResetSocketProcessBridge is called from
// SocketProcessBridgeChild::ActorDestroy if the socket process
// crashes. This is necessary in order to properly initialize the
// restarted socket process.
mSocketProcessBridgeInited = false;
return IPC_OK();
}

Просмотреть файл

@ -241,6 +241,7 @@ class NeckoParent : public PNeckoParent {
mozilla::ipc::IPCResult RecvInitSocketProcessBridge(
InitSocketProcessBridgeResolver&& aResolver);
mozilla::ipc::IPCResult RecvResetSocketProcessBridge();
mozilla::ipc::IPCResult RecvEnsureHSTSData(
EnsureHSTSDataResolver&& aResolver);

Просмотреть файл

@ -147,6 +147,7 @@ parent:
async InitSocketProcessBridge()
returns (Endpoint<PSocketProcessBridgeChild> endpoint);
async ResetSocketProcessBridge();
async EnsureHSTSData()
returns (bool result);

Просмотреть файл

@ -7,6 +7,7 @@
#include "SocketProcessLogging.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/ipc/BackgroundChild.h"
#include "mozilla/net/NeckoChild.h"
#include "nsIObserverService.h"
#include "nsThreadUtils.h"
@ -151,6 +152,24 @@ mozilla::ipc::IPCResult SocketProcessBridgeChild::RecvTest() {
void SocketProcessBridgeChild::ActorDestroy(ActorDestroyReason aWhy) {
LOG(("SocketProcessBridgeChild::ActorDestroy\n"));
if (gNeckoChild) {
// 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");