From 295a3b1ef4d5aeebe957e30387783efc7a56f5d2 Mon Sep 17 00:00:00 2001 From: Qeole Date: Fri, 25 Jul 2014 13:40:17 +0200 Subject: [PATCH] Bug 1040761 - Re-add state info for experiments async shutdown blocker from bug 1012924. r=gfritzsche --- browser/experiments/Experiments.jsm | 67 +++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/browser/experiments/Experiments.jsm b/browser/experiments/Experiments.jsm index 3f6e5080c87f..872437193c7a 100644 --- a/browser/experiments/Experiments.jsm +++ b/browser/experiments/Experiments.jsm @@ -351,11 +351,28 @@ AlreadyShutdownError.prototype.constructor = AlreadyShutdownError; */ Experiments.Experiments = function (policy=new Experiments.Policy()) { - this._log = Log.repository.getLoggerWithMessagePrefix( - "Browser.Experiments.Experiments", - "Experiments #" + gExperimentsCounter++ + "::"); + let log = Log.repository.getLoggerWithMessagePrefix( + "Browser.Experiments.Experiments", + "Experiments #" + gExperimentsCounter++ + "::"); + + // At the time of this writing, Experiments.jsm has severe + // crashes. For forensics purposes, keep the last few log + // messages in memory and upload them in case of crash. + this._forensicsLogs = []; + this._forensicsLogs.length = 3; + this._log = Object.create(log); + this._log.log = (level, string, params) => { + this._forensicsLogs.shift(); + this._forensicsLogs.push(level + ": " + string); + log.log(level, string, params); + }; + this._log.trace("constructor"); + // Capture the latest error, for forensics purposes. + this._latestError = null; + + this._policy = policy; // This is a Map of (string -> ExperimentEntry), keyed with the experiment id. @@ -405,7 +422,10 @@ Experiments.Experiments.prototype = { gPrefsTelemetry.observe(PREF_TELEMETRY_ENABLED, this._telemetryStatusChanged, this); - AddonManager.shutdown.addBlocker("Experiments.jsm shutdown", this.uninit.bind(this)); + AddonManager.shutdown.addBlocker("Experiments.jsm shutdown", + this.uninit.bind(this), + this._getState.bind(this) + ); this._registerWithAddonManager(); @@ -419,6 +439,7 @@ Experiments.Experiments.prototype = { }, (e) => { this._log.error("_loadFromCache caught error: " + e); + this._latestError = e; throw e; } ); @@ -462,12 +483,44 @@ Experiments.Experiments.prototype = { yield this._mainTask; } catch (e if e instanceof AlreadyShutdownError) { // We error out of tasks after shutdown via that exception. + } catch (e) { + this._latestError = e; + throw e; } } this._log.info("Completed uninitialization."); }), + // Return state information, for debugging purposes. + _getState: function() { + let state = { + isShutdown: this._shutdown, + isEnabled: gExperimentsEnabled, + isRefresh: this._refresh, + isDirty: this._dirty, + isFirstEvaluate: this._firstEvaluate, + hasLoadTask: !!this._loadTask, + hasMainTask: !!this._mainTask, + hasTimer: !!this._hasTimer, + hasAddonProvider: !!gAddonProvider, + latestLogs: this._forensicsLogs, + experiments: this._experiments.keys(), + terminateReason: this._terminateReason, + }; + if (this._latestError) { + if (typeof this._latestError == "object") { + state.latestError = { + message: this._latestError.message, + stack: this._latestError.stack + }; + } else { + state.latestError = "" + this._latestError; + } + } + return state; + }, + _registerWithAddonManager: function (previousExperimentsProvider) { this._log.trace("Registering instance with Addon Manager."); @@ -493,9 +546,15 @@ Experiments.Experiments.prototype = { _unregisterWithAddonManager: function () { this._log.trace("Unregistering instance with Addon Manager."); + + this._log.trace("Removing install listener from add-on manager."); AddonManager.removeInstallListener(this); + this._log.trace("Removing addon listener from add-on manager."); AddonManager.removeAddonListener(this); + this._log.trace("Finished unregistering with addon manager."); + if (gAddonProvider) { + this._log.trace("Unregistering previous experiment add-on provider."); AddonManagerPrivate.unregisterProvider(gAddonProvider); gAddonProvider = null; }