From ec8e681026e2276e9480541075ac88e960aafaed Mon Sep 17 00:00:00 2001 From: Cameron Kaiser Date: Thu, 19 Dec 2019 23:15:52 -0800 Subject: [PATCH] #581: M1047098 M1355576 --- browser/base/content/sanitize.js | 83 +++++++++++++++++--------- dom/storage/DOMStorageManager.cpp | 3 +- dom/storage/DOMStorageObserver.cpp | 12 ++++ dom/workers/ServiceWorkerRegistrar.cpp | 46 ++++++++++++-- 4 files changed, 110 insertions(+), 34 deletions(-) diff --git a/browser/base/content/sanitize.js b/browser/base/content/sanitize.js index a2abe400c..76ea9f9c4 100644 --- a/browser/base/content/sanitize.js +++ b/browser/base/content/sanitize.js @@ -17,8 +17,15 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "DownloadsCommon", "resource:///modules/DownloadsCommon.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch", - "resource://gre/modules/TelemetryStopwatch.jsm"); +//XPCOMUtils.defineLazyModuleGetter(this, "//TelemetryStopwatch", +// "resource://gre/modules///TelemetryStopwatch.jsm"); +XPCOMUtils.defineLazyServiceGetter(this, "serviceWorkerManager", + "@mozilla.org/serviceworkers/manager;1", + "nsIServiceWorkerManager"); +XPCOMUtils.defineLazyServiceGetter(this, "quotaManagerService", + "@mozilla.org/dom/quota-manager-service;1", + "nsIQuotaManagerService"); + function Sanitizer() {} Sanitizer.prototype = { @@ -128,7 +135,7 @@ Sanitizer.prototype = { return deferred.promise; } - TelemetryStopwatch.start("FX_SANITIZE_TOTAL"); + //TelemetryStopwatch.start("FX_SANITIZE_TOTAL"); // Cache the range of times to clear if (this.ignoreTimespan) @@ -139,7 +146,7 @@ Sanitizer.prototype = { let itemCount = Object.keys(itemsToClear).length; let onItemComplete = function() { if (!--itemCount) { - TelemetryStopwatch.finish("FX_SANITIZE_TOTAL"); + //TelemetryStopwatch.finish("FX_SANITIZE_TOTAL"); seenError ? deferred.reject() : deferred.resolve(); } }; @@ -185,7 +192,7 @@ Sanitizer.prototype = { cache: { clear: function () { - TelemetryStopwatch.start("FX_SANITIZE_CACHE"); + //TelemetryStopwatch.start("FX_SANITIZE_CACHE"); var cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]. getService(Ci.nsICacheStorageService); @@ -201,7 +208,7 @@ Sanitizer.prototype = { imageCache.clearCache(false); // true=chrome, false=content } catch(er) {} - TelemetryStopwatch.finish("FX_SANITIZE_CACHE"); + //TelemetryStopwatch.finish("FX_SANITIZE_CACHE"); }, get canClear() @@ -213,8 +220,8 @@ Sanitizer.prototype = { cookies: { clear: function (aCallback) { - TelemetryStopwatch.start("FX_SANITIZE_COOKIES"); - TelemetryStopwatch.start("FX_SANITIZE_COOKIES_2"); + //TelemetryStopwatch.start("FX_SANITIZE_COOKIES"); + //TelemetryStopwatch.start("FX_SANITIZE_COOKIES_2"); var cookieMgr = Components.classes["@mozilla.org/cookiemanager;1"] .getService(Ci.nsICookieManager); @@ -234,7 +241,7 @@ Sanitizer.prototype = { cookieMgr.removeAll(); } - TelemetryStopwatch.finish("FX_SANITIZE_COOKIES_2"); + //TelemetryStopwatch.finish("FX_SANITIZE_COOKIES_2"); // Clear deviceIds. Done asynchronously (returns before complete). let mediaMgr = Components.classes["@mozilla.org/mediaManagerService;1"] @@ -242,11 +249,11 @@ Sanitizer.prototype = { mediaMgr.sanitizeDeviceIds(this.range && this.range[0]); // Clear plugin data. - TelemetryStopwatch.start("FX_SANITIZE_PLUGINS"); + //TelemetryStopwatch.start("FX_SANITIZE_PLUGINS"); this.clearPluginCookies().then( function() { - TelemetryStopwatch.finish("FX_SANITIZE_PLUGINS"); - TelemetryStopwatch.finish("FX_SANITIZE_COOKIES"); + //TelemetryStopwatch.finish("FX_SANITIZE_PLUGINS"); + //TelemetryStopwatch.finish("FX_SANITIZE_COOKIES"); aCallback(); }); return true; @@ -301,10 +308,30 @@ Sanitizer.prototype = { offlineApps: { clear: function () { - TelemetryStopwatch.start("FX_SANITIZE_OFFLINEAPPS"); + // AppCache + //TelemetryStopwatch.start("FX_SANITIZE_OFFLINEAPPS"); Components.utils.import("resource:///modules/offlineAppCache.jsm"); OfflineAppCacheHelper.clear(); - TelemetryStopwatch.finish("FX_SANITIZE_OFFLINEAPPS"); + //TelemetryStopwatch.finish("FX_SANITIZE_OFFLINEAPPS"); + + // LocalStorage + Services.obs.notifyObservers(null, "extension:purge-localStorage", null); + + // ServiceWorkers + // NYI because service workers are disabled + // See bug 1047098 +/* + let serviceWorkers = serviceWorkerManager.getAllRegistrations(); + for (let i = 0; i < serviceWorkers.length; i++) { + let sw = serviceWorkers.queryElementAt(i, Ci.nsIServiceWorkerRegistrationInfo); + let host = sw.principal.URI.host; + serviceWorkerManager.removeAndPropagate(host); + } +*/ + + // QuotaManager + // NYI due to missing getUsage() in quotaManagerService + // See bug 1047098 and bug 1348660 (esp. part 5, but unsure if useable) }, get canClear() @@ -316,7 +343,7 @@ Sanitizer.prototype = { history: { clear: function () { - TelemetryStopwatch.start("FX_SANITIZE_HISTORY"); + //TelemetryStopwatch.start("FX_SANITIZE_HISTORY"); if (this.range) PlacesUtils.history.removeVisitsByTimeframe(this.range[0], this.range[1]); @@ -337,7 +364,7 @@ Sanitizer.prototype = { predictor.reset(); } catch (e) { } - TelemetryStopwatch.finish("FX_SANITIZE_HISTORY"); + //TelemetryStopwatch.finish("FX_SANITIZE_HISTORY"); }, get canClear() @@ -351,7 +378,7 @@ Sanitizer.prototype = { formdata: { clear: function () { - TelemetryStopwatch.start("FX_SANITIZE_FORMDATA"); + //TelemetryStopwatch.start("FX_SANITIZE_FORMDATA"); // Clear undo history of all searchBars var windowManager = Components.classes['@mozilla.org/appshell/window-mediator;1'] @@ -378,7 +405,7 @@ Sanitizer.prototype = { } FormHistory.update(change); - TelemetryStopwatch.finish("FX_SANITIZE_FORMDATA"); + //TelemetryStopwatch.finish("FX_SANITIZE_FORMDATA"); }, canClear : function(aCallback, aArg) @@ -425,7 +452,7 @@ Sanitizer.prototype = { downloads: { clear: function () { - TelemetryStopwatch.start("FX_SANITIZE_DOWNLOADS"); + //TelemetryStopwatch.start("FX_SANITIZE_DOWNLOADS"); Task.spawn(function*() { let filterByTime = null; if (this.range) { @@ -439,9 +466,9 @@ Sanitizer.prototype = { // Clear all completed/cancelled downloads let list = yield Downloads.getList(Downloads.ALL); list.removeFinished(filterByTime); - TelemetryStopwatch.finish("FX_SANITIZE_DOWNLOADS"); + //TelemetryStopwatch.finish("FX_SANITIZE_DOWNLOADS"); }.bind(this)).then(null, error => { - TelemetryStopwatch.finish("FX_SANITIZE_DOWNLOADS"); + //TelemetryStopwatch.finish("FX_SANITIZE_DOWNLOADS"); Components.utils.reportError(error); }); }, @@ -456,7 +483,7 @@ Sanitizer.prototype = { sessions: { clear: function () { - TelemetryStopwatch.start("FX_SANITIZE_SESSIONS"); + //TelemetryStopwatch.start("FX_SANITIZE_SESSIONS"); // clear all auth tokens var sdr = Components.classes["@mozilla.org/security/sdr;1"] @@ -468,7 +495,7 @@ Sanitizer.prototype = { .getService(Components.interfaces.nsIObserverService); os.notifyObservers(null, "net:clear-active-logins", null); - TelemetryStopwatch.finish("FX_SANITIZE_SESSIONS"); + //TelemetryStopwatch.finish("FX_SANITIZE_SESSIONS"); }, get canClear() @@ -480,7 +507,7 @@ Sanitizer.prototype = { siteSettings: { clear: function () { - TelemetryStopwatch.start("FX_SANITIZE_SITESETTINGS"); + //TelemetryStopwatch.start("FX_SANITIZE_SITESETTINGS"); // Clear site-specific permissions like "Allow this site to open popups" // we ignore the "end" range and hope it is now() - none of the @@ -530,7 +557,7 @@ Sanitizer.prototype = { dump("Web Push may not be available.\n"); } - TelemetryStopwatch.finish("FX_SANITIZE_SITESETTINGS"); + //TelemetryStopwatch.finish("FX_SANITIZE_SITESETTINGS"); }, get canClear() @@ -592,7 +619,7 @@ Sanitizer.prototype = { // If/once we get here, we should actually be able to close all windows. - TelemetryStopwatch.start("FX_SANITIZE_OPENWINDOWS"); + //TelemetryStopwatch.start("FX_SANITIZE_OPENWINDOWS"); // First create a new window. We do this first so that on non-mac, we don't // accidentally close the app by closing all the windows. @@ -617,7 +644,7 @@ Sanitizer.prototype = { newWindowOpened = true; // If we're the last thing to happen, invoke callback. if (numWindowsClosing == 0) { - TelemetryStopwatch.finish("FX_SANITIZE_OPENWINDOWS"); + //TelemetryStopwatch.finish("FX_SANITIZE_OPENWINDOWS"); aCallback(); } } @@ -629,7 +656,7 @@ Sanitizer.prototype = { Services.obs.removeObserver(onWindowClosed, "xul-window-destroyed"); // If we're the last thing to happen, invoke callback. if (newWindowOpened) { - TelemetryStopwatch.finish("FX_SANITIZE_OPENWINDOWS"); + //TelemetryStopwatch.finish("FX_SANITIZE_OPENWINDOWS"); aCallback(); } } diff --git a/dom/storage/DOMStorageManager.cpp b/dom/storage/DOMStorageManager.cpp index 1fcba5530..e5432cf62 100644 --- a/dom/storage/DOMStorageManager.cpp +++ b/dom/storage/DOMStorageManager.cpp @@ -490,7 +490,8 @@ nsresult DOMStorageManager::Observe(const char* aTopic, const nsACString& aScopePrefix) { // Clear everything, caches + database - if (!strcmp(aTopic, "cookie-cleared")) { + if (!strcmp(aTopic, "cookie-cleared") || + !strcmp(aTopic, "extension:purge-localStorage-caches")) { ClearCaches(DOMStorageCache::kUnloadComplete, EmptyCString()); return NS_OK; } diff --git a/dom/storage/DOMStorageObserver.cpp b/dom/storage/DOMStorageObserver.cpp index 54ca84016..015fceccf 100644 --- a/dom/storage/DOMStorageObserver.cpp +++ b/dom/storage/DOMStorageObserver.cpp @@ -63,6 +63,7 @@ DOMStorageObserver::Init() obs->AddObserver(sSelf, "browser:purge-domain-data", true); obs->AddObserver(sSelf, "last-pb-context-exited", true); obs->AddObserver(sSelf, "webapps-clear-data", true); + obs->AddObserver(sSelf, "extension:purge-localStorage", true); // Shutdown obs->AddObserver(sSelf, "profile-after-change", true); @@ -223,6 +224,17 @@ DOMStorageObserver::Observe(nsISupports* aSubject, return NS_OK; } + if (!strcmp(aTopic, "extension:purge-localStorage")) { + DOMStorageDBBridge* db = DOMStorageCache::StartDatabase(); + NS_ENSURE_TRUE(db, NS_ERROR_FAILURE); + + db->AsyncClearAll(); + + Notify("extension:purge-localStorage-caches"); + + return NS_OK; + } + // Clear everything (including so and pb data) from caches and database // for the gived domain and subdomains. if (!strcmp(aTopic, "browser:purge-domain-data")) { diff --git a/dom/workers/ServiceWorkerRegistrar.cpp b/dom/workers/ServiceWorkerRegistrar.cpp index b9d06c47d..bb9e0347b 100644 --- a/dom/workers/ServiceWorkerRegistrar.cpp +++ b/dom/workers/ServiceWorkerRegistrar.cpp @@ -634,14 +634,44 @@ ServiceWorkerRegistrar::ProfileStopped() } } - PBackgroundChild* child = BackgroundChild::GetForCurrentThread(); - if (!child) { - return; - } - + // We must set the pointer before potentially entering the fast-path shutdown + // below. bool completed = false; mShutdownCompleteFlag = &completed; + PBackgroundChild* child = BackgroundChild::GetForCurrentThread(); + if (!child) { + // Mutations to the ServiceWorkerRegistrar happen on the PBackground thread, + // issued by the ServiceWorkerManagerService, so the appropriate place to + // trigger shutdown is on that thread. + // + // However, it's quite possible that the PBackground thread was not brought + // into existence for xpcshell tests. We don't cause it to be created + // ourselves for any reason, for example. + // + // In this scenario, we know that: + // - We will receive exactly one call to ourself from BlockShutdown() and + // BlockShutdown() will be called (at most) once. + // - The only way our Shutdown() method gets called is via + // BackgroundParentImpl::RecvShutdownServiceWorkerRegistrar() being + // invoked, which only happens if we get to that send below here that we + // can't get to. + // - All Shutdown() does is set mShuttingDown=true (essential for + // invariants) and invoke MaybeScheduleShutdownCompleted(). + // - Since there is no PBackground thread, mRunnableCounter must be 0 + // because only ScheduleSaveData() increments it and it only runs on the + // background thread, so it cannot have run. And so we would expect + // MaybeScheduleShutdownCompleted() to schedule an invocation of + // ShutdownCompleted on the main thread. + // + // So it's appropriate for us to set mShuttingDown=true (as Shutdown would + // do) and directly invoke ShutdownCompleted() (as Shutdown would indirectly + // do via MaybeScheduleShutdownCompleted). + mShuttingDown = true; + ShutdownCompleted(); + return; + } + child->SendShutdownServiceWorkerRegistrar(); nsCOMPtr thread(do_GetCurrentThread()); @@ -682,6 +712,12 @@ ServiceWorkerRegistrar::Observe(nsISupports* aSubject, const char* aTopic, } if (!strcmp(aTopic, "profile-before-change")) { + // Hygiene; gServiceWorkerRegistrar should still be keeping a reference + // alive well past this phase of shutdown, but it's bad form to drop your + // last potentially owning reference and then make a call that requires you + // to still be alive, especially when you spin a nested event loop. + RefPtr kungFuDeathGrip(this); + nsCOMPtr observerService = services::GetObserverService(); observerService->RemoveObserver(this, "profile-before-change");