Bug 864484 - Part 2: Replace CellBroadcastProvider with CellBroadcastService. r=vyang
authorBevis Tseng <btseng@mozilla.com>
Wed, 13 Aug 2014 18:28:34 +0800
changeset 230974 fe5ef66ed15d1e3174a4ac2d88a9ad434ab838a0
parent 230973 37fc37deaf33097e7d0a3bf853e88392658346d3
child 230975 4090b8c651ab9bf642abeaee2ebe20563adac1ad
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvyang
bugs864484
milestone35.0a1
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
Bug 864484 - Part 2: Replace CellBroadcastProvider with CellBroadcastService. r=vyang
dom/cellbroadcast/CellBroadcast.cpp
dom/cellbroadcast/CellBroadcast.h
dom/cellbroadcast/interfaces/moz.build
dom/cellbroadcast/interfaces/nsICellBroadcastProvider.idl
dom/cellbroadcast/interfaces/nsICellBroadcastService.idl
dom/system/gonk/RILContentHelper.js
dom/system/gonk/RadioInterfaceLayer.js
--- a/dom/cellbroadcast/CellBroadcast.cpp
+++ b/dom/cellbroadcast/CellBroadcast.cpp
@@ -4,17 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "CellBroadcast.h"
 #include "mozilla/dom/MozCellBroadcastBinding.h"
 #include "mozilla/dom/MozCellBroadcastEvent.h"
 #include "nsIDOMMozCellBroadcastMessage.h"
 #include "nsServiceManagerUtils.h"
 
-#define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1"
+#define NS_CELLBROADCASTSERVICE_CONTRACTID "@mozilla.org/cellbroadcast/gonkservice;1"
 
 using namespace mozilla::dom;
 
 /**
  * CellBroadcast::Listener Implementation.
  */
 
 class CellBroadcast::Listener MOZ_FINAL : public nsICellBroadcastListener
@@ -53,44 +53,49 @@ NS_IMPL_ISUPPORTS(CellBroadcast::Listene
 
 // static
 already_AddRefed<CellBroadcast>
 CellBroadcast::Create(nsPIDOMWindow* aWindow, ErrorResult& aRv)
 {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(aWindow->IsInnerWindow());
 
-  nsCOMPtr<nsICellBroadcastProvider> provider =
-    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
-  if (!provider) {
+  nsCOMPtr<nsICellBroadcastService> service =
+    do_GetService(NS_CELLBROADCASTSERVICE_CONTRACTID);
+  if (!service) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return nullptr;
   }
 
-  nsRefPtr<CellBroadcast> cb = new CellBroadcast(aWindow, provider);
+  nsRefPtr<CellBroadcast> cb = new CellBroadcast(aWindow, service);
   return cb.forget();
 }
 
 CellBroadcast::CellBroadcast(nsPIDOMWindow *aWindow,
-                             nsICellBroadcastProvider *aProvider)
+                             nsICellBroadcastService *aService)
   : DOMEventTargetHelper(aWindow)
