Backed out changeset 55f3df15eaa6 (bug 1356569)
authorSebastian Hengst <archaeopteryx@coole-files.de>
Fri, 14 Apr 2017 23:39:17 +0200
changeset 563127 6e76e3e17f3828a6eaa629501ee00ddf7806e1bc
parent 563126 68d33da0be4282e9f0d4203a35699f4b9aea74c9
child 563128 d3ab2d3bdab32c0d2776fe240c01e792367ce5d6
push id54218
push userbmo:mstange@themasta.com
push dateSat, 15 Apr 2017 04:22:40 +0000
bugs1356569
milestone55.0a1
backs out55f3df15eaa6831b76ffe94b9c82c7bdc40c63c9
Backed out changeset 55f3df15eaa6 (bug 1356569)
addon-sdk/source/lib/toolkit/require.js
addon-sdk/source/test/addons/e10s-remote/remote-module.js
addon-sdk/source/test/addons/remote/remote-module.js
b2g/chrome/content/devtools/debugger.js
b2g/chrome/content/shell.js
b2g/components/GlobalSimulatorScreen.jsm
b2g/components/SafeMode.jsm
b2g/components/test/unit/test_aboutserviceworkers.js
b2g/components/test/unit/test_fxaccounts.js
browser/base/content/browser-data-submission-info-bar.js
browser/base/content/browser-fullScreenAndPointerLock.js
browser/base/content/browser-fullZoom.js
browser/base/content/browser-syncui.js
browser/base/content/browser.js
browser/base/content/content.js
browser/base/content/nsContextMenu.js
browser/base/content/pageinfo/pageInfo.js
browser/base/content/sanitize.js
browser/base/content/test/alerts/browser_notification_open_settings.js
browser/base/content/test/captivePortal/browser_captivePortal_certErrorUI.js
browser/base/content/test/captivePortal/head.js
browser/base/content/test/general/browser_fxaccounts.js
browser/base/content/test/general/browser_syncui.js
browser/base/content/utilityOverlay.js
browser/components/customizableui/CustomizableWidgets.jsm
browser/components/customizableui/test/browser_synced_tabs_menu.js
browser/components/distribution.js
browser/components/extensions/test/browser/browser_ext_runtime_setUninstallURL.js
browser/components/nsBrowserGlue.js
browser/components/places/content/editBookmarkOverlay.js
browser/components/preferences/SiteDataManager.jsm
browser/components/preferences/in-content-old/applications.js
browser/components/preferences/in-content-old/main.js
browser/components/preferences/in-content-old/preferences.js
browser/components/preferences/in-content-old/privacy.js
browser/components/preferences/in-content-old/tests/browser_advanced_siteData.js
browser/components/preferences/in-content/applications.js
browser/components/preferences/in-content/main.js
browser/components/preferences/in-content/preferences.js
browser/components/preferences/in-content/privacy.js
browser/components/preferences/in-content/tests/browser_siteData.js
browser/components/preferences/siteDataSettings.js
browser/components/privatebrowsing/test/browser/head.js
browser/components/sessionstore/SessionFile.jsm
browser/components/sessionstore/SessionSaver.jsm
browser/components/sessionstore/SessionStore.jsm
browser/components/sessionstore/StartupPerformance.jsm
browser/components/sessionstore/content/aboutSessionRestore.js
browser/components/sessionstore/nsSessionStartup.js
browser/components/sessionstore/test/browser_cleaner.js
browser/components/sessionstore/test/browser_closed_objects_changed_notifications_tabs.js
browser/components/sessionstore/test/browser_closed_objects_changed_notifications_windows.js
browser/components/sessionstore/test/browser_forget_async_closings.js
browser/components/sessionstore/test/browser_purge_shistory.js
browser/components/sessionstore/test/unit/head.js
browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js
browser/experiments/Experiments.jsm
browser/extensions/pdfjs/test/browser_pdfjs_savedialog.js
browser/modules/SelfSupportBackend.jsm
browser/modules/Social.jsm
browser/modules/test/browser/browser_ProcessHangNotifications.js
browser/modules/test/browser/browser_UsageTelemetry.js
devtools/bootstrap.js
devtools/client/aboutdebugging/test/addons/unpacked/bootstrap.js
devtools/client/debugger/test/mochitest/browser_dbg_addon-console.js
devtools/client/debugger/test/mochitest/browser_dbg_addonactor.js
devtools/client/framework/ToolboxProcess.jsm
devtools/client/framework/toolbox-process-window.js
devtools/client/shared/browser-loader.js
devtools/client/shared/css-reload.js
devtools/client/shared/developer-toolbar.js
devtools/client/webconsole/hudservice.js
devtools/client/webconsole/webconsole.js
devtools/client/webide/components/webideCli.js
devtools/server/actors/monitor.js
devtools/server/actors/script.js
dom/console/ConsoleAPIStorage.js
dom/indexedDB/test/bug839193.js
dom/media/PeerConnection.js
dom/media/webspeech/recognition/test/head.js
dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway.js
dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.js
dom/presentation/tests/mochitest/test_presentation_dc_receiver.html
dom/presentation/tests/mochitest/test_presentation_dc_receiver_oop.html
dom/presentation/tests/mochitest/test_presentation_receiver_auxiliary_navigation.js
dom/presentation/tests/mochitest/test_presentation_tcp_receiver.html
dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_error.html
dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_timeout.html
dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_unknown_content_type.js
dom/presentation/tests/mochitest/test_presentation_tcp_receiver_oop.html
dom/presentation/tests/mochitest/test_presentation_terminate.js
dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error.js
dom/push/test/xpcshell/test_quota_observer.js
dom/system/gonk/NetworkManager.js
dom/tests/mochitest/chrome/file_bug1224790-2_nonmodal.xul
dom/tests/mochitest/localstorage/localStorageCommon.js
dom/workers/test/serviceworkers/test_install_event_gc.html
embedding/ios/GeckoEmbed/GeckoEmbed/browser/chrome/content/hello.js
extensions/cookie/test/unit/test_cookies_privatebrowsing.js
extensions/pref/autoconfig/test/unit/test_autoconfig_nonascii.js
layout/forms/test/test_bug536567_perwindowpb.html
mobile/android/chrome/content/browser.js
mobile/android/components/LoginManagerPrompter.js
mobile/android/components/SessionStore.js
mobile/android/modules/Sanitizer.jsm
mobile/android/tests/browser/chrome/test_awsy_lite.html
mobile/android/tests/browser/chrome/test_session_zombification.html
modules/libjar/test/unit/test_jarchannel.js
modules/libpref/test/unit/test_extprefs.js
netwerk/test/unit/test_bug1312782_http1.js
netwerk/test/unit/test_bug248970_cache.js
netwerk/test/unit/test_bug248970_cookie.js
netwerk/test/unit/test_cache2-06-pb-mode.js
netwerk/test/unit/test_httpauth.js
security/manager/pki/resources/content/certViewer.js
security/manager/pki/resources/content/clientauthask.js
security/manager/pki/resources/content/exceptionDialog.js
security/manager/ssl/tests/unit/test_sts_preloadlist_perwindowpb.js
services/common/logmanager.js
services/fxaccounts/FxAccountsManager.jsm
services/fxaccounts/FxAccountsPush.js
services/fxaccounts/tests/xpcshell/test_oauth_token_storage.js
services/fxaccounts/tests/xpcshell/test_oauth_tokens.js
services/fxaccounts/tests/xpcshell/test_profile.js
services/sync/modules/SyncedTabs.jsm
services/sync/modules/browserid_identity.js
services/sync/tps/extensions/mozmill/resource/modules/frame.js
services/sync/tps/extensions/tps/resource/quit.js
storage/test/unit/vacuumParticipant.js
testing/mochitest/browser-test.js
testing/specialpowers/content/specialpowersAPI.js
testing/talos/talos/pageloader/chrome/memory.js
testing/talos/talos/pageloader/chrome/quit.js
testing/xpcshell/dbg-actors.js
testing/xpcshell/head.js
toolkit/components/aboutmemory/content/aboutMemory.js
toolkit/components/asyncshutdown/tests/xpcshell/head.js
toolkit/components/contentprefs/tests/unit/head_contentPrefs.js
toolkit/components/extensions/ExtensionXPCShellUtils.jsm
toolkit/components/extensions/ext-permissions.js
toolkit/components/extensions/test/xpcshell/test_ext_experiments.js
toolkit/components/extensions/test/xpcshell/test_ext_json_parser.js
toolkit/components/extensions/test/xpcshell/test_ext_legacy_extension_embedding.js
toolkit/components/extensions/test/xpcshell/test_ext_management_uninstall_self.js
toolkit/components/extensions/test/xpcshell/test_ext_storage.js
toolkit/components/extensions/test/xpcshell/test_locale_data.js
toolkit/components/formautofill/content/requestAutocomplete.js
toolkit/components/formautofill/test/browser/browser_infrastructure.js
toolkit/components/formautofill/test/chrome/test_infrastructure.js
toolkit/components/formautofill/test/xpcshell/test_infrastructure.js
toolkit/components/jsdownloads/test/unit/common_test_Download.js
toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js
toolkit/components/osfile/tests/xpcshell/test_shutdown.js
toolkit/components/passwordmgr/LoginManagerContent.jsm
toolkit/components/passwordmgr/content/passwordManager.js
toolkit/components/passwordmgr/crypto-SDR.js
toolkit/components/passwordmgr/nsLoginManager.js
toolkit/components/passwordmgr/nsLoginManagerPrompter.js
toolkit/components/passwordmgr/test/LoginTestUtils.jsm
toolkit/components/places/PlacesDBUtils.jsm
toolkit/components/places/nsPlacesExpiration.js
toolkit/components/places/tests/expiration/test_analyze_runs.js
toolkit/components/places/tests/unit/nsDummyObserver.js
toolkit/components/places/tests/unit/test_adaptive.js
toolkit/components/places/tests/unit/test_adaptive_bug527311.js
toolkit/components/processsingleton/MainProcessSingleton.js
toolkit/components/prompts/src/CommonDialog.jsm
toolkit/components/reader/AboutReader.jsm
toolkit/components/satchel/test/unit/test_async_expire.js
toolkit/components/search/tests/xpcshell/test_645970.js
toolkit/components/telemetry/TelemetrySession.jsm
toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js
toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
toolkit/components/terminator/nsTerminatorTelemetry.js
toolkit/components/url-classifier/content/moz/observer.js
toolkit/components/viewsource/content/viewSource-content.js
toolkit/content/aboutSupport.js
toolkit/crashreporter/test/unit/test_crash_AsyncShutdown.js
toolkit/forgetaboutsite/test/unit/test_removeDataFromDomain.js
toolkit/modules/Console.jsm
toolkit/modules/PopupNotifications.jsm
toolkit/modules/tests/xpcshell/test_session_recorder.js
toolkit/mozapps/downloads/tests/unit/head_downloads.js
toolkit/mozapps/extensions/AddonManager.jsm
toolkit/mozapps/extensions/ChromeManifestParser.jsm
toolkit/mozapps/extensions/LightweightThemeManager.jsm
toolkit/mozapps/extensions/content/extensions.js
toolkit/mozapps/extensions/content/extensions.xml
toolkit/mozapps/extensions/content/update.js
toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
toolkit/mozapps/extensions/internal/Content.js
toolkit/mozapps/extensions/internal/XPIProvider.jsm
toolkit/mozapps/extensions/nsBlocklistService.js
toolkit/mozapps/extensions/nsBlocklistServiceContent.js
toolkit/mozapps/extensions/test/addons/bootstrap_globals/bootstrap.js
toolkit/mozapps/extensions/test/addons/test_bootstrap_const/bootstrap.js
toolkit/mozapps/extensions/test/browser/browser_inlinesettings_browser.js
toolkit/mozapps/extensions/test/xpcshell/head_addons.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_metadata_filters.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_prefs.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js
toolkit/mozapps/extensions/test/xpcshell/test_bug393285.js
toolkit/mozapps/extensions/test/xpcshell/test_bug406118.js
toolkit/mozapps/extensions/test/xpcshell/test_bug455906.js
toolkit/mozapps/extensions/test/xpcshell/test_bug514327_2.js
toolkit/mozapps/extensions/test/xpcshell/test_permissions_prefs.js
toolkit/mozapps/extensions/test/xpcshell/test_pluginchange.js
toolkit/mozapps/extensions/test/xpcshell/test_signed_inject.js
toolkit/mozapps/extensions/test/xpcshell/test_softblocked.js
toolkit/mozapps/extensions/test/xpcshell/test_update_webextensions.js
toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js
toolkit/mozapps/update/content/updates.js
uriloader/exthandler/nsHandlerService-json.js
uriloader/exthandler/nsHandlerService.js
uriloader/exthandler/tests/unit/test_handlerService_json.js
uriloader/exthandler/tests/unit/test_handlerService_rdf.js
--- a/addon-sdk/source/lib/toolkit/require.js
+++ b/addon-sdk/source/lib/toolkit/require.js
@@ -42,17 +42,17 @@ const make = (exports, rootURI, componen
       // more than once. Unless we invalidate statup cache changes to a module
       // won't be reflected even after reload. Therefor we must dispatch an
       // nsIObserverService notification that causes cache invalidation.
       // Note: This is not ideal since it destroys whole cache, but since there
       // is no way to invalidate individual entries, we assume performance hit
       // during development is acceptable.
       components.classes["@mozilla.org/observer-service;1"].
         getService(components.interfaces.nsIObserverService).
-        notifyObservers({}, "startupcache-invalidate");
+        notifyObservers({}, "startupcache-invalidate", null);
 
       if (all) {
         for (let uri of Object.keys(loader.sandboxes)) {
           unload(uri);
         }
       }
       else {
         unload(require.resolve(id));
--- a/addon-sdk/source/test/addons/e10s-remote/remote-module.js
+++ b/addon-sdk/source/test/addons/e10s-remote/remote-module.js
@@ -100,17 +100,17 @@ process.port.on('sdk/test/parentload', (
     message
   )
 });
 
 function listener(event) {
   // Use the raw observer service here since it will be usable even if the
   // loader has unloaded
   let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
-  Services.obs.notifyObservers(null, "Test:Reply");
+  Services.obs.notifyObservers(null, "Test:Reply", "");
 }
 
 frames.port.on('sdk/test/registerframesevent', (frame) => {
   frames.addEventListener("Test:Event", listener, true);
 });
 
 frames.port.on('sdk/test/unregisterframesevent', (frame) => {
   frames.removeEventListener("Test:Event", listener, true);
--- a/addon-sdk/source/test/addons/remote/remote-module.js
+++ b/addon-sdk/source/test/addons/remote/remote-module.js
@@ -100,17 +100,17 @@ process.port.on('sdk/test/parentload', (
     message
   )
 });
 
 function listener(event) {
   // Use the raw observer service here since it will be usable even if the
   // loader has unloaded
   let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
-  Services.obs.notifyObservers(null, "Test:Reply");
+  Services.obs.notifyObservers(null, "Test:Reply", "");
 }
 
 frames.port.on('sdk/test/registerframesevent', (frame) => {
   frames.addEventListener("Test:Event", listener, true);
 });
 
 frames.port.on('sdk/test/unregisterframesevent', (frame) => {
   frames.removeEventListener("Test:Event", listener, true);
--- a/b2g/chrome/content/devtools/debugger.js
+++ b/b2g/chrome/content/devtools/debugger.js
@@ -260,17 +260,17 @@ var USBRemoteDebugger = {
       let authenticator = new AuthenticatorType.Server();
       authenticator.allowConnection = RemoteDebugger.allowConnection;
       this._listener = DebuggerServer.createListener();
       this._listener.portOrPath = portOrPath;
       this._listener.authenticator = authenticator;
       this._listener.open();
       // Temporary event, until bug 942756 lands and offers a way to know
       // when the server is up and running.
-      Services.obs.notifyObservers(null, "debugger-server-started");
+      Services.obs.notifyObservers(null, "debugger-server-started", null);
     } catch (e) {
       debug("Unable to start USB debugger server: " + e);
     }
   },
 
   stop: function() {
     if (!this._listener) {
       return;
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -690,17 +690,17 @@ var shell = {
     content.addEventListener('load', this, true);
 
     this.reportCrash(true);
 
     SystemAppProxy.registerFrame(shell.contentBrowser);
 
     this.sendEvent(window, 'ContentStart');
 
-    Services.obs.notifyObservers(null, 'content-start');
+    Services.obs.notifyObservers(null, 'content-start', null);
 
     if (AppConstants.MOZ_GRAPHENE &&
         Services.prefs.getBoolPref("b2g.nativeWindowGeometry.fullscreen")) {
       window.fullScreen = true;
     }
 
     shell.handleCmdLine();
   },
@@ -727,17 +727,17 @@ var shell = {
   // This gets called when window.onload fires on the System app content window,
   // which means things in <html> are parsed and statically referenced <script>s
   // and <script defer>s are loaded and run.
   notifyContentWindowLoaded: function shell_notifyContentWindowLoaded() {
     isGonk && libcutils.property_set('sys.boot_completed', '1');
 
     // This will cause Gonk Widget to remove boot animation from the screen
     // and reveals the page.
-    Services.obs.notifyObservers(null, "browser-ui-startup-complete");
+    Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
 
     SystemAppProxy.setIsLoaded();
   },
 
   // This gets called when the content sends us system-message-listener-ready
   // mozContentEvent, OR when an observer message tell us we should consider
   // the content as ready.
   notifyEventListenerReady: function shell_notifyEventListenerReady() {
@@ -792,17 +792,17 @@ var CustomEventManager = {
   },
 
   handleEvent: function custevt_handleEvent(evt) {
     let detail = evt.detail;
     dump('XXX FIXME : Got a mozContentEvent: ' + detail.type + "\n");
 
     switch(detail.type) {
       case 'system-message-listener-ready':
-        Services.obs.notifyObservers(null, 'system-message-listener-ready');
+        Services.obs.notifyObservers(null, 'system-message-listener-ready', null);
         break;
       case 'captive-portal-login-cancel':
         CaptivePortalLoginHelper.handleEvent(detail);
         break;
       case 'inputmethod-update-layouts':
       case 'inputregistry-add':
       case 'inputregistry-remove':
         KeyboardHelper.handleEvent(detail);
--- a/b2g/components/GlobalSimulatorScreen.jsm
+++ b/b2g/components/GlobalSimulatorScreen.jsm
@@ -66,22 +66,22 @@ this.GlobalSimulatorScreen = {
     }
 
     // If the actual orientation changed,
     // we have to fire mozorientation DOM events
     if (this.mozOrientation != orientation) {
       this.mozOrientation = orientation;
 
       // Notify each app screen object to fire the event
-      Services.obs.notifyObservers(null, 'simulator-orientation-change');
+      Services.obs.notifyObservers(null, 'simulator-orientation-change', null);
     }
 
     // Finally, in any case, we update the window size and orientation
     // (Use wrappedJSObject trick to be able to pass a raw JS object)
-    Services.obs.notifyObservers({wrappedJSObject:this}, 'simulator-adjust-window-size');
+    Services.obs.notifyObservers({wrappedJSObject:this}, 'simulator-adjust-window-size', null);
   },
 
   flipScreen: function() {
     if (this.screenOrientation == 'portrait') {
       this.screenOrientation = 'landscape';
     } else if (this.screenOrientation == 'landscape') {
       this.screenOrientation = 'portrait';
     }
--- a/b2g/components/SafeMode.jsm
+++ b/b2g/components/SafeMode.jsm
@@ -119,17 +119,17 @@ this.SafeMode = {
 
       function notifyContentStart() {
         let window = SafeMode.window;
         window.shell.sendEvent(window, "SafeModeStart");
         contentBrowser.setVisible(true);
 
         // browser-ui-startup-complete is used by the AppShell to stop the
         // boot animation and start gecko rendering.
-        Services.obs.notifyObservers(null, "browser-ui-startup-complete");
+        Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
         content.addEventListener("mozContentEvent", handleEvent, true);
       }
 
       contentBrowser.addEventListener("mozbrowserloadstart", handleEvent, true);
       contentBrowser.src = url;
     });
   },
 
--- a/b2g/components/test/unit/test_aboutserviceworkers.js
+++ b/b2g/components/test/unit/test_aboutserviceworkers.js
@@ -22,25 +22,25 @@ const ORIGINAL_SENDERROR = AboutServiceW
 
 do_get_profile();
 
 var mockSendResult = (aId, aResult) => {
   let msg = {
     id: aId,
     result: aResult
   };
-  Services.obs.notifyObservers({wrappedJSObject: msg}, CHROME_MSG);
+  Services.obs.notifyObservers({wrappedJSObject: msg}, CHROME_MSG, null);
 };
 
 var mockSendError = (aId, aError) => {
   let msg = {
     id: aId,
     result: aError
   };
-  Services.obs.notifyObservers({wrappedJSObject: msg}, CHROME_MSG);
+  Services.obs.notifyObservers({wrappedJSObject: msg}, CHROME_MSG, null);
 };
 
 function attachMocks() {
   AboutServiceWorkers.sendResult = mockSendResult;
   AboutServiceWorkers.sendError = mockSendError;
 }
 
 function restoreMocks() {
--- a/b2g/components/test/unit/test_fxaccounts.js
+++ b/b2g/components/test/unit/test_fxaccounts.js
@@ -27,17 +27,17 @@ do_register_cleanup(function() {
   Services.prefs.clearUserPref("identity.fxaccounts.skipDeviceRegistration");
 });
 
 // Make profile available so that fxaccounts can store user data
 do_get_profile();
 
 // Mock the system app proxy; make message passing possible
 var mockSendCustomEvent = function(aEventName, aMsg) {
-  Services.obs.notifyObservers({wrappedJSObject: aMsg}, aEventName);
+  Services.obs.notifyObservers({wrappedJSObject: aMsg}, aEventName, null);
 };
 
 function run_test() {
   run_next_test();
 }
 
 add_task(function test_overall() {
   // FxA device registration throws from this context
--- a/browser/base/content/browser-data-submission-info-bar.js
+++ b/browser/base/content/browser-data-submission-info-bar.js
@@ -80,17 +80,17 @@ var gDataNotificationInfoBar = {
     this._notificationBox.appendNotification(
       message,
       this._DATA_REPORTING_NOTIFICATION,
       null,
       this._notificationBox.PRIORITY_INFO_HIGH,
       buttons,
       event => {
         if (event == "removed") {
-          Services.obs.notifyObservers(null, "datareporting:notify-data-policy:close");
+          Services.obs.notifyObservers(null, "datareporting:notify-data-policy:close", null);
         }
       }
     );
     // It is important to defer calling onUserNotifyComplete() until we're
     // actually sure the notification was displayed. If we ever called
     // onUserNotifyComplete() without showing anything to the user, that
     // would be very good for user choice. It may also have legal impact.
     request.onUserNotifyComplete();
--- a/browser/base/content/browser-fullScreenAndPointerLock.js
+++ b/browser/base/content/browser-fullScreenAndPointerLock.js
@@ -388,17 +388,17 @@ var FullScreen = {
         }
         break;
       }
       case "DOMFullscreen:Exit": {
         this._windowUtils.remoteFrameFullscreenReverted();
         break;
       }
       case "DOMFullscreen:Painted": {
-        Services.obs.notifyObservers(window, "fullscreen-painted");
+        Services.obs.notifyObservers(window, "fullscreen-painted", "");
         TelemetryStopwatch.finish("FULLSCREEN_CHANGE_MS");
         break;
       }
     }
   },
 
   enterDomFullscreen(aBrowser) {
 
--- a/browser/base/content/browser-fullZoom.js
+++ b/browser/base/content/browser-fullZoom.js
@@ -282,17 +282,17 @@ var FullZoom = {
    * @return A promise which resolves when the zoom reset has been applied.
    */
   reset: function FullZoom_reset(browser = gBrowser.selectedBrowser) {
     let token = this._getBrowserToken(browser);
     let result = this._getGlobalValue(browser).then(value => {
       if (token.isCurrent) {
         ZoomManager.setZoomForBrowser(browser, value === undefined ? 1 : value);
         this._ignorePendingZoomAccesses(browser);
-        Services.obs.notifyObservers(browser, "browser-fullZoom:zoomReset");
+        Services.obs.notifyObservers(browser, "browser-fullZoom:zoomReset", "");
       }
     });
     this._removePref(browser);
     return result;
   },
 
   /**
    * Set the zoom level for a given browser.
@@ -350,17 +350,17 @@ var FullZoom = {
 
   /**
    * Saves the zoom level of the page in the given browser to the content
    * prefs store.
    *
    * @param browser  The zoom of this browser will be saved.  Required.
    */
   _applyZoomToPref: function FullZoom__applyZoomToPref(browser) {
-    Services.obs.notifyObservers(browser, "browser-fullZoom:zoomChange");
+    Services.obs.notifyObservers(browser, "browser-fullZoom:zoomChange", "");
     if (!this.siteSpecific ||
         gInPrintPreviewMode ||
         browser.isSyntheticDocument)
       return;
 
     this._cps2.set(browser.currentURI.spec, this.name,
                    ZoomManager.getZoomForBrowser(browser),
                    this._loadContextFromBrowser(browser), {
@@ -371,17 +371,17 @@ var FullZoom = {
   },
 
   /**
    * Removes from the content prefs store the zoom level of the given browser.
    *
    * @param browser  The zoom of this browser will be removed.  Required.
    */
   _removePref: function FullZoom__removePref(browser) {
-    Services.obs.notifyObservers(browser, "browser-fullZoom:zoomReset");
+    Services.obs.notifyObservers(browser, "browser-fullZoom:zoomReset", "");
     if (browser.isSyntheticDocument)
       return;
     let ctxt = this._loadContextFromBrowser(browser);
     this._cps2.removeByDomainAndName(browser.currentURI.spec, this.name, ctxt, {
       handleCompletion: function() {
         this._isNextContentPrefChangeInternal = true;
       }.bind(this),
     });
@@ -509,17 +509,17 @@ var FullZoom = {
   /**
    * Asynchronously broadcasts "browser-fullZoom:location-change" so that
    * listeners can be notified when the zoom levels on those pages change.
    * The notification is always asynchronous so that observers are guaranteed a
    * consistent behavior.
    */
   _notifyOnLocationChange: function FullZoom__notifyOnLocationChange(browser) {
     this._executeSoon(function() {
-      Services.obs.notifyObservers(browser, "browser-fullZoom:location-change");
+      Services.obs.notifyObservers(browser, "browser-fullZoom:location-change", "");
     });
   },
 
   _executeSoon: function FullZoom__executeSoon(callback) {
     if (!callback)
       return;
     Services.tm.dispatchToMainThread(callback);
   },
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -231,17 +231,17 @@ var gSyncUI = {
   // Commands
   // doSync forces a sync - it *does not* return a promise as it is called
   // via the various UI components.
   doSync() {
     this._needsSetup().then(needsSetup => {
       if (!needsSetup) {
         setTimeout(() => Weave.Service.errorHandler.syncAndReportErrors(), 0);
       }
-      Services.obs.notifyObservers(null, "cloudsync:user-sync");
+      Services.obs.notifyObservers(null, "cloudsync:user-sync", null);
     }).catch(err => {
       this.log.error("Failed to force a sync", err);
     });
   },
 
   // Handle clicking the toolbar button - which either opens the Sync setup
   // pages or forces a sync now. Does *not* return a promise as it is called
   // via the UI.
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1183,17 +1183,17 @@ var gBrowserInit = {
     gHistorySwipeAnimation.init();
 
     SidebarUI.init();
 
     // Certain kinds of automigration rely on this notification to complete
     // their tasks BEFORE the browser window is shown. SessionStore uses it to
     // restore tabs into windows AFTER important parts like gMultiProcessBrowser
     // have been initialized.
-    Services.obs.notifyObservers(window, "browser-window-before-show");
+    Services.obs.notifyObservers(window, "browser-window-before-show", "");
 
     let isResistFingerprintingEnabled = gPrefService.getBoolPref("privacy.resistFingerprinting");
 
     // Set a sane starting width/height for all resolutions on new profiles.
     if (isResistFingerprintingEnabled) {
       // When the fingerprinting resistance is enabled, making sure that we don't
       // have a maximum window to interfere with generating rounded window dimensions.
       document.documentElement.setAttribute("sizemode", "normal");
@@ -1601,17 +1601,17 @@ var gBrowserInit = {
         if (panel.state == "open") {
           panel.hidePopup();
         }
       }
     });
 
     this.delayedStartupFinished = true;
 
-    Services.obs.notifyObservers(window, "browser-delayed-startup-finished");
+    Services.obs.notifyObservers(window, "browser-delayed-startup-finished", "");
     TelemetryTimestamps.add("delayedStartupFinished");
   },
 
   // Returns the URI(s) to load at startup.
   _getUriToLoad() {
     // window.arguments[0]: URI to load (string), or an nsIArray of
     //                      nsISupportsStrings to load, or a xul:tab of
     //                      a tabbrowser, which will be replaced by this
@@ -6155,17 +6155,17 @@ var BrowserOffline = {
     // which we ignore by updating the UI to the current value of io.offline
     this._updateOfflineUI(Services.io.offline);
   },
 
   // BrowserOffline Implementation Methods
   _canGoOffline() {
     try {
       var cancelGoOffline = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
-      Services.obs.notifyObservers(cancelGoOffline, "offline-requested");
+      Services.obs.notifyObservers(cancelGoOffline, "offline-requested", null);
 
       // Something aborted the quit process.
       if (cancelGoOffline.data)
         return false;
     } catch (ex) {
     }
 
     return true;
@@ -6484,35 +6484,36 @@ function warnAboutClosingWindow() {
     }
   }
 
   if (isPBWindow && !otherPBWindowExists) {
     let exitingCanceled = Cc["@mozilla.org/supports-PRBool;1"].
                           createInstance(Ci.nsISupportsPRBool);
     exitingCanceled.data = false;
     Services.obs.notifyObservers(exitingCanceled,
-                                 "last-pb-context-exiting");
+                                 "last-pb-context-exiting",
+                                 null);
     if (exitingCanceled.data)
       return false;
   }
 
   if (nonPopupPresent) {
     return isPBWindow || gBrowser.warnAboutClosingTabs(gBrowser.closingTabsEnum.ALL);
   }
 
   let os = Services.obs;
 
   let closingCanceled = Cc["@mozilla.org/supports-PRBool;1"].
                         createInstance(Ci.nsISupportsPRBool);
   os.notifyObservers(closingCanceled,
-                     "browser-lastwindow-close-requested");
+                     "browser-lastwindow-close-requested", null);
   if (closingCanceled.data)
     return false;
 
-  os.notifyObservers(null, "browser-lastwindow-close-granted");
+  os.notifyObservers(null, "browser-lastwindow-close-granted", null);
 
   // OS X doesn't quit the application when the last window is closed, but keeps
   // the session alive. Hence don't prompt users to save tabs, but warn about
   // closing multiple tabs.
   return AppConstants.platform != "macosx"
          || (isPBWindow || gBrowser.warnAboutClosingTabs(gBrowser.closingTabsEnum.ALL));
 }
 
@@ -6560,17 +6561,17 @@ function BrowserOpenAddonsMgr(aView) {
                                .QueryInterface(Ci.nsIInterfaceRequestor)
                                .getInterface(Ci.nsIDOMWindow);
       if (!emWindow || browserWin == window /* favor the current window */) {
         emWindow = aSubject;
         browserWindow = browserWin;
       }
     }
     Services.obs.addObserver(receivePong, "EM-pong");
-    Services.obs.notifyObservers(null, "EM-ping");
+    Services.obs.notifyObservers(null, "EM-ping", "");
     Services.obs.removeObserver(receivePong, "EM-pong");
 
     if (emWindow) {
       if (aView) {
         emWindow.loadView(aView);
       }
       browserWindow.gBrowser.selectedTab =
         browserWindow.gBrowser._getTabForContentWindow(emWindow);
@@ -8123,17 +8124,17 @@ function safeModeRestart() {
 
     if (cancelQuit.data)
       return;
 
     Services.startup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
     return;
   }
 
-  Services.obs.notifyObservers(null, "restart-in-safe-mode");
+  Services.obs.notifyObservers(null, "restart-in-safe-mode", "");
 }
 
 /* duplicateTabIn duplicates tab in a place specified by the parameter |where|.
  *
  * |where| can be:
  *  "tab"         new tab
  *  "tabshifted"  same as "tab" but in background if default is to select new
  *                tabs, and vice versa
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -108,17 +108,17 @@ var handleContentContextMenu = function(
     return;
 
   let addonInfo = {};
   let subject = {
     event,
     addonInfo,
   };
   subject.wrappedJSObject = subject;
-  Services.obs.notifyObservers(subject, "content-contextmenu");
+  Services.obs.notifyObservers(subject, "content-contextmenu", null);
 
   let doc = event.target.ownerDocument;
   let docLocation = doc.mozDocumentURIIfNotForErrorPages;
   docLocation = docLocation && docLocation.spec;
   let charSet = doc.characterSet;
   let baseURI = doc.baseURI;
   let referrer = doc.referrer;
   let referrerPolicy = doc.referrerPolicy;
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -62,17 +62,17 @@ nsContextMenu.prototype = {
         srcUrl: this.mediaURL,
         frameUrl: gContextMenuContentData ? gContextMenuContentData.docLocation : undefined,
         pageUrl: this.browser ? this.browser.currentURI.spec : undefined,
         linkUrl: this.linkURL,
         selectionText: this.isTextSelected ? this.selectionInfo.text : undefined,
         frameId: this.frameOuterWindowID,
       };
       subject.wrappedJSObject = subject;
-      Services.obs.notifyObservers(subject, "on-build-contextmenu");
+      Services.obs.notifyObservers(subject, "on-build-contextmenu", null);
     }
 
     this.isFrameImage = document.getElementById("isFrameImage");
     this.ellipsis = "\u2026";
     try {
       this.ellipsis = gPrefService.getComplexValue("intl.ellipsis",
                                                    Ci.nsIPrefLocalizedString).data;
     } catch (e) { }
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -331,17 +331,17 @@ function onLoadPageInfo() {
   // init media view
   var imageTree = document.getElementById("imagetree");
   imageTree.view = gImageView;
 
   /* Select the requested tab, if the name is specified */
   loadTab(args);
   Components.classes["@mozilla.org/observer-service;1"]
             .getService(Components.interfaces.nsIObserverService)
-            .notifyObservers(window, "page-info-dialog-loaded");
+            .notifyObservers(window, "page-info-dialog-loaded", null);
 }
 
 function loadPageInfo(frameOuterWindowID, imageElement, browser) {
   browser = browser || window.opener.gBrowser.selectedBrowser;
   let mm = browser.messageManager;
 
   gStrings["application/rss+xml"]  = gBundle.getString("feedRss");
   gStrings["application/atom+xml"] = gBundle.getString("feedAtom");
--- a/browser/base/content/sanitize.js
+++ b/browser/base/content/sanitize.js
@@ -83,17 +83,17 @@ Sanitizer.prototype = {
           fetchState: () => ({ progress })
         }
       );
     }
 
     try {
       yield promise;
     } finally {
-      Services.obs.notifyObservers(null, "sanitizer-sanitization-complete");
+      Services.obs.notifyObservers(null, "sanitizer-sanitization-complete", "");
     }
   }),
 
   _sanitize: Task.async(function*(aItemsToClear, progress = {}) {
     let seenError = false;
     let itemsToClear;
     if (Array.isArray(aItemsToClear)) {
       // Shallow copy the array, as we are going to modify
@@ -432,17 +432,17 @@ Sanitizer.prototype = {
 
         try {
           // clear all auth tokens
           let sdr = Components.classes["@mozilla.org/security/sdr;1"]
                               .getService(Components.interfaces.nsISecretDecoderRing);
           sdr.logoutAndTeardown();
 
           // clear FTP and plain HTTP auth sessions
-          Services.obs.notifyObservers(null, "net:clear-active-logins");
+          Services.obs.notifyObservers(null, "net:clear-active-logins", null);
         } finally {
           TelemetryStopwatch.finish("FX_SANITIZE_SESSIONS", refObj);
         }
       })
     },
 
     siteSettings: {
       clear: Task.async(function* (range) {
--- a/browser/base/content/test/alerts/browser_notification_open_settings.js
+++ b/browser/base/content/test/alerts/browser_notification_open_settings.js
@@ -7,17 +7,17 @@ add_task(function* test_settingsOpen_obs
   yield BrowserTestUtils.withNewTab({
     gBrowser,
     url: "about:robots"
   }, function* dummyTabTask(aBrowser) {
     let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, "about:preferences#privacy");
     info("simulate a notifications-open-settings notification");
     let uri = NetUtil.newURI("https://example.com");
     let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
-    Services.obs.notifyObservers(principal, "notifications-open-settings");
+    Services.obs.notifyObservers(principal, "notifications-open-settings", null);
     let tab = yield tabPromise;
     ok(tab, "The notification settings tab opened");
     yield BrowserTestUtils.removeTab(tab);
   });
 });
 
 add_task(function* test_settingsOpen_button() {
   let pm = Services.perms;
--- a/browser/base/content/test/captivePortal/browser_captivePortal_certErrorUI.js
+++ b/browser/base/content/test/captivePortal/browser_captivePortal_certErrorUI.js
@@ -11,17 +11,17 @@ add_task(function* checkCaptivePortalCer
   yield SpecialPowers.pushPrefEnv({
     set: [["captivedetect.canonicalURL", CANONICAL_URL],
           ["captivedetect.canonicalContent", CANONICAL_CONTENT]],
   });
 
   let captivePortalStatePropagated = TestUtils.topicObserved("ipc:network:captive-portal-set-state");
 
   info("Checking that the alternate about:certerror UI is shown when we are behind a captive portal.");
-  Services.obs.notifyObservers(null, "captive-portal-login");
+  Services.obs.notifyObservers(null, "captive-portal-login", null);
 
   info("Waiting for captive portal state to be propagated to the content process.");
   yield captivePortalStatePropagated;
 
   // Open a page with a cert error.
   let browser;
   let certErrorLoaded;
   let errorTab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
@@ -62,17 +62,17 @@ add_task(function* checkCaptivePortalCer
   });
 
   let portalTab2 = yield portalTabPromise;
   is(portalTab2, portalTab, "The existing portal tab should be focused.");
 
   let portalTabRemoved = BrowserTestUtils.tabRemoved(portalTab);
   let errorTabReloaded = BrowserTestUtils.waitForErrorPage(browser);
 
-  Services.obs.notifyObservers(null, "captive-portal-login-success");
+  Services.obs.notifyObservers(null, "captive-portal-login-success", null);
   yield portalTabRemoved;
 
   info("Waiting for error tab to be reloaded after the captive portal was freed.");
   yield errorTabReloaded;
   yield ContentTask.spawn(browser, null, () => {
     let doc = content.document;
     ok(!doc.body.classList.contains("captiveportal"),
        "Captive portal error page UI is not visible.");
--- a/browser/base/content/test/captivePortal/head.js
+++ b/browser/base/content/test/captivePortal/head.js
@@ -35,25 +35,25 @@ function* setupPrefsAndRecentWindowBehav
 
   registerCleanupFunction(function* cleanUp() {
     RecentWindow.getMostRecentBrowserWindow = getMostRecentBrowserWindowCopy;
     window.CaptivePortalWatcher.init();
   });
 }
 
 function* portalDetected() {
-  Services.obs.notifyObservers(null, "captive-portal-login");
+  Services.obs.notifyObservers(null, "captive-portal-login", null);
   yield BrowserTestUtils.waitForCondition(() => {
     return cps.state == cps.LOCKED_PORTAL;
   }, "Waiting for Captive Portal Service to update state after portal detected.");
 }
 
 function* freePortal(aSuccess) {
   Services.obs.notifyObservers(null,
-    "captive-portal-login-" + (aSuccess ? "success" : "abort"));
+    "captive-portal-login-" + (aSuccess ? "success" : "abort"), null);
   yield BrowserTestUtils.waitForCondition(() => {
     return cps.state != cps.LOCKED_PORTAL;
   }, "Waiting for Captive Portal Service to update state after portal freed.");
 }
 
 // If a window is provided, it will be focused. Otherwise, a new window
 // will be opened and focused.
 function* focusWindowAndWaitForPortalUI(aLongRecheck, win) {
@@ -71,17 +71,17 @@ function* focusWindowAndWaitForPortalUI(
   }
   yield SimpleTest.promiseFocus(win);
 
   // After a new window is opened, CaptivePortalWatcher asks for a recheck, and
   // waits for it to complete. We need to manually tell it a recheck completed.
   yield BrowserTestUtils.waitForCondition(() => {
     return win.CaptivePortalWatcher._waitingForRecheck;
   }, "Waiting for CaptivePortalWatcher to trigger a recheck.");
-  Services.obs.notifyObservers(null, "captive-portal-check-complete");
+  Services.obs.notifyObservers(null, "captive-portal-check-complete", null);
 
   let notification = ensurePortalNotification(win);
 
   if (aLongRecheck) {
     ensureNoPortalTab(win);
     testShowLoginPageButtonVisibility(notification, "visible");
     return win;
   }
--- a/browser/base/content/test/general/browser_fxaccounts.js
+++ b/browser/base/content/test/general/browser_fxaccounts.js
@@ -13,25 +13,25 @@ const TEST_ROOT = "http://example.com/br
 // what it does.
 (function() {
   let unstubs = {}; // The original functions we stub out.
 
   // The stub functions.
   let stubs = {
     updateUI() {
       return unstubs["updateUI"].call(gFxAccounts).then(() => {
-        Services.obs.notifyObservers(null, "test:browser_fxaccounts:updateUI");
+        Services.obs.notifyObservers(null, "test:browser_fxaccounts:updateUI", null);
       });
     },
     // Opening preferences is trickier than it should be as leaks are reported
     // due to the promises it fires off at load time  and there's no clear way to
     // know when they are done.
     // So just ensure openPreferences is called rather than whether it opens.
     openPreferences() {
-      Services.obs.notifyObservers(null, "test:browser_fxaccounts:openPreferences");
+      Services.obs.notifyObservers(null, "test:browser_fxaccounts:openPreferences", null);
     }
   };
 
   for (let name in stubs) {
     unstubs[name] = gFxAccounts[name];
     gFxAccounts[name] = stubs[name];
   }
   // and undo our damage at the end.
@@ -68,17 +68,17 @@ var panelUILabel = document.getElementBy
 var panelUIStatus = document.getElementById("PanelUI-fxa-status");
 var panelUIFooter = document.getElementById("PanelUI-footer-fxa");
 
 // The tests
 add_task(function* test_nouser() {
   let user = yield fxAccounts.getSignedInUser();
   Assert.strictEqual(user, null, "start with no user signed in");
   let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateUI");
-  Services.obs.notifyObservers(null, this.FxAccountsCommon.ONLOGOUT_NOTIFICATION);
+  Services.obs.notifyObservers(null, this.FxAccountsCommon.ONLOGOUT_NOTIFICATION, null);
   yield promiseUpdateDone;
 
   // Check the world - the FxA footer area is visible as it is offering a signin.
   Assert.ok(isFooterVisible())
 
   Assert.equal(panelUILabel.getAttribute("label"), panelUIStatus.getAttribute("defaultlabel"));
   Assert.equal(panelUIStatus.getAttribute("tooltiptext"), panelUIStatus.getAttribute("signedinTooltiptext"));
   Assert.ok(!panelUIFooter.hasAttribute("fxastatus"), "no fxsstatus when signed out");
@@ -147,17 +147,17 @@ add_task(function* test_verifiedUserDisp
                panelUIStatus.getAttribute("signedinTooltiptext"));
   Assert.equal(panelUIFooter.getAttribute("fxastatus"), "signedin");
   yield signOut();
 });
 
 add_task(function* test_profileNotificationsClearsCache() {
   let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateUI", 1);
   gFxAccounts._cachedProfile = { foo: "bar" };
-  Services.obs.notifyObservers(null, this.FxAccountsCommon.ON_PROFILE_CHANGE_NOTIFICATION);
+  Services.obs.notifyObservers(null, this.FxAccountsCommon.ON_PROFILE_CHANGE_NOTIFICATION, null);
   Assert.ok(!gFxAccounts._cachedProfile);
   yield promiseUpdateDone;
 });
 
 add_task(function* test_verifiedUserProfileFailure() {
   // profile failure means only one observer fires.
   let promiseUpdateDone = promiseObserver("test:browser_fxaccounts:updateUI", 1);
   gFxAccounts._cachedProfile = null;
--- a/browser/base/content/test/general/browser_syncui.js
+++ b/browser/base/content/test/general/browser_syncui.js
@@ -21,17 +21,17 @@ function notifyAndPromiseUIUpdated(topic
       return oldPromiseUpdateUI().then(() => {
         // Restore our override.
         gSyncUI._promiseUpdateUI = oldPromiseUpdateUI;
         // Resolve the promise so the caller knows the update is done.
         resolve();
       });
     };
     // Now send the notification.
-    Services.obs.notifyObservers(null, topic);
+    Services.obs.notifyObservers(null, topic, null);
   });
 }
 
 // Sync manages 3 broadcasters so the menus correctly reflect the Sync state.
 // Only one of these 3 should ever be visible - pass the ID of the broadcaster
 // you expect to be visible and it will check it's the only one that is.
 function checkBroadcasterVisible(broadcasterId) {
   let all = ["sync-reauth-state", "sync-setup-state", "sync-syncnow-state"];
@@ -79,17 +79,17 @@ add_task(function* prepare() {
   checkButtonTooltips("Sign In To Sync");
   // mock out the "_needsSetup()" function so we don't short-circuit.
   let oldNeedsSetup = window.gSyncUI._needsSetup;
   window.gSyncUI._needsSetup = () => Promise.resolve(false);
   registerCleanupFunction(() => {
     window.gSyncUI._needsSetup = oldNeedsSetup;
     // and an observer to set the state back to what it should be now we've
     // restored the stub.
-    Services.obs.notifyObservers(null, "weave:service:login:finish");
+    Services.obs.notifyObservers(null, "weave:service:login:finish", null);
   });
   // and a notification to have the state change away from "needs setup"
   yield notifyAndPromiseUIUpdated("weave:service:login:finish");
   checkBroadcasterVisible("sync-syncnow-state");
   // open the sync-button panel so we can check elements in that.
   document.getElementById("sync-button").click();
 });
 
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -337,17 +337,17 @@ function openLinkIn(url, where, params) 
           Services.obs.removeObserver(delayedStartupObserver, "browser-delayed-startup-finished");
           Services.obs.notifyObservers({
             wrappedJSObject: {
               url,
               createdTabBrowser: win.gBrowser.selectedBrowser,
               sourceTabBrowser,
               sourceFrameOuterWindowID: params.frameOuterWindowID,
             },
-          }, "webNavigation-createdNavigationTarget");
+          }, "webNavigation-createdNavigationTarget", null);
         }
       };
       Services.obs.addObserver(delayedStartupObserver, "browser-delayed-startup-finished");
     }
     win = Services.ww.openWindow(sourceWindow, getBrowserURL(), null, features, sa);
     return;
   }
 
@@ -457,17 +457,17 @@ function openLinkIn(url, where, params) 
       // opening a new tab using the keyboard shortcut).
       Services.obs.notifyObservers({
         wrappedJSObject: {
           url,
           createdTabBrowser: targetBrowser,
           sourceTabBrowser: w.gBrowser.selectedBrowser,
           sourceFrameOuterWindowID: params.frameOuterWindowID,
         },
-      }, "webNavigation-createdNavigationTarget");
+      }, "webNavigation-createdNavigationTarget", null);
     }
     break;
   }
 
   // Focus the content, but only if the browser used for the load is selected.
   if (targetBrowser == w.gBrowser.selectedBrowser) {
     targetBrowser.focus();
   }
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -437,17 +437,17 @@ const CustomizableWidgets = [
             this._appendClient(client, fragment);
           }
         }
         this._tabsList.appendChild(fragment);
       }).catch(err => {
         Cu.reportError(err);
       }).then(() => {
         // an observer for tests.
-        Services.obs.notifyObservers(null, "synced-tabs-menu:test:tabs-updated");
+        Services.obs.notifyObservers(null, "synced-tabs-menu:test:tabs-updated", null);
       });
     },
     _clearTabList() {
       let list = this._tabsList;
       while (list.lastChild) {
         list.lastChild.remove();
       }
     },
@@ -618,24 +618,24 @@ const CustomizableWidgets = [
       node.setAttribute("observes", "Social:PageShareable");
       node.setAttribute("command", "Social:SharePage");
 
       let listener = {
         onWidgetAdded: (aWidgetId) => {
           if (aWidgetId != this.id)
             return;
 
-          Services.obs.notifyObservers(null, "social:" + this.id + "-added");
+          Services.obs.notifyObservers(null, "social:" + this.id + "-added", null);
         },
 
         onWidgetRemoved: aWidgetId => {
           if (aWidgetId != this.id)
             return;
 
-          Services.obs.notifyObservers(null, "social:" + this.id + "-removed");
+          Services.obs.notifyObservers(null, "social:" + this.id + "-removed", null);
         },
 
         onWidgetInstanceRemoved: (aWidgetId, aDoc) => {
           if (aWidgetId != this.id || aDoc != aDocument)
             return;
 
           CustomizableUI.removeListener(listener);
         }
--- a/browser/components/customizableui/test/browser_synced_tabs_menu.js
+++ b/browser/components/customizableui/test/browser_synced_tabs_menu.js
@@ -19,17 +19,17 @@ const DECKINDEX_NOCLIENTS = 3;
 
 var initialLocation = gBrowser.currentURI.spec;
 var newTab = null;
 
 // A helper to notify there are new tabs. Returns a promise that is resolved
 // once the UI has been updated.
 function updateTabsPanel() {
   let promiseTabsUpdated = promiseObserverNotified("synced-tabs-menu:test:tabs-updated");
-  Services.obs.notifyObservers(null, SyncedTabs.TOPIC_TABS_CHANGED);
+  Services.obs.notifyObservers(null, SyncedTabs.TOPIC_TABS_CHANGED, null);
   return promiseTabsUpdated;
 }
 
 // This is the mock we use for SyncedTabs.jsm - tests may override various
 // functions.
 let mockedInternal = {
   get isConfiguredToSyncTabs() { return true; },
   getTabClients() { return Promise.resolve([]); },
--- a/browser/components/distribution.js
+++ b/browser/components/distribution.js
@@ -454,17 +454,17 @@ DistributionCustomizer.prototype = {
       } catch (e) {}
     }
 
     let prefDefaultsApplied = this._prefDefaultsApplied || !this._ini;
     if (this._customizationsApplied && this._bookmarksApplied &&
         prefDefaultsApplied) {
       let os = Cc["@mozilla.org/observer-service;1"].
                getService(Ci.nsIObserverService);
-      os.notifyObservers(null, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC);
+      os.notifyObservers(null, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC, null);
     }
   }
 };
 
 function parseValue(value) {
   try {
     value = JSON.parse(value);
   } catch (e) {
--- a/browser/components/extensions/test/browser/browser_ext_runtime_setUninstallURL.js
+++ b/browser/components/extensions/test/browser/browser_ext_runtime_setUninstallURL.js
@@ -4,17 +4,17 @@ let {AddonManager} = Components.utils.im
 let {Extension} = Components.utils.import("resource://gre/modules/Extension.jsm", {});
 
 function* makeAndInstallXPI(id, backgroundScript, loadedURL) {
   let xpi = Extension.generateXPI({
     manifest: {applications: {gecko: {id}}},
     background: backgroundScript,
   });
   SimpleTest.registerCleanupFunction(function cleanupXPI() {
-    Services.obs.notifyObservers(xpi, "flush-cache-entry");
+    Services.obs.notifyObservers(xpi, "flush-cache-entry", null);
     xpi.remove(false);
   });
 
   let loadPromise = BrowserTestUtils.waitForNewTab(gBrowser, loadedURL);
 
 
   info(`installing ${xpi.path}`);
   let addon = yield AddonManager.installTemporaryAddon(xpi);
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -300,17 +300,17 @@ BrowserGlue.prototype = {
         } else if (data == "force-distribution-customization") {
           this._distributionCustomizer.applyPrefDefaults();
           this._distributionCustomizer.applyCustomizations();
           // To apply distribution bookmarks use "places-init-complete".
         } else if (data == "force-places-init") {
           this._initPlaces(false);
         } else if (data == "smart-bookmarks-init") {
           this.ensurePlacesDefaultQueriesInitialized().then(() => {
-            Services.obs.notifyObservers(null, "test-smart-bookmarks-done");
+            Services.obs.notifyObservers(null, "test-smart-bookmarks-done", null);
           });
         } else if (data == "mock-fxaccounts") {
           Object.defineProperty(this, "fxAccounts", {
             value: subject.wrappedJSObject
           });
         }
         break;
       case "initial-migration-will-import-default-bookmarks":
@@ -556,17 +556,17 @@ BrowserGlue.prototype = {
     }
 
     TabCrashHandler.init();
     if (AppConstants.MOZ_CRASHREPORTER) {
       PluginCrashReporter.init();
       UnsubmittedCrashHandler.init();
     }
 
-    Services.obs.notifyObservers(null, "browser-ui-startup-complete");
+    Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
   },
 
   _checkForOldBuildUpdates() {
     // check for update if our build is old
     if (AppConstants.MOZ_UPDATER &&
         Services.prefs.getBoolPref("app.update.enabled") &&
         Services.prefs.getBoolPref("app.update.checkInstallTime")) {
 
@@ -1490,17 +1490,17 @@ BrowserGlue.prototype = {
         this._idleService.addIdleObserver(this, this._bookmarksBackupIdleTime);
       }
 
     }.bind(this)).catch(ex => {
       Cu.reportError(ex);
     }).then(() => {
       // NB: deliberately after the catch so that we always do this, even if
       // we threw halfway through initializing in the Task above.
-      Services.obs.notifyObservers(null, "places-browser-init-complete");
+      Services.obs.notifyObservers(null, "places-browser-init-complete", "");
     });
   },
 
   /**
    * If a backup for today doesn't exist, this creates one.
    */
   _backupBookmarks: function BG__backupBookmarks() {
     return Task.spawn(function*() {
--- a/browser/components/places/content/editBookmarkOverlay.js
+++ b/browser/components/places/content/editBookmarkOverlay.js
@@ -812,17 +812,17 @@ var gEditItemOverlay = {
           containerId != PlacesUtils.toolbarFolderId &&
           containerId != PlacesUtils.bookmarksMenuFolderId) {
         this._markFolderAsRecentlyUsed(containerId)
             .catch(Components.utils.reportError);
       }
 
       // Auto-show the bookmarks toolbar when adding / moving an item there.
       if (containerId == PlacesUtils.toolbarFolderId) {
-        Services.obs.notifyObservers(null, "autoshow-bookmarks-toolbar");
+        Services.obs.notifyObservers(null, "autoshow-bookmarks-toolbar", null);
       }
     }
 
     // Update folder-tree selection
     var folderTreeRow = this._element("folderTreeRow");
     if (!folderTreeRow.collapsed) {
       var selectedNode = this._folderTree.selectedNode;
       if (!selectedNode ||
--- a/browser/components/preferences/SiteDataManager.jsm
+++ b/browser/components/preferences/SiteDataManager.jsm
@@ -38,17 +38,17 @@ this.SiteDataManager = {
 
   _updateQuotaPromise: null,
 
   _updateDiskCachePromise: null,
 
   _quotaUsageRequests: null,
 
   updateSites() {
-    Services.obs.notifyObservers(null, "sitedatamanager:updating-sites");
+    Services.obs.notifyObservers(null, "sitedatamanager:updating-sites", null);
 
     // Clear old data and requests first
     this._sites.clear();
     this._cancelQuotaUpdate();
 
     // Collect sites granted/rejected with the persistent-storage permission
     let perm = null;
     let status = null;
@@ -69,17 +69,17 @@ this.SiteDataManager = {
     }
 
     this._updateQuota();
     this._updateAppCache();
     this._updateDiskCache();
 
     Promise.all([this._updateQuotaPromise, this._updateDiskCachePromise])
            .then(() => {
-             Services.obs.notifyObservers(null, "sitedatamanager:sites-updated");
+             Services.obs.notifyObservers(null, "sitedatamanager:sites-updated", null);
            });
   },
 
   _updateQuota() {
     this._quotaUsageRequests = [];
     let promises = [];
     for (let site of this._sites.values()) {
       promises.push(new Promise(resolve => {
--- a/browser/components/preferences/in-content-old/applications.js
+++ b/browser/components/preferences/in-content-old/applications.js
@@ -794,17 +794,17 @@ function InternalHandlerInfoWrapper(aMIM
 
 InternalHandlerInfoWrapper.prototype = {
   __proto__: HandlerInfoWrapper.prototype,
 
   // Override store so we so we can notify any code listening for registration
   // or unregistration of this handler.
   store() {
     HandlerInfoWrapper.prototype.store.call(this);
-    Services.obs.notifyObservers(null, this._handlerChanged);
+    Services.obs.notifyObservers(null, this._handlerChanged, null);
   },
 
   get enabled() {
     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
 
   get description() {
     return this.element("bundlePreferences").getString(this._appPrefLabel);
@@ -937,17 +937,17 @@ var gApplicationsPane = {
     var _delayedPaneLoad = function(self) {
       self._loadData();
       self._rebuildVisibleTypes();
       self._sortVisibleTypes();
       self._rebuildView();
 
       // Notify observers that the UI is now ready
       Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService).
-      notifyObservers(window, "app-handler-pane-loaded");
+      notifyObservers(window, "app-handler-pane-loaded", null);
     }
     setTimeout(_delayedPaneLoad, 0, this);
   },
 
   destroy() {
     window.removeEventListener("unload", this);
     this._prefSvc.removeObserver(PREF_SHOW_PLUGINS_IN_LIST, this);
     this._prefSvc.removeObserver(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS, this);
--- a/browser/components/preferences/in-content-old/main.js
+++ b/browser/components/preferences/in-content-old/main.js
@@ -122,17 +122,17 @@ var gMainPane = {
       fxAccounts.getSignedInUser().then(data => {
         document.getElementById("getStarted").selectedIndex = data ? 1 : 0;
       });
     }
 
     // Notify observers that the UI is now ready
     Components.classes["@mozilla.org/observer-service;1"]
               .getService(Components.interfaces.nsIObserverService)
-              .notifyObservers(window, "main-pane-loaded");
+              .notifyObservers(window, "main-pane-loaded", null);
   },
 
   enableE10SChange() {
     if (AppConstants.E10S_TESTING_ONLY) {
       let e10sCheckbox = document.getElementById("e10sAutoStart");
       let e10sPref = document.getElementById("browser.tabs.remote.autostart");
       let e10sTempPref = document.getElementById("e10sTempPref");
 
--- a/browser/components/preferences/in-content-old/preferences.js
+++ b/browser/components/preferences/in-content-old/preferences.js
@@ -94,17 +94,17 @@ function init_all() {
     let name = internalPrefCategoryNameToFriendlyName(category.value);
     let helpSelector = `#header-${name} > .help-button`;
     let helpButton = document.querySelector(helpSelector);
     helpButton.setAttribute("href", getHelpLinkURL(category.getAttribute("helpTopic")));
   }
 
   // Wait until initialization of all preferences are complete before
   // notifying observers that the UI is now ready.
-  Services.obs.notifyObservers(window, "advanced-pane-loaded");
+  Services.obs.notifyObservers(window, "advanced-pane-loaded", null);
 }
 
 // Make the space above the categories list shrink on low window heights
 function init_dynamic_padding() {
   let categories = document.getElementById("categories");
   let catPadding = Number.parseInt(getComputedStyle(categories)
                                      .getPropertyValue("padding-top"));
   let fullHeight = categories.lastElementChild.getBoundingClientRect().bottom;
--- a/browser/components/preferences/in-content-old/privacy.js
+++ b/browser/components/preferences/in-content-old/privacy.js
@@ -654,17 +654,17 @@ var gPrivacyPane = {
     }
 
     gSubDialog.open("chrome://browser/content/sanitize.xul", "resizable=no", null, () => {
       // reset the timeSpan pref
       if (aClearEverything) {
         ts.value = timeSpanOrig;
       }
 
-      Services.obs.notifyObservers(null, "clear-private-data");
+      Services.obs.notifyObservers(null, "clear-private-data", null);
     });
   },
 
   /**
    * Enables or disables the "Settings..." button depending
    * on the privacy.sanitize.sanitizeOnShutdown preference value
    */
   _updateSanitizeSettingsButton() {
--- a/browser/components/preferences/in-content-old/tests/browser_advanced_siteData.js
+++ b/browser/components/preferences/in-content-old/tests/browser_advanced_siteData.js
@@ -245,24 +245,24 @@ add_task(function *() {
   yield SiteDataManager.getTotalUsage()
                        .then(usage => {
                          actual = totalSiteDataSizeLabel.textContent;
                          expected = prefStrBundle.getFormattedString(
                            "totalSiteDataSize", DownloadUtils.convertByteUnits(usage));
                           is(actual, expected, "Should show the right total site data size");
                        });
 
-  Services.obs.notifyObservers(null, "sitedatamanager:updating-sites");
+  Services.obs.notifyObservers(null, "sitedatamanager:updating-sites", null);
   is(clearBtn.disabled, true, "Should disable clear button while updating sites");
   is(settingsButton.disabled, true, "Should disable settings button while updating sites");
   actual = totalSiteDataSizeLabel.textContent;
   expected = prefStrBundle.getString("loadingSiteDataSize");
   is(actual, expected, "Should show the loading message while updating");
 
-  Services.obs.notifyObservers(null, "sitedatamanager:sites-updated");
+  Services.obs.notifyObservers(null, "sitedatamanager:sites-updated", null);
   is(clearBtn.disabled, false, "Should enable clear button after sites updated");
   is(settingsButton.disabled, false, "Should enable settings button after sites updated");
   yield SiteDataManager.getTotalUsage()
                        .then(usage => {
                           actual = totalSiteDataSizeLabel.textContent;
                           expected = prefStrBundle.getFormattedString(
                            "totalSiteDataSize", DownloadUtils.convertByteUnits(usage));
                           is(actual, expected, "Should show the right total site data size");
--- a/browser/components/preferences/in-content/applications.js
+++ b/browser/components/preferences/in-content/applications.js
@@ -796,17 +796,17 @@ function InternalHandlerInfoWrapper(aMIM
 
 InternalHandlerInfoWrapper.prototype = {
   __proto__: HandlerInfoWrapper.prototype,
 
   // Override store so we so we can notify any code listening for registration
   // or unregistration of this handler.
   store() {
     HandlerInfoWrapper.prototype.store.call(this);
-    Services.obs.notifyObservers(null, this._handlerChanged);
+    Services.obs.notifyObservers(null, this._handlerChanged, null);
   },
 
   get enabled() {
     throw Cr.NS_ERROR_NOT_IMPLEMENTED;
   },
 
   get description() {
     return this.element("bundlePreferences").getString(this._appPrefLabel);
@@ -941,17 +941,17 @@ var gApplicationsPane = {
     var _delayedPaneLoad = function(self) {
       self._loadData();
       self._rebuildVisibleTypes();
       self._sortVisibleTypes();
       self._rebuildView();
 
       // Notify observers that the UI is now ready
       Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService).
-      notifyObservers(window, "app-handler-pane-loaded");
+      notifyObservers(window, "app-handler-pane-loaded", null);
     }
     setTimeout(_delayedPaneLoad, 0, this);
   },
 
   destroy() {
     window.removeEventListener("unload", this);
     this._prefSvc.removeObserver(PREF_SHOW_PLUGINS_IN_LIST, this);
     this._prefSvc.removeObserver(PREF_HIDE_PLUGINS_WITHOUT_EXTENSIONS, this);
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -192,17 +192,17 @@ var gMainPane = {
         document.getElementById("getStarted").selectedIndex = data ? 1 : 0;
       })
       .catch(Cu.reportError);
     }
 
     // Notify observers that the UI is now ready
     Components.classes["@mozilla.org/observer-service;1"]
               .getService(Components.interfaces.nsIObserverService)
-              .notifyObservers(window, "main-pane-loaded");
+              .notifyObservers(window, "main-pane-loaded", null);
   },
 
   enableE10SChange() {
     if (AppConstants.E10S_TESTING_ONLY) {
       let e10sCheckbox = document.getElementById("e10sAutoStart");
       let e10sPref = document.getElementById("browser.tabs.remote.autostart");
       let e10sTempPref = document.getElementById("e10sTempPref");
 
--- a/browser/components/preferences/in-content/preferences.js
+++ b/browser/components/preferences/in-content/preferences.js
@@ -91,17 +91,17 @@ function init_all() {
     let name = internalPrefCategoryNameToFriendlyName(category.value);
     let helpSelector = `#header-${name} > .help-button`;
     let helpButton = document.querySelector(helpSelector);
     helpButton.setAttribute("href", getHelpLinkURL(category.getAttribute("helpTopic")));
   }
 
   // Wait until initialization of all preferences are complete before
   // notifying observers that the UI is now ready.
-  Services.obs.notifyObservers(window, "advanced-pane-loaded");
+  Services.obs.notifyObservers(window, "advanced-pane-loaded", null);
 }
 
 // Make the space above the categories list shrink on low window heights
 function init_dynamic_padding() {
   let categories = document.getElementById("categories");
   let catPadding = Number.parseInt(getComputedStyle(categories)
                                      .getPropertyValue("padding-top"));
   let fullHeight = categories.lastElementChild.getBoundingClientRect().bottom;
--- a/browser/components/preferences/in-content/privacy.js
+++ b/browser/components/preferences/in-content/privacy.js
@@ -780,17 +780,17 @@ var gPrivacyPane = {
     }
 
     gSubDialog.open("chrome://browser/content/sanitize.xul", "resizable=no", null, () => {
       // reset the timeSpan pref
       if (aClearEverything) {
         ts.value = timeSpanOrig;
       }
 
-      Services.obs.notifyObservers(null, "clear-private-data");
+      Services.obs.notifyObservers(null, "clear-private-data", null);
     });
   },
 
   /**
    * Enables or disables the "Settings..." button depending
    * on the privacy.sanitize.sanitizeOnShutdown preference value
    */
   _updateSanitizeSettingsButton() {
--- a/browser/components/preferences/in-content/tests/browser_siteData.js
+++ b/browser/components/preferences/in-content/tests/browser_siteData.js
@@ -186,24 +186,24 @@ add_task(function *() {
   yield SiteDataManager.getTotalUsage()
                        .then(usage => {
                          actual = totalSiteDataSizeLabel.textContent;
                          expected = prefStrBundle.getFormattedString(
                            "totalSiteDataSize", DownloadUtils.convertByteUnits(usage));
                           is(actual, expected, "Should show the right total site data size");
                        });
 
-  Services.obs.notifyObservers(null, "sitedatamanager:updating-sites");
+  Services.obs.notifyObservers(null, "sitedatamanager:updating-sites", null);
   is(clearBtn.disabled, true, "Should disable clear button while updating sites");
   is(settingsButton.disabled, true, "Should disable settings button while updating sites");
   actual = totalSiteDataSizeLabel.textContent;
   expected = prefStrBundle.getString("loadingSiteDataSize");
   is(actual, expected, "Should show the loading message while updating");
 
-  Services.obs.notifyObservers(null, "sitedatamanager:sites-updated");
+  Services.obs.notifyObservers(null, "sitedatamanager:sites-updated", null);
   is(clearBtn.disabled, false, "Should enable clear button after sites updated");
   is(settingsButton.disabled, false, "Should enable settings button after sites updated");
   yield SiteDataManager.getTotalUsage()
                        .then(usage => {
                          actual = totalSiteDataSizeLabel.textContent;
                          expected = prefStrBundle.getFormattedString(
                            "totalSiteDataSize", DownloadUtils.convertByteUnits(usage));
                           is(actual, expected, "Should show the right total site data size");
--- a/browser/components/preferences/siteDataSettings.js
+++ b/browser/components/preferences/siteDataSettings.js
@@ -37,17 +37,17 @@ let gSiteDataSettings = {
     this._list = document.getElementById("sitesList");
     this._searchBox = document.getElementById("searchBox");
     this._prefStrBundle = document.getElementById("bundlePreferences");
     SiteDataManager.getSites().then(sites => {
       this._sites = sites;
       let sortCol = document.getElementById("hostCol");
       this._sortSites(this._sites, sortCol);
       this._buildSitesList(this._sites);
-      Services.obs.notifyObservers(null, "sitedata-settings-init");
+      Services.obs.notifyObservers(null, "sitedata-settings-init", null);
     });
 
     let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
     let settingsDescription = document.getElementById("settingsDescription");
     settingsDescription.textContent = this._prefStrBundle.getFormattedString("siteDataSettings.description", [brandShortName]);
 
     setEventListener("hostCol", "click", this.onClickTreeCol);
     setEventListener("usageCol", "click", this.onClickTreeCol);
--- a/browser/components/privatebrowsing/test/browser/head.js
+++ b/browser/components/privatebrowsing/test/browser/head.js
@@ -38,17 +38,17 @@ function newFileInDirectory(aDir) {
   let file = aDir.clone();
   file.append("testfile");
   file.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_FILE);
   return file;
 }
 
 function clearHistory() {
   // simulate clearing the private data
-  Services.obs.notifyObservers(null, "browser:purge-session-history");
+  Services.obs.notifyObservers(null, "browser:purge-session-history", "");
 }
 
 function _initTest() {
   // Don't use about:home as the homepage for new windows
   Services.prefs.setIntPref("browser.startup.page", 0);
   registerCleanupFunction(() => Services.prefs.clearUserPref("browser.startup.page"));
 }
 
--- a/browser/components/sessionstore/SessionFile.jsm
+++ b/browser/components/sessionstore/SessionFile.jsm
@@ -369,17 +369,17 @@ var SessionFileInternal = {
     // This code will always be executed because |promise| can't fail anymore.
     // We ensured that by having a reject handler that reports the failure but
     // doesn't forward the rejection.
     return promise.then(() => {
       // Remove the blocker, no matter if writing failed or not.
       AsyncShutdown.profileBeforeChange.removeBlocker(promise);
 
       if (isFinalWrite) {
-        Services.obs.notifyObservers(null, "sessionstore-final-state-write-complete");
+        Services.obs.notifyObservers(null, "sessionstore-final-state-write-complete", "");
       }
     });
   },
 
   wipe() {
     return this._postToWorker("wipe");
   },
 
--- a/browser/components/sessionstore/SessionSaver.jsm
+++ b/browser/components/sessionstore/SessionSaver.jsm
@@ -49,17 +49,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
  * it to happen soon, with "browser.sessionstore.interval".
  */
 const PREF_INTERVAL_ACTIVE = "browser.sessionstore.interval";
 const PREF_INTERVAL_IDLE = "browser.sessionstore.interval.idle";
 const PREF_IDLE_DELAY = "browser.sessionstore.idleDelay";
 
 // Notify observers about a given topic with a given subject.
 function notify(subject, topic) {
-  Services.obs.notifyObservers(subject, topic);
+  Services.obs.notifyObservers(subject, topic, "");
 }
 
 // TelemetryStopwatch helper functions.
 function stopWatch(method) {
   return function(...histograms) {
     for (let hist of histograms) {
       TelemetryStopwatch[method]("FX_SESSION_RESTORE_" + hist);
     }
--- a/browser/components/sessionstore/SessionStore.jsm
+++ b/browser/components/sessionstore/SessionStore.jsm
@@ -947,17 +947,17 @@ var SessionStoreInternal = {
             userTypedValue: null, userTypedClear: null
           });
         }
         break;
       case "SessionStore:restoreTabContentComplete":
         // This callback is used exclusively by tests that want to
         // monitor the progress of network loads.
         if (gDebuggingEnabled) {
-          Services.obs.notifyObservers(browser, NOTIFY_TAB_RESTORED);
+          Services.obs.notifyObservers(browser, NOTIFY_TAB_RESTORED, null);
         }
 
         SessionStoreInternal._resetLocalTabRestoringState(tab);
         SessionStoreInternal.restoreNextTab();
 
         this._sendTabRestoredNotification(tab, data.isRemotenessUpdate);
         break;
       case "SessionStore:crashedTabRevived":
@@ -1144,17 +1144,17 @@ var SessionStoreInternal = {
 
         if (isPrivateWindow) {
           // We're starting with a single private window. Save the state we
           // actually wanted to restore so that we can do it later in case
           // the user opens another, non-private window.
           this._deferredInitialState = gSessionStartup.state;
 
           // Nothing to restore now, notify observers things are complete.
-          Services.obs.notifyObservers(null, NOTIFY_WINDOWS_RESTORED);
+          Services.obs.notifyObservers(null, NOTIFY_WINDOWS_RESTORED, "");
         } else {
           TelemetryTimestamps.add("sessionRestoreRestoring");
           this._restoreCount = aInitialState.windows ? aInitialState.windows.length : 0;
 
           // global data must be restored before restoreWindow is called so that
           // it happens before observers are notified
           this._globalState.setFromState(aInitialState);
 
@@ -1162,17 +1162,17 @@ var SessionStoreInternal = {
           SessionCookies.restore(aInitialState.cookies || []);
 
           let overwrite = this._isCmdLineEmpty(aWindow, aInitialState);
           let options = {firstWindow: true, overwriteTabs: overwrite};
           this.restoreWindows(aWindow, aInitialState, options);
         }
       } else {
         // Nothing to restore, notify observers things are complete.
-        Services.obs.notifyObservers(null, NOTIFY_WINDOWS_RESTORED);
+        Services.obs.notifyObservers(null, NOTIFY_WINDOWS_RESTORED, "");
       }
     // this window was opened by _openWindowWithState
     } else if (!this._isWindowLoaded(aWindow)) {
       let state = this._statesToRestore[aWindow.__SS_restoreID];
       let options = {overwriteTabs: true, isFollowUp: state.windows.length == 1};
       this.restoreWindow(aWindow, state.windows[0], options);
     // The user opened another, non-private window after starting up with
     // a single private one. Let's restore the session we actually wanted to
@@ -1304,17 +1304,17 @@ var SessionStoreInternal = {
 
       if (this._sessionInitialized) {
         this.initializeWindow(aWindow);
       } else {
         let initialState = this.initSession();
         this._sessionInitialized = true;
 
         if (initialState) {
-          Services.obs.notifyObservers(null, NOTIFY_RESTORING_ON_STARTUP);
+          Services.obs.notifyObservers(null, NOTIFY_RESTORING_ON_STARTUP, "");
         }
         TelemetryStopwatch.start("FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS");
         this.initializeWindow(aWindow, initialState);
         TelemetryStopwatch.finish("FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS");
 
         // Let everyone know we're done.
         this._deferredInitialized.resolve();
       }
@@ -2658,17 +2658,17 @@ var SessionStoreInternal = {
    * be opened.
    */
   restoreLastSession: function ssi_restoreLastSession() {
     // Use the public getter since it also checks PB mode
     if (!this.canRestoreLastSession) {
       throw Components.Exception("Last session can not be restored");
     }
 
-    Services.obs.notifyObservers(null, NOTIFY_INITIATING_MANUAL_RESTORE);
+    Services.obs.notifyObservers(null, NOTIFY_INITIATING_MANUAL_RESTORE, "");
 
     // First collect each window with its id...
     let windows = {};
     this._forEachBrowserWindow(function(aWindow) {
       if (aWindow.__SS_lastSessionWindowID)
         windows[aWindow.__SS_lastSessionWindowID] = aWindow;
     });
 
@@ -3438,17 +3438,17 @@ var SessionStoreInternal = {
     tabstrip.smoothScroll = smoothScroll;
 
     TelemetryStopwatch.finish("FX_SESSION_RESTORE_RESTORE_WINDOW_MS");
 
     this._setWindowStateReady(aWindow);
 
     this._sendWindowRestoredNotification(aWindow);
 
-    Services.obs.notifyObservers(aWindow, NOTIFY_SINGLE_WINDOW_RESTORED);
+    Services.obs.notifyObservers(aWindow, NOTIFY_SINGLE_WINDOW_RESTORED, "");
 
     this._sendRestoreCompletedNotifications();
   },
 
   /**
    * Restore multiple windows using the provided state.
    * @param aWindow
    *        Window reference to the first window to use for restoration.
@@ -4028,17 +4028,17 @@ var SessionStoreInternal = {
    * Waits a tick to allow SessionStorage a chance to register the change.
    */
   _notifyOfClosedObjectsChange() {
     if (!this._closedObjectsChanged) {
       return;
     }
     this._closedObjectsChanged = false;
     setTimeout(() => {
-      Services.obs.notifyObservers(null, NOTIFY_CLOSED_OBJECTS_CHANGED);
+      Services.obs.notifyObservers(null, NOTIFY_CLOSED_OBJECTS_CHANGED, null);
     }, 0);
   },
 
   /**
    * Determines whether or not a tab that is being restored needs
    * to have its remoteness flipped first.
    *
    * @param tab (<xul:tab>):
@@ -4419,17 +4419,18 @@ var SessionStoreInternal = {
     }
 
     // observers were already notified
     if (this._restoreCount == -1)
       return;
 
     // This was the last window restored at startup, notify observers.
     Services.obs.notifyObservers(null,
-      this._browserSetState ? NOTIFY_BROWSER_STATE_RESTORED : NOTIFY_WINDOWS_RESTORED);
+      this._browserSetState ? NOTIFY_BROWSER_STATE_RESTORED : NOTIFY_WINDOWS_RESTORED,
+      "");
 
     this._browserSetState = false;
     this._restoreCount = -1;
   },
 
    /**
    * Set the given window's busy state
    * @param aWindow the window
@@ -4981,12 +4982,12 @@ var LastSession = {
 
   setState(state) {
     this._state = state;
   },
 
   clear() {
     if (this._state) {
       this._state = null;
-      Services.obs.notifyObservers(null, NOTIFY_LAST_SESSION_CLEARED);
+      Services.obs.notifyObservers(null, NOTIFY_LAST_SESSION_CLEARED, null);
     }
   }
 };
--- a/browser/components/sessionstore/StartupPerformance.jsm
+++ b/browser/components/sessionstore/StartupPerformance.jsm
@@ -99,17 +99,17 @@ this.StartupPerformance = {
 
     Services.obs.addObserver(this, "sessionstore-single-window-restored");
     this._promiseFinished = new Promise(resolve => {
       this._resolveFinished = resolve;
     });
     this._promiseFinished.then(() => {
       try {
         this._isRestored = true;
-        Services.obs.notifyObservers(null, this.RESTORED_TOPIC);
+        Services.obs.notifyObservers(null, this.RESTORED_TOPIC, "");
 
         if (this._latestRestoredTimeStamp == this._startTimeStamp) {
           // Apparently, we haven't restored any tab.
           return;
         }
 
         // Once we are done restoring tabs, update Telemetry.
         let histogramName = isAutoRestore ?
--- a/browser/components/sessionstore/content/aboutSessionRestore.js
+++ b/browser/components/sessionstore/content/aboutSessionRestore.js
@@ -107,17 +107,17 @@ function updateTabListVisibility() {
   } else {
     tabList.removeAttribute("available");
     container.classList.remove("restore-chosen");
   }
   initTreeView();
 }
 
 function restoreSession() {
-  Services.obs.notifyObservers(null, "sessionstore-initiating-manual-restore");
+  Services.obs.notifyObservers(null, "sessionstore-initiating-manual-restore", "");
   document.getElementById("errorTryAgain").disabled = true;
 
   if (isTreeViewVisible()) {
     if (!gTreeData.some(aItem => aItem.checked)) {
       // This should only be possible when we have no "cancel" button, and thus
       // the "Restore session" button always remains enabled.  In that case and
       // when nothing is selected, we just want a new session.
       startNewSession();
--- a/browser/components/sessionstore/nsSessionStartup.js
+++ b/browser/components/sessionstore/nsSessionStartup.js
@@ -92,17 +92,17 @@ SessionStartup.prototype = {
   _previousSessionCrashed: null,
 
 /* ........ Global Event Handlers .............. */
 
   /**
    * Initialize the component
    */
   init: function sss_init() {
-    Services.obs.notifyObservers(null, "sessionstore-init-started");
+    Services.obs.notifyObservers(null, "sessionstore-init-started", null);
     StartupPerformance.init();
 
     // do not need to initialize anything in auto-started private browsing sessions
     if (PrivateBrowsingUtils.permanentPrivateBrowsing) {
       this._initialized = true;
       gOnceInitializedDeferred.resolve();
       return;
     }
@@ -127,17 +127,17 @@ SessionStartup.prototype = {
    * @param source The Session State string read from disk.
    * @param parsed The object obtained by parsing |source| as JSON.
    */
   _onSessionFileRead({source, parsed, noFilesFound}) {
     this._initialized = true;
 
     // Let observers modify the state before it is used
     let supportsStateString = this._createSupportsString(source);
-    Services.obs.notifyObservers(supportsStateString, "sessionstore-state-read");
+    Services.obs.notifyObservers(supportsStateString, "sessionstore-state-read", "");
     let stateString = supportsStateString.data;
 
     if (stateString != source) {
       // The session has been modified by an add-on, reparse.
       try {
         this._initialState = JSON.parse(stateString);
       } catch (ex) {
         // That's not very good, an add-on has rewritten the initial
@@ -147,17 +147,17 @@ SessionStartup.prototype = {
     } else {
       // No need to reparse
       this._initialState = parsed;
     }
 
     if (this._initialState == null) {
       // No valid session found.
       this._sessionType = Ci.nsISessionStartup.NO_SESSION;
-      Services.obs.notifyObservers(null, "sessionstore-state-finalized");
+      Services.obs.notifyObservers(null, "sessionstore-state-finalized", "");
       gOnceInitializedDeferred.resolve();
       return;
     }
 
     let shouldResumeSessionOnce = Services.prefs.getBoolPref("browser.sessionstore.resume_session_once");
     let shouldResumeSession = shouldResumeSessionOnce ||
           Services.prefs.getIntPref("browser.startup.page") == BROWSER_STARTUP_RESUME_SESSION;
 
@@ -215,17 +215,17 @@ SessionStartup.prototype = {
         this._initialState = null; // reset the state
 
       Services.obs.addObserver(this, "sessionstore-windows-restored", true);
 
       if (this._sessionType != Ci.nsISessionStartup.NO_SESSION)
         Services.obs.addObserver(this, "browser:purge-session-history", true);
 
       // We're ready. Notify everyone else.
-      Services.obs.notifyObservers(null, "sessionstore-state-finalized");
+      Services.obs.notifyObservers(null, "sessionstore-state-finalized", "");
       gOnceInitializedDeferred.resolve();
     });
   },
 
   /**
    * Handle notifications
    */
   observe: function sss_observe(aSubject, aTopic, aData) {
--- a/browser/components/sessionstore/test/browser_cleaner.js
+++ b/browser/components/sessionstore/test/browser_cleaner.js
@@ -113,17 +113,17 @@ add_task(function* test_old_data() {
 
   let state = getClosedState();
   delete state._closedWindows[0].closedAt;
   delete state.windows[0]._closedTabs[0].closedAt;
   delete state.windows[0]._closedTabs[1].closedAt;
   yield promiseBrowserState(state);
 
   info("Sending idle-daily");
-  Services.obs.notifyObservers(null, "idle-daily");
+  Services.obs.notifyObservers(null, "idle-daily", "");
   info("Sent idle-daily");
 
   state = JSON.parse(ss.getBrowserState());
   is(state.windows[0].closedAt || false, false, "4. Main window doesn't have closedAt");
   ok(isRecent(state._closedWindows[0].closedAt), "4. Second window was closed recently");
   ok(isRecent(state.windows[0]._closedTabs[0].closedAt), "4. First tab was closed recently");
   ok(isRecent(state.windows[0]._closedTabs[1].closedAt), "4. Second tab was closed recently");
   yield promiseCleanup();
@@ -139,17 +139,17 @@ add_task(function* test_cleanup() {
   state._closedWindows[0].closedAt = LONG_TIME_AGO;
   state.windows[0]._closedTabs[0].closedAt = LONG_TIME_AGO;
   state.windows[0]._closedTabs[1].closedAt = Date.now();
   let url = state.windows[0]._closedTabs[1].state.entries[0].url;
 
   yield promiseBrowserState(state);
 
   info("Sending idle-daily");
-  Services.obs.notifyObservers(null, "idle-daily");
+  Services.obs.notifyObservers(null, "idle-daily", "");
   info("Sent idle-daily");
 
   state = JSON.parse(ss.getBrowserState());
   is(state._closedWindows[0], undefined, "5. Second window was forgotten");
 
   is(state.windows[0]._closedTabs.length, 1, "5. Only one closed tab left");
   is(state.windows[0]._closedTabs[0].state.entries[0].url, url, "5. The second tab is still here");
   yield promiseCleanup();
--- a/browser/components/sessionstore/test/browser_closed_objects_changed_notifications_tabs.js
+++ b/browser/components/sessionstore/test/browser_closed_objects_changed_notifications_tabs.js
@@ -52,17 +52,17 @@ function* awaitNotification(callback) {
 }
 
 add_task(function* test_closedObjectsChangedNotifications() {
   // Create a closed window so that when we do the purge we can expect a notification.
   yield openAndCloseWindow("about:robots");
 
   // Forget any previous closed windows or tabs from other tests that may have
   // run in the same session.
-  yield awaitNotification(() => Services.obs.notifyObservers(null, "browser:purge-session-history"));
+  yield awaitNotification(() => Services.obs.notifyObservers(null, "browser:purge-session-history", 0));
 
   // Add an observer to count the number of notifications.
   Services.obs.addObserver(countingObserver, TOPIC);
 
   // Open a new window.
   let win = yield openWindow("about:robots");
 
   info("Opening and closing a tab.");
@@ -85,17 +85,17 @@ add_task(function* test_closedObjectsCha
   yield promiseTabRestored(tab);
   assertNotificationCount(4);
 
   info("Closing tab again.");
   yield promiseRemoveTab(tab);
   assertNotificationCount(5);
 
   info("Purging session history.");
-  yield awaitNotification(() => Services.obs.notifyObservers(null, "browser:purge-session-history"));
+  yield awaitNotification(() => Services.obs.notifyObservers(null, "browser:purge-session-history", 0));
   assertNotificationCount(6);
 
   info("Opening and closing another tab.");
   yield openAndCloseTab(win, "http://example.com/");
   assertNotificationCount(7);
 
   info("Purging domain data with no matches.")
   Services.obs.notifyObservers(null, "browser:purge-domain-data", "mozilla.com");
--- a/browser/components/sessionstore/test/browser_closed_objects_changed_notifications_windows.js
+++ b/browser/components/sessionstore/test/browser_closed_objects_changed_notifications_windows.js
@@ -43,17 +43,17 @@ function* awaitNotification(callback) {
 }
 
 add_task(function* test_closedObjectsChangedNotifications() {
   // Create a closed window so that when we do the purge we know to expect a notification
   yield openAndCloseWindow("about:robots");
 
   // Forget any previous closed windows or tabs from other tests that may have
   // run in the same session.
-  yield awaitNotification(() => Services.obs.notifyObservers(null, "browser:purge-session-history"));
+  yield awaitNotification(() => Services.obs.notifyObservers(null, "browser:purge-session-history", 0));
 
   // Add an observer to count the number of notifications.
   Services.obs.addObserver(countingObserver, TOPIC);
 
   info("Opening and closing initial window.");
   yield openAndCloseWindow("about:robots");
   assertNotificationCount(1);
 
@@ -91,25 +91,25 @@ add_task(function* test_closedObjectsCha
 
   info("Setting browser state to trigger change onIdleDaily.")
   let state = Cu.cloneInto(JSON.parse(ss.getBrowserState()), {});
   state._closedWindows[0].closedAt = 1;
   yield promiseBrowserState(state);
   assertNotificationCount(8);
 
   info("Sending idle-daily");
-  yield awaitNotification(() => Services.obs.notifyObservers(null, "idle-daily"));
+  yield awaitNotification(() => Services.obs.notifyObservers(null, "idle-daily", ""));
   assertNotificationCount(9);
 
   info("Opening and closing another window.");
   yield openAndCloseWindow("about:robots");
   assertNotificationCount(10);
 
   info("Purging session history.");
-  yield awaitNotification(() => Services.obs.notifyObservers(null, "browser:purge-session-history"));
+  yield awaitNotification(() => Services.obs.notifyObservers(null, "browser:purge-session-history", 0));
   assertNotificationCount(11);
 
   info("Setting window state.")
   win = yield openWindow("about:mozilla");
   yield awaitNotification(() => SessionStore.setWindowState(win, closedState));
   assertNotificationCount(12);
 
   Services.obs.removeObserver(countingObserver, TOPIC);
--- a/browser/components/sessionstore/test/browser_forget_async_closings.js
+++ b/browser/components/sessionstore/test/browser_forget_async_closings.js
@@ -17,17 +17,17 @@ const PAGE = "http://example.com/";
  */
 let forgetTabHelper = Task.async(function*(forgetFn) {
   // We want to suppress all non-final updates from the browser tabs
   // so as to eliminate any racy-ness with this test.
   yield pushPrefs(["browser.sessionstore.debug.no_auto_updates", true]);
 
   // Forget any previous closed tabs from other tests that may have
   // run in the same session.
-  Services.obs.notifyObservers(null, "browser:purge-session-history");
+  Services.obs.notifyObservers(null, "browser:purge-session-history", 0);
 
   is(ss.getClosedTabCount(window), 0,
      "We should have 0 closed tabs being stored.");
 
   // Create a tab worth remembering.
   let tab = gBrowser.addTab(PAGE);
   let browser = tab.linkedBrowser;
   yield BrowserTestUtils.browserLoaded(browser, false, PAGE);
@@ -64,17 +64,17 @@ let forgetTabHelper = Task.async(functio
  */
 let forgetWinHelper = Task.async(function*(forgetFn) {
   // We want to suppress all non-final updates from the browser tabs
   // so as to eliminate any racy-ness with this test.
   yield pushPrefs(["browser.sessionstore.debug.no_auto_updates", true]);
 
   // Forget any previous closed windows from other tests that may have
   // run in the same session.
-  Services.obs.notifyObservers(null, "browser:purge-session-history");
+  Services.obs.notifyObservers(null, "browser:purge-session-history", 0);
 
   is(ss.getClosedWindowCount(), 0, "We should have 0 closed windows being stored.");
 
   let newWin = yield BrowserTestUtils.openNewBrowserWindow();
 
   // Create a tab worth remembering.
   let tab = newWin.gBrowser.selectedTab;
   let browser = tab.linkedBrowser;
@@ -123,22 +123,22 @@ add_task(function* test_forget_closed_wi
 });
 
 /**
  * Tests that if we choose to purge history while waiting for a
  * final flush of a tab to complete, we don't accidentally store it.
  */
 add_task(function* test_forget_purged_tab() {
   yield forgetTabHelper(() => {
-    Services.obs.notifyObservers(null, "browser:purge-session-history");
+    Services.obs.notifyObservers(null, "browser:purge-session-history", 0);
   });
 });
 
 /**
  * Tests that if we choose to purge history while waiting for a
  * final flush of a window to complete, we don't accidentally
  * store it.
  */
 add_task(function* test_forget_purged_window() {
   yield forgetWinHelper(() => {
-    Services.obs.notifyObservers(null, "browser:purge-session-history");
+    Services.obs.notifyObservers(null, "browser:purge-session-history", 0);
   });
 });
--- a/browser/components/sessionstore/test/browser_purge_shistory.js
+++ b/browser/components/sessionstore/test/browser_purge_shistory.js
@@ -39,17 +39,17 @@ add_task(function* () {
 
   // Prepare the tab state.
   let promise = promiseTabRestoring(tab2);
   ss.setTabState(tab2, JSON.stringify(TAB_STATE));
   ok(tab2.hasAttribute("pending"), "tab is pending");
   yield promise;
 
   // Purge session history.
-  Services.obs.notifyObservers(null, "browser:purge-session-history");
+  Services.obs.notifyObservers(null, "browser:purge-session-history", "");
   yield checkTabContents(browser);
   ok(tab2.hasAttribute("pending"), "tab is still pending");
 
   // Kick off tab restoration.
   gBrowser.selectedTab = tab2;
   yield promiseTabRestored(tab2);
   yield checkTabContents(browser2);
   ok(!tab2.hasAttribute("pending"), "tab is not pending anymore");
--- a/browser/components/sessionstore/test/unit/head.js
+++ b/browser/components/sessionstore/test/unit/head.js
@@ -22,11 +22,11 @@ function afterSessionStartupInitializati
   Components.utils.import("resource://gre/modules/CrashMonitor.jsm");
   CrashMonitor.init();
 
   // Start sessionstartup initialization.
   let startup = Cc["@mozilla.org/browser/sessionstartup;1"].
     getService(Ci.nsIObserver);
   Services.obs.addObserver(startup, "final-ui-startup");
   Services.obs.addObserver(startup, "quit-application");
-  Services.obs.notifyObservers(null, "final-ui-startup");
+  Services.obs.notifyObservers(null, "final-ui-startup", "");
   Services.obs.addObserver(observer, "sessionstore-state-finalized");
 }
--- a/browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js
+++ b/browser/components/syncedtabs/test/xpcshell/test_SyncedTabsDeckComponent.js
@@ -104,31 +104,31 @@ add_task(function* testObserver() {
 
   sinon.spy(component, "observe");
   sinon.stub(component, "updatePanel");
 
   component.init();
   SyncedTabs.syncTabs.restore();
   Assert.ok(component.updatePanel.called, "triggers panel update during init");
 
-  Services.obs.notifyObservers(null, SyncedTabs.TOPIC_TABS_CHANGED);
+  Services.obs.notifyObservers(null, SyncedTabs.TOPIC_TABS_CHANGED, "");
 
   Assert.ok(component.observe.calledWith(null, SyncedTabs.TOPIC_TABS_CHANGED, ""),
     "component is notified");
 
   Assert.ok(listStore.getData.called, "gets list data");
   Assert.ok(component.updatePanel.calledTwice, "triggers panel update");
 
-  Services.obs.notifyObservers(null, FxAccountsCommon.ONLOGIN_NOTIFICATION);
+  Services.obs.notifyObservers(null, FxAccountsCommon.ONLOGIN_NOTIFICATION, "");
 
   Assert.ok(component.observe.calledWith(null, FxAccountsCommon.ONLOGIN_NOTIFICATION, ""),
     "component is notified of login");
   Assert.equal(component.updatePanel.callCount, 3, "triggers panel update again");
 
-  Services.obs.notifyObservers(null, "weave:service:login:change");
+  Services.obs.notifyObservers(null, "weave:service:login:change", "");
 
   Assert.ok(component.observe.calledWith(null, "weave:service:login:change", ""),
     "component is notified of login change");
   Assert.equal(component.updatePanel.callCount, 4, "triggers panel update again");
 });
 
 add_task(function* testPanelStatus() {
   let deckStore = new SyncedTabsDeckStore();
--- a/browser/experiments/Experiments.jsm
+++ b/browser/experiments/Experiments.jsm
@@ -679,17 +679,17 @@ Experiments.Experiments.prototype = {
     yield this._loadTask;
     let e = this._experiments.get(id);
     if (!e) {
       throw new Error("Experiment not found");
     }
     e.branch = String(branchstr);
     this._log.trace("setExperimentBranch(" + id + ", " + e.branch + ") _dirty=" + this._dirty);
     this._dirty = true;
-    Services.obs.notifyObservers(null, EXPERIMENTS_CHANGED_TOPIC);
+    Services.obs.notifyObservers(null, EXPERIMENTS_CHANGED_TOPIC, null);
     yield this._run();
   }),
   /**
    * Get the branch of the specified experiment. If the experiment is unknown,
    * throws an error.
    *
    * @param id The ID of the experiment. Pass null for the currently running
    *           experiment.
@@ -1291,17 +1291,17 @@ Experiments.Experiments.prototype = {
           yield experiment.reconcileAddonState();
         }
       }
     }
 
     gPrefs.set(PREF_ACTIVE_EXPERIMENT, activeExperiment != null);
 
     if (activeChanged || this._firstEvaluate) {
-      Services.obs.notifyObservers(null, EXPERIMENTS_CHANGED_TOPIC);
+      Services.obs.notifyObservers(null, EXPERIMENTS_CHANGED_TOPIC, null);
       this._firstEvaluate = false;
     }
 
     if ("@mozilla.org/toolkit/crash-reporter;1" in Cc && activeExperiment) {
       try {
         gCrashReporter.annotateCrashReport("ActiveExperiment", activeExperiment.id);
         gCrashReporter.annotateCrashReport("ActiveExperimentBranch", activeExperiment.branch);
       } catch (e) {
--- a/browser/extensions/pdfjs/test/browser_pdfjs_savedialog.js
+++ b/browser/extensions/pdfjs/test/browser_pdfjs_savedialog.js
@@ -24,17 +24,17 @@ function changeMimeHandler(preferredActi
   let handlerInfo = mimeService.getFromTypeAndExtension("application/pdf", "pdf");
   var oldAction = [handlerInfo.preferredAction, handlerInfo.alwaysAskBeforeHandling];
 
   // Change and save mime handler settings
   handlerInfo.alwaysAskBeforeHandling = alwaysAskBeforeHandling;
   handlerInfo.preferredAction = preferredAction;
   handlerService.store(handlerInfo);
 
-  Services.obs.notifyObservers(null, "pdfjs:handlerChanged");
+  Services.obs.notifyObservers(null, "pdfjs:handlerChanged", null);
 
   // Refresh data
   handlerInfo = mimeService.getFromTypeAndExtension("application/pdf", "pdf");
 
   // Test: Mime handler was updated
   is(handlerInfo.alwaysAskBeforeHandling, alwaysAskBeforeHandling, "always-ask prompt change successful");
   is(handlerInfo.preferredAction, preferredAction, "mime handler change successful");
 
--- a/browser/modules/SelfSupportBackend.jsm
+++ b/browser/modules/SelfSupportBackend.jsm
@@ -135,17 +135,17 @@ var SelfSupportBackendInternal = {
       this._browser = null;
     }
 
     if (this._frame) {
       this._frame.destroy();
       this._frame = null;
     }
     if (this._testing) {
-      Services.obs.notifyObservers(this._browser, "self-support-browser-destroyed");
+      Services.obs.notifyObservers(this._browser, "self-support-browser-destroyed", "");
     }
   },
 
   /**
    * Handle notifications. Once all windows are created, we wait a little bit more
    * since tabs might still be loading. Then, we open the self support.
    */
   observe(aSubject, aTopic, aData) {
@@ -197,17 +197,17 @@ var SelfSupportBackendInternal = {
       let doc = aFrame.document;
 
       this._browser = doc.createElementNS(XUL_NS, "browser");
       this._browser.setAttribute("type", "content");
       this._browser.setAttribute("disableglobalhistory", "true");
       this._browser.setAttribute("src", aURL);
 
       if (this._testing) {
-        Services.obs.notifyObservers(this._browser, "self-support-browser-created");
+        Services.obs.notifyObservers(this._browser, "self-support-browser-created", "");
       }
       doc.documentElement.appendChild(this._browser);
     });
   },
 
   handleEvent(aEvent) {
     this._log.trace("handleEvent - aEvent.type " + aEvent.type + ", Trusted " + aEvent.isTrusted);
 
--- a/browser/modules/Social.jsm
+++ b/browser/modules/Social.jsm
@@ -96,17 +96,17 @@ this.Social = {
     for (let p of Social.providers) {
       p.enabled = enable;
     }
   },
 
   // Called to update our cache of providers and set the current provider
   _updateProviderCache(providers) {
     this.providers = providers;
-    Services.obs.notifyObservers(null, "social:providers-changed");
+    Services.obs.notifyObservers(null, "social:providers-changed", null);
   },
 
   get enabled() {
     return !this._disabledForSafeMode && this.providers.length > 0;
   },
 
   _getProviderFromOrigin(origin) {
     for (let p of this.providers) {
--- a/browser/modules/test/browser/browser_ProcessHangNotifications.js
+++ b/browser/modules/test/browser/browser_ProcessHangNotifications.js
@@ -86,17 +86,17 @@ let buttonCount = (UpdateUtils.UpdateCha
 
 /**
  * Test if hang reports receive a terminate script callback when the user selects
  * stop in response to a script hang.
  */
 
 add_task(function* terminateScriptTest() {
   let promise = promiseNotificationShown(window, "process-hang");
-  Services.obs.notifyObservers(gTestHangReport, "process-hang-report");
+  Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
   let notification = yield promise;
 
   let buttons = notification.currentNotification.getElementsByTagName("button");
   // Fails on aurora on-push builds, bug 1232204
   // is(buttons.length, buttonCount, "proper number of buttons");
 
   // Click the "Stop It" button, we should get a terminate script callback
   gTestHangReport.hangType = gTestHangReport.SLOW_SCRIPT;
@@ -107,17 +107,17 @@ add_task(function* terminateScriptTest()
 
 /**
  * Test if hang reports receive user canceled callbacks after a user selects wait
  * and the browser frees up from a script hang on its own.
  */
 
 add_task(function* waitForScriptTest() {
   let promise = promiseNotificationShown(window, "process-hang");
-  Services.obs.notifyObservers(gTestHangReport, "process-hang-report");
+  Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
   let notification = yield promise;
 
   let buttons = notification.currentNotification.getElementsByTagName("button");
   // Fails on aurora on-push builds, bug 1232204
   // is(buttons.length, buttonCount, "proper number of buttons");
 
   yield pushPrefs(["browser.hangNotification.waitPeriod", 1000]);
 
@@ -126,53 +126,53 @@ add_task(function* waitForScriptTest() {
   }
   let oldcb = gTestHangReport.testCallback;
   gTestHangReport.testCallback = nocbcheck;
   // Click the "Wait" button this time, we shouldn't get a callback at all.
   buttons[1].click();
   gTestHangReport.testCallback = oldcb;
 
   // send another hang pulse, we should not get a notification here
-  Services.obs.notifyObservers(gTestHangReport, "process-hang-report");
+  Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
   is(notification.currentNotification, null, "no notification should be visible");
 
   gTestHangReport.testCallback = function() {};
-  Services.obs.notifyObservers(gTestHangReport, "clear-hang-report");
+  Services.obs.notifyObservers(gTestHangReport, "clear-hang-report", null);
   gTestHangReport.testCallback = oldcb;
 
   yield popPrefs();
 });
 
 /**
  * Test if hang reports receive user canceled callbacks after the content
  * process stops sending hang notifications.
  */
 
 add_task(function* hangGoesAwayTest() {
   yield pushPrefs(["browser.hangNotification.expiration", 1000]);
 
   let promise = promiseNotificationShown(window, "process-hang");
-  Services.obs.notifyObservers(gTestHangReport, "process-hang-report");
+  Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
   yield promise;
 
   promise = promiseReportCallMade(gTestHangReport.TEST_CALLBACK_CANCELED);
-  Services.obs.notifyObservers(gTestHangReport, "clear-hang-report");
+  Services.obs.notifyObservers(gTestHangReport, "clear-hang-report", null);
   yield promise;
 
   yield popPrefs();
 });
 
 /**
  * Tests if hang reports receive a terminate plugin callback when the user selects
  * stop in response to a plugin hang.
  */
 
 add_task(function* terminatePluginTest() {
   let promise = promiseNotificationShown(window, "process-hang");
-  Services.obs.notifyObservers(gTestHangReport, "process-hang-report");
+  Services.obs.notifyObservers(gTestHangReport, "process-hang-report", null);
   let notification = yield promise;
 
   let buttons = notification.currentNotification.getElementsByTagName("button");
   // Fails on aurora on-push builds, bug 1232204
   // is(buttons.length, buttonCount, "proper number of buttons");
 
   // Click the "Stop It" button, we should get a terminate script callback
   gTestHangReport.hangType = gTestHangReport.PLUGIN_HANG;
--- a/browser/modules/test/browser/browser_UsageTelemetry.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry.js
@@ -6,17 +6,17 @@ const MAX_CONCURRENT_WINDOWS = "browser.
 const WINDOW_OPEN_COUNT = "browser.engagement.window_open_event_count";
 const TOTAL_URI_COUNT = "browser.engagement.total_uri_count";
 const UNIQUE_DOMAINS_COUNT = "browser.engagement.unique_domains_count";
 const UNFILTERED_URI_COUNT = "browser.engagement.unfiltered_uri_count";
 
 const TELEMETRY_SUBSESSION_TOPIC = "internal-telemetry-after-subsession-split";
 
 // Reset internal URI counter in case URIs were opened by other tests.
-Services.obs.notifyObservers(null, TELEMETRY_SUBSESSION_TOPIC);
+Services.obs.notifyObservers(null, TELEMETRY_SUBSESSION_TOPIC, "");
 
 /**
  * Waits for the web progress listener associated with this tab to fire an
  * onLocationChange for a non-error page.
  *
  * @param {xul:browser} browser
  *        A xul:browser.
  *
@@ -160,17 +160,17 @@ add_task(function* test_subsessionSplit(
 
   // Remove a tab.
   yield BrowserTestUtils.removeTab(openedTabs.pop());
 
   // Simulate a subsession split by clearing the scalars (via |snapshotScalars|) and
   // notifying the subsession split topic.
   Services.telemetry.snapshotScalars(Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN,
                                      true /* clearScalars */);
-  Services.obs.notifyObservers(null, TELEMETRY_SUBSESSION_TOPIC);
+  Services.obs.notifyObservers(null, TELEMETRY_SUBSESSION_TOPIC, "");
 
   // After a subsession split, only the MAX_CONCURRENT_* scalars must be available
   // and have the correct value. No tabs, windows or URIs were opened so other scalars
   // must not be reported.
   checkScalars({maxTabs: 4, tabOpenCount: 0, maxWindows: 2, windowsOpenCount: 0,
                 totalURIs: 0, domainCount: 0, totalUnfilteredURIs: 0});
 
   // Remove all the extra windows and tabs.
--- a/devtools/bootstrap.js
+++ b/devtools/bootstrap.js
@@ -165,25 +165,25 @@ function reload(event) {
   if (browserConsole) {
     browserConsole.close();
     reopenBrowserConsole = true;
   }
 
   dump("Reload DevTools.  (reload-toolbox:" + reloadToolbox + ")\n");
 
   // Invalidate xul cache in order to see changes made to chrome:// files
-  Services.obs.notifyObservers(null, "startupcache-invalidate");
+  Services.obs.notifyObservers(null, "startupcache-invalidate", null);
 
   // This frame script is going to be executed in all processes:
   // parent and child
   Services.ppmm.loadProcessScript("data:,new " + function () {
     /* Flush message manager cached frame scripts as well as chrome locales */
     let obs = Components.classes["@mozilla.org/observer-service;1"]
                         .getService(Components.interfaces.nsIObserverService);
-    obs.notifyObservers(null, "message-manager-flush-caches");
+    obs.notifyObservers(null, "message-manager-flush-caches", null);
 
     /* Also purge cached modules in child processes, we do it a few lines after
        in the parent process */
     if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
       Services.obs.notifyObservers(null, "devtools-unload", "reload");
     }
   }, false);
 
--- a/devtools/client/aboutdebugging/test/addons/unpacked/bootstrap.js
+++ b/devtools/client/aboutdebugging/test/addons/unpacked/bootstrap.js
@@ -6,17 +6,17 @@
 
 "use strict";
 
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 // This function is called from the webconsole test:
 // browser_addons_debug_bootstrapped.js
 function myBootstrapAddonFunction() { // eslint-disable-line no-unused-vars
-  Services.obs.notifyObservers(null, "addon-console-works");
+  Services.obs.notifyObservers(null, "addon-console-works", null);
 }
 
 function startup() {
-  Services.obs.notifyObservers(null, "test-devtools");
+  Services.obs.notifyObservers(null, "test-devtools", null);
 }
 function shutdown() {}
 function install() {}
 function uninstall() {}
--- a/devtools/client/debugger/test/mochitest/browser_dbg_addon-console.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_addon-console.js
@@ -29,17 +29,17 @@ function test() {
     let messages = yield getCachedMessages(webConsole);
     is(messages.length, 1, "Should be one cached message");
     is(messages[0].arguments[0].type, "object", "Should have logged an object");
     is(messages[0].arguments[0].preview.ownProperties.msg.value, "Hello from the test add-on", "Should have got the right message");
 
     let consolePromise = addonDebugger.once("console");
 
     console.log("Bad message");
-    Services.obs.notifyObservers(null, "addon-test-ping");
+    Services.obs.notifyObservers(null, "addon-test-ping", "");
 
     let messageGrip = yield consolePromise;
     is(messageGrip.arguments[0].type, "object", "Should have logged an object");
     is(messageGrip.arguments[0].preview.ownProperties.msg.value, "Hello again", "Should have got the right message");
 
     yield addonDebugger.destroy();
     yield removeAddon(addon);
     finish();
--- a/devtools/client/debugger/test/mochitest/browser_dbg_addonactor.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_addonactor.js
@@ -59,17 +59,17 @@ function testDebugger() {
   info("Entering testDebugger");
   let deferred = promise.defer();
 
   once(gClient, "paused").then(() => {
     ok(true, "Should be able to attach to addon actor");
     gThreadClient.resume(deferred.resolve);
   });
 
-  Services.obs.notifyObservers(null, "debuggerAttached");
+  Services.obs.notifyObservers(null, "debuggerAttached", null);
 
   return deferred.promise;
 }
 
 function testSources() {
   let deferred = promise.defer();
 
   gThreadClient.getSources(aResponse => {
--- a/devtools/client/framework/ToolboxProcess.jsm
+++ b/devtools/client/framework/ToolboxProcess.jsm
@@ -328,9 +328,9 @@ function dumpn(str) {
 var wantLogging = Services.prefs.getBoolPref("devtools.debugger.log");
 
 Services.prefs.addObserver("devtools.debugger.log", {
   observe: (...args) => {
     wantLogging = Services.prefs.getBoolPref(args.pop());
   }
 });
 
-Services.obs.notifyObservers(null, "ToolboxProcessLoaded");
+Services.obs.notifyObservers(null, "ToolboxProcessLoaded", null);
--- a/devtools/client/framework/toolbox-process-window.js
+++ b/devtools/client/framework/toolbox-process-window.js
@@ -205,17 +205,17 @@ function raise() {
 
 function setTitle(title) {
   document.title = title;
 }
 
 function quitApp() {
   let quit = Cc["@mozilla.org/supports-PRBool;1"]
              .createInstance(Ci.nsISupportsPRBool);
-  Services.obs.notifyObservers(quit, "quit-application-requested");
+  Services.obs.notifyObservers(quit, "quit-application-requested", null);
 
   let shouldProceed = !quit.data;
   if (shouldProceed) {
     Services.startup.quit(Ci.nsIAppStartup.eForceQuit);
   }
 }
 
 function getParameterByName (name) {
--- a/devtools/client/shared/browser-loader.js
+++ b/devtools/client/shared/browser-loader.js
@@ -32,17 +32,17 @@ const COMMON_LIBRARY_DIRS = [
 //
 // An example:
 // * `resource://devtools/client/inspector/components`
 // * `resource://devtools/client/inspector/shared/components`
 const browserBasedDirsRegExp =
   /^resource\:\/\/devtools\/client\/\S*\/components\//;
 
 function clearCache() {
-  Services.obs.notifyObservers(null, "startupcache-invalidate");
+  Services.obs.notifyObservers(null, "startupcache-invalidate", null);
 }
 
 /*
  * Create a loader to be used in a browser environment. This evaluates
  * modules in their own environment, but sets window (the normal
  * global object) as the sandbox prototype, so when a variable is not
  * defined it checks `window` before throwing an error. This makes all
  * browser APIs available to modules by default, like a normal browser
--- a/devtools/client/shared/css-reload.js
+++ b/devtools/client/shared/css-reload.js
@@ -20,17 +20,17 @@ function iterStyleNodes(window, func) {
   for (let node of links) {
     func(node);
   }
 }
 
 function replaceCSS(window, fileURI) {
   const document = window.document;
   const randomKey = Math.random();
-  Services.obs.notifyObservers(null, "startupcache-invalidate");
+  Services.obs.notifyObservers(null, "startupcache-invalidate", null);
 
   // Scan every CSS tag and reload ones that match the file we are
   // looking for.
   iterStyleNodes(window, node => {
     if (node.nodeType === 7) {
       // xml-stylesheet declaration
       if (node.data.includes(fileURI)) {
         const newNode = window.document.createProcessingInstruction(
--- a/devtools/client/shared/developer-toolbar.js
+++ b/devtools/client/shared/developer-toolbar.js
@@ -620,17 +620,17 @@ DeveloperToolbar.prototype.destroy = fun
 
 /**
  * Utility for sending notifications
  * @param topic a NOTIFICATION constant
  */
 DeveloperToolbar.prototype._notify = function (topic) {
   let data = { toolbar: this };
   data.wrappedJSObject = data;
-  Services.obs.notifyObservers(data, topic);
+  Services.obs.notifyObservers(data, topic, null);
 };
 
 /**
  * Update various parts of the UI when the current tab changes
  */
 DeveloperToolbar.prototype.handleEvent = function (ev) {
   if (ev.type == "TabSelect" || ev.type == "load") {
     if (this.visible) {
--- a/devtools/client/webconsole/hudservice.js
+++ b/devtools/client/webconsole/hudservice.js
@@ -583,17 +583,17 @@ WebConsole.prototype = {
           yield this.target.activeTab.focus();
         }
         catch (ex) {
           // Tab focus can fail if the tab or target is closed.
         }
       }
 
       let id = WebConsoleUtils.supportsString(this.hudId);
-      Services.obs.notifyObservers(id, "web-console-destroyed");
+      Services.obs.notifyObservers(id, "web-console-destroyed", null);
       this._destroyer.resolve(null);
     }.bind(this));
 
     if (this.ui) {
       this.ui.destroy().then(onDestroy);
     }
     else {
       onDestroy();
--- a/devtools/client/webconsole/webconsole.js
+++ b/devtools/client/webconsole/webconsole.js
@@ -483,17 +483,17 @@ WebConsoleFrame.prototype = {
       return connectionInited;
     });
 
     // This notification is only used in tests. Don't chain it onto
     // the returned promise because the console panel needs to be attached
     // to the toolbox before the web-console-created event is receieved.
     let notifyObservers = () => {
       let id = WebConsoleUtils.supportsString(this.hudId);
-      Services.obs.notifyObservers(id, "web-console-created");
+      Services.obs.notifyObservers(id, "web-console-created", null);
     };
     allReady.then(notifyObservers, notifyObservers);
 
     if (this.NEW_CONSOLE_OUTPUT_ENABLED) {
       allReady.then(this.newConsoleOutput.init);
     }
 
     return allReady;
--- a/devtools/client/webide/components/webideCli.js
+++ b/devtools/client/webide/components/webideCli.js
@@ -40,17 +40,17 @@ webideCli.prototype = {
                                    "chrome,centerscreen,resizable,dialog=no",
                                    null);
     }
 
     if (cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH) {
       // If this is a new Firefox instance, and because we will only start
       // webide, we need to notify "sessionstore-windows-restored" to trigger
       // addons registration (for simulators and adb helper).
-      Services.obs.notifyObservers(null, "sessionstore-windows-restored");
+      Services.obs.notifyObservers(null, "sessionstore-windows-restored", "");
     }
   },
 
   helpInfo: "",
 
   classID: Components.ID("{79b7b44e-de5e-4e4c-b7a2-044003c615d9}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
 };
--- a/devtools/server/actors/monitor.js
+++ b/devtools/server/actors/monitor.js
@@ -27,26 +27,26 @@ MonitorActor.prototype = {
   },
 
   // Methods available from the front.
 
   start: function () {
     if (!this._started) {
       this._started = true;
       Services.obs.addObserver(this, "devtools-monitor-update");
-      Services.obs.notifyObservers(null, "devtools-monitor-start");
+      Services.obs.notifyObservers(null, "devtools-monitor-start", "");
       this._agents.forEach(agent => this._startAgent(agent));
     }
     return {};
   },
 
   stop: function () {
     if (this._started) {
       this._agents.forEach(agent => agent.stop());
-      Services.obs.notifyObservers(null, "devtools-monitor-stop");
+      Services.obs.notifyObservers(null, "devtools-monitor-stop", "");
       Services.obs.removeObserver(this, "devtools-monitor-update");
       this._started = false;
     }
     return {};
   },
 
   destroy: function () {
     this.stop();
--- a/devtools/server/actors/script.js
+++ b/devtools/server/actors/script.js
@@ -1018,17 +1018,17 @@ const ThreadActor = ActorClassWithSpec(t
         this._maybeListenToEvents(aRequest);
       }
 
       let packet = this._resumed();
       this._popThreadPause();
       // Tell anyone who cares of the resume (as of now, that's the xpcshell harness and
       // devtools-startup.js when handling the --wait-for-jsdebugger flag)
       if (Services.obs) {
-        Services.obs.notifyObservers(this, "devtools-thread-resumed");
+        Services.obs.notifyObservers(this, "devtools-thread-resumed", null);
       }
       return packet;
     }, error => {
       return error instanceof Error
         ? { error: "unknownError",
             message: DevToolsUtils.safeErrorString(error) }
         // It is a known error, and the promise was rejected with an error
         // packet.
--- a/dom/console/ConsoleAPIStorage.js
+++ b/dom/console/ConsoleAPIStorage.js
@@ -155,14 +155,14 @@ ConsoleAPIStorageService.prototype = {
    */
   clearEvents: function CS_clearEvents(aId)
   {
     if (aId != null) {
       _consoleStorage.delete(aId);
     }
     else {
       _consoleStorage.clear();
-      Services.obs.notifyObservers(null, "console-storage-reset");
+      Services.obs.notifyObservers(null, "console-storage-reset", null);
     }
   },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ConsoleAPIStorageService]);
--- a/dom/indexedDB/test/bug839193.js
+++ b/dom/indexedDB/test/bug839193.js
@@ -16,17 +16,17 @@ function onLoad()
   let principal = Components.classes["@mozilla.org/scriptsecuritymanager;1"]
                             .getService(Components.interfaces.nsIScriptSecurityManager)
                             .createCodebasePrincipal(gURI, {});
   var quotaRequest = quotaManagerService.getUsageForPrincipal(principal,
                                                               onUsageCallback);
   quotaRequest.cancel();
   Components.classes["@mozilla.org/observer-service;1"]
             .getService(Components.interfaces.nsIObserverService)
-            .notifyObservers(window, "bug839193-loaded");
+            .notifyObservers(window, "bug839193-loaded", null);
 }
 
 function onUnload()
 {
   Components.classes["@mozilla.org/observer-service;1"]
             .getService(Components.interfaces.nsIObserverService)
-            .notifyObservers(window, "bug839193-unloaded");
+            .notifyObservers(window, "bug839193-unloaded", null);
 }
--- a/dom/media/PeerConnection.js
+++ b/dom/media/PeerConnection.js
@@ -835,17 +835,17 @@ class RTCPeerConnection {
         this._havePermission = new Promise((resolve, reject) => {
           this._settlePermission = { allow: resolve, deny: reject };
           let outerId = this._win.QueryInterface(Ci.nsIInterfaceRequestor).
               getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
 
           let chrome = new CreateOfferRequest(outerId, this._winID,
                                               this._globalPCListId, false);
           let request = this._win.CreateOfferRequest._create(this._win, chrome);
-          Services.obs.notifyObservers(request, "PeerConnection:request");
+          Services.obs.notifyObservers(request, "PeerConnection:request", null);
         });
       }
     }
     return await this._havePermission;
   }
 
   setLocalDescription(desc, onSucc, onErr) {
     return this._auto(onSucc, onErr, () => this._setLocalDescription(desc));
--- a/dom/media/webspeech/recognition/test/head.js
+++ b/dom/media/webspeech/recognition/test/head.js
@@ -122,17 +122,17 @@ function EventManager(sr) {
 
     info("requesting " + eventName);
     Services.obs.notifyObservers(null,
                                  SPEECH_RECOGNITION_TEST_REQUEST_EVENT_TOPIC,
                                  eventName);
   }
 
   self.requestTestEnd = function EventManager_requestTestEnd() {
-    Services.obs.notifyObservers(null, SPEECH_RECOGNITION_TEST_END_TOPIC);
+    Services.obs.notifyObservers(null, SPEECH_RECOGNITION_TEST_END_TOPIC, null);
   }
 }
 
 function buildResultCallback(transcript) {
   return (function(evt) {
     is(evt.results[0][0].transcript, transcript, "expect correct transcript");
   });
 }
--- a/dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway.js
+++ b/dom/presentation/tests/mochitest/test_presentation_1ua_connection_wentaway.js
@@ -62,17 +62,17 @@ function setup() {
 
     var promise = new Promise(function(aResolve, aReject) {
       document.body.appendChild(receiverIframe);
       aResolve(receiverIframe);
     });
 
     var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
                            .getService(SpecialPowers.Ci.nsIObserverService);
-    obs.notifyObservers(promise, 'setup-request-promise');
+    obs.notifyObservers(promise, 'setup-request-promise', null);
   });
 
   gScript.addMessageListener('promise-setup-ready', function promiseSetupReadyHandler() {
     debug('Got message: promise-setup-ready');
     gScript.removeMessageListener('promise-setup-ready',
                                   promiseSetupReadyHandler);
     gScript.sendAsyncMessage('trigger-on-session-request', receiverUrl);
   });
--- a/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.js
+++ b/dom/presentation/tests/mochitest/test_presentation_1ua_sender_and_receiver.js
@@ -71,17 +71,17 @@ function setup() {
 
     var promise = new Promise(function(aResolve, aReject) {
       document.body.appendChild(receiverIframe);
       aResolve(receiverIframe);
     });
 
     var obs = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
                            .getService(SpecialPowers.Ci.nsIObserverService);
-    obs.notifyObservers(promise, 'setup-request-promise');
+    obs.notifyObservers(promise, 'setup-request-promise', null);
   });
 
   gScript.addMessageListener('promise-setup-ready', function promiseSetupReadyHandler() {
     debug('Got message: promise-setup-ready');
     gScript.removeMessageListener('promise-setup-ready', promiseSetupReadyHandler);
     gScript.sendAsyncMessage('trigger-on-session-request', receiverUrl);
   });
 
--- a/dom/presentation/tests/mochitest/test_presentation_dc_receiver.html
+++ b/dom/presentation/tests/mochitest/test_presentation_dc_receiver.html
@@ -51,17 +51,17 @@ function setup() {
       }
     });
 
     var promise = new Promise(function(aResolve, aReject) {
       document.body.appendChild(iframe);
 
       aResolve(iframe);
     });
-    obs.notifyObservers(promise, 'setup-request-promise');
+    obs.notifyObservers(promise, 'setup-request-promise', null);
 
     gScript.addMessageListener('offer-received', function offerReceivedHandler() {
       gScript.removeMessageListener('offer-received', offerReceivedHandler);
       info("An offer is received.");
     });
 
     gScript.addMessageListener('answer-sent', function answerSentHandler(aIsValid) {
       gScript.removeMessageListener('answer-sent', answerSentHandler);
--- a/dom/presentation/tests/mochitest/test_presentation_dc_receiver_oop.html
+++ b/dom/presentation/tests/mochitest/test_presentation_dc_receiver_oop.html
@@ -73,17 +73,17 @@ function setup() {
       document.body.appendChild(receiverIframe);
       receiverIframe.addEventListener("mozbrowserloadstart", function() {
         var mm = SpecialPowers.getBrowserFrameMessageManager(receiverIframe);
         mm.loadFrameScript("data:,(" + loadPrivilegedScriptTest.toString() + ")();", false);
       }, {once: true});
 
       aResolve(receiverIframe);
     });
-    obs.notifyObservers(promise, 'setup-request-promise');
+    obs.notifyObservers(promise, 'setup-request-promise', null);
 
     // Create a non-receiver OOP iframe.
     var nonReceiverIframe = document.createElement('iframe');
     nonReceiverIframe.setAttribute('remote', 'true');
     nonReceiverIframe.setAttribute('mozbrowser', 'true');
     nonReceiverIframe.setAttribute('src', nonReceiverUrl);
 
     // This event is triggered when the iframe calls "alert".
--- a/dom/presentation/tests/mochitest/test_presentation_receiver_auxiliary_navigation.js
+++ b/dom/presentation/tests/mochitest/test_presentation_receiver_auxiliary_navigation.js
@@ -37,17 +37,17 @@ function setup() {
       }
     });
 
     var promise = new Promise(function(aResolve, aReject) {
       document.body.appendChild(iframe);
 
       aResolve(iframe);
     });
-    obs.notifyObservers(promise, "setup-request-promise");
+    obs.notifyObservers(promise, "setup-request-promise", null);
 
     aResolve();
   });
 }
 
 function teardown() {
   gScript.addMessageListener("teardown-complete", function teardownCompleteHandler() {
     gScript.removeMessageListener("teardown-complete", teardownCompleteHandler);
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver.html
+++ b/dom/presentation/tests/mochitest/test_presentation_tcp_receiver.html
@@ -52,17 +52,17 @@ function setup() {
       }
     });
 
     var promise = new Promise(function(aResolve, aReject) {
       document.body.appendChild(iframe);
 
       aResolve(iframe);
     });
-    obs.notifyObservers(promise, 'setup-request-promise');
+    obs.notifyObservers(promise, 'setup-request-promise', null);
 
     gScript.addMessageListener('offer-received', function offerReceivedHandler() {
       gScript.removeMessageListener('offer-received', offerReceivedHandler);
       info("An offer is received.");
     });
 
     gScript.addMessageListener('answer-sent', function answerSentHandler(aIsValid) {
       gScript.removeMessageListener('answer-sent', answerSentHandler);
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_error.html
+++ b/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_error.html
@@ -48,17 +48,17 @@ function setup() {
       }
     });
 
     var promise = new Promise(function(aResolve, aReject) {
       document.body.appendChild(iframe);
 
       aResolve(iframe);
     });
-    obs.notifyObservers(promise, 'setup-request-promise');
+    obs.notifyObservers(promise, 'setup-request-promise', null);
 
     gScript.addMessageListener('control-channel-closed', function controlChannelClosedHandler(aReason) {
       gScript.removeMessageListener('control-channel-closed', controlChannelClosedHandler);
       is(aReason, 0x80004004 /* NS_ERROR_ABORT */, "The control channel is closed abnormally.");
     });
 
     aResolve();
   });
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_timeout.html
+++ b/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_timeout.html
@@ -21,17 +21,17 @@ var obs = SpecialPowers.Cc["@mozilla.org
 
 function setup() {
   return new Promise(function(aResolve, aReject) {
     gScript.sendAsyncMessage('trigger-device-add');
 
     var promise = new Promise(function(aResolve, aReject) {
       // In order to trigger timeout, do not resolve the promise.
     });
-    obs.notifyObservers(promise, 'setup-request-promise');
+    obs.notifyObservers(promise, 'setup-request-promise', null);
 
     aResolve();
   });
 }
 
 function testIncomingSessionRequestReceiverLaunchTimeout() {
   return new Promise(function(aResolve, aReject) {
     gScript.addMessageListener('receiver-launching', function launchReceiverHandler(aSessionId) {
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_unknown_content_type.js
+++ b/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_establish_connection_unknown_content_type.js
@@ -19,17 +19,17 @@ function setup() {
     var oop = location.pathname.indexOf('_inproc') == -1;
     receiverIframe.setAttribute("remote", oop);
 
     var promise = new Promise(function(aResolve, aReject) {
       document.body.appendChild(receiverIframe);
 
       aResolve(receiverIframe);
     });
-    obs.notifyObservers(promise, 'setup-request-promise');
+    obs.notifyObservers(promise, 'setup-request-promise', null);
 
     aResolve();
   });
 }
 
 function testIncomingSessionRequestReceiverLaunchUnknownContentType() {
   let promise = Promise.all([
     new Promise(function(aResolve, aReject) {
--- a/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_oop.html
+++ b/dom/presentation/tests/mochitest/test_presentation_tcp_receiver_oop.html
@@ -62,17 +62,17 @@ function setup() {
       }
     });
 
     var promise = new Promise(function(aResolve, aReject) {
       document.body.appendChild(receiverIframe);
 
       aResolve(receiverIframe);
     });
-    obs.notifyObservers(promise, 'setup-request-promise');
+    obs.notifyObservers(promise, 'setup-request-promise', null);
 
     // Create a non-receiver OOP iframe.
     var nonReceiverIframe = document.createElement('iframe');
     nonReceiverIframe.setAttribute('remote', 'true');
     nonReceiverIframe.setAttribute('mozbrowser', 'true');
     nonReceiverIframe.setAttribute('src', nonReceiverUrl);
 
     // This event is triggered when the iframe calls "alert".
--- a/dom/presentation/tests/mochitest/test_presentation_terminate.js
+++ b/dom/presentation/tests/mochitest/test_presentation_terminate.js
@@ -62,17 +62,17 @@ function setup() {
 
     var promise = new Promise(function(aResolve, aReject) {
       document.body.appendChild(receiverIframe);
       aResolve(receiverIframe);
     });
 
     var obs = SpecialPowers.Cc['@mozilla.org/observer-service;1']
                            .getService(SpecialPowers.Ci.nsIObserverService);
-    obs.notifyObservers(promise, 'setup-request-promise');
+    obs.notifyObservers(promise, 'setup-request-promise', null);
   });
 
   gScript.addMessageListener('promise-setup-ready', function promiseSetupReadyHandler() {
     debug('Got message: promise-setup-ready');
     gScript.removeMessageListener('promise-setup-ready',
                                   promiseSetupReadyHandler);
     gScript.sendAsyncMessage('trigger-on-session-request', receiverUrl);
   });
--- a/dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error.js
+++ b/dom/presentation/tests/mochitest/test_presentation_terminate_establish_connection_error.js
@@ -67,17 +67,17 @@ function setup() {
 
     var promise = new Promise(function(aResolve, aReject) {
       document.body.appendChild(receiverIframe);
       aResolve(receiverIframe);
     });
 
     var obs = SpecialPowers.Cc['@mozilla.org/observer-service;1']
                            .getService(SpecialPowers.Ci.nsIObserverService);
-    obs.notifyObservers(promise, 'setup-request-promise');
+    obs.notifyObservers(promise, 'setup-request-promise', null);
   });
 
   gScript.addMessageListener('promise-setup-ready', function promiseSetupReadyHandler() {
     debug('Got message: promise-setup-ready');
     gScript.removeMessageListener('promise-setup-ready',
                                   promiseSetupReadyHandler);
     gScript.sendAsyncMessage('trigger-on-session-request', receiverUrl);
   });
--- a/dom/push/test/xpcshell/test_quota_observer.js
+++ b/dom/push/test/xpcshell/test_quota_observer.js
@@ -136,17 +136,17 @@ add_task(function* test_expiration_histo
 
   // Now visit the site...
   yield PlacesTestUtils.addVisits({
     uri: 'https://example.com/another-page',
     title: 'Infrequently-visited page',
     visitDate: Date.now() * 1000,
     transition: Ci.nsINavHistoryService.TRANSITION_LINK
   });
-  Services.obs.notifyObservers(null, 'idle-daily');
+  Services.obs.notifyObservers(null, 'idle-daily', '');
 
   // And we should receive notifications for both scopes.
   yield subChangePromise;
   deepEqual(notifiedScopes.sort(), [
     'https://example.com/auctions',
     'https://example.com/deals'
   ], 'Wrong scopes for subscription changes');
 
--- a/dom/system/gonk/NetworkManager.js
+++ b/dom/system/gonk/NetworkManager.js
@@ -283,17 +283,17 @@ NetworkManager.prototype = {
     let networkId = this.getNetworkId(network.info);
     if (networkId in this.networkInterfaces) {
       throw Components.Exception("Network with that type already registered!",
                                  Cr.NS_ERROR_INVALID_ARG);
     }
     this.networkInterfaces[networkId] = network;
     this.networkInterfaceLinks[networkId] = new NetworkInterfaceLinks();
 
-    Services.obs.notifyObservers(network.info, TOPIC_INTERFACE_REGISTERED);
+    Services.obs.notifyObservers(network.info, TOPIC_INTERFACE_REGISTERED, null);
     debug("Network '" + networkId + "' registered.");
   },
 
   _addSubnetRoutes: function(network) {
     let ips = {};
     let prefixLengths = {};
     let length = network.getAddresses(ips, prefixLengths);
     let promises = [];
@@ -480,17 +480,17 @@ NetworkManager.prototype = {
     // This is for in case a network gets unregistered without being
     // DISCONNECTED.
     if (this.isNetworkTypeMobile(network.info.type)) {
       this._cleanupAllHostRoutes(networkId);
     }
 
     delete this.networkInterfaces[networkId];
 
-    Services.obs.notifyObservers(network.info, TOPIC_INTERFACE_UNREGISTERED);
+    Services.obs.notifyObservers(network.info, TOPIC_INTERFACE_UNREGISTERED, null);
     debug("Network '" + networkId + "' unregistered.");
   },
 
   _manageOfflineStatus: true,
 
   networkInterfaces: null,
 
   networkInterfaceLinks: null,
@@ -838,17 +838,17 @@ NetworkManager.prototype = {
     if (this._overriddenActive) {
       debug("We have an override for the active network: " +
             this._overriddenActive.info.name);
       // The override was just set, so reconfigure the network.
       if (this._activeNetwork != this._overriddenActive) {
         this._activeNetwork = this._overriddenActive;
         this._setDefaultRouteAndProxy(this._activeNetwork, oldActive);
         Services.obs.notifyObservers(this.activeNetworkInfo,
-                                     TOPIC_ACTIVE_CHANGED);
+                                     TOPIC_ACTIVE_CHANGED, null);
       }
       return;
     }
 
     // The active network is already our preferred type.
     if (this.activeNetworkInfo &&
         this.activeNetworkInfo.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED &&
         this.activeNetworkInfo.type == this._preferredNetworkType) {
@@ -899,17 +899,17 @@ NetworkManager.prototype = {
           return Promise.resolve();
         }
 
         return this._setDefaultRouteAndProxy(this._activeNetwork, oldActive);
       })
       .then(() => {
         if (this._activeNetwork != oldActive) {
           Services.obs.notifyObservers(this.activeNetworkInfo,
-                                       TOPIC_ACTIVE_CHANGED);
+                                       TOPIC_ACTIVE_CHANGED, null);
         }
 
         if (this._manageOfflineStatus) {
           Services.io.offline = !anyConnected &&
                                 (gTetheringService.state ===
                                  Ci.nsITetheringService.TETHERING_STATE_INACTIVE);
         }
       });
--- a/dom/tests/mochitest/chrome/file_bug1224790-2_nonmodal.xul
+++ b/dom/tests/mochitest/chrome/file_bug1224790-2_nonmodal.xul
@@ -25,17 +25,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     // Request cycle collection to trigger destructor for parent modal window,
     // that mutates mAncestorLink of this window.
     const Ci = Components.interfaces;
     const Cu = Components.utils;
     var { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
     var windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor).
       getInterface(Ci.nsIDOMWindowUtils);
 
-    Services.obs.notifyObservers(null, "child-cc-request");
+    Services.obs.notifyObservers(null, "child-cc-request", null);
     windowUtils.cycleCollect();
 
     // Wait for a while.
     setTimeout(function() {
       window.close();
       grandparent.wrappedJSObject.nonModalClosed();
     }, 3000);
   }
--- a/dom/tests/mochitest/localstorage/localStorageCommon.js
+++ b/dom/tests/mochitest/localstorage/localStorageCommon.js
@@ -36,17 +36,17 @@ function localStorageClearDomain(domain)
 
 function os()
 {
   return SpecialPowers.Services.obs;
 }
 
 function notify(top)
 {
-  os().notifyObservers(null, top);
+  os().notifyObservers(null, top, null);
 }
 
 /**
  * Enable testing observer notifications in DOMStorageObserver.cpp.
  */
 function localStorageEnableTestingMode(cb)
 {
   SpecialPowers.pushPrefEnv({ "set": [["dom.storage.testing", true]] }, cb);
--- a/dom/workers/test/serviceworkers/test_install_event_gc.html
+++ b/dom/workers/test/serviceworkers/test_install_event_gc.html
@@ -71,19 +71,19 @@ function gcWorker() {
     // At the current time, the service worker will exist in our same process
     // and notifyObservers is synchronous.  However, in the future, service
     // workers may end up in a separate process and in that case it will be
     // appropriate to use notifyObserversInParentProcess or something like it.
     // (notifyObserversInParentProcess is a synchronous IPC call to the parent
     // process's main thread.  IPDL PContent::CycleCollect is an async message.
     // Ordering will be maintained if the postMessage goes via PContent as well,
     // but that seems unlikely.)
-    SpecialPowers.notifyObservers(null, 'child-gc-request');
-    SpecialPowers.notifyObservers(null, 'child-cc-request');
-    SpecialPowers.notifyObservers(null, 'child-gc-request');
+    SpecialPowers.notifyObservers(null, 'child-gc-request', null);
+    SpecialPowers.notifyObservers(null, 'child-cc-request', null);
+    SpecialPowers.notifyObservers(null, 'child-gc-request', null);
     // (Only send the ping after we set the gc/cc/gc in motion.)
     registration.installing.postMessage({ type: 'ping' });
   });
 }
 
 function terminateWorker() {
   return SpecialPowers.pushPrefEnv({
     set: [
--- a/embedding/ios/GeckoEmbed/GeckoEmbed/browser/chrome/content/hello.js
+++ b/embedding/ios/GeckoEmbed/GeckoEmbed/browser/chrome/content/hello.js
@@ -1,8 +1,9 @@
 Components.utils.import("resource://gre/modules/Services.jsm");
 addEventListener("DOMContentLoaded", function loaded() {
   removeEventListener("DOMContentLoaded", loaded);
   var b = document.getElementById("browser");
   Services.obs.notifyObservers(b.docShell,
-                               "geckoembed-browser-loaded");
+                               "geckoembed-browser-loaded",
+                               null);
   b.loadURI("http://people.mozilla.org/~tmielczarek/iosstart.html");
 });
--- a/extensions/cookie/test/unit/test_cookies_privatebrowsing.js
+++ b/extensions/cookie/test/unit/test_cookies_privatebrowsing.js
@@ -46,25 +46,25 @@ function* do_run_test() {
   chan2.QueryInterface(Ci.nsIPrivateBrowsingChannel);
   chan2.setPrivate(true);
 
   Services.cookies.setCookieString(uri2, null, "oh=hai; max-age=1000", chan2);
   do_check_eq(Services.cookiemgr.getCookieString(uri1, chan1), null);
   do_check_eq(Services.cookiemgr.getCookieString(uri2, chan2), "oh=hai");
 
   // Remove cookies and check counts.
-  Services.obs.notifyObservers(null, "last-pb-context-exited");
+  Services.obs.notifyObservers(null, "last-pb-context-exited", null);
   do_check_eq(Services.cookiemgr.getCookieString(uri1, chan1), null);
   do_check_eq(Services.cookiemgr.getCookieString(uri2, chan2), null);
 
   Services.cookies.setCookieString(uri2, null, "oh=hai; max-age=1000", chan2);
   do_check_eq(Services.cookiemgr.getCookieString(uri2, chan2), "oh=hai");
 
   // Leave private browsing mode and check counts.
-  Services.obs.notifyObservers(null, "last-pb-context-exited");
+  Services.obs.notifyObservers(null, "last-pb-context-exited", null);
   do_check_eq(Services.cookiemgr.countCookiesFromHost(uri1.host), 1);
   do_check_eq(Services.cookiemgr.countCookiesFromHost(uri2.host), 0);
 
   // Fake a profile change.
   do_close_profile(test_generator);
   yield;
   do_load_profile();
 
@@ -84,17 +84,17 @@ function* do_run_test() {
   do_load_profile();
 
   // We're still in private browsing mode, but should have a new session.
   // Check counts.
   do_check_eq(Services.cookiemgr.getCookieString(uri1, chan1), null);
   do_check_eq(Services.cookiemgr.getCookieString(uri2, chan2), null);
 
   // Leave private browsing mode and check counts.
-  Services.obs.notifyObservers(null, "last-pb-context-exited");
+  Services.obs.notifyObservers(null, "last-pb-context-exited", null);
   do_check_eq(Services.cookiemgr.countCookiesFromHost(uri1.host), 1);
   do_check_eq(Services.cookiemgr.countCookiesFromHost(uri2.host), 0);
 
   // Enter private browsing mode.
 
   // Fake a profile change, but wait for async read completion.
   do_close_profile(test_generator);
   yield;
@@ -102,14 +102,14 @@ function* do_run_test() {
   yield;
 
   // We're still in private browsing mode, but should have a new session.
   // Check counts.
   do_check_eq(Services.cookiemgr.getCookieString(uri1, chan1), null);
   do_check_eq(Services.cookiemgr.getCookieString(uri2, chan2), null);
 
   // Leave private browsing mode and check counts.
-  Services.obs.notifyObservers(null, "last-pb-context-exited");
+  Services.obs.notifyObservers(null, "last-pb-context-exited", null);
   do_check_eq(Services.cookiemgr.countCookiesFromHost(uri1.host), 1);
   do_check_eq(Services.cookiemgr.countCookiesFromHost(uri2.host), 0);
 
   finish_test();
 }
--- a/extensions/pref/autoconfig/test/unit/test_autoconfig_nonascii.js
+++ b/extensions/pref/autoconfig/test/unit/test_autoconfig_nonascii.js
@@ -49,17 +49,17 @@ function run_test() {
       for (let prefName in test.prefs) {
         do_check_eq(Ci.nsIPrefBranch.PREF_INVALID, prefs.getPrefType(prefName));
       }
 
       let autoConfigCfg = testDir.clone();
       autoConfigCfg.append(test.filename);
       autoConfigCfg.copyTo(greD, "autoconfig.cfg");
   
-      obsvc.notifyObservers(ps, "prefservice:before-read-userprefs");
+      obsvc.notifyObservers(ps, "prefservice:before-read-userprefs", null);
   
       for (let prefName in test.prefs) {
         do_check_eq(test.prefs[prefName],
                     prefs.getStringPref(prefName));
       }
   
       ps.resetPrefs();
       // Make sure pref values are reset.
--- a/layout/forms/test/test_bug536567_perwindowpb.html
+++ b/layout/forms/test/test_bug536567_perwindowpb.html
@@ -105,17 +105,17 @@ function runTest() {
     content = privateWindowIframe;
     testIndex++;
     runTest();
   } else if (test == "pb off") {
     content = normalWindowIframe;
     testIndex++;
     runTest();
   } else if (test == "clear history") {
-    Services.obs.notifyObservers(null, "browser:purge-session-history");
+    Services.obs.notifyObservers(null, "browser:purge-session-history", "");
     testIndex++;
     runTest();
   } else {
     var file = dirs[test[2]].clone();
     file.append("file.file");
     MockFilePicker.setFiles([file]);
     content.setAttribute('src', domains[test[0]] + '/chrome/layout/forms/test/bug536567_subframe.html');
   }
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -377,17 +377,17 @@ var BrowserApp = {
   // Note that the deck list order does not necessarily reflect the user visible tab order (see
   // bug 1331154 for the reason), so deck.selectedIndex should not be used (though
   // deck.selectedPanel is still valid) - use selectedTabIndex instead.
   deck: null,
 
   startup: function startup() {
     window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow = new nsBrowserAccess();
     dump("zerdatime " + Date.now() + " - browser chrome startup finished.");
-    Services.obs.notifyObservers(this.browser, "BrowserChrome:Ready");
+    Services.obs.notifyObservers(this.browser, "BrowserChrome:Ready", null);
 
     this.deck = document.getElementById("browsers");
 
     BrowserEventHandler.init();
 
     ViewportHandler.init();
 
     Services.androidBridge.browserApp = this;
@@ -543,17 +543,17 @@ var BrowserApp = {
     }
 
     // Notify Java that Gecko has loaded.
     GlobalEventDispatcher.sendRequest({ type: "Gecko:Ready" });
 
     this.deck.addEventListener("DOMContentLoaded", function() {
       InitLater(() => Cu.import("resource://gre/modules/NotificationDB.jsm"));
 
-      InitLater(() => Services.obs.notifyObservers(window, "browser-delayed-startup-finished"));
+      InitLater(() => Services.obs.notifyObservers(window, "browser-delayed-startup-finished", ""));
       InitLater(() => GlobalEventDispatcher.sendRequest({ type: "Gecko:DelayedStartup" }));
 
       if (!AppConstants.RELEASE_OR_BETA) {
         InitLater(() => WebcompatReporter.init());
       }
 
       // Collect telemetry data.
       // We do this at startup because we want to move away from "gather-telemetry" (bug 1127907)
@@ -1054,17 +1054,17 @@ var BrowserApp = {
       if (!name && Services.prefs.prefHasUserValue("browser.search.defaultenginename.US")) {
         name = Services.prefs.getCharPref("browser.search.defaultenginename.US");
       }
       if (name) {
         Services.search.init(() => {
           let engine = Services.search.getEngineByName(name);
           if (engine) {
             Services.search.defaultEngine = engine;
-            Services.obs.notifyObservers(null, "default-search-engine-migrated");
+            Services.obs.notifyObservers(null, "default-search-engine-migrated", "");
           }
         });
       }
     }
 
     if (currentUIVersion < 3) {
       const kOldSafeBrowsingPref = "browser.safebrowsing.enabled";
       // Default value is set to true, a user pref means that the pref was
@@ -1432,24 +1432,24 @@ var BrowserApp = {
     let evt = document.createEvent("UIEvents");
     evt.initUIEvent("TabSelect", true, false, window, null);
     aTab.browser.dispatchEvent(evt);
   },
 
   quit: function quit(aClear = { sanitize: {}, dontSaveSession: false }) {
     // Notify all windows that an application quit has been requested.
     let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
-    Services.obs.notifyObservers(cancelQuit, "quit-application-requested");
+    Services.obs.notifyObservers(cancelQuit, "quit-application-requested", null);
 
     // Quit aborted.
     if (cancelQuit.data) {
       return;
     }
 
-    Services.obs.notifyObservers(null, "quit-application-proceeding");
+    Services.obs.notifyObservers(null, "quit-application-proceeding", null);
 
     // Tell session store to forget about this window
     if (aClear.dontSaveSession) {
       let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
       ss.removeWindow(window);
     }
 
     BrowserApp.sanitize(aClear.sanitize, function() {
@@ -1524,17 +1524,17 @@ var BrowserApp = {
 
       switch (key) {
         case "cookies_sessions":
           promises.push(Sanitizer.clearItem("cookies"));
           promises.push(Sanitizer.clearItem("sessions"));
           break;
         case "openTabs":
           if (aShutdown === true) {
-            Services.obs.notifyObservers(null, "browser:purge-session-tabs");
+            Services.obs.notifyObservers(null, "browser:purge-session-tabs", "");
             break;
           }
           // fall-through if aShutdown is false
         default:
           promises.push(Sanitizer.clearItem(key));
       }
     }
 
@@ -2808,17 +2808,17 @@ var NativeWindow = {
         this._target = null;
 
         return;
       }
 
       // If no context-menu for long-press event, it may be meant to trigger text-selection.
       this.menus = null;
       Services.obs.notifyObservers(
-        {target: this._target, x: event.clientX, y: event.clientY}, "context-menu-not-shown");
+        {target: this._target, x: event.clientX, y: event.clientY}, "context-menu-not-shown", "");
     },
 
     // Returns a title for a context menu. If no title attribute exists, will fall back to looking for a url
     _getTitle: function(node) {
       if (node.hasAttribute && node.hasAttribute("title")) {
         return node.getAttribute("title");
       }
       return this._getUrl(node);
@@ -4523,17 +4523,17 @@ Tab.prototype = {
 
     notifyManifestStatus(this.browser);
 
     if (!sameDocument) {
       // XXX This code assumes that this is the earliest hook we have at which
       // browser.contentDocument is changed to the new document we're loading
       this.contentDocumentIsDisplayed = false;
       this.hasTouchListener = false;
-      Services.obs.notifyObservers(this.browser, "Session:NotifyLocationChange");
+      Services.obs.notifyObservers(this.browser, "Session:NotifyLocationChange", null);
     }
   },
 
   _stripAboutReaderURL: function (originalURI) {
     try {
       let strippedURL = ReaderMode.getOriginalUrl(originalURI.spec);
       if(strippedURL){
         // Continue to create exposable uri if original uri is stripped.
@@ -4562,46 +4562,46 @@ Tab.prototype = {
       tabID: this.id,
       identity: identity
     };
 
     GlobalEventDispatcher.sendRequest(message);
   },
 
   OnHistoryNewEntry: function(newURI, oldIndex) {
-    Services.obs.notifyObservers(this.browser, "Content:HistoryChange");
+    Services.obs.notifyObservers(this.browser, "Content:HistoryChange", null);
   },
 
   OnHistoryGoBack: function(backURI) {
-    Services.obs.notifyObservers(this.browser, "Content:HistoryChange");
+    Services.obs.notifyObservers(this.browser, "Content:HistoryChange", null);
     return true;
   },
 
   OnHistoryGoForward: function(forwardURI) {
-    Services.obs.notifyObservers(this.browser, "Content:HistoryChange");
+    Services.obs.notifyObservers(this.browser, "Content:HistoryChange", null);
     return true;
   },
 
   OnHistoryReload: function(reloadURI, reloadFlags) {
-    Services.obs.notifyObservers(this.browser, "Content:HistoryChange");
+    Services.obs.notifyObservers(this.browser, "Content:HistoryChange", null);
     return true;
   },
 
   OnHistoryGotoIndex: function(index, gotoURI) {
-    Services.obs.notifyObservers(this.browser, "Content:HistoryChange");
+    Services.obs.notifyObservers(this.browser, "Content:HistoryChange", null);
     return true;
   },
 
   OnHistoryPurge: function(numEntries) {
-    Services.obs.notifyObservers(this.browser, "Content:HistoryChange");
+    Services.obs.notifyObservers(this.browser, "Content:HistoryChange", null);
     return true;
   },
 
   OnHistoryReplaceEntry: function(index) {
-    Services.obs.notifyObservers(this.browser, "Content:HistoryChange");
+    Services.obs.notifyObservers(this.browser, "Content:HistoryChange", null);
   },
 
   ShouldNotifyMediaPlaybackChange: function(activeState) {
     // If the media is active, we would check it's duration, because we don't
     // want to show the media control interface for the short sound which
     // duration is smaller than the threshold. The basic unit is second.
     // Note : the streaming format's duration is infinite.
     if (activeState === "inactive") {
@@ -5592,17 +5592,17 @@ var XPInstallObserver = {
       label: Strings.browser.GetStringFromName("notificationRestart.button"),
       callback: function() {
         // Notify all windows that an application quit has been requested
         let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
         Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
 
         // If nothing aborted, quit the app
         if (cancelQuit.data == false) {
-          Services.obs.notifyObservers(null, "quit-application-proceeding");
+          Services.obs.notifyObservers(null, "quit-application-proceeding", null);
           SharedPreferences.forApp().setBoolPref("browser.sessionstore.resume_session_once", true);
           let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
           appStartup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
         }
       },
       positive: true
     }];
 
@@ -6848,17 +6848,17 @@ var Distribution = {
             defaults.setCharPref(key, value);
             break;
         }
       } catch (e) { /* ignore bad prefs and move on */ }
     }
 
     // Apply a lightweight theme if necessary
     if (prefs && prefs["lightweightThemes.selectedThemeID"]) {
-      Services.obs.notifyObservers(null, "lightweight-theme-apply");
+      Services.obs.notifyObservers(null, "lightweight-theme-apply", "");
     }
 
     let localizedString = Cc["@mozilla.org/pref-localizedstring;1"].createInstance(Ci.nsIPrefLocalizedString);
     let localizeablePrefs = aData["LocalizablePreferences"];
     for (let key in localizeablePrefs) {
       try {
         let value = localizeablePrefs[key];
         value = value.replace(/%LOCALE%/g, locale);
--- a/mobile/android/components/LoginManagerPrompter.js
+++ b/mobile/android/components/LoginManagerPrompter.js
@@ -124,17 +124,17 @@ LoginManagerPrompter.prototype = {
 
   /*
    * promptToSavePassword
    *
    */
   promptToSavePassword : function (aLogin) {
     this._showSaveLoginNotification(aLogin);
       Services.telemetry.getHistogramById("PWMGR_PROMPT_REMEMBER_ACTION").add(PROMPT_DISPLAYED);
-    Services.obs.notifyObservers(aLogin, "passwordmgr-prompt-save");
+    Services.obs.notifyObservers(aLogin, "passwordmgr-prompt-save", null);
   },
 
   /*
    * _showLoginNotification
    *
    * Displays a notification doorhanger.
    * @param aBody
    *        String message to be displayed in the doorhanger
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -194,17 +194,17 @@ SessionStore.prototype = {
           Services.obs.addObserver(restoreCleanup, "sessionstore-windows-restored");
 
           // Do a restore, triggered by Java
           this.restoreLastSession(data.sessionString);
         } else {
           // Not doing a restore; just send restore message
           this._startupRestoreFinished = true;
           log("startupRestoreFinished = true");
-          Services.obs.notifyObservers(null, "sessionstore-windows-restored");
+          Services.obs.notifyObservers(null, "sessionstore-windows-restored", "");
         }
         break;
       }
 
       case "Session:RestoreRecentTabs":
         this._restoreTabs(data);
         break;
 
@@ -326,17 +326,17 @@ SessionStore.prototype = {
           this.saveState();
         } else if (this._loadState <= STATE_QUITTING) {
           this.saveStateDelayed();
           if (this._loadState == STATE_QUITTING_FLUSHED) {
             this.flushPendingState();
           }
         }
 
-        Services.obs.notifyObservers(null, "sessionstore-state-purge-complete");
+        Services.obs.notifyObservers(null, "sessionstore-state-purge-complete", "");
         if (this._notifyClosedTabs) {
           this._sendClosedTabsToJava(Services.wm.getMostRecentWindow("navigator:browser"));
         }
         break;
       case "timer-callback":
         if (this._loadState == STATE_RUNNING) {
           // Timer call back for delayed saving
           this._saveTimer = null;
@@ -1168,17 +1168,17 @@ SessionStore.prototype = {
     TelemetryStopwatch.start("FX_SESSION_RESTORE_SERIALIZE_DATA_MS");
     let state = JSON.stringify(aData);
     TelemetryStopwatch.finish("FX_SESSION_RESTORE_SERIALIZE_DATA_MS");
 
     // Convert data string to a utf-8 encoded array buffer
     let buffer = new TextEncoder().encode(state);
     Services.telemetry.getHistogramById("FX_SESSION_RESTORE_FILE_SIZE_BYTES").add(buffer.byteLength);
 
-    Services.obs.notifyObservers(null, "sessionstore-state-write");
+    Services.obs.notifyObservers(null, "sessionstore-state-write", "");
     let startWriteMs = Cu.now();
 
     log("_writeFile(aAsync = " + aAsync + "), _pendingWrite = " + this._pendingWrite);
     this._writeInProgress = true;
     let pendingWrite = this._pendingWrite;
     this._write(aFile, aFileTemp, buffer, aAsync).then(() => {
       let stopWriteMs = Cu.now();
 
@@ -1190,17 +1190,17 @@ SessionStore.prototype = {
         this._writeInProgress = false;
       }
 
       log("_writeFile() _write() returned, _pendingWrite = " + this._pendingWrite);
 
       // We don't use a stopwatch here since the calls are async and stopwatches can only manage
       // a single timer per histogram.
       Services.telemetry.getHistogramById("FX_SESSION_RESTORE_WRITE_FILE_MS").add(Math.round(stopWriteMs - startWriteMs));
-      Services.obs.notifyObservers(null, "sessionstore-state-write-complete");
+      Services.obs.notifyObservers(null, "sessionstore-state-write-complete", "");
       this._sessionDataIsGood = true;
     });
   },
 
   /**
    * Writes the session state to a disk file, using async or sync methods
    * @param aFile nsIFile used for saving the session
    * @param aFileTemp nsIFile used as a temporary file in writing the data
--- a/mobile/android/modules/Sanitizer.jsm
+++ b/mobile/android/modules/Sanitizer.jsm
@@ -163,17 +163,17 @@ Sanitizer.prototype = {
         let refObj = {};
         TelemetryStopwatch.start("FX_SANITIZE_HISTORY", refObj);
 
         return EventDispatcher.instance.sendRequestForResult({ type: "Sanitize:ClearHistory" })
           .catch(e => Cu.reportError("Java-side history clearing failed: " + e))
           .then(function() {
             TelemetryStopwatch.finish("FX_SANITIZE_HISTORY", refObj);
             try {
-              Services.obs.notifyObservers(null, "browser:purge-session-history");
+              Services.obs.notifyObservers(null, "browser:purge-session-history", "");
             }
             catch (e) { }
 
             try {
               var predictor = Cc["@mozilla.org/network/predictor;1"].getService(Ci.nsINetworkPredictor);
               predictor.reset();
             } catch (e) { }
           });
@@ -193,17 +193,17 @@ Sanitizer.prototype = {
         let refObj = {};
         TelemetryStopwatch.start("FX_SANITIZE_OPENWINDOWS", refObj);
 
         return EventDispatcher.instance.sendRequestForResult({ type: "Sanitize:OpenTabs" })
           .catch(e => Cu.reportError("Java-side tab clearing failed: " + e))
           .then(function() {
             try {
               // clear "Recently Closed" tabs in Android App
-              Services.obs.notifyObservers(null, "browser:purge-session-tabs");
+              Services.obs.notifyObservers(null, "browser:purge-session-tabs", "");
             }
             catch (e) { }
             TelemetryStopwatch.finish("FX_SANITIZE_OPENWINDOWS", refObj);
           });
       },
 
       get canClear()
       {
@@ -319,17 +319,17 @@ Sanitizer.prototype = {
           let refObj = {};
           TelemetryStopwatch.start("FX_SANITIZE_SESSIONS", refObj);
 
           // clear all auth tokens
           var sdr = Cc["@mozilla.org/security/sdr;1"].getService(Ci.nsISecretDecoderRing);
           sdr.logoutAndTeardown();
 
           // clear FTP and plain HTTP auth sessions
-          Services.obs.notifyObservers(null, "net:clear-active-logins");
+          Services.obs.notifyObservers(null, "net:clear-active-logins", null);
 
           TelemetryStopwatch.finish("FX_SANITIZE_SESSIONS", refObj);
           resolve();
         });
       },
 
       get canClear()
       {
--- a/mobile/android/tests/browser/chrome/test_awsy_lite.html
+++ b/mobile/android/tests/browser/chrome/test_awsy_lite.html
@@ -70,29 +70,29 @@
     function runSoon(f) {
         threadMan.dispatchToMainThread({ run: f });
     }
 
     function cc() {
         if (domWindowUtils.cycleCollect) {
             domWindowUtils.cycleCollect();
         }
-        Services.obs.notifyObservers(null, "child-cc-request");
+        Services.obs.notifyObservers(null, "child-cc-request", null);
     }
 
     function minimizeInner() {
         // In order of preference: schedulePreciseShrinkingGC, schedulePreciseGC
         // garbageCollect
         if (++j <= aIterations) {
             var schedGC = Cu.schedulePreciseShrinkingGC;
             if (!schedGC) {
                 schedGC = Cu.schedulePreciseGC;
             }
 
-            Services.obs.notifyObservers(null, "child-gc-request");
+            Services.obs.notifyObservers(null, "child-gc-request", null);
 
             if (schedGC) {
                 schedGC.call(Cu, { callback: function () {
                     runSoon(function () { cc(); runSoon(minimizeInner); });
                 } });
             } else {
                 if (domWindowUtils.garbageCollect) {
                     domWindowUtils.garbageCollect();
--- a/mobile/android/tests/browser/chrome/test_session_zombification.html
+++ b/mobile/android/tests/browser/chrome/test_session_zombification.html
@@ -158,17 +158,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 
     // Switch back to the test tab and check that it remains zombified
     BrowserApp.selectTab(tabTest);
     yield promiseTabEvent(BrowserApp.deck, "TabSelect");
     is(BrowserApp.selectedTab, tabTest, "Test tab is selected.");
     ok(tabTest.browser.__SS_restore, "Test tab is still set for delay loading.");
 
     // Fake an "application-foreground" notification
-    observerService.notifyObservers(null, "application-foreground");
+    observerService.notifyObservers(null, "application-foreground", null);
 
     // The test tab should now start reloading
     yield promiseBrowserEvent(tabTest.browser, "DOMContentLoaded");
     ok(!tabTest.browser.__SS_restore, "Test tab is no longer set for delay loading.");
     is(tabTest.browser.currentURI.spec, url1, "Test tab is showing the test URL.");
 
     cleanupTabs();
   });
--- a/modules/libjar/test/unit/test_jarchannel.js
+++ b/modules/libjar/test/unit/test_jarchannel.js
@@ -164,17 +164,17 @@ add_test(function testSyncCloseUnlocks()
     file.copyTo(copy.parent, copy.leafName);
     var uri = "jar:" + ios.newFileURI(copy).spec + "!/inner40.zip";
     var chan = NetUtil.newChannel({uri: uri, loadUsingSystemPrincipal: true});
     var stream = chan.open2();
     do_check_true(chan.contentLength > 0);
     stream.close();
 
     // Drop any jar caches
-    obs.notifyObservers(null, "chrome-flush-caches");
+    obs.notifyObservers(null, "chrome-flush-caches", null);
 
     try {
         copy.remove(false);
     }
     catch (ex) {
         do_throw(ex);
     }
 
@@ -192,17 +192,17 @@ add_test(function testAsyncCloseUnlocks(
 
     var uri = "jar:" + ios.newFileURI(copy).spec + "!/inner40.zip";
     var chan = NetUtil.newChannel({uri: uri, loadUsingSystemPrincipal: true});
 
     chan.asyncOpen2(new Listener(function (l) {
         do_check_true(chan.contentLength > 0);
 
         // Drop any jar caches
-        obs.notifyObservers(null, "chrome-flush-caches");
+        obs.notifyObservers(null, "chrome-flush-caches", null);
 
         try {
             copy.remove(false);
         }
         catch (ex) {
             do_throw(ex);
         }
 
--- a/modules/libpref/test/unit/test_extprefs.js
+++ b/modules/libpref/test/unit/test_extprefs.js
@@ -52,17 +52,17 @@ function run_test() {
   
   ps.readUserPrefs(prefFile);
 
   do_check_true(ps.getBoolPref("testPref.bool1"));
   ps.setBoolPref("testPref.bool1", false);
   do_check_false(ps.getBoolPref("testPref.bool1"));
   
   dirSvc.registerProvider(extProvider);
-  Services.obs.notifyObservers(null, "load-extension-defaults");
+  Services.obs.notifyObservers(null, "load-extension-defaults", null);
 
   // The extension default should be available.
   do_check_true(ps.getBoolPref("testExtPref.bool"));
 
   // The extension default should not override existing user prefs
   do_check_false(ps.getBoolPref("testPref.bool2"));
 
   // The extension default should not modify existing set values
--- a/netwerk/test/unit/test_bug1312782_http1.js
+++ b/netwerk/test/unit/test_bug1312782_http1.js
@@ -172,10 +172,10 @@ function run_test() {
   setup_http_server();
   setup_dummyHttpRequests();
 
   var windowIdWrapper = Cc["@mozilla.org/supports-PRUint64;1"]
                         .createInstance(Ci.nsISupportsPRUint64);
   windowIdWrapper.data = FOCUSED_WINDOW_ID;
   var obsvc = Cc["@mozilla.org/observer-service;1"].
     getService(Ci.nsIObserverService);
-  obsvc.notifyObservers(windowIdWrapper, "net:current-toplevel-outer-content-windowid");
+  obsvc.notifyObservers(windowIdWrapper, "net:current-toplevel-outer-content-windowid", null);
 }
--- a/netwerk/test/unit/test_bug248970_cache.js
+++ b/netwerk/test/unit/test_bug248970_cache.js
@@ -135,17 +135,17 @@ function run_test2() {
   // Check if cache-A, cache-A2, cache-B and cache-C are available
   check_entries(run_test3, false);
 }
 
 function run_test3() {
   // Simulate all private browsing instances being closed
   var obsvc = Cc["@mozilla.org/observer-service;1"].
     getService(Ci.nsIObserverService);
-  obsvc.notifyObservers(null, "last-pb-context-exited");
+  obsvc.notifyObservers(null, "last-pb-context-exited", null);
 
   // Make sure the memory device is not empty
   get_device_entry_count(kMemoryDevice, null, function(count) {
     do_check_eq(count, 1);
     // Check if cache-A is gone, and cache-B and cache-C are still available
     check_entries(do_test_finished, true);
   });
 }
--- a/netwerk/test/unit/test_bug248970_cookie.js
+++ b/netwerk/test/unit/test_bug248970_cookie.js
@@ -118,17 +118,17 @@ function run_test() {
   // The following test only works in a non-e10s situation at the moment,
   // since the notification needs to run in the parent process but there is
   // no existing mechanism to make that happen.  
   if (!inChildProcess()) {
     tests.push(function() {
       // Simulate all private browsing instances being closed
       var obsvc = Cc["@mozilla.org/observer-service;1"].
         getService(Ci.nsIObserverService);
-      obsvc.notifyObservers(null, "last-pb-context-exited");
+      obsvc.notifyObservers(null, "last-pb-context-exited", null);
       // Check that all private cookies are now unavailable in new private requests
       check_cookie_presence("C2=V2", true, false, runNextTest);
     });
   }
   
   tests.push(function() { httpserver.stop(do_test_finished); });
   
   runNextTest();
--- a/netwerk/test/unit/test_cache2-06-pb-mode.js
+++ b/netwerk/test/unit/test_cache2-06-pb-mode.js
@@ -1,13 +1,13 @@
 function exitPB()
 {
   var obsvc = Cc["@mozilla.org/observer-service;1"].
     getService(Ci.nsIObserverService);
-  obsvc.notifyObservers(null, "last-pb-context-exited");
+  obsvc.notifyObservers(null, "last-pb-context-exited", null);
 }
 
 function run_test()
 {
   do_get_profile();
 
   // Store PB entry
   asyncOpenCacheEntry("http://p1/", "disk", Ci.nsICacheStorage.OPEN_NORMALLY, LoadContextInfo.private,
--- a/netwerk/test/unit/test_httpauth.js
+++ b/netwerk/test/unit/test_httpauth.js
@@ -65,17 +65,17 @@ function run_test() {
       do_throw("Auth entry should not be retrievable outside of private browsing mode");
     } catch (x) {
       do_check_eq(domain.value, kEmpty);
       do_check_eq(user.value, kEmpty);
       do_check_eq(pass.value, kEmpty);
     }
 
     // simulate leaving private browsing mode
-    Services.obs.notifyObservers(null, "last-pb-context-exited");
+    Services.obs.notifyObservers(null, "last-pb-context-exited", null);
 
     // make sure the added auth entry is no longer accessible in any privacy state
     domain = {value: kEmpty}, user = {value: kEmpty}, pass = {value: kEmpty};
     try {
       // should throw (not available in public mode)
       am.getAuthIdentity(kHTTP, kHost2, kPort, kBasic, kRealm, kEmpty, domain, user, pass, NOT_PRIVATE);
       do_throw("Auth entry should not be retrievable after exiting the private browsing mode");
     } catch (e) {
--- a/security/manager/pki/resources/content/certViewer.js
+++ b/security/manager/pki/resources/content/certViewer.js
@@ -210,17 +210,17 @@ function displayUsages(results) {
     if (!verifystr) {
       verifystr = bundle.getString("certNotVerified_Unknown");
     }
     verified.textContent = verifystr;
   }
   // Notify that we are done determining the certificate's valid usages (this
   // should be treated as an implementation detail that enables tests to run
   // efficiently - other code in the browser probably shouldn't rely on this).
-  Services.obs.notifyObservers(window, "ViewCertDetails:CertUsagesDone");
+  Services.obs.notifyObservers(window, "ViewCertDetails:CertUsagesDone", null);
 }
 
 function addChildrenToTree(parentTree, label, value, addTwistie) {
   let treeChild1 = document.createElement("treechildren");
   let treeElement = addTreeItemToTreeChild(treeChild1, label, value,
                                            addTwistie);
   parentTree.appendChild(treeChild1);
   return treeElement;
--- a/security/manager/pki/resources/content/clientauthask.js
+++ b/security/manager/pki/resources/content/clientauthask.js
@@ -96,17 +96,17 @@ function onLoad() {
     if (i == 0) {
       selectElement.selectedItem = menuItemNode;
     }
   }
 
   setDetails();
 
   Services.obs.notifyObservers(document.getElementById("certAuthAsk"),
-                               "cert-dialog-loaded");
+                               "cert-dialog-loaded", null);
 }
 
 /**
  * Populates the details section with information concerning the selected cert.
  */
 function setDetails() {
   let index = parseInt(document.getElementById("nicknames").value);
   let cert = certArray.queryElementAt(index, Ci.nsIX509Cert);
--- a/security/manager/pki/resources/content/exceptionDialog.js
+++ b/security/manager/pki/resources/content/exceptionDialog.js
@@ -261,17 +261,17 @@ function updateCertStatus() {
 
     // We're done checking the certificate, so allow the user to check it again.
     document.getElementById("checkCertButton").disabled = false;
     document.getElementById("viewCertButton").disabled = false;
 
     // Notify observers about the availability of the certificate
     Components.classes["@mozilla.org/observer-service;1"]
               .getService(Components.interfaces.nsIObserverService)
-              .notifyObservers(null, "cert-exception-ui-ready");
+              .notifyObservers(null, "cert-exception-ui-ready", null);
   } else if (gChecking) {
     shortDesc = "addExceptionCheckingShort";
     longDesc  = "addExceptionCheckingLong2";
     // We're checking the certificate, so we disable the Get Certificate
     // button to make sure that the user can't interrupt the process and
     // trigger another certificate fetch.
     document.getElementById("checkCertButton").disabled = true;
     document.getElementById("viewCertButton").disabled = true;
--- a/security/manager/ssl/tests/unit/test_sts_preloadlist_perwindowpb.js
+++ b/security/manager/ssl/tests/unit/test_sts_preloadlist_perwindowpb.js
@@ -207,17 +207,17 @@ function test_private_browsing1() {
   ok(gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
                             IS_PRIVATE));
   gSSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
                            "max-age=1", sslStatus, IS_PRIVATE);
   do_timeout(1250, function() {
     ok(!gSSService.isSecureURI(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
                                IS_PRIVATE));
     // Simulate leaving private browsing mode
-    Services.obs.notifyObservers(null, "last-pb-context-exited");
+    Services.obs.notifyObservers(null, "last-pb-context-exited", null);
   });
 }
 
 function test_private_browsing2() {
   // if this test gets this far, it means there's a private browsing service
   ok(gSSService.isSecureURI(
        Ci.nsISiteSecurityService.HEADER_HSTS,
        Services.io.newURI("https://includesubdomains.preloaded.test"), 0));
--- a/services/common/logmanager.js
+++ b/services/common/logmanager.js
@@ -321,11 +321,11 @@ LogManager.prototype = {
         this._log.debug("Encountered error trying to clean up old log file "
                         + entry.name, ex);
       }
     }.bind(this)));
     iterator.close();
     this._cleaningUpFileLogs = false;
     this._log.debug("Done deleting files.");
     // This notification is used only for tests.
-    Services.obs.notifyObservers(null, "services-tests:common:log-manager:cleanup-logs");
+    Services.obs.notifyObservers(null, "services-tests:common:log-manager:cleanup-logs", null);
   }),
 }
--- a/services/fxaccounts/FxAccountsManager.jsm
+++ b/services/fxaccounts/FxAccountsManager.jsm
@@ -33,17 +33,17 @@ this.FxAccountsManager = {
   },
 
   observe(aSubject, aTopic, aData) {
     // Both topics indicate our cache is invalid
     this._activeSession = null;
 
     if (aData == ONVERIFIED_NOTIFICATION) {
       log.debug("FxAccountsManager: cache cleared, broadcasting: " + aData);
-      Services.obs.notifyObservers(null, aData);
+      Services.obs.notifyObservers(null, aData, null);
     }
   },
 
   // We don't really need to save fxAccounts instance but this way we allow
   // to mock FxAccounts from tests.
   _fxAccounts: fxAccounts,
 
   // We keep the session details here so consumers don't need to deal with
--- a/services/fxaccounts/FxAccountsPush.js
+++ b/services/fxaccounts/FxAccountsPush.js
@@ -169,17 +169,17 @@ FxAccountsPushService.prototype = {
         Services.obs.notifyObservers(null, ON_DEVICE_CONNECTED_NOTIFICATION, payload.data.deviceName);
         break;
       case ON_DEVICE_DISCONNECTED_NOTIFICATION:
         this.fxAccounts.handleDeviceDisconnection(payload.data.id);
         return;
       case ON_PROFILE_UPDATED_NOTIFICATION:
         // We already have a "profile updated" notification sent via WebChannel,
         // let's just re-use that.
-        Services.obs.notifyObservers(null, ON_PROFILE_CHANGE_NOTIFICATION);
+        Services.obs.notifyObservers(null, ON_PROFILE_CHANGE_NOTIFICATION, null);
         return;
       case ON_PASSWORD_CHANGED_NOTIFICATION:
       case ON_PASSWORD_RESET_NOTIFICATION:
         this._onPasswordChanged();
         return;
       case ON_COLLECTION_CHANGED_NOTIFICATION:
         Services.obs.notifyObservers(null, ON_COLLECTION_CHANGED_NOTIFICATION, payload.data.collections);
       default:
@@ -192,17 +192,17 @@ FxAccountsPushService.prototype = {
    * ON_ACCOUNT_STATE_CHANGE_NOTIFICATION that the account may have changed
    *
    * @returns {Promise}
    * @private
    */
   _onPasswordChanged: Task.async(function* () {
     if (!(yield this.fxAccounts.sessionStatus())) {
       yield this.fxAccounts.resetCredentials();
-      Services.obs.notifyObservers(null, ON_ACCOUNT_STATE_CHANGE_NOTIFICATION);
+      Services.obs.notifyObservers(null, ON_ACCOUNT_STATE_CHANGE_NOTIFICATION, null);
     }
   }),
   /**
    * Fired when the Push server drops a subscription, or the subscription identifier changes.
    *
    * https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIPushService#Receiving_Push_Messages
    *
    * @returns {Promise}
--- a/services/fxaccounts/tests/xpcshell/test_oauth_token_storage.js
+++ b/services/fxaccounts/tests/xpcshell/test_oauth_token_storage.js
@@ -129,17 +129,17 @@ function run_test() {
 add_task(function* testCacheStorage() {
   let fxa = yield createMockFxA();
 
   // Hook what the impl calls to save to disk.
   let cas = fxa.internal.currentAccountState;
   let origPersistCached = cas._persistCachedTokens.bind(cas)
   cas._persistCachedTokens = function() {
     return origPersistCached().then(() => {
-      Services.obs.notifyObservers(null, "testhelper-fxa-cache-persist-done");
+      Services.obs.notifyObservers(null, "testhelper-fxa-cache-persist-done", null);
     });
   };
 
   let promiseWritten = promiseNotification("testhelper-fxa-cache-persist-done");
   let tokenData = {token: "token1", somethingelse: "something else"};
   let scopeArray = ["foo", "bar"];
   cas.setCachedToken(scopeArray, tokenData);
   deepEqual(cas.getCachedToken(scopeArray), tokenData);
--- a/services/fxaccounts/tests/xpcshell/test_oauth_tokens.js
+++ b/services/fxaccounts/tests/xpcshell/test_oauth_tokens.js
@@ -87,17 +87,17 @@ function MockFxAccounts(mockGrantClient)
       // we use a real accountState but mocked storage.
       let storage = new MockStorageManager();
       storage.initialize(credentials);
       return new AccountState(storage);
     },
     _destroyOAuthToken(tokenData) {
       // somewhat sad duplication of _destroyOAuthToken, but hard to avoid.
       return mockGrantClient.destroyToken(tokenData.token).then( () => {
-        Services.obs.notifyObservers(null, "testhelper-fxa-revoke-complete");
+        Services.obs.notifyObservers(null, "testhelper-fxa-revoke-complete", null);
       });
     },
     _getDeviceName() {
       return "mock device name";
     },
     fxaPushService: {
       registerPushEndpoint() {
         return new Promise((resolve) => {
--- a/services/fxaccounts/tests/xpcshell/test_profile.js
+++ b/services/fxaccounts/tests/xpcshell/test_profile.js
@@ -351,17 +351,17 @@ add_task(function* fetchAndCacheProfileB
     return Promise.resolve({ avatar: "myimg"});
   };
   let profile = CreateFxAccountsProfile(null, client);
   profile.PROFILE_FRESHNESS_THRESHOLD = 1000;
 
   yield profile.getProfile();
   do_check_eq(numFetches, 1);
 
-  Services.obs.notifyObservers(null, ON_PROFILE_CHANGE_NOTIFICATION);
+  Services.obs.notifyObservers(null, ON_PROFILE_CHANGE_NOTIFICATION, null);
 
   yield profile.getProfile();
   do_check_eq(numFetches, 2);
 });
 
 add_test(function tearDown_ok() {
   let profile = CreateFxAccountsProfile();
 
--- a/services/sync/modules/SyncedTabs.jsm
+++ b/services/sync/modules/SyncedTabs.jsm
@@ -191,25 +191,25 @@ let SyncedTabsInternal = {
       case "weave:engine:sync:finish":
         if (data != "tabs") {
           return;
         }
         // The tabs engine just finished syncing
         // Set our lastTabFetch pref here so it tracks both explicit sync calls
         // and normally scheduled ones.
         Preferences.set("services.sync.lastTabFetch", Math.floor(Date.now() / 1000));
-        Services.obs.notifyObservers(null, TOPIC_TABS_CHANGED);
+        Services.obs.notifyObservers(null, TOPIC_TABS_CHANGED, null);
         break;
       case "weave:service:start-over":
         // start-over needs to notify so consumers find no tabs.
         Preferences.reset("services.sync.lastTabFetch");
-        Services.obs.notifyObservers(null, TOPIC_TABS_CHANGED);
+        Services.obs.notifyObservers(null, TOPIC_TABS_CHANGED, null);
         break;
       case "nsPref:changed":
-        Services.obs.notifyObservers(null, TOPIC_TABS_CHANGED);
+        Services.obs.notifyObservers(null, TOPIC_TABS_CHANGED, null);
         break;
       default:
         break;
     }
   },
 
   // Returns true if Sync is configured to Sync tabs, false otherwise
   get isConfiguredToSyncTabs() {
--- a/services/sync/modules/browserid_identity.js
+++ b/services/sync/modules/browserid_identity.js
@@ -211,17 +211,17 @@ this.BrowserIDManager.prototype = {
         }
         this._shouldHaveSyncKeyBundle = true; // and we should actually have one...
         this.whenReadyToAuthenticate.resolve();
         this._log.info("Background fetch for key bundle done");
         Weave.Status.login = LOGIN_SUCCEEDED;
         if (isInitialSync) {
           this._log.info("Doing initial sync actions");
           Svc.Prefs.set("firstSync", "resetClient");
-          Services.obs.notifyObservers(null, "weave:service:setup-complete");
+          Services.obs.notifyObservers(null, "weave:service:setup-complete", null);
           Weave.Utils.nextTick(Weave.Service.sync, Weave.Service);
         }
       }).catch(authErr => {
         // report what failed...
         this._log.error("Background fetch for key bundle failed", authErr);
         this._shouldHaveSyncKeyBundle = true; // but we probably don't have one...
         this.whenReadyToAuthenticate.reject(authErr);
       });
@@ -271,17 +271,17 @@ this.BrowserIDManager.prototype = {
 
       if (!firstLogin) {
         // We still want to trigger these even if it isn't our first login.
         // Note that the promise returned by `initializeWithCurrentIdentity`
         // is resolved at the start of authentication, but we don't want to fire
         // this event or start the next sync until after authentication is done
         // (which is signaled by `this.whenReadyToAuthenticate.promise` resolving).
         this.whenReadyToAuthenticate.promise.then(() => {
-          Services.obs.notifyObservers(null, "weave:service:setup-complete");
+          Services.obs.notifyObservers(null, "weave:service:setup-complete", null);
           return new Promise(resolve => { Weave.Utils.nextTick(resolve, null); })
         }).then(() => {
           Weave.Service.sync();
         }).catch(e => {
           this._log.warn("Failed to trigger setup complete notification", e);
         });
       }
     } break;
@@ -648,17 +648,17 @@ this.BrowserIDManager.prototype = {
   // Returns a promise that is resolved when we have a valid token for the
   // current user stored in this._token.  When resolved, this._token is valid.
   _ensureValidToken() {
     if (this.hasValidToken()) {
       this._log.debug("_ensureValidToken already has one");
       return Promise.resolve();
     }
     const notifyStateChanged =
-      () => Services.obs.notifyObservers(null, "weave:service:login:change");
+      () => Services.obs.notifyObservers(null, "weave:service:login:change", null);
     // reset this._token as a safety net to reduce the possibility of us
     // repeatedly attempting to use an invalid token if _fetchTokenForUser throws.
     this._token = null;
     return this._fetchTokenForUser().then(
       token => {
         this._token = token;
         // we store the hashed UID from the token so that if we see a transient
         // error fetching a new token we still know the "most recent" hashed
--- a/services/sync/tps/extensions/mozmill/resource/modules/frame.js
+++ b/services/sync/tps/extensions/mozmill/resource/modules/frame.js
@@ -58,17 +58,17 @@ function shutdownApplication(aFlags) {
   }
 
   // Send a request to shutdown the application. That will allow us and other
   // components to finish up with any shutdown code. Please note that we don't
   // care if other components or add-ons want to prevent this via cancelQuit,
   // we really force the shutdown.
   let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"].
                    createInstance(Components.interfaces.nsISupportsPRBool);
-  Services.obs.notifyObservers(cancelQuit, "quit-application-requested");
+  Services.obs.notifyObservers(cancelQuit, "quit-application-requested", null);
 
   // Use a timer to trigger the application restart, which will allow us to
   // send an ACK packet via jsbridge if the method has been called via Python.
   var event = {
     notify: function(timer) {
       Services.startup.quit(flags);
     }
   }
--- a/services/sync/tps/extensions/tps/resource/quit.js
+++ b/services/sync/tps/extensions/tps/resource/quit.js
@@ -10,17 +10,17 @@
 var EXPORTED_SYMBOLS = ["goQuitApplication"];
 
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 function canQuitApplication() {
   try {
     var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]
                      .createInstance(Components.interfaces.nsISupportsPRBool);
-    Services.obs.notifyObservers(cancelQuit, "quit-application-requested");
+    Services.obs.notifyObservers(cancelQuit, "quit-application-requested", null);
 
     // Something aborted the quit process.
     if (cancelQuit.data) {
       return false;
     }
   } catch (ex) {}
 
   return true;
--- a/storage/test/unit/vacuumParticipant.js
+++ b/storage/test/unit/vacuumParticipant.js
@@ -48,17 +48,17 @@ vacuumParticipant.prototype =
   },
 
   _grant: true,
   onBeginVacuum: function TVP_onBeginVacuum() {
     if (!this._grant) {
       this._grant = true;
       return false;
     }
-    Services.obs.notifyObservers(null, "test-begin-vacuum");
+    Services.obs.notifyObservers(null, "test-begin-vacuum", null);
     return true;
   },
   onEndVacuum: function TVP_EndVacuum(aSucceeded) {
     if (this._stmt) {
       this._stmt.finalize();
     }
     Services.obs.notifyObservers(null, "test-end-vacuum", aSucceeded);
   },
--- a/testing/mochitest/browser-test.js
+++ b/testing/mochitest/browser-test.js
@@ -639,17 +639,17 @@ Tester.prototype = {
 
 
         let {AsyncShutdown} =
           Cu.import("resource://gre/modules/AsyncShutdown.jsm", {});
 
         let barrier = new AsyncShutdown.Barrier(
           "ShutdownLeaks: Wait for cleanup to be finished before checking for leaks");
         Services.obs.notifyObservers({wrappedJSObject: barrier},
-          "shutdown-leaks-before-check");
+          "shutdown-leaks-before-check", null);
 
         barrier.client.addBlocker("ShutdownLeaks: Wait for tabs to finish closing",
                                   TabDestroyObserver.wait());
 
         barrier.wait().then(() => {
           // Simulate memory pressure so that we're forced to free more resources
           // and thus get rid of more false leaks like already terminated workers.
           Services.obs.notifyObservers(null, "memory-pressure", "heap-minimize");
--- a/testing/specialpowers/content/specialpowersAPI.js
+++ b/testing/specialpowers/content/specialpowersAPI.js
@@ -1186,17 +1186,17 @@ SpecialPowersAPI.prototype = {
   },
 
   _proxiedObservers: {
     "specialpowers-http-notify-request": function(aMessage) {
       let uri = aMessage.json.uri;
       Services.obs.notifyObservers(null, "specialpowers-http-notify-request", uri);
     },
     "specialpowers-browser-fullZoom:zoomReset": function() {
-      Services.obs.notifyObservers(null, "specialpowers-browser-fullZoom:zoomReset");
+      Services.obs.notifyObservers(null, "specialpowers-browser-fullZoom:zoomReset", null);
     },
   },
 
   _addObserverProxy: function(notification) {
     if (notification in this._proxiedObservers) {
       this._addMessageListener(notification, this._proxiedObservers[notification]);
     }
   },
--- a/testing/talos/talos/pageloader/chrome/memory.js
+++ b/testing/talos/talos/pageloader/chrome/memory.js
@@ -47,17 +47,17 @@ function initializeMemoryCollector(callb
  */
 function collectMemory(callback, args) {
   gMemCallback = function() { return callback(args); };
 
   if (gChildProcess) {
     var os = Components.classes["@mozilla.org/observer-service;1"].
         getService(Components.interfaces.nsIObserverService);
 
-    os.notifyObservers(null, "child-memory-reporter-request");
+    os.notifyObservers(null, "child-memory-reporter-request", null);
   } else {
     collectAndReport(null, null, null);
   }
 }
 
 function collectAndReport(aSubject, aTopic, aData) {
   dumpLine(collectRSS());
   gMemCallback();
--- a/testing/talos/talos/pageloader/chrome/quit.js
+++ b/testing/talos/talos/pageloader/chrome/quit.js
@@ -48,17 +48,17 @@ function canQuitApplication()
   {
     return true;
   }
   
   try 
   {
     var cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]
       .createInstance(Components.interfaces.nsISupportsPRBool);
-    os.notifyObservers(cancelQuit, "quit-application-requested");
+    os.notifyObservers(cancelQuit, "quit-application-requested", null);
     
     // Something aborted the quit process. 
     if (cancelQuit.data)
     {
       return false;
     }
   }
   catch (ex) 
--- a/testing/xpcshell/dbg-actors.js
+++ b/testing/xpcshell/dbg-actors.js
@@ -22,17 +22,17 @@ const { BrowserTabList } = devtools.requ
 function createRootActor(connection)
 {
   let parameters = {
     tabList: new XPCSTTabList(connection),
     globalActorFactories: DebuggerServer.globalActorFactories,
     onShutdown() {
       // If the user never switches to the "debugger" tab we might get a
       // shutdown before we've attached.
-      Services.obs.notifyObservers(null, "xpcshell-test-devtools-shutdown");
+      Services.obs.notifyObservers(null, "xpcshell-test-devtools-shutdown", null);
     }
   };
   return new RootActor(connection, parameters);
 }
 
 /**
  * A "stub" TabList implementation that provides no tabs.
  */
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -616,20 +616,20 @@ function _execute_test() {
   // Restore idle service to avoid leaks.
   _fakeIdleService.deactivate();
 
   if (_profileInitialized) {
     // Since we have a profile, we will notify profile shutdown topics at
     // the end of the current test, to ensure correct cleanup on shutdown.
     let obs = Components.classes["@mozilla.org/observer-service;1"]
                         .getService(Components.interfaces.nsIObserverService);
-    obs.notifyObservers(null, "profile-change-net-teardown");
-    obs.notifyObservers(null, "profile-change-teardown");
-    obs.notifyObservers(null, "profile-before-change");
-    obs.notifyObservers(null, "profile-before-change-qm");
+    obs.notifyObservers(null, "profile-change-net-teardown", null);
+    obs.notifyObservers(null, "profile-change-teardown", null);
+    obs.notifyObservers(null, "profile-before-change", null);
+    obs.notifyObservers(null, "profile-before-change-qm", null);
 
     _profileInitialized = false;
   }
 
   try {
     _PromiseTestUtils.ensureDOMPromiseRejectionsProcessed();
     _PromiseTestUtils.assertNoUncaughtRejections();
     _PromiseTestUtils.assertNoMoreExpectedRejections();
--- a/toolkit/components/aboutmemory/content/aboutMemory.js
+++ b/toolkit/components/aboutmemory/content/aboutMemory.js
@@ -416,33 +416,33 @@ function onLoad() {
       }
     }
   }
 }
 
 // ---------------------------------------------------------------------------
 
 function doGC() {
-  Services.obs.notifyObservers(null, "child-gc-request");
+  Services.obs.notifyObservers(null, "child-gc-request", null);
   Cu.forceGC();
   updateMainAndFooter("Garbage collection completed", SHOW_TIMESTAMP,
                       HIDE_FOOTER);
 }
 
 function doCC() {
-  Services.obs.notifyObservers(null, "child-cc-request");
+  Services.obs.notifyObservers(null, "child-cc-request", null);
   window.QueryInterface(Ci.nsIInterfaceRequestor)
         .getInterface(Ci.nsIDOMWindowUtils)
         .cycleCollect();
   updateMainAndFooter("Cycle collection completed", SHOW_TIMESTAMP,
                       HIDE_FOOTER);
 }
 
 function doMMU() {
-  Services.obs.notifyObservers(null, "child-mmu-request");
+  Services.obs.notifyObservers(null, "child-mmu-request", null);
   gMgr.minimizeMemoryUsage(
     () => updateMainAndFooter("Memory minimization completed",
                               SHOW_TIMESTAMP, HIDE_FOOTER));
 }
 
 function doMeasure() {
   updateAboutMemoryFromReporters();
 }
--- a/toolkit/components/asyncshutdown/tests/xpcshell/head.js
+++ b/toolkit/components/asyncshutdown/tests/xpcshell/head.js
@@ -39,17 +39,17 @@ function makeLock(kind) {
     return {
       addBlocker(...args) {
         return phase.addBlocker(...args);
       },
       removeBlocker(blocker) {
         return phase.removeBlocker(blocker);
       },
       wait() {
-        Services.obs.notifyObservers(null, topic);
+        Services.obs.notifyObservers(null, topic, null);
         return Promise.resolve();
       }
     };
   } else if (kind == "barrier") {
     let name = "test-Barrier-" + ++makeLock.counter;
     let barrier = new AsyncShutdown.Barrier(name);
     return {
       addBlocker: barrier.client.addBlocker,
--- a/toolkit/components/contentprefs/tests/unit/head_contentPrefs.js
+++ b/toolkit/components/contentprefs/tests/unit/head_contentPrefs.js
@@ -135,17 +135,17 @@ let loadContext = Cc["@mozilla.org/loadc
                     createInstance(Ci.nsILoadContext);
 let privateLoadContext = Cc["@mozilla.org/privateloadcontext;1"].
                            createInstance(Ci.nsILoadContext);
 function enterPBMode(cps) {
   cps.loadContext = privateLoadContext;
 }
 function exitPBMode(cps) {
   cps.loadContext = loadContext;
-  Services.obs.notifyObservers(null, "last-pb-context-exited");
+  Services.obs.notifyObservers(null, "last-pb-context-exited", null);
 }
 
 ContentPrefTest.deleteDatabase();
 
 do_register_cleanup(function() {
   ContentPrefTest.deleteDatabase();
   ContentPrefTest.__dirSvc = null;
 });
--- a/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
+++ b/toolkit/components/extensions/ExtensionXPCShellUtils.jsm
@@ -407,17 +407,17 @@ class AOMExtensionWrapper extends Extens
 
     AddonTestUtils.off("addon-manager-shutdown", this.onEvent);
     AddonTestUtils.off("addon-manager-started", this.onEvent);
 
     AddonManager.removeAddonListener(this);
 
     for (let file of this.cleanupFiles.splice(0)) {
       try {
-        Services.obs.notifyObservers(file, "flush-cache-entry");
+        Services.obs.notifyObservers(file, "flush-cache-entry", null);
         file.remove(false);
       } catch (e) {
         Cu.reportError(e);
       }
     }
   }
 
   setRestarting() {
--- a/toolkit/components/extensions/ext-permissions.js
+++ b/toolkit/components/extensions/ext-permissions.js
@@ -41,17 +41,17 @@ this.permissions = class extends Extensi
                 wrappedJSObject: {
                   browser: context.xulBrowser,
                   name: context.extension.name,
                   icon: context.extension.iconURL,
                   permissions: {permissions, origins},
                   resolve,
                 },
               };
-              Services.obs.notifyObservers(subject, "webextension-optional-permission-prompt");
+              Services.obs.notifyObservers(subject, "webextension-optional-permission-prompt", null);
             });
             if (!allow) {
               return false;
             }
           }
 
           await ExtensionPermissions.add(context.extension, perms);
           return true;
--- a/toolkit/components/extensions/test/xpcshell/test_ext_experiments.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_experiments.js
@@ -111,17 +111,17 @@ add_task(function* test_experiments_api(
       if (browser.meh) {
         browser.meh.hello("Here I should not be");
       }
     },
   });
 
   do_register_cleanup(() => {
     for (let file of [apiAddonFile, addonFile, boringAddonFile]) {
-      Services.obs.notifyObservers(file, "flush-cache-entry");
+      Services.obs.notifyObservers(file, "flush-cache-entry", null);
       file.remove(false);
     }
   });
 
 
   let resolveHello;
   let observer = (subject, topic, data) => {
     if (topic == "webext-api-loaded") {
--- a/toolkit/components/extensions/test/xpcshell/test_ext_json_parser.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_json_parser.js
@@ -27,11 +27,11 @@ add_task(function* test_json_parser() {
 
   let extension = new ExtensionData(uri);
 
   yield extension.parseManifest();
 
   Assert.deepEqual(extension.rawManifest, expectedManifest,
                    "Manifest with correctly-filtered comments");
 
-  Services.obs.notifyObservers(xpi, "flush-cache-entry");
+  Services.obs.notifyObservers(xpi, "flush-cache-entry", null);
   xpi.remove(false);
 });
--- a/toolkit/components/extensions/test/xpcshell/test_ext_legacy_extension_embedding.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_legacy_extension_embedding.js
@@ -50,17 +50,17 @@ add_task(function* test_embedded_webexte
       },
     },
     "webextension/bg.js": `new ${backgroundScript}`,
   });
 
   // Remove the generated xpi file and flush the its jar cache
   // on cleanup.
   do_register_cleanup(() => {
-    Services.obs.notifyObservers(fakeHybridAddonFile, "flush-cache-entry");
+    Services.obs.notifyObservers(fakeHybridAddonFile, "flush-cache-entry", null);
     fakeHybridAddonFile.remove(false);
   });
 
   let fileURI = Services.io.newFileURI(fakeHybridAddonFile);
   let resourceURI = Services.io.newURI(`jar:${fileURI.spec}!/`);
 
   let embeddedExtension = LegacyExtensionsUtils.getEmbeddedExtensionFor({
     id, resourceURI,
@@ -112,17 +112,17 @@ add_task(function* test_embedded_webexte
   equal(EmbeddedExtensionManager.embeddedExtensionsByAddonId.size, 0,
         "EmbeddedExtension instances has been untracked from the EmbeddedExtensionManager");
 });
 
 function* createManifestErrorTestCase(id, xpi, expectedError) {
   // Remove the generated xpi file and flush the its jar cache
   // on cleanup.
   do_register_cleanup(() => {
-    Services.obs.notifyObservers(xpi, "flush-cache-entry");
+    Services.obs.notifyObservers(xpi, "flush-cache-entry", null);
     xpi.remove(false);
   });
 
   let fileURI = Services.io.newFileURI(xpi);
   let resourceURI = Services.io.newURI(`jar:${fileURI.spec}!/`);
 
   let embeddedExtension = LegacyExtensionsUtils.getEmbeddedExtensionFor({
     id, resourceURI,
--- a/toolkit/components/extensions/test/xpcshell/test_ext_management_uninstall_self.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_management_uninstall_self.js
@@ -62,17 +62,17 @@ add_task(function* test_management_unins
     useAddonManager: "temporary",
   });
 
   yield extension.startup();
   let addon = yield AddonManager.getAddonByID(id);
   notEqual(addon, null, "Add-on is installed");
   extension.sendMessage("uninstall");
   yield waitForUninstalled();
-  Services.obs.notifyObservers(extension.extension.file, "flush-cache-entry");
+  Services.obs.notifyObservers(extension.extension.file, "flush-cache-entry", null);
 });
 
 add_task(function* test_management_uninstall_prompt_uninstall() {
   promptService._response = 0;
 
   function background() {
     browser.test.onMessage.addListener(msg => {
       browser.management.uninstallSelf({showConfirmDialog: true});
@@ -92,17 +92,17 @@ add_task(function* test_management_unins
   yield waitForUninstalled();
 
   // Test localization strings
   equal(promptService._confirmExArgs[1], `Uninstall ${manifest.name}`);
   equal(promptService._confirmExArgs[2],
         `The extension “${manifest.name}” is requesting to be uninstalled. What would you like to do?`);
   equal(promptService._confirmExArgs[4], "Uninstall");
   equal(promptService._confirmExArgs[5], "Keep Installed");
-  Services.obs.notifyObservers(extension.extension.file, "flush-cache-entry");
+  Services.obs.notifyObservers(extension.extension.file, "flush-cache-entry", null);
 });
 
 add_task(function* test_management_uninstall_prompt_keep() {
   promptService._response = 1;
 
   function background() {
     browser.test.onMessage.addListener(async msg => {
       await browser.test.assertRejects(
--- a/toolkit/components/extensions/test/xpcshell/test_ext_storage.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_storage.js
@@ -60,17 +60,17 @@ add_task(function* test_local_cache_inva
   });
 
   yield extension.startup();
   yield extension.awaitMessage("ready");
 
   extension.sendMessage("set-initial");
   yield extension.awaitMessage("set-initial-done");
 
-  Services.obs.notifyObservers(null, "extension-invalidate-storage-cache");
+  Services.obs.notifyObservers(null, "extension-invalidate-storage-cache", "");
 
   extension.sendMessage("check");
   yield extension.awaitMessage("check-done");
 
   yield extension.unload();
 });
 
 add_task(function* test_config_flag_needed() {
--- a/toolkit/components/extensions/test/xpcshell/test_locale_data.js
+++ b/toolkit/components/extensions/test/xpcshell/test_locale_data.js
@@ -9,17 +9,17 @@ const uuidGenerator = Cc["@mozilla.org/u
 function* generateAddon(data) {
   let id = uuidGenerator.generateUUID().number;
 
   data = Object.assign({embedded: true}, data);
   data.manifest = Object.assign({applications: {gecko: {id}}}, data.manifest);
 
   let xpi = Extension.generateXPI(data);
   do_register_cleanup(() => {
-    Services.obs.notifyObservers(xpi, "flush-cache-entry");
+    Services.obs.notifyObservers(xpi, "flush-cache-entry", null);
     xpi.remove(false);
   });
 
   let fileURI = Services.io.newFileURI(xpi);
   let jarURI = NetUtil.newURI(`jar:${fileURI.spec}!/webextension/`);
 
   let extension = new ExtensionData(jarURI);
   yield extension.loadManifest();
--- a/toolkit/components/formautofill/content/requestAutocomplete.js
+++ b/toolkit/components/formautofill/content/requestAutocomplete.js
@@ -26,17 +26,17 @@ const RequestAutocompleteDialog = {
     Task.spawn(function* () {
       let args = window.arguments[0].wrappedJSObject;
       this.resolveFn = args.resolveFn;
       this.autofillData = args.autofillData;
 
       window.sizeToContent();
 
       Services.obs.notifyObservers(window,
-                                   "formautofill-window-initialized");
+                                   "formautofill-window-initialized", "");
     }.bind(this)).catch(Cu.reportError);
   },
 
   onAccept() {
     // TODO: Replace with autofill storage module (bug 1018304).
     const dummyDB = {
       "": {
         "name": "Mozzy La",
--- a/toolkit/components/formautofill/test/browser/browser_infrastructure.js
+++ b/toolkit/components/formautofill/test/browser/browser_infrastructure.js
@@ -33,16 +33,16 @@ add_task(function* test_utility_function
   let path = yield TestUtils.getTempFile("test-infrastructure.txt");
   yield OS.File.writeAtomic(path, new TextEncoder().encode(randomString));
 
   // Test a few utility functions.
   yield TestUtils.waitForTick();
   yield TestUtils.waitMs(50);
 
   let promiseMyNotification = TestUtils.waitForNotification("my-topic");
-  Services.obs.notifyObservers(null, "my-topic");
+  Services.obs.notifyObservers(null, "my-topic", "");
   yield promiseMyNotification;
 
   // Check the file size.  The file will be deleted automatically later.
   Assert.equal((yield OS.File.stat(path)).size, randomString.length);
 });
 
 add_task(terminationTaskFn);
--- a/toolkit/components/formautofill/test/chrome/test_infrastructure.js
+++ b/toolkit/components/formautofill/test/chrome/test_infrastructure.js
@@ -35,17 +35,17 @@ add_task(function* test_utility_function
   let path = yield TestUtils.getTempFile("test-infrastructure.txt");
   yield OS.File.writeAtomic(path, new TextEncoder().encode(randomString));
 
   // Test a few utility functions.
   yield TestUtils.waitForTick();
   yield TestUtils.waitMs(50);
 
   let promiseMyNotification = TestUtils.waitForNotification("my-topic");
-  Services.obs.notifyObservers(null, "my-topic");
+  Services.obs.notifyObservers(null, "my-topic", "");
   yield promiseMyNotification;
 
   // Check the file size.  The file will be deleted automatically later.
   Assert.equal((yield OS.File.stat(path)).size, randomString.length);
 });
 
 /**
  * This type of test has access to the content declared above.
--- a/toolkit/components/formautofill/test/xpcshell/test_infrastructure.js
+++ b/toolkit/components/formautofill/test/xpcshell/test_infrastructure.js
@@ -33,16 +33,16 @@ add_task(function* test_utility_function
   let path = yield TestUtils.getTempFile("test-infrastructure.txt");
   yield OS.File.writeAtomic(path, new TextEncoder().encode(randomString));
 
   // Test a few utility functions.
   yield TestUtils.waitForTick();
   yield TestUtils.waitMs(50);
 
   let promiseMyNotification = TestUtils.waitForNotification("my-topic");
-  Services.obs.notifyObservers(null, "my-topic");
+  Services.obs.notifyObservers(null, "my-topic", "");
   yield promiseMyNotification;
 
   // Check the file size.  The file will be deleted automatically later.
   Assert.equal((yield OS.File.stat(path)).size, randomString.length);
 });
 
 add_task(terminationTaskFn);
--- a/toolkit/components/jsdownloads/test/unit/common_test_Download.js
+++ b/toolkit/components/jsdownloads/test/unit/common_test_Download.js
@@ -2367,17 +2367,17 @@ add_task(function* test_launchWhenSuccee
 
   Services.prefs.clearUserPref(kDeleteTempFileOnExit);
 
   do_check_true(yield OS.File.exists(autoDeleteTargetPathOne));
   do_check_true(yield OS.File.exists(autoDeleteTargetPathTwo));
   do_check_true(yield OS.File.exists(noAutoDeleteTargetPath));
 
   // Simulate leaving private browsing mode
-  Services.obs.notifyObservers(null, "last-pb-context-exited");
+  Services.obs.notifyObservers(null, "last-pb-context-exited", null);
   do_check_false(yield OS.File.exists(autoDeleteTargetPathOne));
 
   // Simulate browser shutdown
   let expire = Cc["@mozilla.org/uriloader/external-helper-app-service;1"]
                  .getService(Ci.nsIObserver);
   expire.observe(null, "profile-before-change", null);
   do_check_false(yield OS.File.exists(autoDeleteTargetPathTwo));
   do_check_true(yield OS.File.exists(noAutoDeleteTargetPath));
--- a/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js
+++ b/toolkit/components/jsdownloads/test/unit/test_DownloadIntegration.js
@@ -20,28 +20,28 @@
  *        the expected downloads count for private browsing observer.
  */
 function notifyPromptObservers(aIsPrivate, aExpectedCount, aExpectedPBCount) {
   let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].
                    createInstance(Ci.nsISupportsPRBool);
 
   // Notify quit application requested observer.
   DownloadIntegration._testPromptDownloads = -1;
-  Services.obs.notifyObservers(cancelQuit, "quit-application-requested");
+  Services.obs.notifyObservers(cancelQuit, "quit-application-requested", null);
   do_check_eq(DownloadIntegration._testPromptDownloads, aExpectedCount);
 
   // Notify offline requested observer.
   DownloadIntegration._testPromptDownloads = -1;
-  Services.obs.notifyObservers(cancelQuit, "offline-requested");
+  Services.obs.notifyObservers(cancelQuit, "offline-requested", null);
   do_check_eq(DownloadIntegration._testPromptDownloads, aExpectedCount);
 
   if (aIsPrivate) {
     // Notify last private browsing requested observer.
     DownloadIntegration._testPromptDownloads = -1;
-    Services.obs.notifyObservers(cancelQuit, "last-pb-context-exiting");
+    Services.obs.notifyObservers(cancelQuit, "last-pb-context-exiting", null);
     do_check_eq(DownloadIntegration._testPromptDownloads, aExpectedPBCount);
   }
 
   delete DownloadIntegration._testPromptDownloads;
 }
 
 // Tests
 
@@ -332,31 +332,31 @@ add_task(function* test_suspend_resume()
 
   let download1 = yield addDownload(publicList);
   let download2 = yield addDownload(publicList);
   let download3 = yield addDownload(privateList);
   let download4 = yield addDownload(privateList);
   let download5 = yield addDownload(publicList);
 
   // First, check that the downloads are all canceled when going to sleep.
-  Services.obs.notifyObservers(null, "sleep_notification");
+  Services.obs.notifyObservers(null, "sleep_notification", null);
   do_check_true(download1.canceled);
   do_check_true(download2.canceled);
   do_check_true(download3.canceled);
   do_check_true(download4.canceled);
   do_check_true(download5.canceled);
 
   // Remove a download. It should not be started again.
   publicList.remove(download5);
   do_check_true(download5.canceled);
 
   // When waking up again, the downloads start again after the wake delay. To be
   // more robust, don't check after a delay but instead just wait for the
   // downloads to finish.
-  Services.obs.notifyObservers(null, "wake_notification");
+  Services.obs.notifyObservers(null, "wake_notification", null);
   yield download1.whenSucceeded();
   yield download2.whenSucceeded();
   yield download3.whenSucceeded();
   yield download4.whenSucceeded();
 
   // Downloads should no longer be canceled. However, as download5 was removed
   // from the public list, it will not be restarted.
   do_check_false(download1.canceled);
@@ -365,17 +365,17 @@ add_task(function* test_suspend_resume()
   // Create four new downloads and check for going offline and then online again.
 
   download1 = yield addDownload(publicList);
   download2 = yield addDownload(publicList);
   download3 = yield addDownload(privateList);
   download4 = yield addDownload(privateList);
 
   // Going offline should cancel the downloads.
-  Services.obs.notifyObservers(null, "network:offline-about-to-go-offline");
+  Services.obs.notifyObservers(null, "network:offline-about-to-go-offline", null);
   do_check_true(download1.canceled);
   do_check_true(download2.canceled);
   do_check_true(download3.canceled);
   do_check_true(download4.canceled);
 
   // Going back online should start the downloads again.
   Services.obs.notifyObservers(null, "network:offline-status-changed", "online");
   yield download1.whenSucceeded();
@@ -406,16 +406,16 @@ add_task(function* test_exit_private_bro
   // Complete the download.
   yield promiseAttempt1;
 
   do_check_eq((yield privateList.getAll()).length, 2);
 
   // Simulate exiting the private browsing.
   yield new Promise(resolve => {
     DownloadIntegration._testResolveClearPrivateList = resolve;
-    Services.obs.notifyObservers(null, "last-pb-context-exited");
+    Services.obs.notifyObservers(null, "last-pb-context-exited", null);
   });
   delete DownloadIntegration._testResolveClearPrivateList;
 
   do_check_eq((yield privateList.getAll()).length, 0);
 
   continueResponses();
 });
--- a/toolkit/components/osfile/tests/xpcshell/test_shutdown.js
+++ b/toolkit/components/osfile/tests/xpcshell/test_shutdown.js
@@ -45,17 +45,17 @@ add_task(function* system_shutdown() {
           do_execute_soon(deferred.resolve);
         } catch (ex) {
           do_execute_soon(function() {
             deferred.reject(ex);
           });
         }
       };
       Services.console.registerListener(observer);
-      Services.obs.notifyObservers(null, topic);
+      Services.obs.notifyObservers(null, topic, null);
       do_timeout(1000, function() {
         do_print("Timeout while waiting for resource: " + resource);
         deferred.reject("timeout");
       });
 
       let resolved = false;
       try {
         yield deferred.promise;
--- a/toolkit/components/passwordmgr/LoginManagerContent.jsm
+++ b/toolkit/components/passwordmgr/LoginManagerContent.jsm
@@ -1270,17 +1270,17 @@ var LoginManagerContent = {
       }
 
       if (usernameField) {
         log("_fillForm: Attaching event listeners to usernameField");
         usernameField.addEventListener("focus", observer);
         usernameField.addEventListener("mousedown", observer);
       }
 
-      Services.obs.notifyObservers(form.rootElement, "passwordmgr-processed-form");
+      Services.obs.notifyObservers(form.rootElement, "passwordmgr-processed-form", null);
     }
   },
 
   /**
    * Given a field, determine whether that field was last filled as a username
    * field AND whether the username is still filled in with the username AND
    * whether the associated password field has the matching password.
    *
--- a/toolkit/components/passwordmgr/content/passwordManager.js
+++ b/toolkit/components/passwordmgr/content/passwordManager.js
@@ -48,17 +48,17 @@ let signonReloadDisplay = {
           signons.length = 0;
           LoadSignons();
           // apply the filter if needed
           if (filterField && filterField.value != "") {
             FilterPasswords();
           }
           break;
       }
-      Services.obs.notifyObservers(null, "passwordmgr-dialog-updated");
+      Services.obs.notifyObservers(null, "passwordmgr-dialog-updated", null);
     }
   }
 };
 
 // Formatter for localization.
 let dateFormatter = Services.intl.createDateTimeFormat(undefined,
                       { dateStyle: "medium" });
 let dateAndTimeFormatter = Services.intl.createDateTimeFormat(undefined,
@@ -445,17 +445,17 @@ function TogglePasswordVisible() {
     togglePasswordsButton.label = kSignonBundle.getString(showingPasswords ? "hidePasswords" : "showPasswords");
     togglePasswordsButton.accessKey = kSignonBundle.getString(showingPasswords ? "hidePasswordsAccessKey" : "showPasswordsAccessKey");
     document.getElementById("passwordCol").hidden = !showingPasswords;
     FilterPasswords();
   }
 
   // Notify observers that the password visibility toggling is
   // completed.  (Mostly useful for tests)
-  Services.obs.notifyObservers(null, "passwordmgr-password-toggle-complete");
+  Services.obs.notifyObservers(null, "passwordmgr-password-toggle-complete", null);
   Services.telemetry.getHistogramById("PWMGR_MANAGE_VISIBILITY_TOGGLED").add(showingPasswords);
 }
 
 function AskUserShowPasswords() {
   let prompter = Cc["@mozilla.org/embedcomp/prompt-service;1"].getService(Ci.nsIPromptService);
   let dummy = { value: false };
 
   // Confirm the user wants to display passwords
--- a/toolkit/components/passwordmgr/crypto-SDR.js
+++ b/toolkit/components/passwordmgr/crypto-SDR.js
@@ -175,17 +175,17 @@ LoginManagerCrypto_SDR.prototype = {
   },
 
 
   /*
    * _notifyObservers
    */
   _notifyObservers(topic) {
     this.log("Prompted for a master password, notifying for " + topic);
-    Services.obs.notifyObservers(null, topic);
+    Services.obs.notifyObservers(null, topic, null);
   },
 }; // end of nsLoginManagerCrypto_SDR implementation
 
 XPCOMUtils.defineLazyGetter(this.LoginManagerCrypto_SDR.prototype, "log", () => {
   let logger = LoginHelper.createLogger("Login crypto");
   return logger.log.bind(logger);
 });
 
--- a/toolkit/components/passwordmgr/nsLoginManager.js
+++ b/toolkit/components/passwordmgr/nsLoginManager.js
@@ -165,17 +165,17 @@ LoginManager.prototype = {
         delete this._pwmgr._prefBranch;
         this._pwmgr = null;
       } else if (topic == "passwordmgr-storage-replace") {
         Task.spawn(function* () {
           yield this._pwmgr._storage.terminate();
           this._pwmgr._initStorage();
           yield this._pwmgr.initializationPromise;
           Services.obs.notifyObservers(null,
-                       "passwordmgr-storage-replace-complete");
+                       "passwordmgr-storage-replace-complete", null);
         }.bind(this));
       } else if (topic == "gather-telemetry") {
         // When testing, the "data" parameter is a string containing the
         // reference time in milliseconds for time-based statistics.
         this._pwmgr._gatherTelemetry(data ? parseInt(data)
                                           : new Date().getTime());
       } else {
         log.debug("Oops! Unexpected notification:", topic);
--- a/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
+++ b/toolkit/components/passwordmgr/nsLoginManagerPrompter.js
@@ -964,17 +964,17 @@ LoginManagerPrompter.prototype = {
 
     // The main action is the "Save" or "Update" button.
     let mainAction = {
       label: this._getLocalizedString(initialMsgNames.buttonLabel),
       accessKey: this._getLocalizedString(initialMsgNames.buttonAccessKey),
       callback: () => {
         histogram.add(PROMPT_ADD_OR_UPDATE);
         if (histogramName == "PWMGR_PROMPT_REMEMBER_ACTION") {
-          Services.obs.notifyObservers(null, "LoginStats:NewSavedPassword");
+          Services.obs.notifyObservers(null, "LoginStats:NewSavedPassword", null);
         }
         readDataFromUI();
         persistData();
         browser.focus();
       }
     };
 
     let secondaryActions = [{
@@ -1133,17 +1133,17 @@ LoginManagerPrompter.prototype = {
           callback() { /* NOP */ }
         }
       ];
 
       this._showLoginNotification(aNotifyObj, "password-save",
                                   notificationText, buttons);
     }
 
-    Services.obs.notifyObservers(aLogin, "passwordmgr-prompt-save");
+    Services.obs.notifyObservers(aLogin, "passwordmgr-prompt-save", null);
   },
 
   _removeLoginNotifications() {
     var popupNote = this._getPopupNote();
     if (popupNote)
       popupNote = popupNote.getNotification("password");
     if (popupNote)
       popupNote.remove();
@@ -1214,17 +1214,17 @@ LoginManagerPrompter.prototype = {
     } else if (userChoice == 0) {
       this.log("Saving login for " + aLogin.hostname);
       this._pwmgr.addLogin(aLogin);
     } else {
       // userChoice == 1 --> just ignore the login.
       this.log("Ignoring login.");
     }
 
-    Services.obs.notifyObservers(aLogin, "passwordmgr-prompt-save");
+    Services.obs.notifyObservers(aLogin, "passwordmgr-prompt-save", null);
   },
 
 
   /**
    * Called when we think we detect a password or username change for
    * an existing login, when the form being submitted contains multiple
    * password fields.
    *
--- a/toolkit/components/passwordmgr/test/LoginTestUtils.jsm
+++ b/toolkit/components/passwordmgr/test/LoginTestUtils.jsm
@@ -32,17 +32,17 @@ this.LoginTestUtils = {
     Assert = assert; // eslint-disable-line no-native-reassign
   },
 
   /**
    * Forces the storage module to save all data, and the Login Manager service
    * to replace the storage module with a newly initialized instance.
    */
   * reloadData() {
-    Services.obs.notifyObservers(null, "passwordmgr-storage-replace");
+    Services.obs.notifyObservers(null, "passwordmgr-storage-replace", null);
     yield TestUtils.topicObserved("passwordmgr-storage-replace-complete");
   },
 
   /**
    * Erases all the data stored by the Login Manager service.
    */
   clearData() {
     Services.logins.removeAllLogins();
--- a/toolkit/components/places/PlacesDBUtils.jsm
+++ b/toolkit/components/places/PlacesDBUtils.jsm
@@ -57,17 +57,17 @@ this.PlacesDBUtils = {
       }
 
       if (aTasks.callback) {
         let scope = aTasks.scope || Cu.getGlobalForObject(aTasks.callback);
         aTasks.callback.call(scope, aTasks.messages);
       }
 
       // Notify observers that maintenance finished.
-      Services.obs.notifyObservers(null, FINISHED_MAINTENANCE_TOPIC);
+      Services.obs.notifyObservers(null, FINISHED_MAINTENANCE_TOPIC, null);
     }
   },
 
   _isShuttingDown: false,
   shutdown: function PDBU_shutdown() {
     PlacesDBUtils._isShuttingDown = true;
   },
 
--- a/toolkit/components/places/nsPlacesExpiration.js
+++ b/toolkit/components/places/nsPlacesExpiration.js
@@ -743,17 +743,17 @@ nsPlacesExpiration.prototype = {
           }
           this._telemetrySteps = 1;
         }
 
         delete this._expectedResultsCount;
       }
 
       // Dispatch a notification that expiration has finished.
-      Services.obs.notifyObservers(null, TOPIC_EXPIRATION_FINISHED);
+      Services.obs.notifyObservers(null, TOPIC_EXPIRATION_FINISHED, null);
     }
   },
 
   // nsPlacesExpiration
 
   _urisLimit: PREF_MAX_URIS_NOTSET,
   _interval: PREF_INTERVAL_SECONDS_NOTSET,
   _shuttingDown: false,
--- a/toolkit/components/places/tests/expiration/test_analyze_runs.js
+++ b/toolkit/components/places/tests/expiration/test_analyze_runs.js
@@ -65,17 +65,18 @@ add_task(function* init_tests() {
                                            Ci.nsIAutoCompleteController]),
     get popup() { return thing; },
     get controller() { return thing; },
     popupOpen: true,
     selectedIndex: 0,
     getValueAt() { return TEST_URI.spec; },
     searchString: TEST_TITLE,
   };
-  Services.obs.notifyObservers(thing, TOPIC_AUTOCOMPLETE_FEEDBACK_INCOMING);
+  Services.obs.notifyObservers(thing, TOPIC_AUTOCOMPLETE_FEEDBACK_INCOMING,
+                               null);
 });
 
 add_task(function* test_timed() {
   clearAnalyzeData();
 
   // Set a low interval and wait for the timed expiration to start.
   let promise = promiseTopicObserved(PlacesUtils.TOPIC_EXPIRATION_FINISHED);
   setInterval(3);
--- a/toolkit/components/places/tests/unit/nsDummyObserver.js
+++ b/toolkit/components/places/tests/unit/nsDummyObserver.js
@@ -5,37 +5,37 @@
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 // Dummy boomark/history observer
 function DummyObserver() {
-  Services.obs.notifyObservers(null, "dummy-observer-created");
+  Services.obs.notifyObservers(null, "dummy-observer-created", null);
 }
 
 DummyObserver.prototype = {
   // history observer
   onBeginUpdateBatch() {},
   onEndUpdateBatch() {},
   onVisit(aURI, aVisitID, aTime, aSessionID, aReferringID, aTransitionType) {
-    Services.obs.notifyObservers(null, "dummy-observer-visited");
+    Services.obs.notifyObservers(null, "dummy-observer-visited", null);
   },
   onTitleChanged() {},
   onDeleteURI() {},
   onClearHistory() {},
   onPageChanged() {},
   onDeleteVisits() {},
 
   // bookmark observer
   // onBeginUpdateBatch: function() {},
   // onEndUpdateBatch: function() {},
   onItemAdded(aItemId, aParentId, aIndex, aItemType, aURI) {
-    Services.obs.notifyObservers(null, "dummy-observer-item-added");
+    Services.obs.notifyObservers(null, "dummy-observer-item-added", null);
   },
   onItemChanged() {},
   onItemRemoved() {},
   onItemVisited() {},
   onItemMoved() {},
 
   classID: Components.ID("62e221d3-68c3-4e1a-8943-a27beb5005fe"),
 
--- a/toolkit/components/places/tests/unit/test_adaptive.js
+++ b/toolkit/components/places/tests/unit/test_adaptive.js
@@ -121,17 +121,17 @@ function* task_setCountRank(aURI, aCount
     getValueAt() {
       return aURI.spec;
     },
     searchString: aSearch
   };
 
   // Bump up the instrumentation feedback.
   for (let i = 0; i < aRank; i++) {
-    Services.obs.notifyObservers(thing, "autocomplete-will-enter-text");
+    Services.obs.notifyObservers(thing, "autocomplete-will-enter-text", null);
   }
 
   // If this is supposed to be a bookmark, add it.
   if (aBookmark) {
     PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
                                          aURI,
                                          PlacesUtils.bookmarks.DEFAULT_INDEX,
                                          "test_book");
--- a/toolkit/components/places/tests/unit/test_adaptive_bug527311.js
+++ b/toolkit/components/places/tests/unit/test_adaptive_bug527311.js
@@ -115,17 +115,17 @@ function addAdaptiveFeedback(aUrl, aSear
     get popup() { return thing; },
     get controller() { return thing; },
     popupOpen: true,
     selectedIndex: 0,
     getValueAt: () => aUrl,
     searchString: aSearch
   };
 
-  os.notifyObservers(thing, "autocomplete-will-enter-text");
+  os.notifyObservers(thing, "autocomplete-will-enter-text", null);
 }
 
 
 function run_test() {
   do_test_pending();
 
   // Add a bookmark to our url.
   bs.insertBookmark(bs.unfiledBookmarksFolder, uri(TEST_URL),
--- a/toolkit/components/processsingleton/MainProcessSingleton.js
+++ b/toolkit/components/processsingleton/MainProcessSingleton.js
@@ -16,17 +16,17 @@ function MainProcessSingleton() {}
 MainProcessSingleton.prototype = {
   classID: Components.ID("{0636a680-45cb-11e4-916c-0800200c9a66}"),
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference]),
 
   logConsoleMessage(message) {
     let logMsg = message.data;
     logMsg.wrappedJSObject = logMsg;
-    Services.obs.notifyObservers(logMsg, "console-api-log-event");
+    Services.obs.notifyObservers(logMsg, "console-api-log-event", null);
   },
 
   // Called when a webpage calls window.external.AddSearchProvider
   addSearchEngine({ target: browser, data: { pageURL, engineURL } }) {
     pageURL = NetUtil.newURI(pageURL);
     engineURL = NetUtil.newURI(engineURL, null, pageURL);
 
     let iconURL;
--- a/toolkit/components/prompts/src/CommonDialog.jsm
+++ b/toolkit/components/prompts/src/CommonDialog.jsm
@@ -183,17 +183,17 @@ CommonDialog.prototype = {
             }
         } catch (e) {
             Cu.reportError("Couldn't play common dialog event sound: " + e);
         }
 
         let topic = "common-dialog-loaded";
         if (!xulDialog)
             topic = "tabmodal-dialog-loaded";
-        Services.obs.notifyObservers(this.ui.prompt, topic);
+        Services.obs.notifyObservers(this.ui.prompt, topic, null);
     },
 
     setLabelForNode(aNode, aLabel) {
         // This is for labels which may contain embedded access keys.
         // If we end in (&X) where X represents the access key, optionally preceded
         // by spaces and/or followed by the ':' character, store the access key and
         // remove the access key placeholder + leading spaces from the label.
         // Otherwise a character preceded by one but not two &s is the access key.
--- a/toolkit/components/reader/AboutReader.jsm
+++ b/toolkit/components/reader/AboutReader.jsm
@@ -813,17 +813,17 @@ AboutReader.prototype = {
     this._contentElement.style.display = "block";
     this._updateImageMargins();
 
     this._requestFavicon();
     this._doc.body.classList.add("loaded");
 
     this._goToReference(articleUri.ref);
 
-    Services.obs.notifyObservers(this._win, "AboutReader:Ready");
+    Services.obs.notifyObservers(this._win, "AboutReader:Ready", "");
 
     this._doc.dispatchEvent(
       new this._win.CustomEvent("AboutReaderContentReady", { bubbles: true, cancelable: false }));
   },
 
   _hideContent() {
     this._headerElement.style.display = "none";
     this._contentElement.style.display = "none";
--- a/toolkit/components/satchel/test/unit/test_async_expire.js
+++ b/toolkit/components/satchel/test/unit/test_async_expire.js
@@ -4,17 +4,17 @@
 
 var dbFile, oldSize;
 var currentTestIndex = 0;
 
 function triggerExpiration() {
   // We can't easily fake a "daily idle" event, so for testing purposes form
   // history listens for another notification to trigger an immediate
   // expiration.
-  Services.obs.notifyObservers(null, "formhistory-expire-now");
+  Services.obs.notifyObservers(null, "formhistory-expire-now", null);
 }
 
 var checkExists = function(num) { do_check_true(num > 0); next_test(); }
 var checkNotExists = function(num) { do_check_true(!num); next_test(); }
 
 var TestObserver = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]),
 
--- a/toolkit/components/search/tests/xpcshell/test_645970.js
+++ b/toolkit/components/search/tests/xpcshell/test_645970.js
@@ -11,10 +11,10 @@ function run_test() {
   do_load_manifest("data/chrome.manifest");
 
   configureToLoadJarEngines();
 
   // The search service needs to be started after the jarURIs pref has been
   // set in order to initiate it correctly
   let engine = Services.search.getEngineByName("bug645970");
   do_check_neq(engine, null);
-  Services.obs.notifyObservers(null, "quit-application");
+  Services.obs.notifyObservers(null, "quit-application", null);
 }
--- a/toolkit/components/telemetry/TelemetrySession.jsm
+++ b/toolkit/components/telemetry/TelemetrySession.jsm
@@ -1411,17 +1411,17 @@ var Impl = {
       if (!Utils.isContentProcess && clearSubsession) {
         this.startNewSubsession();
         // Persist session data to disk (don't wait until it completes).
         let sessionData = this._getSessionDataObject();
         TelemetryStorage.saveSessionData(sessionData);
 
         // Notify that there was a subsession split in the parent process. This is an
         // internal topic and is only meant for internal Telemetry usage.
-        Services.obs.notifyObservers(null, "internal-telemetry-after-subsession-split");
+        Services.obs.notifyObservers(null, "internal-telemetry-after-subsession-split", null);
       }
     }
 
     return payload;
   },
 
   /**
    * Send data to the server. Record success/send-time in histograms
@@ -1716,17 +1716,17 @@ var Impl = {
               this.handleMemoryReport(
               "MEMORY_DISTRIBUTION_AMONG_CONTENT",
               Ci.nsIMemoryReporter.UNITS_COUNT,
               value,
               key);
             });
 
             // This notification is for testing only.
-            Services.obs.notifyObservers(null, "gather-memory-telemetry-finished");
+            Services.obs.notifyObservers(null, "gather-memory-telemetry-finished", null);
           }
           this._USSFromChildProcesses = undefined;
         }
       } else {
         this._log.trace("Child USS report was missed");
       }
       break;
     }
@@ -1973,17 +1973,17 @@ var Impl = {
       break;
     case "idle-daily":
       // Enqueue to main-thread, otherwise components may be inited by the
       // idle-daily category and miss the gather-telemetry notification.
       Services.tm.dispatchToMainThread((function() {
         // Notify that data should be gathered now.
         // TODO: We are keeping this behaviour for now but it will be removed as soon as
         // bug 1127907 lands.
-        Services.obs.notifyObservers(null, "gather-telemetry");
+        Services.obs.notifyObservers(null, "gather-telemetry", null);
       }));
       break;
 
     case "application-background":
       if (AppConstants.platform !== "android") {
         break;
       }
       // On Android, we can get killed without warning once we are in the background,
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryEnvironment.js
@@ -859,17 +859,17 @@ add_task(function* setup() {
   TelemetryEnvironment.delayedInit();
 });
 
 add_task(function* test_checkEnvironment() {
   let environmentData = yield TelemetryEnvironment.onInitialized();
   checkEnvironmentData(environmentData, true);
 
   spoofPartnerInfo();
-  Services.obs.notifyObservers(null, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC);
+  Services.obs.notifyObservers(null, DISTRIBUTION_CUSTOMIZATION_COMPLETE_TOPIC, null);
 
   environmentData = TelemetryEnvironment.currentEnvironment;
   checkEnvironmentData(environmentData);
 });
 
 add_task(function* test_prefWatchPolicies() {
   const PREF_TEST_1 = "toolkit.telemetry.test.pref_new";
   const PREF_TEST_2 = "toolkit.telemetry.test.pref1";
@@ -1038,17 +1038,17 @@ add_task(function* test_pluginsWatch_Add
   let receivedNotifications = 0;
   let callback = (reason, data) => {
     receivedNotifications++;
     Assert.equal(reason, "addons-changed");
     deferred.resolve();
   };
   TelemetryEnvironment.registerChangeListener("testWatchPlugins_Add", callback);
 
-  Services.obs.notifyObservers(null, PLUGIN_UPDATED_TOPIC);
+  Services.obs.notifyObservers(null, PLUGIN_UPDATED_TOPIC, null);
   yield deferred.promise;
 
   Assert.equal(TelemetryEnvironment.currentEnvironment.addons.activePlugins.length, 2);
 
   TelemetryEnvironment.unregisterChangeListener("testWatchPlugins_Add");
 
   Assert.equal(receivedNotifications, 1, "We must only receive one notification.");
 });
@@ -1069,17 +1069,17 @@ add_task(function* test_pluginsWatch_Rem
   let deferred = PromiseUtils.defer();
   let receivedNotifications = 0;
   let callback = () => {
     receivedNotifications++;
     deferred.resolve();
   };
   TelemetryEnvironment.registerChangeListener("testWatchPlugins_Remove", callback);
 
-  Services.obs.notifyObservers(null, PLUGIN_UPDATED_TOPIC);
+  Services.obs.notifyObservers(null, PLUGIN_UPDATED_TOPIC, null);
   yield deferred.promise;
 
   TelemetryEnvironment.unregisterChangeListener("testWatchPlugins_Remove");
 
   Assert.equal(receivedNotifications, 1, "We must only receive one notification.");
 });
 
 add_task(function* test_addonsWatch_NotInterestingChange() {
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryReportingPolicy.js
@@ -77,23 +77,23 @@ add_task(function* test_firstRun() {
   const OTHER_RUNS_TIMEOUT_MSEC = 10 * 1000; // 10s
 
   Preferences.reset(PREF_FIRST_RUN);
 
   let startupTimeout = 0;
   fakeShowPolicyTimeout((callback, timeout) => startupTimeout = timeout, () => {});
   TelemetryReportingPolicy.reset();
 
-  Services.obs.notifyObservers(null, "sessionstore-windows-restored");
+  Services.obs.notifyObservers(null, "sessionstore-windows-restored", null);
   Assert.equal(startupTimeout, FIRST_RUN_TIMEOUT_MSEC,
                "The infobar display timeout should be 60s on the first run.");
 
   // Run again, and check that we actually wait only 10 seconds.
   TelemetryReportingPolicy.reset();
-  Services.obs.notifyObservers(null, "sessionstore-windows-restored");
+  Services.obs.notifyObservers(null, "sessionstore-windows-restored", null);
   Assert.equal(startupTimeout, OTHER_RUNS_TIMEOUT_MSEC,
                "The infobar display timeout should be 10s on other runs.");
 });
 
 add_task(function* test_prefs() {
   TelemetryReportingPolicy.reset();
 
   let now = fakeNow(2009, 11, 18);
--- a/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySession.js
@@ -1810,17 +1810,17 @@ add_task(function* test_schedulerCompute
   // This can happen due to timeouts not running out during sleep times,
   // see bug 1262386, bug 1204823 et al.
   // Note that we don't get wake notifications on Linux due to bug 758848.
   nowDate = fakeNow(futureDate(nowDate, 1 * MS_IN_ONE_DAY));
 
   // We emulate the mentioned timeout behavior by sending the wake notification
   // instead of triggering the timeout callback.
   // This should trigger a daily ping, because we passed midnight.
-  Services.obs.notifyObservers(null, "wake_notification");
+  Services.obs.notifyObservers(null, "wake_notification", null);
 
   dailyPing = yield PingServer.promiseNextPing();
   Assert.equal(dailyPing.payload.info.reason, REASON_DAILY,
                "The wake notification should have triggered a daily ping.");
   Assert.equal(dailyPing.creationDate, nowDate.toISOString(),
                "The daily ping date should be correct.");
 
   yield TelemetryController.testShutdown();
--- a/toolkit/components/terminator/nsTerminatorTelemetry.js
+++ b/toolkit/components/terminator/nsTerminatorTelemetry.js
@@ -88,16 +88,17 @@ nsTerminatorTelemetry.prototype = {
           // but otherwise, ignore it.
           Promise.reject(ex);
           continue;
         }
       }
 
       // Inform observers that we are done.
       Services.obs.notifyObservers(null,
-        "shutdown-terminator-telemetry-updated");
+        "shutdown-terminator-telemetry-updated",
+        "");
     });
   },
 };
 
 // Module
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([nsTerminatorTelemetry]);
--- a/toolkit/components/url-classifier/content/moz/observer.js
+++ b/toolkit/components/url-classifier/content/moz/observer.js
@@ -127,18 +127,18 @@ this.TEST_G_Observer = function TEST_G_O
 
     var o1 = new G_ObserverWrapper(topic, regularObserver);
     service.addObserver(o1, topic);
 
     new G_ObserverServiceObserver(topic, 
                                   observerServiceObserver, true /* once */);
 
     // Notifications happen synchronously, so this is easy
-    service.notifyObservers(null, topic);
-    service.notifyObservers(null, topic);
+    service.notifyObservers(null, topic, null);
+    service.notifyObservers(null, topic, null);
 
     G_Assert(z, regularObserverRan == 2, "Regular observer broken");
     G_Assert(z, observerServiceObserverRan == 1, "ObsServObs broken");
 
     service.removeObserver(o1, topic);
     G_Debug(z, "PASSED");
   }
 }
--- a/toolkit/components/viewsource/content/viewSource-content.js
+++ b/toolkit/components/viewsource/content/viewSource-content.js
@@ -453,17 +453,17 @@ var ViewSourceContent = {
   onContextMenu(event) {
     let addonInfo = {};
     let subject = {
       event,
       addonInfo,
     };
 
     subject.wrappedJSObject = subject;
-    Services.obs.notifyObservers(subject, "content-contextmenu");
+    Services.obs.notifyObservers(subject, "content-contextmenu", null);
 
     let node = event.target;
 
     let result = {
       isEmail: false,
       isLink: false,
       href: "",
       // We have to pass these in the event that we're running in
--- a/toolkit/content/aboutSupport.js
+++ b/toolkit/content/aboutSupport.js
@@ -1020,17 +1020,17 @@ function setupEventListeners() {
   $("copy-to-clipboard").addEventListener("click", function(event) {
     copyContentsToClipboard();
   });
   $("profile-dir-button").addEventListener("click", function(event) {
     openProfileDirectory();
   });
   $("restart-in-safe-mode-button").addEventListener("click", function(event) {
     if (Services.obs.enumerateObservers("restart-in-safe-mode").hasMoreElements()) {
-      Services.obs.notifyObservers(null, "restart-in-safe-mode");
+      Services.obs.notifyObservers(null, "restart-in-safe-mode", "");
     } else {
       safeModeRestart();
     }
   });
   $("verify-place-integrity-button").addEventListener("click", function(event) {
     PlacesDBUtils.checkAndFixDatabase(function(aLog) {
       let msg = aLog.join("\n");
       $("verify-place-result").style.display = "block";
--- a/toolkit/crashreporter/test/unit/test_crash_AsyncShutdown.js
+++ b/toolkit/crashreporter/test/unit/test_crash_AsyncShutdown.js
@@ -18,17 +18,17 @@ function setup_crash() {
   let TOPIC = "testing-async-shutdown-crash";
   let phase = AsyncShutdown._getPhase(TOPIC);
   phase.addBlocker("A blocker that is never satisfied", function() {
     dump("Installing blocker\n");
     let deferred = Promise.defer();
     return deferred.promise;
   });
 
-  Services.obs.notifyObservers(null, TOPIC);
+  Services.obs.notifyObservers(null, TOPIC, null);
   dump(new Error().stack + "\n");
   dump("Waiting for crash\n");
 }
 
 function after_crash(mdump, extra) {
   do_print("after crash: " + extra.AsyncShutdownTimeout);
   let info = JSON.parse(extra.AsyncShutdownTimeout);
   Assert.equal(info.phase, "testing-async-shutdown-crash");
@@ -47,17 +47,17 @@ function setup_osfile_crash_noerror() {
   Components.utils.import("resource://gre/modules/Promise.jsm", this);
 
   Services.prefs.setIntPref("toolkit.asyncshutdown.crash_timeout", 1);
   Services.prefs.setBoolPref("toolkit.osfile.native", false);
 
   OS.File.profileBeforeChange.addBlocker("Adding a blocker that will never be resolved", () => Promise.defer().promise);
   OS.File.getCurrentDirectory();
 
-  Services.obs.notifyObservers(null, "profile-before-change");
+  Services.obs.notifyObservers(null, "profile-before-change", null);
   dump("Waiting for crash\n");
 }
 
 function after_osfile_crash_noerror(mdump, extra) {
   do_print("after OS.File crash: " + extra.AsyncShutdownTimeout);
   let info = JSON.parse(extra.AsyncShutdownTimeout);
   let state = info.conditions[0].state;
   do_print("Keys: " + Object.keys(state).join(", "));
@@ -78,17 +78,17 @@ function setup_osfile_crash_exn() {
   Components.utils.import("resource://gre/modules/Promise.jsm", this);
 
   Services.prefs.setIntPref("toolkit.asyncshutdown.crash_timeout", 1);
   Services.prefs.setBoolPref("toolkit.osfile.native", false);
 
   OS.File.profileBeforeChange.addBlocker("Adding a blocker that will never be resolved", () => Promise.defer().promise);
   OS.File.read("I do not exist");
 
-  Services.obs.notifyObservers(null, "profile-before-change");
+  Services.obs.notifyObservers(null, "profile-before-change", null);
   dump("Waiting for crash\n");
 }
 
 function after_osfile_crash_exn(mdump, extra) {
   do_print("after OS.File crash: " + extra.AsyncShutdownTimeout);
   let info = JSON.parse(extra.AsyncShutdownTimeout);
   let state = info.conditions[0].state;
   do_print("Keys: " + Object.keys(state).join(", "));
--- a/toolkit/forgetaboutsite/test/unit/test_removeDataFromDomain.js
+++ b/toolkit/forgetaboutsite/test/unit/test_removeDataFromDomain.js
@@ -512,17 +512,17 @@ function* test_cache_cleared() {
   //       notification, we have actually cleared the cache.
   // This seems to happen asynchronously...
   let os = Cc["@mozilla.org/observer-service;1"].
            getService(Ci.nsIObserverService);
   let observer = {
     observe(aSubject, aTopic, aData) {
       os.removeObserver(observer, "cacheservice:empty-cache");
       // Shutdown the download manager.
-      Services.obs.notifyObservers(null, "quit-application");
+      Services.obs.notifyObservers(null, "quit-application", null);
       do_test_finished();
     }
   };
   os.addObserver(observer, "cacheservice:empty-cache");
   yield ForgetAboutSite.removeDataFromDomain("mozilla.org");
   do_test_pending();
 }
 
--- a/toolkit/modules/Console.jsm
+++ b/toolkit/modules/Console.jsm
@@ -696,30 +696,30 @@ ConsoleAPI.prototype = {
     if (!shouldLog("profile", this.maxLogLevel)) {
       return;
     }
     Services.obs.notifyObservers({
       wrappedJSObject: {
         action: "profile",
         arguments: [ profileName ]
       }
-    }, "console-api-profiler");
+    }, "console-api-profiler", null);
     dumpMessage(this, "profile", `'${profileName}'`);
   },
 
   profileEnd(profileName) {
     if (!shouldLog("profileEnd", this.maxLogLevel)) {
       return;
     }
     Services.obs.notifyObservers({
       wrappedJSObject: {
         action: "profileEnd",
         arguments: [ profileName ]
       }
-    }, "console-api-profiler");
+    }, "console-api-profiler", null);
     dumpMessage(this, "profileEnd", `'${profileName}'`);
   },
 
   get maxLogLevel() {
     return this._maxLogLevel || "all";
   },
 
   set maxLogLevel(aValue) {
--- a/toolkit/modules/PopupNotifications.jsm
+++ b/toolkit/modules/PopupNotifications.jsm
@@ -1498,11 +1498,11 @@ PopupNotifications.prototype = {
       return;
     }
 
     this._remove(target.notification);
     this._update();
   },
 
   _notify: function PopupNotifications_notify(topic) {
-    Services.obs.notifyObservers(null, "PopupNotifications-" + topic);
+    Services.obs.notifyObservers(null, "PopupNotifications-" + topic, "");
   },
 };
--- a/toolkit/modules/tests/xpcshell/test_session_recorder.js
+++ b/toolkit/modules/tests/xpcshell/test_session_recorder.js
@@ -267,39 +267,39 @@ add_task(function* test_multiple_session
 add_task(function* test_record_activity() {
   let recorder = getRecorder("record_activity");
   yield sleep(25);
   recorder.onStartup();
   let total = recorder.totalTime;
   yield sleep(25);
 
   for (let i = 0; i < 3; i++) {
-    Services.obs.notifyObservers(null, "user-interaction-active");
+    Services.obs.notifyObservers(null, "user-interaction-active", null);
     yield sleep(25);
     do_check_true(recorder.fineTotalTime > total);
     total = recorder.fineTotalTime;
   }
 
   do_check_eq(recorder.activeTicks, 3);
 
   // Now send inactive. We should increment total time but not active.
-  Services.obs.notifyObservers(null, "user-interaction-inactive");
+  Services.obs.notifyObservers(null, "user-interaction-inactive", null);
   do_check_eq(recorder.activeTicks, 3);
   do_check_true(recorder.fineTotalTime > total);
   total = recorder.fineTotalTime;
   yield sleep(25);
 
   // If we send active again, this should be counted as inactive.
-  Services.obs.notifyObservers(null, "user-interaction-active");
+  Services.obs.notifyObservers(null, "user-interaction-active", null);
   do_check_eq(recorder.activeTicks, 3);
   do_check_true(recorder.fineTotalTime > total);
   total = recorder.fineTotalTime;
   yield sleep(25);
 
   // If we send active again, this should be counted as active.
-  Services.obs.notifyObservers(null, "user-interaction-active");
+  Services.obs.notifyObservers(null, "user-interaction-active", null);
   do_check_eq(recorder.activeTicks, 4);
 
-  Services.obs.notifyObservers(null, "user-interaction-active");
+  Services.obs.notifyObservers(null, "user-interaction-active", null);
   do_check_eq(recorder.activeTicks, 5);
 
   recorder.onShutdown();
 });
--- a/toolkit/mozapps/downloads/tests/unit/head_downloads.js
+++ b/toolkit/mozapps/downloads/tests/unit/head_downloads.js
@@ -1,5 +1,5 @@
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 do_register_cleanup(function() {
-  Services.obs.notifyObservers(null, "quit-application");
+  Services.obs.notifyObservers(null, "quit-application", null);
 });
--- a/toolkit/mozapps/extensions/AddonManager.jsm
+++ b/toolkit/mozapps/extensions/AddonManager.jsm
@@ -1353,17 +1353,17 @@ var AddonManagerInternal = {
     }
 
     return new Promise((resolve, reject) => {
       let subject = {wrappedJSObject: {
         addon: info.addon,
         permissions: difference,
         resolve, reject
       }};
-      Services.obs.notifyObservers(subject, "webextension-update-permissions");
+      Services.obs.notifyObservers(subject, "webextension-update-permissions", null);
     });
   },
 
   /**
    * Performs a background update check by starting an update for all add-ons
    * that can be updated.
    * @return Promise{null} Resolves when the background update check is complete
    *                       (the resulting addon installations may still be in progress).
@@ -1377,17 +1377,17 @@ var AddonManagerInternal = {
       let hotfixID = this.hotfixID;
 
       let appUpdateEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_ENABLED) &&
                              Services.prefs.getBoolPref(PREF_APP_UPDATE_AUTO);
       let checkHotfix = hotfixID && appUpdateEnabled;
 
       logger.debug("Background update check beginning");
 
-      Services.obs.notifyObservers(null, "addons-background-update-start");
+      Services.obs.notifyObservers(null, "addons-background-update-start", null);
 
       if (this.updateEnabled) {
         let scope = {};
         Components.utils.import("resource://gre/modules/LightweightThemeManager.jsm", scope);
         scope.LightweightThemeManager.updateCurrentTheme();
 
         let allAddons = yield this.getAllAddons();
 
@@ -1526,17 +1526,18 @@ var AddonManagerInternal = {
           yield AddonManagerInternal._getProviderByName("XPIProvider").updateSystemAddons();
         } catch (e) {
           logger.warn("Failed to update system addons", e);
         }
       }
 
       logger.debug("Background update check complete");
       Services.obs.notifyObservers(null,
-                                   "addons-background-update-complete");
+                                   "addons-background-update-complete",
+                                   null);
     }.bind(this));
     // Fork the promise chain so we can log the error and let our caller see it too.
     buPromise.then(null, e => logger.warn("Error in background update", e));
     return buPromise;
   },
 
   /**
    * Adds a add-on to the list of detected changes for this startup. If
@@ -1764,17 +1765,17 @@ var AddonManagerInternal = {
                                  Cr.NS_ERROR_NOT_INITIALIZED);
 
     return Task.spawn(function*() {
       for (let provider of this.providers) {
         yield promiseCallProvider(provider, "updateAddonRepositoryData");
       }
 
       // only tests should care about this
-      Services.obs.notifyObservers(null, "TEST:addon-repository-data-updated");
+      Services.obs.notifyObservers(null, "TEST:addon-repository-data-updated", null);
     }.bind(this));
   },
 
   /**
    * Asynchronously gets an AddonInstall for a URL.
    *
    * @param  aUrl
    *         The string represenation of the URL the add-on is located at
@@ -2012,17 +2013,17 @@ var AddonManagerInternal = {
     let info = {
       wrappedJSObject: {
         browser: aBrowser,
         originatingURI: aUri,
         installs: [aInstall],
         install: aInstallFn,
       },
     };
-    Services.obs.notifyObservers(info, aTopic);
+    Services.obs.notifyObservers(info, aTopic, null);
   },
 
   startInstall(browser, url, install) {
     this.installNotifyObservers("addon-install-started", browser, url, install);
 
     // Local installs may already be in a failed state in which case
     // we won't get any further events, detect those cases now.
     if (install.state == AddonManager.STATE_DOWNLOADED && install.addon.appDisabled) {
@@ -2069,17 +2070,17 @@ var AddonManagerInternal = {
             install.addon.appDisabled == false) {
               install.addon.userDisabled = false;
         }
 
         let needsRestart = (install.addon.pendingOperations != AddonManager.PENDING_NONE);
 
         if (WEBEXT_PERMISSION_PROMPTS && !needsRestart) {
           let subject = {wrappedJSObject: {target: browser, addon: install.addon}};
-          Services.obs.notifyObservers(subject, "webextension-install-notify");
+          Services.obs.notifyObservers(subject, "webextension-install-notify", null);
         } else {
           self.installNotifyObservers("addon-install-complete", browser, url, install);
         }
       },
     };
 
     install.addListener(listener);
 
@@ -2811,17 +2812,17 @@ var AddonManagerInternal = {
       if (info.addon.userPermissions && WEBEXT_PERMISSION_PROMPTS) {
         let subject = {
           wrappedJSObject: {
             target: browser,
             info: Object.assign({resolve, reject, source}, info),
           }
         };
         subject.wrappedJSObject.info.permissions = info.addon.userPermissions;
-        Services.obs.notifyObservers(subject, "webextension-permission-prompt");
+        Services.obs.notifyObservers(subject, "webextension-permission-prompt", null);
       } else if (requireConfirm) {
         // The methods below all want to call the install() or cancel()
         // method on the provided AddonInstall object to either accept
         // or reject the confirmation.  Fit that into our promise-based
         // control flow by wrapping the install object.  However,
         // xpInstallConfirm.xul matches the install object it is passed
         // with the argument passed to an InstallListener, so give it
         // access to the underlying object through the .wrapped property.
@@ -3051,17 +3052,17 @@ var AddonManagerInternal = {
         return Promise.reject(`invalid id ${id}`);
       }
       let result = state.install.install();
 
       return state.installPromise.then(addon => new Promise(resolve => {
         let callback = () => resolve(result);
         if (Preferences.get(PREF_WEBEXT_PERM_PROMPTS, false)) {
           let subject = {wrappedJSObject: {target, addon, callback}};
-          Services.obs.notifyObservers(subject, "webextension-install-notify")
+          Services.obs.notifyObservers(subject, "webextension-install-notify", null)
         } else {
           callback();
         }
       }));
     },
 
     addonInstallCancel(target, id) {
       let state = this.installs.get(id);
--- a/toolkit/mozapps/extensions/ChromeManifestParser.jsm
+++ b/toolkit/mozapps/extensions/ChromeManifestParser.jsm
@@ -19,17 +19,17 @@ const MSG_JAR_FLUSH = "AddonJarFlush";
 
 /**
  * Sends local and remote notifications to flush a JAR file cache entry
  *
  * @param aJarFile
  *        The ZIP/XPI/JAR file as a nsIFile
  */
 function flushJarCache(aJarFile) {
-  Services.obs.notifyObservers(aJarFile, "flush-cache-entry");
+  Services.obs.notifyObservers(aJarFile, "flush-cache-entry", null);
   Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageBroadcaster)
     .broadcastAsyncMessage(MSG_JAR_FLUSH, aJarFile.path);
 }
 
 
 /**
  * Parses chrome manifest files.
  */
--- a/toolkit/mozapps/extensions/LightweightThemeManager.jsm
+++ b/toolkit/mozapps/extensions/LightweightThemeManager.jsm
@@ -316,17 +316,17 @@ this.LightweightThemeManager = {
     }
 
     if (aData)
       _prefs.setCharPref("selectedThemeID", aData.id);
     else
       _prefs.setCharPref("selectedThemeID", "");
 
     _notifyWindows(aData);
-    Services.obs.notifyObservers(null, "lightweight-theme-changed");
+    Services.obs.notifyObservers(null, "lightweight-theme-changed", null);
   },
 
   /**
    * Starts the Addons provider and enables the new lightweight theme if
    * necessary.
    */
   startup() {
     if (Services.prefs.prefHasUserValue(PREF_LWTHEME_TO_SELECT)) {
@@ -782,17 +782,17 @@ function _updateUsedThemes(aList) {
     let wrapper = new AddonWrapper(aList[aList.length - 1]);
     AddonManagerPrivate.callAddonListeners("onUninstalling", wrapper, false);
     aList.pop();
     AddonManagerPrivate.callAddonListeners("onUninstalled", wrapper);
   }
 
   _prefs.setStringPref("usedThemes", JSON.stringify(aList));
 
-  Services.obs.notifyObservers(null, "lightweight-theme-list-changed");
+  Services.obs.notifyObservers(null, "lightweight-theme-list-changed", null);
 }
 
 function _notifyWindows(aThemeData) {
   Services.obs.notifyObservers(null, "lightweight-theme-styling-update",
                                JSON.stringify(aThemeData));
 }
 
 var _previewTimer;
--- a/toolkit/mozapps/extensions/content/extensions.js
+++ b/toolkit/mozapps/extensions/content/extensions.js
@@ -238,17 +238,17 @@ function initialize(event) {
     gViewDefault = "addons://list/extension";
   }
 
   gViewController.initialize();
   gCategories.initialize();
   gHeader.initialize();
   gEventManager.initialize();
   Services.obs.addObserver(sendEMPong, "EM-ping");
-  Services.obs.notifyObservers(window, "EM-loaded");
+  Services.obs.notifyObservers(window, "EM-loaded", "");
 
   // If the initial view has already been selected (by a call to loadView from
   // the above notifications) then bail out now
   if (gViewController.initialViewSelected)
     return;
 
   // If there is a history state to restore then use that
   if (window.history.state) {
@@ -284,17 +284,17 @@ function shutdown() {
   gCategories.shutdown();
   gSearchView.shutdown();
   gEventManager.shutdown();
   gViewController.shutdown();
   Services.obs.removeObserver(sendEMPong, "EM-ping");
 }
 
 function sendEMPong(aSubject, aTopic, aData) {
-  Services.obs.notifyObservers(window, "EM-pong");
+  Services.obs.notifyObservers(window, "EM-pong", "");
 }
 
 // Used by external callers to load a specific view into the manager
 function loadView(aViewId) {
   if (!gViewController.initialViewSelected) {
     // The caller opened the window and immediately loaded the view so it
     // should be the initial history entry
 
@@ -740,17 +740,17 @@ function attachUpdateHandler(install) {
             addon: info.addon,
             icon: info.addon.icon,
             permissions: difference,
             resolve,
             reject,
           },
         },
       };
-      Services.obs.notifyObservers(subject, "webextension-permission-prompt");
+      Services.obs.notifyObservers(subject, "webextension-permission-prompt", null);
     });
   };
 }
 
 var gViewController = {
   viewPort: null,
   currentViewId: "",
   currentViewObj: null,
@@ -1108,17 +1108,17 @@ var gViewController = {
           if (pendingChecks > 0)
             return;
 
           this.inProgress = false;
           gViewController.updateCommand("cmd_findAllUpdates");
           document.getElementById("updates-progress").hidden = true;
           gUpdatesView.maybeRefresh();
 
-          Services.obs.notifyObservers(null, "EM-update-check-finished");
+          Services.obs.notifyObservers(null, "EM-update-check-finished", null);
 
           if (numManualUpdates > 0 && numUpdated == 0) {
             document.getElementById("updates-manualUpdatesFound-btn").hidden = false;
             return;
           }
 
           if (numUpdated == 0) {
             document.getElementById("updates-noneFound").hidden = false;
@@ -1302,17 +1302,17 @@ var gViewController = {
                   addon: aAddon,
                   icon: aAddon.iconURL,
                   permissions: perms,
                   resolve() { aAddon.userDisabled = false },
                   reject() {},
                 },
               },
             };
-            Services.obs.notifyObservers(subject, "webextension-permission-prompt");
+            Services.obs.notifyObservers(subject, "webextension-permission-prompt", null);
             return;
           }
         }
         aAddon.userDisabled = false;
       },
       getTooltip(aAddon) {
         if (!aAddon)
           return "";
@@ -2761,17 +2761,17 @@ var gSearchView = {
     for (let item of this._listBox.childNodes) {
       if (item.mInstall == aInstall) {
         let subject = {
           wrappedJSObject: {
             target: getBrowserElement(),
             addon: aInstall.addon,
           },
         };
-        Services.obs.notifyObservers(subject, "webextension-install-notify");
+        Services.obs.notifyObservers(subject, "webextension-install-notify", null);
         return;
       }
     }
   },
 
   removeInstall(aInstall) {
     for (let item of this._listBox.childNodes) {
       if (item.mInstall == aInstall) {
--- a/toolkit/mozapps/extensions/content/extensions.xml
+++ b/toolkit/mozapps/extensions/content/extensions.xml
@@ -670,17 +670,17 @@
                     source: "AMO",
                     icon: info.addon.iconURL,
                     permissions: info.addon.userPermissions,
                     resolve,
                     reject,
                   },
                 },
               };
-              Services.obs.notifyObservers(subject, "webextension-permission-prompt");
+              Services.obs.notifyObservers(subject, "webextension-permission-prompt", null);
             });
           }
           this.mInstall.install();
         ]]></body>
       </method>
 
       <method name="undoAction">
         <body><![CDATA[
--- a/toolkit/mozapps/extensions/content/update.js
+++ b/toolkit/mozapps/extensions/content/update.js
@@ -491,17 +491,17 @@ var gInstallingPage = {
   startNextInstall() {
     if (this._currentInstall >= 0) {
       this._installs[this._currentInstall].removeListener(this);
     }
 
     this._currentInstall++;
 
     if (this._installs.length == this._currentInstall) {
-      Services.obs.notifyObservers(null, "TEST:all-updates-done");
+      Services.obs.notifyObservers(null, "TEST:all-updates-done", null);
       AddonManagerPrivate.recordSimpleMeasure("appUpdate_upgraded",
           gUpdateWizard.upgraded);
       AddonManagerPrivate.recordSimpleMeasure("appUpdate_upgradeFailed",
           gUpdateWizard.upgradeFailed);
       AddonManagerPrivate.recordSimpleMeasure("appUpdate_upgradeDeclined",
           gUpdateWizard.upgradeDeclined);
       this._installing = false;
       if (gUpdateWizard.shuttingDown) {
--- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
@@ -539,17 +539,17 @@ var AddonTestUtils = {
 
     return Promise.resolve();
   },
 
   promiseShutdownManager() {
     if (!this.addonIntegrationService)
       return Promise.resolve(false);
 
-    Services.obs.notifyObservers(null, "quit-application-granted");
+    Services.obs.notifyObservers(null, "quit-application-granted", null);
     return MockAsyncShutdown.hook()
       .then(() => {
         this.emit("addon-manager-shutdown");
 
         this.addonIntegrationService = null;
 
         // Load the add-ons list as it was after application shutdown
         this.loadAddonsList();
@@ -900,17 +900,17 @@ var AddonTestUtils = {
    *        packed XPI.
    */
   manuallyUninstall(installLocation, id, unpacked = this.testUnpacked) {
     let file = this.getFileForAddon(installLocation, id, unpacked);
 
     // In reality because the app is restarted a flush isn't necessary for XPIs
     // removed outside the app, but for testing we must flush manually.
     if (file.isFile())
-      Services.obs.notifyObservers(file, "flush-cache-entry");
+      Services.obs.notifyObservers(file, "flush-cache-entry", null);
 
     file.remove(true);
   },
 
   /**
    * Gets the nsIFile for where an add-on is installed. It may point to a file or
    * a directory depending on whether add-ons are being installed unpacked or not.
    *
--- a/toolkit/mozapps/extensions/internal/Content.js
+++ b/toolkit/mozapps/extensions/internal/Content.js
@@ -19,16 +19,16 @@ const MSG_MESSAGE_MANAGER_CACHES_FLUSH =
 try {
   if (Services.appinfo.processType !== Services.appinfo.PROCESS_TYPE_DEFAULT) {
     // Propagate JAR cache flush notifications across process boundaries.
     addMessageListener(MSG_JAR_FLUSH, function(message) {
       Services.obs.notifyObservers(null, "flush-cache-entry", message.data);
     });
     // Propagate message manager caches flush notifications across processes.
     addMessageListener(MSG_MESSAGE_MANAGER_CACHES_FLUSH, function() {
-      Services.obs.notifyObservers(null, "message-manager-flush-caches");
+      Services.obs.notifyObservers(null, "message-manager-flush-caches", null);
     });
   }
 } catch (e) {
   Cu.reportError(e);
 }
 
 })();
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -1684,25 +1684,25 @@ function buildJarURI(aJarfile, aPath) {
 
 /**
  * Sends local and remote notifications to flush a JAR file cache entry
  *
  * @param aJarFile
  *        The ZIP/XPI/JAR file as a nsIFile
  */
 function flushJarCache(aJarFile) {
-  Services.obs.notifyObservers(aJarFile, "flush-cache-entry");
+  Services.obs.notifyObservers(aJarFile, "flush-cache-entry", null);
   Services.mm.broadcastAsyncMessage(MSG_JAR_FLUSH, aJarFile.path);
 }
 
 function flushChromeCaches() {
   // Init this, so it will get the notification.
-  Services.obs.notifyObservers(null, "startupcache-invalidate");
+  Services.obs.notifyObservers(null, "startupcache-invalidate", null);
   // Flush message manager cached scripts
-  Services.obs.notifyObservers(null, "message-manager-flush-caches");
+  Services.obs.notifyObservers(null, "message-manager-flush-caches", null);
   // Also dispatch this event to child processes
   Services.mm.broadcastAsyncMessage(MSG_MESSAGE_MANAGER_CACHES_FLUSH, null);
 }
 
 /**
  * Creates and returns a new unique temporary file. The caller should delete
  * the file when it is no longer needed.
  *
@@ -2845,23 +2845,23 @@ this.XPIProvider = {
         let addonsToUpdate = this.shouldForceUpdateCheck(aAppChanged);
         if (addonsToUpdate) {
           this.showUpgradeUI(addonsToUpdate);
           flushCaches = true;
         }
       }
 
       if (flushCaches) {
-        Services.obs.notifyObservers(null, "startupcache-invalidate");
+        Services.obs.notifyObservers(null, "startupcache-invalidate", null);
         // UI displayed early in startup (like the compatibility UI) may have
         // caused us to cache parts of the skin or locale in memory. These must
         // be flushed to allow extension provided skins and locales to take full
         // effect
-        Services.obs.notifyObservers(null, "chrome-flush-skin-caches");
-        Services.obs.notifyObservers(null, "chrome-flush-caches");
+        Services.obs.notifyObservers(null, "chrome-flush-skin-caches", null);
+        Services.obs.notifyObservers(null, "chrome-flush-caches", null);
       }
 
       this.enabledAddons = Preferences.get(PREF_EM_ENABLED_ADDONS, "");
 
       if ("nsICrashReporter" in Ci &&
           Services.appinfo instanceof Ci.nsICrashReporter) {
         // Annotate the crash report with relevant add-on information.
         try {
@@ -2990,28 +2990,28 @@ this.XPIProvider = {
     this.extensionsActive = false;
     this._addonFileMap.clear();
 
     if (gLazyObjectsLoaded) {
       let done = XPIDatabase.shutdown();
       done.then(
         ret => {
           logger.debug("Notifying XPI shutdown observers");
-          Services.obs.notifyObservers(null, "xpi-provider-shutdown");
+          Services.obs.notifyObservers(null, "xpi-provider-shutdown", null);
         },
         err => {
           logger.debug("Notifying XPI shutdown observers");
           this._shutdownError = err;
           Services.obs.notifyObservers(null, "xpi-provider-shutdown", err);
         }
       );
       return done;
     }
     logger.debug("Notifying XPI shutdown observers");
-    Services.obs.notifyObservers(null, "xpi-provider-shutdown");
+    Services.obs.notifyObservers(null, "xpi-provider-shutdown", null);
     return undefined;
   },
 
   /**
    * Applies any pending theme change to the preferences.
    */
   applyThemeChange() {
     if (!Preferences.get(PREF_SKIN_SWITCHPENDING, false))
@@ -7735,17 +7735,17 @@ AddonWrapper.prototype = {
     return new Promise((resolve) => {
       const addon = addonFor(this);
 
       logger.debug(`reloading add-on ${addon.id}`);
 
       if (!this.temporarilyInstalled) {
         let addonFile = addon.getResourceURI;
         XPIProvider.updateAddonDisabledState(addon, true);
-        Services.obs.notifyObservers(addonFile, "flush-cache-entry");
+        Services.obs.notifyObservers(addonFile, "flush-cache-entry", null);
         XPIProvider.updateAddonDisabledState(addon, false)
         resolve();
       } else {
         // This function supports re-installing an existing add-on.
         resolve(AddonManager.installTemporaryAddon(addon._sourceBundle));
       }
     });
   },
--- a/toolkit/mozapps/extensions/nsBlocklistService.js
+++ b/toolkit/mozapps/extensions/nsBlocklistService.js
@@ -198,17 +198,17 @@ function newURI(spec) {
 
 // Restarts the application checking in with observers first
 function restartApp() {
   // Notify all windows that an application quit has been requested.
   var os = Cc["@mozilla.org/observer-service;1"].
            getService(Ci.nsIObserverService);
   var cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].
                    createInstance(Ci.nsISupportsPRBool);
-  os.notifyObservers(cancelQuit, "quit-application-requested");
+  os.notifyObservers(cancelQuit, "quit-application-requested", null);
 
   // Something aborted the quit process.
   if (cancelQuit.data)
     return;
 
   var as = Cc["@mozilla.org/toolkit/app-startup;1"].
            getService(Ci.nsIAppStartup);
   as.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
@@ -355,17 +355,17 @@ Blocklist.prototype = {
   // Message manager message handlers
   receiveMessage(aMsg) {
     switch (aMsg.name) {
       case "Blocklist:getPluginBlocklistState":
         return this.getPluginBlocklistState(aMsg.data.addonData,
                                             aMsg.data.appVersion,
                                             aMsg.data.toolkitVersion);
       case "Blocklist:content-blocklist-updated":
-        Services.obs.notifyObservers(null, "content-blocklist-updated");
+        Services.obs.notifyObservers(null, "content-blocklist-updated", null);
         break;
       default:
         throw new Error("Unknown blocklist message received from content: " + aMsg.name);
     }
     return undefined;
   },
 
   /* See nsIBlocklistService */
@@ -1289,17 +1289,17 @@ Blocklist.prototype = {
         }
         return `${key}:${value}`;
       }).join("\t");
     }).join("\n");
     Services.obs.notifyObservers(null, "blocklist-data-gfxItems", payload);
   },
 
   _notifyObserversBlocklistUpdated() {
-    Services.obs.notifyObservers(this, "blocklist-updated");
+    Services.obs.notifyObservers(this, "blocklist-updated", "");
     Services.ppmm.broadcastAsyncMessage("Blocklist:blocklistInvalidated", {});
   },
 
   _blocklistUpdated(oldAddonEntries, oldPluginEntries) {
     if (AppConstants.MOZ_B2G) {
       return;
     }
 
--- a/toolkit/mozapps/extensions/nsBlocklistServiceContent.js
+++ b/toolkit/mozapps/extensions/nsBlocklistServiceContent.js
@@ -47,17 +47,17 @@ Blocklist.prototype = {
       break;
     }
   },
 
   // Message manager message handlers
   receiveMessage(aMsg) {
     switch (aMsg.name) {
       case "Blocklist:blocklistInvalidated":
-        Services.obs.notifyObservers(null, "blocklist-updated");
+        Services.obs.notifyObservers(null, "blocklist-updated", null);
         Services.cpmm.sendAsyncMessage("Blocklist:content-blocklist-updated");
         break;
       default:
         throw new Error("Unknown blocklist message received from content: " + aMsg.name);
     }
   },
 
   /*
--- a/toolkit/mozapps/extensions/test/addons/bootstrap_globals/bootstrap.js
+++ b/toolkit/mozapps/extensions/test/addons/bootstrap_globals/bootstrap.js
@@ -4,27 +4,27 @@ Components.utils.import("resource://gre/
 var seenGlobals = new Set();
 var scope = this;
 function checkGlobal(name, type) {
   if (scope[name] && typeof(scope[name]) == type)
     seenGlobals.add(name);
 }
 
 var wrapped = {};
-Services.obs.notifyObservers({ wrappedJSObject: wrapped }, "bootstrap-request-globals");
+Services.obs.notifyObservers({ wrappedJSObject: wrapped }, "bootstrap-request-globals", null);
 for (let [name, type] of wrapped.expectedGlobals) {
   checkGlobal(name, type);
 }
 
 function install(data, reason) {
 }
 
 function startup(data, reason) {
   Services.obs.notifyObservers({
     wrappedJSObject: seenGlobals
-  }, "bootstrap-seen-globals");
+  }, "bootstrap-seen-globals", null);
 }
 
 function shutdown(data, reason) {
 }
 
 function uninstall(data, reason) {
 }
--- a/toolkit/mozapps/extensions/test/addons/test_bootstrap_const/bootstrap.js
+++ b/toolkit/mozapps/extensions/test/addons/test_bootstrap_const/bootstrap.js
@@ -1,6 +1,6 @@
 /* exported install */
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 const install = function() {
-  Services.obs.notifyObservers(null, "addon-install");
+  Services.obs.notifyObservers(null, "addon-install", "");
 }
--- a/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_browser.js
+++ b/toolkit/mozapps/extensions/test/browser/browser_inlinesettings_browser.js
@@ -19,17 +19,17 @@ function installAddon(details) {
   }
   details.manifest.applications = {gecko: {id}};
   let xpi = Extension.generateXPI(details);
 
   return AddonManager.installTemporaryAddon(xpi).then(addon => {
     SimpleTest.registerCleanupFunction(function() {
       addon.uninstall();
 
-      Services.obs.notifyObservers(xpi, "flush-cache-entry");
+      Services.obs.notifyObservers(xpi, "flush-cache-entry", null);
       xpi.remove(false);
     });
 
     return addon;
   });
 }
 
 add_task(function*() {
--- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
@@ -1066,17 +1066,17 @@ function promiseWebExtensionStartup() {
     Management.on("ready", listener);
   });
 }
 
 function promiseInstallWebExtension(aData) {
   let addonFile = createTempWebExtensionFile(aData);
 
   return promiseInstallAllFiles([addonFile]).then(installs => {
-    Services.obs.notifyObservers(addonFile, "flush-cache-entry");
+    Services.obs.notifyObservers(addonFile, "flush-cache-entry", null);
     // Since themes are disabled by default, it won't start up.
     if (aData.manifest.theme)
       return installs[0].addon;
     return promiseWebExtensionStartup();
   });
 }
 
 // By default use strict compatibility
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_metadata_filters.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_metadata_filters.js
@@ -31,17 +31,17 @@ var WindowWatcher = {
     // Simulate auto-disabling any softblocks
     var list = args.wrappedJSObject.list;
     list.forEach(function(aItem) {
       if (!aItem.blocked)
         aItem.disable = true;
     });
 
     // run the code after the blocklist is closed
-    Services.obs.notifyObservers(null, "addon-blocklist-closed");
+    Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
 
   },
 
   QueryInterface(iid) {
     if (iid.equals(Ci.nsIWindowWatcher)
      || iid.equals(Ci.nsISupports))
       return this;
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_prefs.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_prefs.js
@@ -37,17 +37,17 @@ var WindowWatcher = {
     // Simulate auto-disabling any softblocks
     var list = args.wrappedJSObject.list;
     list.forEach(function(aItem) {
       if (!aItem.blocked)
         aItem.disable = true;
     });
 
     // run the code after the blocklist is closed
-    Services.obs.notifyObservers(null, "addon-blocklist-closed");
+    Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
 
   },
 
   QueryInterface(iid) {
     if (iid.equals(Ci.nsIWindowWatcher)
      || iid.equals(Ci.nsISupports))
       return this;
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklist_regexp.js
@@ -32,17 +32,17 @@ var WindowWatcher = {
     // Simulate auto-disabling any softblocks
     var list = args.wrappedJSObject.list;
     list.forEach(function(aItem) {
       if (!aItem.blocked)
         aItem.disable = true;
     });
 
     // run the code after the blocklist is closed
-    Services.obs.notifyObservers(null, "addon-blocklist-closed");
+    Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
 
   },
 
   QueryInterface(iid) {
     if (iid.equals(Ci.nsIWindowWatcher)
      || iid.equals(Ci.nsISupports))
       return this;
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_blocklistchange.js
@@ -341,17 +341,17 @@ var WindowWatcher = {
     // Simulate auto-disabling any softblocks
     var list = openArgs.wrappedJSObject.list;
     list.forEach(function(aItem) {
       if (!aItem.blocked)
         aItem.disable = true;
     });
 
     // run the code after the blocklist is closed
-    Services.obs.notifyObservers(null, "addon-blocklist-closed");
+    Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
 
   },
 
   QueryInterface(iid) {
     if (iid.equals(Ci.nsIWindowWatcher)
      || iid.equals(Ci.nsISupports))
       return this;
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug393285.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug393285.js
@@ -44,17 +44,17 @@ var WindowWatcher = {
     // Simulate auto-disabling any softblocks
     var list = args.wrappedJSObject.list;
     list.forEach(function(aItem) {
       if (!aItem.blocked)
         aItem.disable = true;
     });
 
     // run the code after the blocklist is closed
-    Services.obs.notifyObservers(null, "addon-blocklist-closed");
+    Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
 
   },
 
   QueryInterface(iid) {
     if (iid.equals(Ci.nsIWindowWatcher)
      || iid.equals(Ci.nsISupports))
       return this;
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug406118.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug406118.js
@@ -33,17 +33,17 @@ var WindowWatcher = {
     // Simulate auto-disabling any softblocks
     var list = args.wrappedJSObject.list;
     list.forEach(function(aItem) {
       if (!aItem.blocked)
         aItem.disable = true;
     });
 
     // run the code after the blocklist is closed
-    Services.obs.notifyObservers(null, "addon-blocklist-closed");
+    Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
 
   },
 
   QueryInterface(iid) {
     if (iid.equals(Ci.nsIWindowWatcher)
      || iid.equals(Ci.nsISupports))
       return this;
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug455906.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug455906.js
@@ -141,17 +141,17 @@ var WindowWatcher = {
     do_check_eq(url, URI_EXTENSION_BLOCKLIST_DIALOG);
 
     if (gNotificationCheck) {
       var args = windowArguments.wrappedJSObject;
       gNotificationCheck(args);
     }
 
     // run the code after the blocklist is closed
-    Services.obs.notifyObservers(null, "addon-blocklist-closed");
+    Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
 
     // Call the next test after the blocklist has finished up
     do_timeout(0, gTestCheck);
   },
 
   QueryInterface(iid) {
     if (iid.equals(Ci.nsIWindowWatcher)
      || iid.equals(Ci.nsISupports))
--- a/toolkit/mozapps/extensions/test/xpcshell/test_bug514327_2.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug514327_2.js
@@ -28,14 +28,14 @@ function run_test() {
 
   prefs.setBoolPref("plugin.load_flash_only", false);
 
   var plugin = get_test_plugintag();
   if (!plugin)
     do_throw("Plugin tag not found");
 
   // run the code after the blocklist is closed
-  Services.obs.notifyObservers(null, "addon-blocklist-closed");
+  Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
   do_execute_soon(function() {
     // should be marked as outdated by the blocklist
     do_check_true(blocklist.getPluginBlocklistState(plugin, "1", "1.9") == nsIBLS.STATE_OUTDATED);
   });
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_permissions_prefs.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_permissions_prefs.js
@@ -57,17 +57,17 @@ function run_test() {
   clear_imported_preferences_cache();
   Services.prefs.setCharPref("xpinstall.whitelist.add.TEST2", "https://whitelist2.example.com");
   Services.obs.notifyObservers(null, "flush-pending-permissions", "install");
   do_check_permission_prefs(preferences);
 
   // Then, request to flush just install permissions
   clear_imported_preferences_cache();
   Services.prefs.setCharPref("xpinstall.whitelist.add.TEST3", "https://whitelist3.example.com");
-  Services.obs.notifyObservers(null, "flush-pending-permissions");
+  Services.obs.notifyObservers(null, "flush-pending-permissions", "");
   do_check_permission_prefs(preferences);
 
   // And a request to flush some other permissions sholdn't flush install permissions
   clear_imported_preferences_cache();
   Services.prefs.setCharPref("xpinstall.whitelist.add.TEST4", "https://whitelist4.example.com");
   Services.obs.notifyObservers(null, "flush-pending-permissions", "lolcats");
   do_check_eq(Services.prefs.getCharPref("xpinstall.whitelist.add.TEST4"), "https://whitelist4.example.com");
 }
--- a/toolkit/mozapps/extensions/test/xpcshell/test_pluginchange.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_pluginchange.js
@@ -96,17 +96,17 @@ function run_test_1() {
 // No change to the list should not trigger any events or changes in the API
 function run_test_2() {
   // Reorder the list a bit
   let tag = PLUGINS[0];
   PLUGINS[0] = PLUGINS[2];
   PLUGINS[2] = PLUGINS[1];
   PLUGINS[1] = tag;
 
-  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC);
+  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC, null);
 
   AddonManager.getAddonsByTypes(["plugin"], function(addons) {
     sortAddons(addons);
 
     do_check_eq(addons.length, 2);
 
     do_check_eq(addons[0].name, "Flash");
     do_check_false(addons[0].userDisabled);
@@ -128,17 +128,17 @@ function run_test_3() {
     ["onInstalling", false],
     "onInstalled"
   ];
 
   prepare_test(test_params, [
     "onExternalInstall"
   ]);
 
-  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC);
+  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC, null);
 
   ensure_test_completed();
 
   AddonManager.getAddonsByTypes(["plugin"], function(addons) {
     sortAddons(addons);
 
     do_check_eq(addons.length, 3);
 
@@ -161,17 +161,17 @@ function run_test_4() {
   let test_params = {};
   test_params[id] = [
     ["onUninstalling", false],
     "onUninstalled"
   ];
 
   prepare_test(test_params);
 
-  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC);
+  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC, null);
 
   ensure_test_completed();
 
   AddonManager.getAddonsByTypes(["plugin"], function(addons) {
     sortAddons(addons);
 
     do_check_eq(addons.length, 2);
 
@@ -183,17 +183,17 @@ function run_test_4() {
     run_test_5();
   });
 }
 
 // Removing part of the flash plugin should have no effect
 function run_test_5() {
   PLUGINS.splice(0, 1);
 
-  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC);
+  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC, null);
 
   ensure_test_completed();
 
   AddonManager.getAddonsByTypes(["plugin"], function(addons) {
     sortAddons(addons);
 
     do_check_eq(addons.length, 2);
 
@@ -222,17 +222,17 @@ function run_test_6() {
     ["onInstalling", false],
     "onInstalled"
   ];
 
   prepare_test(test_params, [
     "onExternalInstall"
   ]);
 
-  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC);
+  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC, null);
 
   ensure_test_completed();
 
   AddonManager.getAddonsByTypes(["plugin"], function(addons) {
     sortAddons(addons);
 
     do_check_eq(addons.length, 2);
 
@@ -259,17 +259,17 @@ function run_test_7() {
   ];
   test_params[getIDHashForString(PLUGINS[1].name + PLUGINS[1].description)] = [
     ["onEnabling", false],
     "onEnabled"
   ];
 
   prepare_test(test_params);
 
-  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC);
+  Services.obs.notifyObservers(null, LIST_UPDATED_TOPIC, null);
 
   ensure_test_completed();
 
   AddonManager.getAddonsByTypes(["plugin"], function(addons) {
     sortAddons(addons);
 
     do_check_eq(addons.length, 2);
 
--- a/toolkit/mozapps/extensions/test/xpcshell/test_signed_inject.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_signed_inject.js
@@ -48,17 +48,17 @@ function resetPrefs() {
   Services.prefs.setIntPref("bootstraptest.install_oldversion", -1);
   Services.prefs.setIntPref("bootstraptest.uninstall_newversion", -1);
 }
 
 function clearCache(file) {
   if (TEST_UNPACKED)
     return;
 
-  Services.obs.notifyObservers(file, "flush-cache-entry");
+  Services.obs.notifyObservers(file, "flush-cache-entry", null);
 }
 
 function getActiveVersion() {
   return Services.prefs.getIntPref("bootstraptest.active_version");
 }
 
 function run_test() {
   createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "4", "4");
--- a/toolkit/mozapps/extensions/test/xpcshell/test_softblocked.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_softblocked.js
@@ -26,17 +26,17 @@ var WindowWatcher = {
     // Simulate auto-disabling any softblocks
     var list = openArgs.wrappedJSObject.list;
     list.forEach(function(aItem) {
       if (!aItem.blocked)
         aItem.disable = true;
     });
 
     // run the code after the blocklist is closed
-    Services.obs.notifyObservers(null, "addon-blocklist-closed");
+    Services.obs.notifyObservers(null, "addon-blocklist-closed", null);
   },
 
   QueryInterface(iid) {
     if (iid.equals(Ci.nsIWindowWatcher)
      || iid.equals(Ci.nsISupports))
       return this;
 
     throw Cr.NS_ERROR_NO_INTERFACE;
--- a/toolkit/mozapps/extensions/test/xpcshell/test_update_webextensions.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_update_webextensions.js
@@ -39,17 +39,17 @@ function serveManifest(request, response
 function promiseInstallWebExtension(aData) {
   let addonFile = createTempWebExtensionFile(aData);
 
   let startupPromise = promiseWebExtensionStartup();
 
   return promiseInstallAllFiles([addonFile]).then(() => {
     return startupPromise;
   }).then(() => {
-    Services.obs.notifyObservers(addonFile, "flush-cache-entry");
+    Services.obs.notifyObservers(addonFile, "flush-cache-entry", null);
     return promiseAddonByID(aData.id);
   });
 }
 
 var checkUpdates = Task.async(function* (aData, aReason = AddonManager.UPDATE_WHEN_PERIODIC_UPDATE) {
   function provide(obj, path, value) {
     path = path.split(".");
     let prop = path.pop();
@@ -233,17 +233,17 @@ add_task(function* checkIllegalUpdateURL
 
   for (let url of URLS) {
     let { messages } = yield promiseConsoleOutput(() => {
       let addonFile = createTempWebExtensionFile({
         manifest: { applications: { gecko: { update_url: url } } },
       });
 
       return AddonManager.getInstallForFile(addonFile).then(install => {
-        Services.obs.notifyObservers(addonFile, "flush-cache-entry");
+        Services.obs.notifyObservers(addonFile, "flush-cache-entry", null);
 
         if (!install || install.state != AddonManager.STATE_DOWNLOAD_FAILED)
           throw new Error("Unexpected state: " + (install && install.state));
       });
     });
 
     ok(messages.some(msg => /Access denied for URL|may not load or link to|is not a valid URL/.test(msg)),
        "Got checkLoadURI error");
--- a/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install.js
@@ -105,17 +105,17 @@ add_task(function* test_unsigned_no_id_t
   const [secondAddon] = yield Promise.all([
     AddonManager.installTemporaryAddon(addonDir),
     promiseWebExtensionStartup(),
   ]);
   // The IDs should be the same.
   equal(secondAddon.id, addon.id, "Reinstalled add-on has the expected ID");
 
   secondAddon.uninstall();
-  Services.obs.notifyObservers(addonDir, "flush-cache-entry");
+  Services.obs.notifyObservers(addonDir, "flush-cache-entry", null);
   addonDir.remove(true);
   AddonTestUtils.useRealCertChecks = false;
 });
 
 // We should be able to install two extensions from manifests without IDs
 // at different locations and get two unique extensions.
 add_task(function* test_multiple_no_id_extensions() {
   AddonTestUtils.useRealCertChecks = true;
--- a/toolkit/mozapps/update/content/updates.js
+++ b/toolkit/mozapps/update/content/updates.js
@@ -1344,17 +1344,17 @@ var gFinishedPage = {
   onExtra1() {
     gUpdates.wiz.cancel();
   },
 
   /**
    * When elevation is required and the user clicks "No Thanks" in the wizard.
    */
   onExtra2: Task.async(function*() {
-    Services.obs.notifyObservers(null, "update-canceled");
+    Services.obs.notifyObservers(null, "update-canceled", null);
     let um = CoC["@mozilla.org/updates/update-manager;1"].
                getService(CoI.nsIUpdateManager);
     um.cleanupActiveUpdate();
     gUpdates.never();
     gUpdates.wiz.cancel();
   }),
 };
 
--- a/uriloader/exthandler/nsHandlerService-json.js
+++ b/uriloader/exthandler/nsHandlerService-json.js
@@ -152,17 +152,17 @@ HandlerService.prototype = {
 
   // nsIObserver
   observe(subject, topic, data) {
     if (topic != "handlersvc-json-replace") {
       return;
     }
     let promise = this._onDBChange();
     promise.then(() => {
-      Services.obs.notifyObservers(null, "handlersvc-json-replace-complete");
+      Services.obs.notifyObservers(null, "handlersvc-json-replace-complete", null);
     });
   },
 
   // nsIHandlerService
   enumerate() {
     let handlers = Cc["@mozilla.org/array;1"].
                      createInstance(Ci.nsIMutableArray);
     for (let type of Object.keys(this._store.data.mimetypes)) {
--- a/uriloader/exthandler/nsHandlerService.js
+++ b/uriloader/exthandler/nsHandlerService.js
@@ -289,17 +289,17 @@ HandlerService.prototype = {
       case "profile-do-change":
         this._updateDB();
         break;
       case "handlersvc-rdf-replace":
         if (this.__ds) {
           this._rdf.UnregisterDataSource(this.__ds);
           this.__ds = null;
         }
-        this._observerSvc.notifyObservers(null, "handlersvc-rdf-replace-complete");
+        this._observerSvc.notifyObservers(null, "handlersvc-rdf-replace-complete", null);
         break;
     }
   },
 
 
   //**************************************************************************//
   // nsIHandlerService
 
--- a/uriloader/exthandler/tests/unit/test_handlerService_json.js
+++ b/uriloader/exthandler/tests/unit/test_handlerService_json.js
@@ -25,11 +25,11 @@ var removeImportDB = Task.async(function
 
   yield OS.File.remove(jsonPath, { ignoreAbsent: true });
 });
 
 var reloadData = Task.async(function* () {
   // Force the initialization of handlerService to prevent observer is not initialized yet.
   let svc = gHandlerService;
   let promise = TestUtils.topicObserved("handlersvc-json-replace-complete");
-  Services.obs.notifyObservers(null, "handlersvc-json-replace");
+  Services.obs.notifyObservers(null, "handlersvc-json-replace", null);
   yield promise;
 });
--- a/uriloader/exthandler/tests/unit/test_handlerService_rdf.js
+++ b/uriloader/exthandler/tests/unit/test_handlerService_rdf.js
@@ -27,11 +27,11 @@ var removeImportDB = Task.async(function
 
   yield OS.File.remove(rdfFile.path, { ignoreAbsent: true });
 });
 
 var reloadData = Task.async(function* () {
   // Force the initialization of handlerService to prevent observer is not initialized yet.
   let svc = gHandlerService;
   let promise = TestUtils.topicObserved("handlersvc-rdf-replace-complete");
-  Services.obs.notifyObservers(null, "handlersvc-rdf-replace");
+  Services.obs.notifyObservers(null, "handlersvc-rdf-replace", null);
   yield promise;
 });