Bug 1834556 - Have a shutdown blocker for the UserIdleService that disables it during shutdown. r=xpcom-reviewers,kmag

The user idle service should stop notifying any of its listeners once shutdown started as this is at the best unwanted noise and worst case error prone for unexpected side effects.
It should also stop from being able to be newly instantiated during shutdown.

We also change the daily idle service's shutdown awareness to be based on AppShutdown::IsInOrBeyond, removing the now obsolete notification registrations.

Testing: If no existing tests break we are probably fine enough.

Differential Revision: https://phabricator.services.mozilla.com/D178951
This commit is contained in:
Jens Stutte 2023-06-05 08:06:33 +00:00
parent 669b302e69
commit c5a87cfeab
2 changed files with 63 additions and 30 deletions

View file

@ -5,6 +5,8 @@
* 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 "nsError.h"
#include "nsIAsyncShutdown.h"
#include "nsUserIdleService.h"
#include "nsString.h"
#include "nsIObserverService.h"
@ -14,6 +16,7 @@
#include "prinrval.h"
#include "mozilla/Logging.h"
#include "prtime.h"
#include "mozilla/AppShutdown.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/Services.h"
#include "mozilla/Preferences.h"
@ -63,22 +66,13 @@ NS_IMPL_ISUPPORTS(nsUserIdleServiceDaily, nsIObserver, nsISupportsWeakReference)
NS_IMETHODIMP
nsUserIdleServiceDaily::Observe(nsISupports*, const char* aTopic,
const char16_t*) {
auto shutdownInProgress =
AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed);
MOZ_LOG(sLog, LogLevel::Debug,
("nsUserIdleServiceDaily: Observe '%s' (%d)", aTopic,
mShutdownInProgress));
shutdownInProgress));
if (strcmp(aTopic, "profile-after-change") == 0) {
// We are back. Start sending notifications again.
mShutdownInProgress = false;
return NS_OK;
}
if (strcmp(aTopic, "xpcom-will-shutdown") == 0 ||
strcmp(aTopic, "profile-change-teardown") == 0) {
mShutdownInProgress = true;
}
if (mShutdownInProgress || strcmp(aTopic, OBSERVER_TOPIC_ACTIVE) == 0) {
if (shutdownInProgress || strcmp(aTopic, OBSERVER_TOPIC_ACTIVE) == 0) {
return NS_OK;
}
MOZ_ASSERT(strcmp(aTopic, OBSERVER_TOPIC_IDLE) == 0);
@ -144,7 +138,6 @@ nsUserIdleServiceDaily::nsUserIdleServiceDaily(nsIUserIdleService* aIdleService)
: mIdleService(aIdleService),
mTimer(NS_NewTimer()),
mCategoryObservers(OBSERVER_TOPIC_IDLE_DAILY),
mShutdownInProgress(false),
mExpectedTriggerTime(0),
mIdleDailyTriggerWait(DAILY_SIGNIFICANT_IDLE_SERVICE_SEC) {}
@ -215,17 +208,6 @@ void nsUserIdleServiceDaily::Init() {
DailyCallback, this, milliSecLeftUntilDaily, nsITimer::TYPE_ONE_SHOT,
"nsUserIdleServiceDaily::Init");
}
// Register for when we should terminate/pause
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
MOZ_LOG(
sLog, LogLevel::Debug,
("nsUserIdleServiceDaily: Registering for system event observers."));
obs->AddObserver(this, "xpcom-will-shutdown", true);
obs->AddObserver(this, "profile-change-teardown", true);
obs->AddObserver(this, "profile-after-change", true);
}
}
nsUserIdleServiceDaily::~nsUserIdleServiceDaily() {
@ -368,10 +350,43 @@ nsUserIdleService* gIdleService;
} // namespace
already_AddRefed<nsUserIdleService> nsUserIdleService::GetInstance() {
// Avoid late instantiation or resurrection during shutdown.
if (AppShutdown::IsInOrBeyond(ShutdownPhase::AppShutdownConfirmed)) {
return nullptr;
}
RefPtr<nsUserIdleService> instance(gIdleService);
return instance.forget();
}
class UserIdleBlocker final : public nsIAsyncShutdownBlocker {
~UserIdleBlocker() = default;
public:
explicit UserIdleBlocker() = default;
NS_IMETHOD
GetName(nsAString& aNameOut) override {
aNameOut = nsLiteralString(u"UserIdleBlocker");
return NS_OK;
}
NS_IMETHOD
BlockShutdown(nsIAsyncShutdownClient* aClient) override {
if (gIdleService) {
gIdleService->SetDisabledForShutdown();
}
aClient->RemoveBlocker(this);
return NS_OK;
}
NS_IMETHOD
GetState(nsIPropertyBag**) override { return NS_OK; }
NS_DECL_ISUPPORTS
};
NS_IMPL_ISUPPORTS(UserIdleBlocker, nsIAsyncShutdownBlocker)
nsUserIdleService::nsUserIdleService()
: mCurrentlySetToTimeoutAt(TimeStamp()),
mIdleObserverCount(0),
@ -383,6 +398,18 @@ nsUserIdleService::nsUserIdleService()
mDailyIdle = new nsUserIdleServiceDaily(this);
mDailyIdle->Init();
}
nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdownService();
MOZ_ASSERT(svc);
nsCOMPtr<nsIAsyncShutdownClient> client;
auto rv = svc->GetQuitApplicationGranted(getter_AddRefs(client));
if (NS_FAILED(rv)) {
// quitApplicationGranted can be undefined in some environments.
rv = svc->GetXpcomWillShutdown(getter_AddRefs(client));
}
MOZ_ASSERT(NS_SUCCEEDED(rv));
client->AddBlocker(new UserIdleBlocker(),
NS_LITERAL_STRING_FROM_CSTRING(__FILE__), __LINE__,
u""_ns);
}
nsUserIdleService::~nsUserIdleService() {
@ -397,6 +424,14 @@ nsUserIdleService::~nsUserIdleService() {
NS_IMPL_ISUPPORTS(nsUserIdleService, nsIUserIdleService,
nsIUserIdleServiceInternal)
void nsUserIdleService::SetDisabledForShutdown() {
SetDisabled(true);
if (mTimer) {
mTimer->Cancel();
mTimer = nullptr;
}
}
NS_IMETHODIMP
nsUserIdleService::AddIdleObserver(nsIObserver* aObserver,
uint32_t aIdleTimeInS) {

View file

@ -92,11 +92,6 @@ class nsUserIdleServiceDaily : public nsIObserver,
*/
nsCategoryCache<nsIObserver> mCategoryObservers;
/**
* Boolean set to true when daily idle notifications should be disabled.
*/
bool mShutdownInProgress;
/**
* Next time we expect an idle-daily timer to fire, in case timers aren't
* very reliable on the platform. Value is in PR_Now microsecond units.
@ -140,6 +135,9 @@ class nsUserIdleService : public nsIUserIdleServiceInternal {
*/
virtual bool PollIdleTime(uint32_t* aIdleTime);
public:
void SetDisabledForShutdown();
private:
/**
* Ensure that the timer is expiring at least at the given time