-  , mProvider(aProvider)
 {
   mListener = new Listener(this);
-  DebugOnly<nsresult> rv = mProvider->RegisterCellBroadcastMsg(mListener);
+  DebugOnly<nsresult> rv = aService->RegisterListener(mListener);
   NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
-                   "Failed registering Cell Broadcast callback with provider");
+                   "Failed registering Cell Broadcast callback");
 }
 
 CellBroadcast::~CellBroadcast()
 {
-  MOZ_ASSERT(mProvider && mListener);
+  MOZ_ASSERT(mListener);
 
   mListener->Disconnect();
-  mProvider->UnregisterCellBroadcastMsg(mListener);
+  nsCOMPtr<nsICellBroadcastService> service =
+    do_GetService(NS_CELLBROADCASTSERVICE_CONTRACTID);
+  if (service) {
+    service->UnregisterListener(mListener);
+  }
+
+  mListener = nullptr;
 }
 
 NS_IMPL_ISUPPORTS_INHERITED0(CellBroadcast, DOMEventTargetHelper)
 
 JSObject*
 CellBroadcast::WrapObject(JSContext* aCx)
 {
   return MozCellBroadcastBinding::Wrap(aCx, this);
--- a/dom/cellbroadcast/CellBroadcast.h
+++ b/dom/cellbroadcast/CellBroadcast.h
@@ -4,31 +4,31 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_CellBroadcast_h__
 #define mozilla_dom_CellBroadcast_h__
 
 #include "mozilla/Attributes.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/ErrorResult.h"
-#include "nsICellBroadcastProvider.h"
+#include "nsICellBroadcastService.h"
 #include "js/TypeDecls.h"
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class CellBroadcast MOZ_FINAL : public DOMEventTargetHelper,
                                 private nsICellBroadcastListener
 {
   /**
    * Class CellBroadcast doesn't actually expose nsICellBroadcastListener.
    * Instead, it owns an nsICellBroadcastListener derived instance mListener
-   * and passes it to nsICellBroadcastProvider. The onreceived events are first
+   * and passes it to nsICellBroadcastService. The onreceived events are first
    * delivered to mListener and then forwarded to its owner, CellBroadcast. See
    * also bug 775997 comment #51.
    */
   class Listener;
 
   // MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
   ~CellBroadcast();
 
@@ -38,27 +38,26 @@ public:
 
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
 
   static already_AddRefed<CellBroadcast>
   Create(nsPIDOMWindow* aOwner, ErrorResult& aRv);
 
   CellBroadcast() MOZ_DELETE;
   CellBroadcast(nsPIDOMWindow *aWindow,
-                nsICellBroadcastProvider* aProvider);
+                nsICellBroadcastService* aService);
 
   nsPIDOMWindow*
   GetParentObject() const { return GetOwner(); }
 
   virtual JSObject*
   WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   IMPL_EVENT_HANDLER(received)
 
 private:
-  nsCOMPtr<nsICellBroadcastProvider> mProvider;
   nsRefPtr<Listener> mListener;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_CellBroadcast_h__ */
--- a/dom/cellbroadcast/interfaces/moz.build
+++ b/dom/cellbroadcast/interfaces/moz.build
@@ -1,16 +1,15 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 XPIDL_SOURCES += [
-    'nsICellBroadcastProvider.idl',
     'nsICellBroadcastService.idl',
     'nsIDOMMozCellBroadcastMessage.idl',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_B2G_RIL']:
     XPIDL_SOURCES += [
         'nsIGonkCellBroadcastService.idl',
     ]
deleted file mode 100644
--- a/dom/cellbroadcast/interfaces/nsICellBroadcastProvider.idl
+++ /dev/null
@@ -1,35 +0,0 @@
-/* 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/. */
-
-#include "nsISupports.idl"
-
-interface nsIDOMMozCellBroadcastMessage;
-
-[scriptable, uuid(4c6fb794-31bd-4ed7-b21a-34b82aa3efbe)]
-interface nsICellBroadcastListener : nsISupports
-{
-  /**
-   * Called when a Cell Broadcast message has been received by the network.
-   *
-   * @param message
-   *        The received Cell Broadcast Message.
-   */
-  void notifyMessageReceived(in nsIDOMMozCellBroadcastMessage message);
-};
-
-/**
- * XPCOM component (in the content process) that provides the cell broadcast
- * information.
- */
-[scriptable, uuid(e6c01d18-829e-4d5a-9611-60fca36e6b46)]
-interface nsICellBroadcastProvider : nsISupports
-{
-  /**
-   * Called when a content process registers receiving unsolicited messages from
-   * RadioInterfaceLayer in the chrome process. Only a content process that has
-   * the 'cellbroadcast' permission is allowed to register.
-   */
-  void registerCellBroadcastMsg(in nsICellBroadcastListener listener);
-  void unregisterCellBroadcastMsg(in nsICellBroadcastListener listener);
-};
--- a/dom/cellbroadcast/interfaces/nsICellBroadcastService.idl
+++ b/dom/cellbroadcast/interfaces/nsICellBroadcastService.idl
@@ -1,16 +1,27 @@
 /* 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/. */
 
 #include "nsISupports.idl"
 
 interface nsIDOMMozCellBroadcastMessage;
-interface nsICellBroadcastListener;
+
+[scriptable, uuid(e70bb4cc-2297-11e4-aecd-9f8fb3d2b646)]
+interface nsICellBroadcastListener : nsISupports
+{
+  /**
+   * Called when a Cell Broadcast message has been received by the network.
+   *
+   * @param message
+   *        The received Cell Broadcast Message.
+   */
+  void notifyMessageReceived(in nsIDOMMozCellBroadcastMessage message);
+};
 
 /**
  * XPCOM component that provides the cell broadcast information.
  */
 [scriptable, uuid(05099b34-21f7-11e4-b3b9-1b1b03487cab)]
 interface nsICellBroadcastService : nsISupports
 {
   /**
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -42,31 +42,26 @@ function debug(s) {
 const RILCONTENTHELPER_CID =
   Components.ID("{472816e1-1fd6-4405-996c-806f9ea68174}");
 const ICCINFO_CID =
   Components.ID("{39d64d90-26a6-11e4-8c21-0800200c9a66}");
 const GSMICCINFO_CID =
   Components.ID("{e0fa785b-ad3f-46ed-bc56-fcb0d6fe4fa8}");
 const CDMAICCINFO_CID =
   Components.ID("{3d1f844f-9ec5-48fb-8907-aed2e5421709}");
-const CELLBROADCASTMESSAGE_CID =
-  Components.ID("{29474c96-3099-486f-bb4a-3c9a1da834e4}");
-const CELLBROADCASTETWSINFO_CID =
-  Components.ID("{59f176ee-9dcd-4005-9d47-f6be0cd08e17}");
 const ICCCARDLOCKERROR_CID =
   Components.ID("{08a71987-408c-44ff-93fd-177c0a85c3dd}");
 
 const RIL_IPC_MSG_NAMES = [
   "RIL:CardStateChanged",
   "RIL:IccInfoChanged",
   "RIL:CardLockResult",
   "RIL:CardLockRetryCount",
   "RIL:StkCommand",
   "RIL:StkSessionEnd",
-  "RIL:CellBroadcastReceived",
   "RIL:IccOpenChannel",
   "RIL:IccCloseChannel",
   "RIL:IccExchangeAPDU",
   "RIL:ReadIccContacts",
   "RIL:UpdateIccContact",
   "RIL:MatchMvno"
 ];
 
@@ -163,81 +158,16 @@ CdmaIccInfo.prototype = {
   }),
 
   // nsIDOMMozCdmaIccInfo
 
   mdn: null,
   prlVersion: 0
 };
 
-function CellBroadcastMessage(clientId, pdu) {
-  this.serviceId = clientId;
-  this.gsmGeographicalScope = RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[pdu.geographicalScope];
-  this.messageCode = pdu.messageCode;
-  this.messageId = pdu.messageId;
-  this.language = pdu.language;
-  this.body = pdu.fullBody;
-  this.messageClass = pdu.messageClass;
-  this.timestamp = pdu.timestamp;
-
-  if (pdu.etws != null) {
-    this.etws = new CellBroadcastEtwsInfo(pdu.etws);
-  }
-
-  this.cdmaServiceCategory = pdu.serviceCategory;
-}
-CellBroadcastMessage.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozCellBroadcastMessage]),
-  classID:        CELLBROADCASTMESSAGE_CID,
-  classInfo:      XPCOMUtils.generateCI({
-    classID:          CELLBROADCASTMESSAGE_CID,
-    classDescription: "CellBroadcastMessage",
-    flags:            Ci.nsIClassInfo.DOM_OBJECT,
-    interfaces:       [Ci.nsIDOMMozCellBroadcastMessage]
-  }),
-
-  // nsIDOMMozCellBroadcastMessage
-  serviceId: -1,
-
-  gsmGeographicalScope: null,
-  messageCode: null,
-  messageId: null,
-  language: null,
-  body: null,
-  messageClass: null,
-  timestamp: null,
-
-  etws: null,
-  cdmaServiceCategory: null
-};
-
-function CellBroadcastEtwsInfo(etwsInfo) {
-  if (etwsInfo.warningType != null) {
-    this.warningType = RIL.CB_ETWS_WARNING_TYPE_NAMES[etwsInfo.warningType];
-  }
-  this.emergencyUserAlert = etwsInfo.emergencyUserAlert;
-  this.popup = etwsInfo.popup;
-}
-CellBroadcastEtwsInfo.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozCellBroadcastEtwsInfo]),
-  classID:        CELLBROADCASTETWSINFO_CID,
-  classInfo:      XPCOMUtils.generateCI({
-    classID:          CELLBROADCASTETWSINFO_CID,
-    classDescription: "CellBroadcastEtwsInfo",
-    flags:            Ci.nsIClassInfo.DOM_OBJECT,
-    interfaces:       [Ci.nsIDOMMozCellBroadcastEtwsInfo]
-  }),
-
-  // nsIDOMMozCellBroadcastEtwsInfo
-
-  warningType: null,
-  emergencyUserAlert: null,
-  popup: null
-};
-
 function IccCardLockError() {
 }
 IccCardLockError.prototype = {
   classDescription: "IccCardLockError",
   classID:          ICCCARDLOCKERROR_CID,
   contractID:       "@mozilla.org/dom/icccardlock-error;1",
   QueryInterface:   XPCOMUtils.generateQI([Ci.nsISupports]),
   __init: function(lockType, errorMsg, retryCount) {
@@ -258,36 +188,33 @@ function RILContentHelper() {
     this.rilContexts[clientId] = {
       cardState:            RIL.GECKO_CARDSTATE_UNKNOWN,
       iccInfo:              null
     };
   }
 
   this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES);
   this._windowsMap = [];
-  this._cellBroadcastListeners = [];
   this._iccListeners = [];
 
   Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
 
   Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false);
 }
 
 RILContentHelper.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsICellBroadcastProvider,
-                                         Ci.nsIIccProvider,
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccProvider,
                                          Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference]),
   classID:   RILCONTENTHELPER_CID,
   classInfo: XPCOMUtils.generateCI({classID: RILCONTENTHELPER_CID,
                                     classDescription: "RILContentHelper",
-                                    interfaces: [Ci.nsICellBroadcastProvider,
-                                                 Ci.nsIIccProvider]}),
+                                    interfaces: [Ci.nsIIccProvider]}),
 
   updateDebugFlag: function() {
     try {
       DEBUG = RIL.DEBUG_CONTENT_HELPER ||
               Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
     } catch (e) {}
   },
 
@@ -633,17 +560,16 @@ RILContentHelper.prototype = {
         contact: iccContact,
         pin2: pin2
       }
     });
 
     return request;
   },
 
-  _cellBroadcastListeners: null,
   _iccListeners: null,
 
   registerListener: function(listenerType, clientId, listener) {
     if (!this[listenerType]) {
       return;
     }
     let listeners = this[listenerType][clientId];
     if (!listeners) {
@@ -669,32 +595,16 @@ RILContentHelper.prototype = {
 
     let index = listeners.indexOf(listener);
     if (index != -1) {
       listeners.splice(index, 1);
       if (DEBUG) debug("Unregistered listener: " + listener);
     }
   },
 
-  registerCellBroadcastMsg: function(listener) {
-    if (DEBUG) debug("Registering for Cell Broadcast related messages");
-    // Instead of registering multiple listeners for Multi-SIM, we reuse
-    // clientId 0 to route all CBS messages to single listener and provide the
-    // |clientId| info by |CellBroadcastMessage.serviceId|.
-    this.registerListener("_cellBroadcastListeners", 0, listener);
-    cpmm.sendAsyncMessage("RIL:RegisterCellBroadcastMsg");
-  },
-
-  unregisterCellBroadcastMsg: function(listener) {
-    // Instead of unregistering multiple listeners for Multi-SIM, we reuse
-    // clientId 0 to route all CBS messages to single listener and provide the
-    // |clientId| info by |CellBroadcastMessage.serviceId|.
-    this.unregisterListener("_cellBroadcastListeners", 0, listener);
-  },
-
   registerIccMsg: function(clientId, listener) {
     if (DEBUG) debug("Registering for ICC related messages");
     this.registerListener("_iccListeners", clientId, listener);
     cpmm.sendAsyncMessage("RIL:RegisterIccMsg");
   },
 
   unregisterIccMsg: function(clientId, listener) {
     this.unregisterListener("_iccListeners", clientId, listener);
@@ -855,26 +765,16 @@ RILContentHelper.prototype = {
         this.handleReadIccContacts(data);
         break;
       case "RIL:UpdateIccContact":
         this.handleUpdateIccContact(data);
         break;
       case "RIL:MatchMvno":
         this.handleSimpleRequest(data.requestId, data.errorMsg, data.result);
         break;
-      case "RIL:CellBroadcastReceived": {
-        // All CBS messages are to routed the listener for clientId 0 and
-        // provide the |clientId| info by |CellBroadcastMessage.serviceId|.
-        let message = new CellBroadcastMessage(clientId, data);
-        this._deliverEvent(0, // route to clientId 0.
-                           "_cellBroadcastListeners",
-                           "notifyMessageReceived",
-                           [message]);
-        break;
-      }
     }
   },
 
   handleSimpleRequest: function(requestId, errorMsg, result) {
     if (errorMsg) {
       this.fireRequestError(requestId, errorMsg);
     } else {
       this.fireRequestSuccess(requestId, result);
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -122,20 +122,16 @@ const RIL_IPC_ICCMANAGER_MSG_NAMES = [
   "RIL:IccExchangeAPDU",
   "RIL:IccCloseChannel",
   "RIL:ReadIccContacts",
   "RIL:UpdateIccContact",
   "RIL:RegisterIccMsg",
   "RIL:MatchMvno"
 ];
 
-const RIL_IPC_CELLBROADCAST_MSG_NAMES = [
-  "RIL:RegisterCellBroadcastMsg"
-];
-
 // set to true in ril_consts.js to see debug messages
 var DEBUG = RIL.DEBUG_RIL;
 
 function updateDebugFlag() {
   // Read debug setting from pref
   let debugPref;
   try {
     debugPref = Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
@@ -193,16 +189,20 @@ XPCOMUtils.defineLazyServiceGetter(this,
 XPCOMUtils.defineLazyServiceGetter(this, "gTelephonyService",
                                    "@mozilla.org/telephony/telephonyservice;1",
                                    "nsIGonkTelephonyService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
                                    "@mozilla.org/mobileconnection/mobileconnectionservice;1",
                                    "nsIGonkMobileConnectionService");
 
+XPCOMUtils.defineLazyServiceGetter(this, "gCellBroadcastService",
+                                   "@mozilla.org/cellbroadcast/gonkservice;1",
+                                   "nsIGonkCellBroadcastService");
+
 XPCOMUtils.defineLazyGetter(this, "WAP", function() {
   let wap = {};
   Cu.import("resource://gre/modules/WapPushManager.js", wap);
   return wap;
 });
 
 XPCOMUtils.defineLazyGetter(this, "PhoneNumberUtils", function() {
   let ns = {};
@@ -240,29 +240,23 @@ XPCOMUtils.defineLazyGetter(this, "gMess
       this._unregisterMessageListeners();
     },
 
     _registerMessageListeners: function() {
       ppmm.addMessageListener("child-process-shutdown", this);
       for (let msgName of RIL_IPC_ICCMANAGER_MSG_NAMES) {
         ppmm.addMessageListener(msgName, this);
       }
-      for (let msgname of RIL_IPC_CELLBROADCAST_MSG_NAMES) {
-        ppmm.addMessageListener(msgname, this);
-      }
     },
 
     _unregisterMessageListeners: function() {
       ppmm.removeMessageListener("child-process-shutdown", this);
       for (let msgName of RIL_IPC_ICCMANAGER_MSG_NAMES) {
         ppmm.removeMessageListener(msgName, this);
       }
-      for (let msgname of RIL_IPC_CELLBROADCAST_MSG_NAMES) {
-        ppmm.removeMessageListener(msgname, this);
-      }
       ppmm = null;
     },
 
     _registerMessageTarget: function(topic, target) {
       let targets = this.targetsByTopic[topic];
       if (!targets) {
         targets = this.targetsByTopic[topic] = [];
         let list = this.topics;
@@ -368,36 +362,25 @@ XPCOMUtils.defineLazyGetter(this, "gMess
       if (RIL_IPC_ICCMANAGER_MSG_NAMES.indexOf(msg.name) != -1) {
         if (!msg.target.assertPermission("mobileconnection")) {
           if (DEBUG) {
             debug("IccManager message " + msg.name +
                   " from a content process with no 'mobileconnection' privileges.");
           }
           return null;
         }
-      } else if (RIL_IPC_CELLBROADCAST_MSG_NAMES.indexOf(msg.name) != -1) {
-        if (!msg.target.assertPermission("cellbroadcast")) {
-          if (DEBUG) {
-            debug("Cell Broadcast message " + msg.name +
-                  " from a content process with no 'cellbroadcast' privileges.");
-          }
-          return null;
-        }
       } else {
         if (DEBUG) debug("Ignoring unknown message type: " + msg.name);
         return null;
       }
 
       switch (msg.name) {
         case "RIL:RegisterIccMsg":
           this._registerMessageTarget("icc", msg.target);
           return null;
-        case "RIL:RegisterCellBroadcastMsg":
-          this._registerMessageTarget("cellbroadcast", msg.target);
-          return null;
       }
 
       let clientId = msg.json.clientId || 0;
       let radioInterface = this.ril.getRadioInterface(clientId);
       if (!radioInterface) {
         if (DEBUG) debug("No such radio interface: " + clientId);
         return null;
       }
@@ -423,23 +406,16 @@ XPCOMUtils.defineLazyGetter(this, "gMess
 
     sendMobileConnectionMessage: function(message, clientId, data) {
       this._sendTargetMessage("mobileconnection", message, {
         clientId: clientId,
         data: data
       });
     },
 
-    sendCellBroadcastMessage: function(message, clientId, data) {
-      this._sendTargetMessage("cellbroadcast", message, {
-        clientId: clientId,
-        data: data
-      });
-    },
-
     sendIccMessage: function(message, clientId, data) {
       this._sendTargetMessage("icc", message, {
         clientId: clientId,
         data: data
       });
     }
   };
 });
@@ -2125,18 +2101,17 @@ RadioInterface.prototype = {
                                        this.clientId, message);
         break;
       case "sms-received":
         this.handleSmsMultipart(message);
         break;
       case "cellbroadcast-received":
         message.timestamp = Date.now();
         this.broadcastCbsSystemMessage(message);
-        gMessageManager.sendCellBroadcastMessage("RIL:CellBroadcastReceived",
-                                                 this.clientId, message);
+        this.handleCellbroadcastMessageReceived(message);
         break;
       case "nitzTime":
         this.handleNitzTime(message);
         break;
       case "iccinfochange":
         this.handleIccInfoChange(message);
         break;
       case "iccimsi":
@@ -2656,18 +2631,17 @@ RadioInterface.prototype = {
     }
   },
 
   portAddressedSmsApps: null,
   handleSmsReceived: function(message) {
     if (DEBUG) this.debug("handleSmsReceived: " + JSON.stringify(message));
 
     if (message.messageType == RIL.PDU_CDMA_MSG_TYPE_BROADCAST) {
-      gMessageManager.sendCellBroadcastMessage("RIL:CellBroadcastReceived",
-                                               this.clientId, message);
+      this.handleCellbroadcastMessageReceived(message);
       return true;
     }
 
     // Dispatch to registered handler if application port addressing is
     // available. Note that the destination port can possibly be zero when
     // representing a UDP/TCP port.
     if (message.destinationPort != null) {
       let handler = this.portAddressedSmsApps[message.destinationPort];
@@ -3008,16 +2982,41 @@ RadioInterface.prototype = {
     if (iccId) {
       gSystemMessenger.broadcastMessage("icc-stkcommand",
                                         {iccId: iccId,
                                          command: message});
     }
     gMessageManager.sendIccMessage("RIL:StkCommand", this.clientId, message);
   },
 
+  handleCellbroadcastMessageReceived: function(aMessage) {
+    let etwsInfo = aMessage.etws;
+    let hasEtwsInfo = etwsInfo != null;
+    let serviceCategory = (aMessage.serviceCategory)
+      ? aMessage.serviceCategory
+      : Ci.nsICellBroadcastService.CDMA_SERVICE_CATEGORY_INVALID;
+
+    gCellBroadcastService
+      .notifyMessageReceived(this.clientId,
+                             RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[aMessage.geographicalScope],
+                             aMessage.messageCode,
+                             aMessage.messageId,
+                             aMessage.language,
+                             aMessage.fullBody,
+                             aMessage.messageClass,
+                             aMessage.timestamp,
+                             serviceCategory,
+                             hasEtwsInfo,
+                             (hasEtwsInfo && etwsInfo.warningType != null)
+                               ? RIL.CB_ETWS_WARNING_TYPE_NAMES[etwsInfo.warningType]
+                               : null,
+                             hasEtwsInfo ? etwsInfo.emergencyUserAlert : false,
+                             hasEtwsInfo ? etwsInfo.popup : false);
+  },
+
   // nsIObserver
 
   observe: function(subject, topic, data) {
     switch (topic) {
       case kMozSettingsChangedObserverTopic:
         if ("wrappedJSObject" in subject) {
           subject = subject.wrappedJSObject;
         }