Backed out 4 changesets (bug 1440022) for nsSocketTransport crashes when trying to access the internet CLOSED TREE
authorBogdan Tara <btara@mozilla.com>
Mon, 11 Jun 2018 22:17:53 +0300
changeset 476522 95ce39e2c83c6cc253db9c7ddd47575977f21efa
parent 476521 9fa127e6df5659a424ab6a187a03a5c99b1c9bec
child 476523 64960572836b471f9f68ad4abb78ffb3cb0e61c4
push id9374
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:43:20 +0000
treeherdermozilla-beta@160e085dfb0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1440022
milestone62.0a1
backs out9fa127e6df5659a424ab6a187a03a5c99b1c9bec
4f84a6745a51bda3ea268cdabb59e912c89b264a
00cf71bb3861d5352b3f74cf6d35db4b777ce7b4
b7d5b0db60adc73acbdfe0fb88d40252685d6aff
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 4 changesets (bug 1440022) for nsSocketTransport crashes when trying to access the internet CLOSED TREE Backed out changeset 9fa127e6df56 (bug 1440022) Backed out changeset 4f84a6745a51 (bug 1440022) Backed out changeset 00cf71bb3861 (bug 1440022) Backed out changeset b7d5b0db60ad (bug 1440022)
dom/push/PushBroadcastService.jsm
dom/push/PushService.jsm
dom/push/PushServiceAndroidGCM.jsm
dom/push/PushServiceHttp2.jsm
dom/push/PushServiceWebSocket.jsm
dom/push/moz.build
dom/push/test/xpcshell/broadcast_handler.jsm
dom/push/test/xpcshell/head.js
dom/push/test/xpcshell/moz.build
dom/push/test/xpcshell/test_broadcast_success.js
dom/push/test/xpcshell/xpcshell.ini
services/settings/remote-settings.js
deleted file mode 100644
--- a/dom/push/PushBroadcastService.jsm
+++ /dev/null
@@ -1,216 +0,0 @@
-/* jshint moz: true, esnext: true */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-"use strict";
-
-ChromeUtils.import("resource://gre/modules/osfile.jsm");
-ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-ChromeUtils.defineModuleGetter(this, "JSONFile", "resource://gre/modules/JSONFile.jsm");
-
-var EXPORTED_SYMBOLS = ["pushBroadcastService"];
-
-// We are supposed to ignore any updates with this version.
-// FIXME: what is the actual "dummy" version?
-// See bug 1467550.
-const DUMMY_VERSION_STRING = "dummy";
-
-XPCOMUtils.defineLazyGetter(this, "console", () => {
-  let {ConsoleAPI} = ChromeUtils.import("resource://gre/modules/Console.jsm", {});
-  return new ConsoleAPI({
-    maxLogLevelPref: "dom.push.loglevel",
-    prefix: "BroadcastService",
-  });
-});
-ChromeUtils.defineModuleGetter(this, "PushService", "resource://gre/modules/PushService.jsm");
-
-class InvalidSourceInfo extends Error {
-  constructor(message) {
-    super(message);
-    this.name = 'InvalidSourceInfo';
-  }
-}
-
-const BROADCAST_SERVICE_VERSION = 1;
-
-var BroadcastService = class {
-  constructor(pushService, path) {
-    this.pushService = pushService;
-    this.jsonFile = new JSONFile({
-      path,
-      dataPostProcessor: this._initializeJSONFile,
-    });
-    this.initializePromise = this.jsonFile.load();
-  }
-
-  /**
-   * Convert the listeners from our on-disk format to the format
-   * needed by a hello message.
-   */
-  async getListeners() {
-    await this.initializePromise;
-    return Object.entries(this.jsonFile.data.listeners).reduce((acc, [k, v]) => {
-      acc[k] = v.version;
-      return acc;
-    }, {});
-  }
-
-  _initializeJSONFile(data) {
-    if (!data.version) {
-      data.version = BROADCAST_SERVICE_VERSION;
-    }
-    if (!data.hasOwnProperty("listeners")) {
-      data.listeners = {};
-    }
-    return data;
-  }
-
-  /**
-   * Reset to a state akin to what you would get in a new profile.
-   * In particular, wipe anything from storage.
-   *
-   * Used mainly for testing.
-   */
-  async _resetListeners() {
-    await this.initializePromise;
-    this.jsonFile.data = this._initializeJSONFile({});
-    this.initializePromise = Promise.resolve();
-  }
-
-  /**
-   * Ensure that a sourceInfo is correct (has the expected fields).
-   */
-  _validateSourceInfo(sourceInfo) {
-    const {moduleURI, symbolName} = sourceInfo;
-    if (typeof moduleURI !== "string") {
-      throw new InvalidSourceInfo(`moduleURI must be a string (got ${typeof moduleURI})`);
-    }
-    if (typeof symbolName !== "string") {
-      throw new InvalidSourceInfo(`symbolName must be a string (got ${typeof symbolName})`);
-    }
-  }
-
-  /**
-   * Add an entry for a given listener if it isn't present, or update
-   * one if it is already present.
-   *
-   * Note that this means only a single listener can be set for a
-   * given subscription. This is a limitation in the current API that
-   * stems from the fact that there can only be one source of truth
-   * for the subscriber's version. As a workaround, you can define a
-   * listener which calls multiple other listeners.
-   *
-   * @param {string} broadcastId The broadcastID to listen for
-   * @param {string} version The most recent version we have for
-   *   updates from this broadcastID
-   * @param {Object} sourceInfo A description of the handler for
-   *   updates on this broadcastID
-   */
-  async addListener(broadcastId, version, sourceInfo) {
-    console.info("addListener: adding listener", broadcastId, version, sourceInfo);
-    await this.initializePromise;
-    this._validateSourceInfo(sourceInfo);
-    if (typeof version !== "string") {
-      throw new TypeError("version should be a string");
-    }
-    const isNew = !this.jsonFile.data.listeners.hasOwnProperty(broadcastId);
-
-    // Update listeners before telling the pushService to subscribe,
-    // in case it would disregard the update in the small window
-    // between getting listeners and setting state to RUNNING.
-    this.jsonFile.data.listeners[broadcastId] = {version, sourceInfo};
-    this.jsonFile.saveSoon();
-
-    if (isNew) {
-      await this.pushService.subscribeBroadcast(broadcastId, version);
-    }
-  }
-
-  async receivedBroadcastMessage(broadcasts) {
-    console.info("receivedBroadcastMessage:", broadcasts);
-    await this.initializePromise;
-    for (const broadcastId in broadcasts) {
-      const version = broadcasts[broadcastId];
-      if (version === DUMMY_VERSION_STRING) {
-        console.info("Ignoring", version, "because it's the dummy version");
-        continue;
-      }
-      // We don't know this broadcastID. This is probably a bug?
-      if (!this.jsonFile.data.listeners.hasOwnProperty(broadcastId)) {
-        console.warn("receivedBroadcastMessage: unknown broadcastId", broadcastId);
-        continue;
-      }
-
-      const {sourceInfo} = this.jsonFile.data.listeners[broadcastId];
-      try {
-        this._validateSourceInfo(sourceInfo);
-      } catch (e) {
-        console.error("receivedBroadcastMessage: malformed sourceInfo", sourceInfo, e);
-        continue;
-      }
-
-      const {moduleURI, symbolName} = sourceInfo;
-
-      const module = {};
-      try {
-        ChromeUtils.import(moduleURI, module);
-      } catch (e) {
-        console.error("receivedBroadcastMessage: couldn't invoke", broadcastId,
-                      "because import of module", moduleURI,
-                      "failed", e);
-        continue;
-      }
-
-      if (!module[symbolName]) {
-        console.error("receivedBroadcastMessage: couldn't invoke", broadcastId,
-                      "because module", moduleName, "missing attribute", symbolName);
-        continue;
-      }
-
-      const handler = module[symbolName];
-
-      if (!handler.receivedBroadcastMessage) {
-        console.error("receivedBroadcastMessage: couldn't invoke", broadcastId,
-                      "because handler returned by", `${moduleURI}.${symbolName}`,
-                      "has no receivedBroadcastMessage method");
-        continue;
-      }
-
-      try {
-        await handler.receivedBroadcastMessage(version, broadcastId);
-      } catch (e) {
-        console.error("receivedBroadcastMessage: handler for", broadcastId,
-                      "threw error:", e);
-        continue;
-      }
-
-      // Broadcast message applied successfully. Update the version we
-      // received if it's different than the one we had.  We don't
-      // enforce an ordering here (i.e. we use != instead of <)
-      // because we don't know what the ordering of the service's
-      // versions is going to be.
-      if (this.jsonFile.data.listeners[broadcastId].version != version) {
-        this.jsonFile.data.listeners[broadcastId].version = version;
-        this.jsonFile.saveSoon();
-      }
-    }
-  }
-
-  // For test only.
-  _saveImmediately() {
-    return this.jsonFile._save();
-  }
-}
-
-function initializeBroadcastService() {
-  // Fallback path for xpcshell tests.
-  let path = "broadcast-listeners.json";
-  if (OS.Constants.Path.profileDir) {
-    // Real path for use in a real profile.
-    path = OS.Path.join(OS.Constants.Path.profileDir, path);
-  }
-  return new BroadcastService(PushService, path);
-};
-
-var pushBroadcastService = initializeBroadcastService();
--- a/dom/push/PushService.jsm
+++ b/dom/push/PushService.jsm
@@ -27,17 +27,16 @@ const CONNECTION_PROTOCOLS = (function()
     const {PushServiceAndroidGCM} = ChromeUtils.import("resource://gre/modules/PushServiceAndroidGCM.jsm");
     return [PushServiceAndroidGCM];
   }
 })();
 
 XPCOMUtils.defineLazyServiceGetter(this, "gPushNotifier",
                                    "@mozilla.org/push/Notifier;1",
                                    "nsIPushNotifier");
