Bug 1761182: Improve ContentParent shutdown blocker singletons lifecycles. r=mccr8,smaug,a=dsmith
This patch cleans up the `ContentParent`'s shutdown blocker client usage. It is expected to not change any behavior
in release if not excluding to ever crash on missing singletons. However, it adds lifecycle check asserts in order to
see if we are systematically violating our lifecycle assumptions.
Differential Revision:
https://phabricator.services.mozilla.com/D142082
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -3,16 +3,17 @@
/* 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/. */
#ifdef MOZ_WIDGET_ANDROID
# include "AndroidDecoderModule.h"
#endif
+#include "mozilla/AppShutdown.h"
#include "mozilla/DebugOnly.h"
#include "base/basictypes.h"
#include "base/shared_memory.h"
#include "ContentParent.h"
#include "mozilla/ipc/ProcessUtils.h"
#include "mozilla/CmdLineAndEnvUtils.h"
@@ -3523,47 +3524,69 @@ ContentParent::GetState(nsIPropertyBag**
RemoteTypePrefix(mRemoteType));
*aResult = props.forget().downcast<nsIWritablePropertyBag>().take();
return NS_OK;
}
static StaticRefPtr<nsIAsyncShutdownClient> sXPCOMShutdownClient;
static StaticRefPtr<nsIAsyncShutdownClient> sProfileBeforeChangeClient;
-static void InitClients() {
+static void InitShutdownClients() {
if (!sXPCOMShutdownClient) {
nsresult rv;
nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdownService();
+ if (!svc) {
+ return;
+ }
nsCOMPtr<nsIAsyncShutdownClient> client;
- rv = svc->GetXpcomWillShutdown(getter_AddRefs(client));
- sXPCOMShutdownClient = client.forget();
- ClearOnShutdown(&sXPCOMShutdownClient);
- MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv), "XPCOMShutdown shutdown blocker");
-
- rv = svc->GetProfileBeforeChange(getter_AddRefs(client));
- sProfileBeforeChangeClient = client.forget();
- ClearOnShutdown(&sProfileBeforeChangeClient);
- MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv),
- "profileBeforeChange shutdown blocker");
+ // TODO: It seems as if getPhase from AsyncShutdown.jsm does not check if
+ // we are beyond our phase already. See bug 1762840.
+ if (!AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMWillShutdown)) {
+ rv = svc->GetXpcomWillShutdown(getter_AddRefs(client));
+ if (NS_SUCCEEDED(rv)) {
+ sXPCOMShutdownClient = client.forget();
+ ClearOnShutdown(&sXPCOMShutdownClient);
+ }
+ }
+ if (!AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdown)) {
+ rv = svc->GetProfileBeforeChange(getter_AddRefs(client));
+ if (NS_SUCCEEDED(rv)) {
+ sProfileBeforeChangeClient = client.forget();
+ ClearOnShutdown(&sProfileBeforeChangeClient);
+ }
+ }
}
}
void ContentParent::AddShutdownBlockers() {
- InitClients();
-
- sXPCOMShutdownClient->AddBlocker(
- this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
- sProfileBeforeChangeClient->AddBlocker(
- this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
+ InitShutdownClients();
+ MOZ_ASSERT(sXPCOMShutdownClient);
+ MOZ_ASSERT(sProfileBeforeChangeClient);
+
+ if (sXPCOMShutdownClient) {
+ sXPCOMShutdownClient->AddBlocker(
+ this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
+ }
+ if (sProfileBeforeChangeClient) {
+ sProfileBeforeChangeClient->AddBlocker(
+ this, NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__, u""_ns);
+ }
}
void ContentParent::RemoveShutdownBlockers() {
- Unused << sXPCOMShutdownClient->RemoveBlocker(this);
- Unused << sProfileBeforeChangeClient->RemoveBlocker(this);
+ MOZ_ASSERT(sXPCOMShutdownClient);
+ MOZ_ASSERT(sProfileBeforeChangeClient);
+
+ if (sXPCOMShutdownClient) {
+ Unused << sXPCOMShutdownClient->RemoveBlocker(this);
+ }
+ if (sProfileBeforeChangeClient) {
+ Unused << sProfileBeforeChangeClient->RemoveBlocker(this);
+ }
}
NS_IMETHODIMP
ContentParent::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData) {
if (IsDead() || !mSubprocess) {
return NS_OK;
}