-ChromeUtils.defineModuleGetter(this, "pushBroadcastService", "resource://gre/modules/PushBroadcastService.jsm");
 
 var EXPORTED_SYMBOLS = ["PushService"];
 
 XPCOMUtils.defineLazyGetter(this, "console", () => {
   let {ConsoleAPI} = ChromeUtils.import("resource://gre/modules/Console.jsm", {});
   return new ConsoleAPI({
     maxLogLevelPref: "dom.push.loglevel",
     prefix: "PushService",
@@ -236,29 +235,24 @@ var PushService = {
     if (this._state == PUSH_SERVICE_RUNNING) {
       // PushService was not in the offline state, but got notification to
       // go online (a offline notification has not been sent).
       // Disconnect first.
       this._service.disconnect();
     }
 
     let records = await this.getAllUnexpired();
-    let broadcastListeners = await pushBroadcastService.getListeners();
 
-    // In principle, a listener could be added to the
-    // pushBroadcastService here, after we have gotten listeners and
-    // before we're RUNNING, but this can't happen in practice because
-    // the only caller that can add listeners is PushBroadcastService,
-    // and it waits on the same promise we are before it can add
-    // listeners. If PushBroadcastService gets woken first, it will
-    // update the value that is eventually returned from
-    // getListeners.
     this._setState(PUSH_SERVICE_RUNNING);
 
-    this._service.connect(records, broadcastListeners);
+    if (records.length > 0 || prefs.get("alwaysConnect")) {
+      // Connect if we have existing subscriptions, or if the always-on pref
+      // is set.
+      this._service.connect(records);
+    }
   },
 
   _changeStateConnectionEnabledEvent: function(enabled) {
     console.debug("changeStateConnectionEnabledEvent()", enabled);
 
     if (this._state < PUSH_SERVICE_CONNECTION_DISABLE &&
         this._state != PUSH_SERVICE_ACTIVATING) {
       return Promise.resolve();
@@ -487,23 +481,23 @@ var PushService = {
     this._setState(PUSH_SERVICE_ACTIVATING);
 
     prefs.observe("serverURL", this);
     Services.obs.addObserver(this, "quit-application");
 
     if (options.serverURI) {
       // this is use for xpcshell test.
 
-      return this._stateChangeProcessEnqueue(_ =>
+      this._stateChangeProcessEnqueue(_ =>
         this._changeServerURL(options.serverURI, STARTING_SERVICE_EVENT, options));
 
     } else {
       // This is only used for testing. Different tests require connecting to
       // slightly different URLs.
-      return this._stateChangeProcessEnqueue(_ =>
+      this._stateChangeProcessEnqueue(_ =>
         this._changeServerURL(prefs.get("serverURL"), STARTING_SERVICE_EVENT));
     }
   },
 
   _startObservers: function() {
     console.debug("startObservers()");
 
     if (this._state != PUSH_SERVICE_ACTIVATING) {
@@ -766,26 +760,16 @@ var PushService = {
       return this._decryptAndNotifyApp(record, messageID, headers, data);
     }).catch(error => {
       console.error("receivedPushMessage: Error notifying app", error);
       return Ci.nsIPushErrorReporter.ACK_NOT_DELIVERED;
     });
   },
 
   /**
-   * Dispatches a broadcast notification to the BroadcastService.
-   */
-  receivedBroadcastMessage(message) {
-    pushBroadcastService.receivedBroadcastMessage(message.broadcasts)
-      .catch(e => {
-        console.error(e);
-      });;
-  },
-
-  /**
    * Updates a registration record after receiving a push message.
    *
    * @param {String} keyID The push registration ID.
    * @param {Function} updateFunc The function passed to `receivedPushMessage`.
    * @returns {Promise} Resolves with the updated record, or rejects if the
    *  record was not updated.
    */
   _updateRecordAfterPush(keyID, updateFunc) {
@@ -1093,31 +1077,16 @@ var PushService = {
           }
           throw new Error("Push subscription expired");
         }).then(_ => this._lookupOrPutPendingRequest(aPageRecord));
       }
       return record.toSubscription();
     });
   },
 
-  /*
-   * Called only by the PushBroadcastService on the receipt of a new
-   * subscription. Don't call this directly. Go through PushBroadcastService.
-   */
-  async subscribeBroadcast(broadcastId, version) {
-    if (this._state != PUSH_SERVICE_RUNNING) {
-      // Ignore any request to subscribe before we send a hello.
-      // We'll send all the broadcast listeners as part of the hello
-      // anyhow.
-      return;
-    }
-
-    await this._service.sendSubscribeBroadcast(broadcastId, version);
-  },
-
   /**
    * Called on message from the child process.
    *
    * Why is the record being deleted from the local database before the server
    * is told?
    *
    * Unregistration is for the benefit of the app and the AppServer
    * so that the AppServer does not keep pinging a channel the UserAgent isn't
--- a/dom/push/PushServiceAndroidGCM.jsm
+++ b/dom/push/PushServiceAndroidGCM.jsm
@@ -162,17 +162,17 @@ var PushServiceAndroidGCM = {
     Services.obs.removeObserver(this, "PushServiceAndroidGCM:ReceivedPushMessage");
     prefs.ignore("debug", this);
   },
 
   onAlarmFired: function() {
     // No action required.
   },
 
-  connect: function(records, broadcastListeners) {
+  connect: function(records) {
     console.debug("connect:", records);
     // It's possible for the registration or subscriptions backing the
     // PushService to not be registered with the underlying AndroidPushService.
     // Expire those that are unrecognized.
     return EventDispatcher.instance.sendRequestForResult({
       type: "PushServiceAndroidGCM:DumpSubscriptions",
     })
     .then(subscriptions => {
@@ -189,20 +189,16 @@ var PushServiceAndroidGCM = {
         return this._mainPushService.dropRegistrationAndNotifyApp(record.keyID)
           .catch(error => {
             console.error("connect: Error dropping registration", record.keyID, error);
           });
       }));
     });
   },
 
-  sendSubscribeBroadcast: async function(serviceId, version) {
-    // Not implemented yet
-  },
-
   isConnected: function() {
     return this._mainPushService != null;
   },
 
   disconnect: function() {
     console.debug("disconnect");
   },
 
--- a/dom/push/PushServiceHttp2.jsm
+++ b/dom/push/PushServiceHttp2.jsm
@@ -421,24 +421,20 @@ var PushServiceHttp2 = {
 
   validServerURI: function(serverURI) {
     if (serverURI.scheme == "http") {
       return !!prefs.getBoolPref("testing.allowInsecureServerURL", false);
     }
     return serverURI.scheme == "https";
   },
 
-  connect: function(subscriptions, broadcastListeners) {
+  connect: function(subscriptions) {
     this.startConnections(subscriptions);
   },
 
-  sendSubscribeBroadcast: async function(serviceId, version) {
-    // Not implemented yet
-  },
-
   isConnected: function() {
     return this._mainPushService != null;
   },
 
   disconnect: function() {
     this._shutdownConnections(false);
   },
 
--- a/dom/push/PushServiceWebSocket.jsm
+++ b/dom/push/PushServiceWebSocket.jsm
@@ -309,18 +309,16 @@ var PushServiceWebSocket = {
     this._ws.sendMsg(msg);
   },
 
   init: function(options, mainPushService, serverURI) {
     console.debug("init()");
 
     this._mainPushService = mainPushService;
     this._serverURI = serverURI;
-    // Filled in at connect() time
-    this._broadcastListeners = null;
 
     // Override the default WebSocket factory function. The returned object
     // must be null or satisfy the nsIWebSocketChannel interface. Used by
     // the tests to provide a mock WebSocket implementation.
     if (options.makeWebSocket) {
       this._makeWebSocket = options.makeWebSocket;
     }
 
@@ -509,19 +507,18 @@ var PushServiceWebSocket = {
       this._currentState = STATE_WAITING_FOR_WS_START;
     } catch(e) {
       console.error("beginWSSetup: Error opening websocket.",
         "asyncOpen failed", e);
       this._reconnect();
     }
   },
 
-  connect: function(records, broadcastListeners) {
-    console.debug("connect()", broadcastListeners);
-    this._broadcastListeners = broadcastListeners;
+  connect: function(records) {
+    console.debug("connect()");
     this._beginWSSetup();
   },
 
   isConnected: function() {
     return !!this._ws;
   },
 
   /**
@@ -564,23 +561,16 @@ var PushServiceWebSocket = {
       this._sendPendingRequests();
     };
 
     function finishHandshake() {
       this._UAID = reply.uaid;
       this._currentState = STATE_READY;
       prefs.observe("userAgentID", this);
 
-      // Handle broadcasts received in response to the "hello" message.
-      if (reply.broadcasts) {
-        // The reply isn't technically a broadcast message, but it has
-        // the shape of a broadcast message (it has a broadcasts field).
-        this._mainPushService.receivedBroadcastMessage(reply);
-      }
-
       this._dataEnabled = !!reply.use_webpush;
       if (this._dataEnabled) {
         this._mainPushService.getAllUnexpired().then(records =>
           Promise.all(records.map(record =>
             this._mainPushService.ensureCrypto(record).catch(error => {
               console.error("finishHandshake: Error updating record",
                 record.keyID, error);
             })
@@ -752,20 +742,16 @@ var PushServiceWebSocket = {
       if (typeof version === "number" && version >= 0) {
         // FIXME(nsm): this relies on app update notification being infallible!
         // eventually fix this
         this._receivedUpdate(update.channelID, version);
       }
     }
   },
 
-  _handleBroadcastReply: function(reply) {
-    this._mainPushService.receivedBroadcastMessage(reply);
-  },
-
   reportDeliveryError(messageID, reason) {
     console.debug("reportDeliveryError()");
     let code = kDELIVERY_REASON_TO_CODE[reason];
     if (!code) {
       throw new Error('Invalid delivery error reason');
     }
     let data = {messageType: 'nack',
                 version: messageID,
@@ -954,17 +940,16 @@ var PushServiceWebSocket = {
     if (this._currentState != STATE_WAITING_FOR_WS_START) {
       console.error("wsOnStart: NOT in STATE_WAITING_FOR_WS_START. Current",
         "state", this._currentState, "Skipping");
       return;
     }
 
     let data = {
       messageType: "hello",
-      broadcasts: this._broadcastListeners,
       use_webpush: true,
     };
 
     if (this._UAID) {
       data.uaid = this._UAID;
     }
 
     this._wsSendMessage(data);
@@ -1023,17 +1008,17 @@ var PushServiceWebSocket = {
 
     // If it is a ping, do not handle the message.
     if (doNotHandle) {
       return;
     }
 
     // A whitelist of protocol handlers. Add to these if new messages are added
     // in the protocol.
-    let handlers = ["Hello", "Register", "Unregister", "Notification", "Broadcast"];
+    let handlers = ["Hello", "Register", "Unregister", "Notification"];
 
     // Build up the handler name to call from messageType.
     // e.g. messageType == "register" -> _handleRegisterReply.
     let handlerName = reply.messageType[0].toUpperCase() +
                       reply.messageType.slice(1).toLowerCase();
 
     if (!handlers.includes(handlerName)) {
       console.warn("wsOnMessageAvailable: No whitelisted handler", handlerName,
@@ -1122,27 +1107,16 @@ var PushServiceWebSocket = {
       return null;
     }
     this._pendingRequests.delete(key);
     if (!this._hasPendingRequests()) {
       this._requestTimeoutTimer.cancel();
     }
     return request;
   },
-
-  sendSubscribeBroadcast(serviceId, version) {
-    let data = {
-      messageType: "broadcast_subscribe",
-      broadcasts: {
-        [serviceId]: version
-      },
-    };
-
-    this._queueRequest(data);
-  },
 };
 
 function PushRecordWebSocket(record) {
   PushRecord.call(this, record);
   this.channelID = record.channelID;
   this.version = record.version;
 }
 
--- a/dom/push/moz.build
+++ b/dom/push/moz.build
@@ -8,17 +8,16 @@ with Files("**"):
 
 EXTRA_COMPONENTS += [
     'Push.js',
     'Push.manifest',
     'PushComponents.js',
 ]
 
 EXTRA_JS_MODULES += [
-    'PushBroadcastService.jsm',
     'PushCrypto.jsm',
     'PushDB.jsm',
     'PushRecord.jsm',
     'PushService.jsm',
 ]
 
 if CONFIG['MOZ_BUILD_APP'] != 'mobile/android':
     # Everything but Fennec.
deleted file mode 100644
--- a/dom/push/test/xpcshell/broadcast_handler.jsm
+++ /dev/null
@@ -1,16 +0,0 @@
-"use strict";
-
-var EXPORTED_SYMBOLS = ["broadcastHandler"];
-
-var broadcastHandler = {
-  reset() {
-    this.notifications = [];
-
-    this.wasNotified = new Promise((resolve, reject) => {
-      this.receivedBroadcastMessage = function() {
-        resolve();
-        this.notifications.push(Array.from(arguments));
-      };
-    });
-  }
-};
--- a/dom/push/test/xpcshell/head.js
+++ b/dom/push/test/xpcshell/head.js
@@ -10,19 +10,17 @@ ChromeUtils.import('resource://gre/modul
 ChromeUtils.import('resource://gre/modules/PlacesUtils.jsm');
 ChromeUtils.import('resource://gre/modules/ObjectUtils.jsm');
 
 ChromeUtils.defineModuleGetter(this, 'PlacesTestUtils',
                                'resource://testing-common/PlacesTestUtils.jsm');
 XPCOMUtils.defineLazyServiceGetter(this, 'PushServiceComponent',
                                    '@mozilla.org/push/Service;1', 'nsIPushService');
 
-const pushServiceExports = ChromeUtils.import('resource://gre/modules/PushService.jsm', {});
-const broadcastServiceExports = ChromeUtils.import('resource://gre/modules/PushBroadcastService.jsm', {});
-const serviceExports = {...pushServiceExports, ...broadcastServiceExports};
+const serviceExports = ChromeUtils.import('resource://gre/modules/PushService.jsm', {});
 const servicePrefs = new Preferences('dom.push.');
 
 const WEBSOCKET_CLOSE_GOING_AWAY = 1001;
 
 const MS_IN_ONE_DAY = 24 * 60 * 60 * 1000;
 
 var isParent = Cc['@mozilla.org/xre/runtime;1']
                  .getService(Ci.nsIXULRuntime).processType ==
@@ -182,17 +180,16 @@ function compareAscending(a, b) {
  */
 function MockWebSocket(originalURI, handlers = {}) {
   this._originalURI = originalURI;
   this._onHello = handlers.onHello;
   this._onRegister = handlers.onRegister;
   this._onUnregister = handlers.onUnregister;
   this._onACK = handlers.onACK;
   this._onPing = handlers.onPing;
-  this._onBroadcastSubscribe = handlers.onBroadcastSubscribe;
 }
 
 MockWebSocket.prototype = {
   _originalURI: null,
   _onHello: null,
   _onRegister: null,
   _onUnregister: null,
   _onACK: null,
@@ -255,23 +252,16 @@ MockWebSocket.prototype = {
       if (typeof this._onPing == 'function') {
         this._onPing(request);
       } else {
         // Echo ping packets.
         this.serverSendMsg('{}');
       }
       break;
 
-    case 'broadcast_subscribe':
-      if (typeof this._onBroadcastSubscribe != 'function') {
-        throw new Error('Unexpected broadcast_subscribe');
-      }
-      this._onBroadcastSubscribe(request);
-      break;
-
     default:
       throw new Error('Unexpected message: ' + messageType);
     }
   },
 
   sendMsg(msg) {
     this._handleMessage(msg);
   },
--- a/dom/push/test/xpcshell/moz.build
+++ b/dom/push/test/xpcshell/moz.build
@@ -1,8 +1,4 @@
 EXTRA_COMPONENTS += [
     'PushServiceHandler.js',
     'PushServiceHandler.manifest',
 ]
-
-EXTRA_JS_MODULES += [
-    'broadcast_handler.jsm',
-]
deleted file mode 100644
--- a/dom/push/test/xpcshell/test_broadcast_success.js
+++ /dev/null
@@ -1,265 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-'use strict';
-
-const {PushDB, PushService, PushServiceWebSocket, pushBroadcastService: broadcastService} = serviceExports;
-const {BroadcastService} = ChromeUtils.import("resource://gre/modules/PushBroadcastService.jsm", {});
-ChromeUtils.import("resource://gre/modules/JSONFile.jsm");
-
-ChromeUtils.import("resource://testing-common/Assert.jsm");
-ChromeUtils.import("resource://testing-common/FileTestUtils.jsm");
-ChromeUtils.import("resource://test/broadcast_handler.jsm");
-
-const assert = new Assert();
-const userAgentID = 'bd744428-f125-436a-b6d0-dd0c9845837f';
-const channelID = '0ef2ad4a-6c49-41ad-af6e-95d2425276bf';
-
-function run_test() {
-  do_get_profile();
-  setPrefs({
-    userAgentID,
-    requestTimeout: 1000,
-    retryBaseInterval: 150
-  });
-  run_next_test();
-}
-
-function getPushServiceMock() {
-  return {
-    subscribed: [],
-    subscribeBroadcast: function(broadcastId, version) {
-      this.subscribed.push([broadcastId, version]);
-    },
-  };
-}
-
-add_task(async function test_register_success() {
-  await broadcastService._resetListeners();
-  let db = PushServiceWebSocket.newPushDB();
-  broadcastHandler.reset();
-  let notifications = broadcastHandler.notifications;
-  let socket;
-  registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
-
-  await broadcastService.addListener("broadcast-test", "2018-02-01", {
-    moduleURI: "resource://test/broadcast_handler.jsm",
-    symbolName: "broadcastHandler",
-  });
-
-  PushServiceWebSocket._generateID = () => channelID;
-
-  var broadcastSubscriptions = [];
-
-  await PushService.init({
-    serverURI: "wss://push.example.org/",
-    db,
-    makeWebSocket(uri) {
-      return new MockWebSocket(uri, {
-        onHello(data) {
-          socket = this;
-          deepEqual(data.broadcasts, {"broadcast-test": "2018-02-01"}, "Handshake: doesn't consult listeners");
-          equal(data.messageType, 'hello', 'Handshake: wrong message type');
-          equal(data.uaid, userAgentID, 'Handshake: wrong device ID');
-          this.serverSendMsg(JSON.stringify({
-            messageType: 'hello',
-            status: 200,
-            uaid: userAgentID
-          }));
-        },
-
-        onBroadcastSubscribe(data) {
-          broadcastSubscriptions.push(data);
-        },
-      });
-    }
-  })
-
-  socket.serverSendMsg(JSON.stringify({
-    messageType: "broadcast",
-    broadcasts: {
-      "broadcast-test": "2018-03-02"
-    }
-  }));
-
-  await broadcastHandler.wasNotified;
-
-  deepEqual(notifications, [["2018-03-02", "broadcast-test"]], "Broadcast notification didn't get delivered");
-
-  deepEqual(await broadcastService.getListeners(), {
-    "broadcast-test": "2018-03-02"
-  }, "Broadcast version wasn't updated");
-
-  await broadcastService.addListener("example-listener", "2018-03-01", {
-    moduleURI: "resource://gre/modules/not-real-example.jsm",
-    symbolName: "doesntExist"
-  });
-
-  deepEqual(broadcastSubscriptions, [{
-    messageType: "broadcast_subscribe",
-    broadcasts: {"example-listener": "2018-03-01"}
-  }]);
-});
-
-add_task(async function test_handle_hello_broadcasts() {
-  PushService.uninit();
-  await broadcastService._resetListeners();
-  let db = PushServiceWebSocket.newPushDB();
-  broadcastHandler.reset();
-  let notifications = broadcastHandler.notifications;
-  registerCleanupFunction(() => {return db.drop().then(_ => db.close());});
-
-  await broadcastService.addListener("broadcast-test", "2018-02-01", {
-    moduleURI: "resource://test/broadcast_handler.jsm",
-    symbolName: "broadcastHandler",
-  });
-
-  PushServiceWebSocket._generateID = () => channelID;
-
-  await PushService.init({
-    serverURI: "wss://push.example.org/",
-    db,
-    makeWebSocket(uri) {
-      return new MockWebSocket(uri, {
-        onHello(data) {
-          deepEqual(data.broadcasts, {"broadcast-test": "2018-02-01"}, "Handshake: doesn't consult listeners");
-          equal(data.messageType, 'hello', 'Handshake: wrong message type');
-          equal(data.uaid, userAgentID, 'Handshake: wrong device ID');
-          this.serverSendMsg(JSON.stringify({
-            messageType: 'hello',
-            status: 200,
-            uaid: userAgentID,
-            broadcasts: {
-              "broadcast-test": "2018-02-02"
-            }
-          }));
-        },
-
-        onBroadcastSubscribe(data) {
-          broadcastSubscriptions.push(data);
-        },
-      });
-    }
-  })
-
-  await broadcastHandler.wasNotified;
-
-  deepEqual(notifications, [["2018-02-02", "broadcast-test"]], "Broadcast notification on hello was delivered");
-
-  deepEqual(await broadcastService.getListeners(), {
-    "broadcast-test": "2018-02-02"
-  }, "Broadcast version wasn't updated");
-});
-
-add_task(async function test_broadcast_unit() {
-  const fakeListenersData = {
-    "abc": {
-      version: "2018-03-04",
-      sourceInfo: {
-        moduleURI: "resource://gre/modules/abc.jsm",
-        symbolName: "getAbc"
-      }
-    },
-    "def": {
-      version: "2018-04-05",
-      sourceInfo: {
-        moduleURI: "resource://gre/modules/def.jsm",
-        symbolName: "getDef"
-      }
-    }
-  };
-  const path = FileTestUtils.getTempFile("broadcast-listeners.json").path;
-
-  const jsonFile = new JSONFile({path});
-  jsonFile.data = {
-    listeners: fakeListenersData,
-  };
-  await jsonFile._save();
-
-  const pushServiceMock = getPushServiceMock();
-
-  const broadcastService = new BroadcastService(pushServiceMock, path);
-  const listeners = await broadcastService.getListeners();
-  deepEqual(listeners, {
-    "abc": "2018-03-04",
-    "def": "2018-04-05"
-  });
-
-  await broadcastService.addListener("ghi", "2018-05-06", {
-    moduleURI: "resource://gre/modules/ghi.jsm",
-    symbolName: "getGhi"
-  });
-
-  deepEqual(pushServiceMock.subscribed, [
-    ["ghi", "2018-05-06"]
-  ]);
-
-  await broadcastService._saveImmediately();
-
-  const newJSONFile = new JSONFile({path});
-  await newJSONFile.load();
-
-  deepEqual(newJSONFile.data, {
-    listeners: {
-      ...fakeListenersData,
-      ghi: {
-        version: "2018-05-06",
-        sourceInfo: {
-          moduleURI: "resource://gre/modules/ghi.jsm",
-          symbolName: "getGhi"
-        }
-      }
-    },
-    version: 1,
-  });
-
-  deepEqual(await broadcastService.getListeners(), {
-    "abc": "2018-03-04",
-    "def": "2018-04-05",
-    "ghi": "2018-05-06"
-  });
-});
-
-add_task(async function test_broadcast_initialize_sane() {
-  const path = FileTestUtils.getTempFile("broadcast-listeners.json").path;
-  const broadcastService = new BroadcastService(getPushServiceMock(), path);
-  deepEqual(await broadcastService.getListeners(), {}, "listeners should start out sane");
-  await broadcastService._saveImmediately();
-  let onDiskJSONFile = new JSONFile({path});
-  await onDiskJSONFile.load();
-  deepEqual(onDiskJSONFile.data, {listeners: {}, version: 1},
-            "written JSON file has listeners and version fields");
-
-  await broadcastService.addListener("ghi", "2018-05-06", {
-    moduleURI: "resource://gre/modules/ghi.jsm",
-    symbolName: "getGhi"
-  });
-
-  await broadcastService._saveImmediately();
-
-  onDiskJSONFile = new JSONFile({path});
-  await onDiskJSONFile.load();
-
-  deepEqual(onDiskJSONFile.data, {
-    listeners: {
-      ghi: {
-        version: "2018-05-06",
-        sourceInfo: {
-          moduleURI: "resource://gre/modules/ghi.jsm",
-          symbolName: "getGhi"
-        }
-      }
-    },
-    version: 1,
-  }, "adding listeners to initial state is written OK");
-});
-
-add_task(async function test_broadcast_reject_invalid_sourceinfo() {
-  const path = FileTestUtils.getTempFile("broadcast-listeners.json").path;
-  const broadcastService = new BroadcastService(getPushServiceMock(), path);
-
-  await assert.rejects(broadcastService.addListener("ghi", "2018-05-06", {
-      moduleName: "resource://gre/modules/ghi.jsm",
-      symbolName: "getGhi"
-  }), "missing moduleURI", "rejects sourceInfo that doesn't have moduleURI");
-});
--- a/dom/push/test/xpcshell/xpcshell.ini
+++ b/dom/push/test/xpcshell/xpcshell.ini
@@ -1,15 +1,13 @@
 [DEFAULT]
 head = head.js head-http2.js
 # Push notifications and alarms are currently disabled on Android.
 skip-if = toolkit == 'android'
-support-files = broadcast_handler.jsm
 
-[test_broadcast_success.js]
 [test_clear_forgetAboutSite.js]
 [test_clear_origin_data.js]
 [test_crypto.js]
 [test_crypto_encrypt.js]
 [test_drop_expired.js]
 [test_handler_service.js]
 support-files = PushServiceHandler.js PushServiceHandler.manifest
 [test_notification_ack.js]
--- a/services/settings/remote-settings.js
+++ b/services/settings/remote-settings.js
@@ -1,20 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-/* global __URI__ */
-
 "use strict";
 
 var EXPORTED_SYMBOLS = [
   "RemoteSettings",
-  "jexlFilterFunc",
-  "remoteSettingsBroadcastHandler",
+  "jexlFilterFunc"
 ];
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm", {});
 XPCOMUtils.defineLazyGlobalGetters(this, ["fetch", "indexedDB"]);
 
 ChromeUtils.defineModuleGetter(this, "Kinto",
@@ -24,18 +21,16 @@ ChromeUtils.defineModuleGetter(this, "Ki
 ChromeUtils.defineModuleGetter(this, "CanonicalJSON",
                                "resource://gre/modules/CanonicalJSON.jsm");
 ChromeUtils.defineModuleGetter(this, "UptakeTelemetry",
                                "resource://services-common/uptake-telemetry.js");
 ChromeUtils.defineModuleGetter(this, "ClientEnvironmentBase",
                                "resource://gre/modules/components-utils/ClientEnvironment.jsm");
 ChromeUtils.defineModuleGetter(this, "FilterExpressions",
                                "resource://gre/modules/components-utils/FilterExpressions.jsm");
-ChromeUtils.defineModuleGetter(this, "pushBroadcastService",
-                               "resource://gre/modules/PushBroadcastService.jsm");
 
 const PREF_SETTINGS_SERVER             = "services.settings.server";
 const PREF_SETTINGS_DEFAULT_BUCKET     = "services.settings.default_bucket";
 const PREF_SETTINGS_DEFAULT_SIGNER     = "services.settings.default_signer";
 const PREF_SETTINGS_VERIFY_SIGNATURE   = "services.settings.verify_signature";
 const PREF_SETTINGS_SERVER_BACKOFF     = "services.settings.server.backoff";
 const PREF_SETTINGS_CHANGES_PATH       = "services.settings.changes.path";
 const PREF_SETTINGS_LAST_UPDATE        = "services.settings.last_update_seconds";
@@ -733,28 +728,12 @@ function remoteSettingsFunction() {
     // Save current Etag for next poll.
     if (currentEtag) {
       Services.prefs.setCharPref(PREF_SETTINGS_LAST_ETAG, currentEtag);
     }
 
     Services.obs.notifyObservers(null, "remote-settings-changes-polled");
   };
 
-
-  const broadcastID = "remote-settings/monitor_changes";
-  const currentVersion = Services.prefs.getStringValue(PREF_SETTINGS_LAST_ETAG, "");
-  const moduleInfo = {
-    moduleURI: __URI__,
-    symbolName: "remoteSettingsBroadcastHandler",
-  };
-  pushBroadcastService.addListener(broadcastID, currentVersion,
-                                   moduleInfo);
-
   return remoteSettings;
 }
 
 var RemoteSettings = remoteSettingsFunction();
-
-var remoteSettingsBroadcastHandler = {
-  async receivedBroadcastMessage(data, broadcastID) {
-    return RemoteSettings.pollChanges();
-  }
-};