Bug 1087847 - Make sure the Icc status in MobileConnection and IccManager are synced. r=hsinyi,smaug
authorEdgar Chen <echen@mozilla.com>
Thu, 13 Nov 2014 19:12:11 +0800
changeset 238076 8f1c3e86aa200c6fa9275949056ee3a9e4433774
parent 238075 e4f547bcdf87f6e685e282335fe6ceca967ed3bc
child 238077 d72e42ac4706f92034ac8d095704462f517e9e8e
push id7472
push userraliiev@mozilla.com
push dateMon, 12 Jan 2015 20:36:27 +0000
treeherdermozilla-aurora@300ca104f8fb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewershsinyi, smaug
bugs1087847
milestone37.0a1
Bug 1087847 - Make sure the Icc status in MobileConnection and IccManager are synced. r=hsinyi,smaug
dom/bluetooth/BluetoothRilListener.cpp
dom/bluetooth2/BluetoothRilListener.cpp
dom/icc/IccManager.cpp
dom/icc/IccManager.h
dom/icc/tests/marionette/test_icc_detected_undetected_event.js
dom/mobileconnection/MobileConnection.cpp
dom/mobileconnection/MobileConnection.h
dom/mobileconnection/gonk/MobileConnectionService.js
dom/mobileconnection/gonk/nsIGonkMobileConnectionService.idl
dom/mobileconnection/interfaces/nsIMobileConnectionService.idl
dom/mobileconnection/ipc/MobileConnectionChild.cpp
dom/mobileconnection/ipc/MobileConnectionChild.h
dom/mobileconnection/ipc/MobileConnectionParent.cpp
dom/mobileconnection/ipc/MobileConnectionParent.h
dom/mobileconnection/ipc/PMobileConnection.ipdl
dom/mobileconnection/moz.build
dom/mobileconnection/tests/marionette/test_mobile_icc_change.js
dom/system/gonk/RadioInterfaceLayer.js
--- a/dom/bluetooth/BluetoothRilListener.cpp
+++ b/dom/bluetooth/BluetoothRilListener.cpp
@@ -126,22 +126,16 @@ MobileConnectionListener::NotifyEmergenc
 
 NS_IMETHODIMP
 MobileConnectionListener::NotifyOtaStatusChanged(const nsAString & status)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-MobileConnectionListener::NotifyIccChanged()
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 MobileConnectionListener::NotifyRadioStateChanged()
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MobileConnectionListener::NotifyClirModeChanged(uint32_t aMode)
 {
--- a/dom/bluetooth2/BluetoothRilListener.cpp
+++ b/dom/bluetooth2/BluetoothRilListener.cpp
@@ -126,22 +126,16 @@ MobileConnectionListener::NotifyEmergenc
 
 NS_IMETHODIMP
 MobileConnectionListener::NotifyOtaStatusChanged(const nsAString & status)
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
-MobileConnectionListener::NotifyIccChanged()
-{
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 MobileConnectionListener::NotifyRadioStateChanged()
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MobileConnectionListener::NotifyClirModeChanged(uint32_t aMode)
 {
--- a/dom/icc/IccManager.cpp
+++ b/dom/icc/IccManager.cpp
@@ -1,16 +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/. */
 
 #include "IccManager.h"
 #include "mozilla/dom/MozIccManagerBinding.h"
 #include "Icc.h"
 #include "IccListener.h"
+#include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/dom/IccChangeEvent.h"
 #include "mozilla/Preferences.h"
 #include "nsIIccInfo.h"
 
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IccManager)
 
@@ -69,34 +70,42 @@ IccManager::NotifyIccAdd(const nsAString
 
   IccChangeEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
   init.mIccId = aIccId;
 
   nsRefPtr<IccChangeEvent> event =
     IccChangeEvent::Constructor(this, NS_LITERAL_STRING("iccdetected"), init);
+  event->SetTrusted(true);
 
-  return DispatchTrustedEvent(event);
+  nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
+    new AsyncEventDispatcher(this, event);
+
+  return asyncDispatcher->PostDOMEvent();
 }
 
 nsresult
 IccManager::NotifyIccRemove(const nsAString& aIccId)
 {
   MozIccManagerBinding::ClearCachedIccIdsValue(this);
 
   IccChangeEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
   init.mIccId = aIccId;
 
   nsRefPtr<IccChangeEvent> event =
     IccChangeEvent::Constructor(this, NS_LITERAL_STRING("iccundetected"), init);
+  event->SetTrusted(true);
 
-  return DispatchTrustedEvent(event);
+  nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
+    new AsyncEventDispatcher(this, event);
+
+  return asyncDispatcher->PostDOMEvent();
 }
 
 // MozIccManager
 
 void
 IccManager::GetIccIds(nsTArray<nsString>& aIccIds)
 {
   nsTArray<nsRefPtr<IccListener>>::size_type i;
--- a/dom/icc/IccManager.h
+++ b/dom/icc/IccManager.h
@@ -8,18 +8,18 @@
 #include "mozilla/DOMEventTargetHelper.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIIccProvider.h"
 #include "nsTArrayHelpers.h"
 
 namespace mozilla {
 namespace dom {
 
+class Icc;
 class IccListener;
-class Icc;
 
 class IccManager MOZ_FINAL : public DOMEventTargetHelper
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
 
--- a/dom/icc/tests/marionette/test_icc_detected_undetected_event.js
+++ b/dom/icc/tests/marionette/test_icc_detected_undetected_event.js
@@ -29,16 +29,20 @@ taskHelper.push(function testIccUndetect
     iccManager.removeEventListener("iccundetected", oniccundetected);
 
     is(evt.iccId, iccId, "icc " + evt.iccId + " becomes undetected");
     is(iccManager.iccIds.length, origNumICCs - 1,
        "iccIds.length becomes to " + iccManager.iccIds.length);
     is(iccManager.getIccById(evt.iccId), null,
        "should not get a valid icc object here");
 
+    // The mozMobileConnection.iccId should be in sync.
+    is(navigator.mozMobileConnections[0].iccId, null,
+       "check mozMobileConnection.iccId");
+
     taskHelper.runNext();
   });
 });
 
 /* Test iccdetected event */
 taskHelper.push(function testIccDetectedEvent() {
   setRadioEnabled(true);
   iccManager.addEventListener("iccdetected", function oniccdetected(evt) {
@@ -46,14 +50,18 @@ taskHelper.push(function testIccDetected
     iccManager.removeEventListener("iccdetected", oniccdetected);
 
     is(evt.iccId, iccId, "icc " + evt.iccId + " is detected");
     is(iccManager.iccIds.length, origNumICCs,
        "iccIds.length becomes to " + iccManager.iccIds.length);
     ok(iccManager.getIccById(evt.iccId) instanceof MozIcc,
        "should get a valid icc object here");
 
+    // The mozMobileConnection.iccId should be in sync.
+    is(navigator.mozMobileConnections[0].iccId, iccId,
+       "check mozMobileConnection.iccId");
+
     taskHelper.runNext();
   });
 });
 
 // Start test
 taskHelper.runNext();
--- a/dom/mobileconnection/MobileConnection.cpp
+++ b/dom/mobileconnection/MobileConnection.cpp
@@ -1,30 +1,36 @@
 /* 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 "mozilla/dom/MobileConnection.h"
 
 #include "MobileConnectionCallback.h"
+#include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/dom/CFStateChangeEvent.h"
 #include "mozilla/dom/DataErrorEvent.h"
 #include "mozilla/dom/MozClirModeEvent.h"
 #include "mozilla/dom/MozEmergencyCbModeEvent.h"
 #include "mozilla/dom/MozOtaStatusEvent.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "nsIDOMDOMRequest.h"
 #include "nsIPermissionManager.h"
 #include "nsIVariant.h"
 #include "nsJSON.h"
 #include "nsJSUtils.h"
+#include "nsRadioInterfaceLayer.h"
 #include "nsServiceManagerUtils.h"
 
+#ifdef MOZ_B2G_RIL
+#include "nsIIccInfo.h"
+#endif // MOZ_B2G_RIL
+
 #define MOBILECONN_ERROR_INVALID_PARAMETER NS_LITERAL_STRING("InvalidParameter")
 #define MOBILECONN_ERROR_INVALID_PASSWORD  NS_LITERAL_STRING("InvalidPassword")
 
 #ifdef CONVERT_STRING_TO_NULLABLE_ENUM
 #undef CONVERT_STRING_TO_NULLABLE_ENUM
 #endif
 #define CONVERT_STRING_TO_NULLABLE_ENUM(_string, _enumType, _enum)      \
 {                                                                       \
@@ -38,22 +44,28 @@
   }                                                                     \
 }
 
 using mozilla::ErrorResult;
 using namespace mozilla::dom;
 using namespace mozilla::dom::mobileconnection;
 
 class MobileConnection::Listener MOZ_FINAL : public nsIMobileConnectionListener
+#ifdef MOZ_B2G_RIL
+                                           , public nsIIccListener
+#endif // MOZ_B2G_RIL
 {
   MobileConnection* mMobileConnection;
 
 public:
   NS_DECL_ISUPPORTS
   NS_FORWARD_SAFE_NSIMOBILECONNECTIONLISTENER(mMobileConnection)
+#ifdef MOZ_B2G_RIL
+  NS_FORWARD_SAFE_NSIICCLISTENER(mMobileConnection)
+#endif // MOZ_B2G_RIL
 
   explicit Listener(MobileConnection* aMobileConnection)
     : mMobileConnection(aMobileConnection)
   {
     MOZ_ASSERT(mMobileConnection);
   }
 
   void Disconnect()
@@ -64,17 +76,22 @@ public:
 
 private:
   ~Listener()
   {
     MOZ_ASSERT(!mMobileConnection);
   }
 };
 
+#ifdef MOZ_B2G_RIL
+NS_IMPL_ISUPPORTS(MobileConnection::Listener, nsIMobileConnectionListener,
+                  nsIIccListener)
+#else
 NS_IMPL_ISUPPORTS(MobileConnection::Listener, nsIMobileConnectionListener)
+#endif // MOZ_B2G_RIL
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(MobileConnection)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MobileConnection,
                                                   DOMEventTargetHelper)
   // Don't traverse mListener because it doesn't keep any reference to
   // MobileConnection but a raw pointer instead. Neither does mMobileConnection
   // because it's an xpcom service owned object and is only released at shutting
@@ -96,55 +113,76 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
   // to us.
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(MobileConnection, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(MobileConnection, DOMEventTargetHelper)
 
 MobileConnection::MobileConnection(nsPIDOMWindow* aWindow, uint32_t aClientId)
   : DOMEventTargetHelper(aWindow)
+  , mClientId(aClientId)
 {
   nsCOMPtr<nsIMobileConnectionService> service =
     do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID);
 
   // Not being able to acquire the service isn't fatal since we check
   // for it explicitly below.
   if (!service) {
     NS_WARNING("Could not acquire nsIMobileConnectionService!");
     return;
   }
 
-  nsresult rv = service->GetItemByServiceId(aClientId,
+  nsresult rv = service->GetItemByServiceId(mClientId,
                                             getter_AddRefs(mMobileConnection));
+#ifdef MOZ_B2G_RIL
+  mIcc = do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
+
+  if (NS_FAILED(rv) || !mMobileConnection || !mIcc) {
+    NS_WARNING("Could not acquire nsIMobileConnection or nsIIccProvider!");
+#else
   if (NS_FAILED(rv) || !mMobileConnection) {
     NS_WARNING("Could not acquire nsIMobileConnection!");
+#endif // MOZ_B2G_RIL
     return;
   }
 
   mListener = new Listener(this);
   mVoice = new MobileConnectionInfo(GetOwner());
   mData = new MobileConnectionInfo(GetOwner());
 
   if (CheckPermission("mobileconnection")) {
     DebugOnly<nsresult> rv = mMobileConnection->RegisterListener(mListener);
     NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
                      "Failed registering mobile connection messages with service");
     UpdateVoice();
     UpdateData();
+
+#ifdef MOZ_B2G_RIL
+    rv = mIcc->RegisterIccMsg(mClientId, mListener);
+    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
+                     "Failed registering icc messages with service");
+    UpdateIccId();
+#endif // MOZ_B2G_RIL
   }
 }
 
 void
 MobileConnection::Shutdown()
 {
   if (mListener) {
     if (mMobileConnection) {
       mMobileConnection->UnregisterListener(mListener);
     }
 
+#ifdef MOZ_B2G_RIL
+    if (mIcc) {
+      mIcc->UnregisterIccMsg(mClientId, mListener);
+    }
+#endif // MOZ_B2G_RIL
+
     mListener->Disconnect();
     mListener = nullptr;
   }
 }
 
 MobileConnection::~MobileConnection()
 {
   Shutdown();
@@ -196,16 +234,39 @@ MobileConnection::UpdateData()
     return;
   }
 
   nsCOMPtr<nsIMobileConnectionInfo> info;
   mMobileConnection->GetData(getter_AddRefs(info));
   mData->Update(info);
 }
 
+bool
+MobileConnection::UpdateIccId()
+{
+#ifdef MOZ_B2G_RIL
+  nsAutoString iccId;
+  nsCOMPtr<nsIIccInfo> iccInfo;
+  if (mIcc &&
+      NS_SUCCEEDED(mIcc->GetIccInfo(mClientId, getter_AddRefs(iccInfo))) &&
+      iccInfo) {
+    iccInfo->GetIccid(iccId);
+  } else {
+    iccId.SetIsVoid(true);
+  }
+
+  if (!mIccId.Equals(iccId)) {
+    mIccId = iccId;
+    return true;
+  }
+#endif // MOZ_B2G_RIL
+
+  return false;
+}
+
 nsresult
 MobileConnection::NotifyError(nsIDOMDOMRequest* aRequest, const nsAString& aMessage)
 {
   nsCOMPtr<nsIDOMRequestService> rs = do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
   NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
 
   return rs->FireErrorAsync(aRequest, aMessage);
 }
@@ -317,23 +378,17 @@ MobileConnectionInfo*
 MobileConnection::Data() const
 {
   return mData;
 }
 
 void
 MobileConnection::GetIccId(nsString& aRetVal) const
 {
-  aRetVal.SetIsVoid(true);
-
-  if (!mMobileConnection) {
-    return;
-  }
-
-  mMobileConnection->GetIccId(aRetVal);
+  aRetVal = mIccId;
 }
 
 Nullable<MobileNetworkSelectionMode>
 MobileConnection::GetNetworkSelectionMode() const
 {
   Nullable<MobileNetworkSelectionMode> retVal =
     Nullable<MobileNetworkSelectionMode>();
 
@@ -1025,26 +1080,16 @@ MobileConnection::NotifyOtaStatusChanged
 
   nsRefPtr<MozOtaStatusEvent> event =
     MozOtaStatusEvent::Constructor(this, NS_LITERAL_STRING("otastatuschange"), init);
 
   return DispatchTrustedEvent(event);
 }
 
 NS_IMETHODIMP
-MobileConnection::NotifyIccChanged()
-{
-  if (!CheckPermission("mobileconnection")) {
-    return NS_OK;
-  }
-
-  return DispatchTrustedEvent(NS_LITERAL_STRING("iccchange"));
-}
-
-NS_IMETHODIMP
 MobileConnection::NotifyRadioStateChanged()
 {
   if (!CheckPermission("mobileconnection")) {
     return NS_OK;
   }
 
   return DispatchTrustedEvent(NS_LITERAL_STRING("radiostatechange"));
 }
@@ -1079,8 +1124,47 @@ MobileConnection::NotifyLastKnownHomeNet
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MobileConnection::NotifyNetworkSelectionModeChanged()
 {
   return NS_OK;
 }
+
+#ifdef MOZ_B2G_RIL
+// nsIIccListener
+
+NS_IMETHODIMP
+MobileConnection::NotifyStkCommand(const nsAString& aMessage)
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+MobileConnection::NotifyStkSessionEnd()
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+MobileConnection::NotifyCardStateChanged()
+{
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+MobileConnection::NotifyIccInfoChanged()
+{
+  if (!CheckPermission("mobileconnection")) {
+    return NS_OK;
+  }
+
+  if (!UpdateIccId()) {
+    return NS_OK;
+  }
+
+  nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
+    new AsyncEventDispatcher(this, NS_LITERAL_STRING("iccchange"), false);
+
+  return asyncDispatcher->PostDOMEvent();
+}
+#endif // MOZ_B2G_RIL
--- a/dom/mobileconnection/MobileConnection.h
+++ b/dom/mobileconnection/MobileConnection.h
@@ -9,35 +9,45 @@
 #include "mozilla/dom/DOMRequest.h"
 #include "mozilla/dom/MobileConnectionInfo.h"
 #include "mozilla/dom/MobileNetworkInfo.h"
 #include "mozilla/dom/MozMobileConnectionBinding.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIMobileConnectionService.h"
 #include "nsWeakPtr.h"
 
+#ifdef MOZ_B2G_RIL
+#include "nsIIccProvider.h"
+#endif // MOZ_B2G_RIL
+
 namespace mozilla {
 namespace dom {
 
-class MobileConnection MOZ_FINAL : public DOMEventTargetHelper,
-                                   private nsIMobileConnectionListener
+class MobileConnection MOZ_FINAL : public DOMEventTargetHelper
+                                 , private nsIMobileConnectionListener
+#ifdef MOZ_B2G_RIL
+                                 , private nsIIccListener
+#endif // MOZ_B2G_RIL
 {
   /**
    * Class MobileConnection doesn't actually expose
    * nsIMobileConnectionListener. Instead, it owns an
    * nsIMobileConnectionListener derived instance mListener and passes it to
    * nsIMobileConnectionService. The onreceived events are first delivered to
    * mListener and then forwarded to its owner, MobileConnection. See also bug
    * 775997 comment #51.
    */
   class Listener;
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIMOBILECONNECTIONLISTENER
+#ifdef MOZ_B2G_RIL
+  NS_DECL_NSIICCLISTENER
+#endif // MOZ_B2G_RIL
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MobileConnection,
                                            DOMEventTargetHelper)
 
   MobileConnection(nsPIDOMWindow *aWindow, uint32_t aClientId);
 
   void
   Shutdown();
@@ -151,30 +161,38 @@ public:
   IMPL_EVENT_HANDLER(iccchange)
   IMPL_EVENT_HANDLER(radiostatechange)
   IMPL_EVENT_HANDLER(clirmodechange)
 
 private:
   ~MobileConnection();
 
 private:
+  uint32_t mClientId;
+  nsString mIccId;
   nsCOMPtr<nsIMobileConnection> mMobileConnection;
+#ifdef MOZ_B2G_RIL
+  nsCOMPtr<nsIIccProvider> mIcc;
+#endif // MOZ_B2G_RIL
   nsRefPtr<Listener> mListener;
   nsRefPtr<MobileConnectionInfo> mVoice;
   nsRefPtr<MobileConnectionInfo> mData;
 
   bool
   CheckPermission(const char* aType) const;
 
   void
   UpdateVoice();
 
   void
   UpdateData();
 
+  bool
+  UpdateIccId();
+
   nsresult
   NotifyError(nsIDOMDOMRequest* aRequest, const nsAString& aMessage);
 
   bool
   IsValidPassword(const nsAString& aPassword);
 
   bool
   IsValidCallBarringOptions(const MozCallBarringOptions& aOptions, bool isSetting);
--- a/dom/mobileconnection/gonk/MobileConnectionService.js
+++ b/dom/mobileconnection/gonk/MobileConnectionService.js
@@ -300,17 +300,16 @@ MobileConnectionProvider.prototype = {
   /**
    * The networks that are currently trying to be selected (or "automatic").
    * This helps ensure that only one network per client is selected at a time.
    */
   _selectingNetwork: null,
 
   voice: null,
   data: null,
-  iccId: null,
   networkSelectionMode: Ci.nsIMobileConnection.NETWORK_SELECTION_MODE_UNKNOWN,
   radioState: Ci.nsIMobileConnection.MOBILE_RADIO_STATE_UNKNOWN,
   lastKnownNetwork: null,
   lastKnownHomeNetwork: null,
   supportedNetworkTypes: null,
 
   /**
    * A utility function to dump debug message.
@@ -581,25 +580,16 @@ MobileConnectionProvider.prototype = {
     // If the data is not registered, no need to update signal information.
     if (this.data.state === RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED) {
       if (this._updateInfo(this.data, aNewInfo.data) && !aBatch) {
         this.deliverListenerEvent("notifyDataChanged");
       }
     }
   },
 
-  updateIccId: function(aIccId) {
-    if (this.iccId === aIccId) {
-      return;
-    }
-
-    this.iccId = aIccId;
-    this.deliverListenerEvent("notifyIccChanged");
-  },
-
   updateRadioState: function(aRadioState) {
     if (this.radioState === aRadioState) {
       return;
     }
 
     this.radioState = aRadioState;
     this.deliverListenerEvent("notifyRadioStateChanged");
   },
@@ -1138,24 +1128,16 @@ MobileConnectionService.prototype = {
     if (DEBUG) {
       debug("notifyOtaStatusChanged for " + aClientId + ": " + aStatus);
     }
 
     this.getItemByServiceId(aClientId)
         .deliverListenerEvent("notifyOtaStatusChanged", [aStatus]);
   },
 
-  notifyIccChanged: function(aClientId, aIccId) {
-    if (DEBUG) {
-      debug("notifyIccChanged for " + aClientId + ": " + aIccId);
-    }
-
-    this.getItemByServiceId(aClientId).updateIccId(aIccId);
-  },
-
   notifyRadioStateChanged: function(aClientId, aRadioState) {
     if (DEBUG) {
       debug("notifyRadioStateChanged for " + aClientId + ": " + aRadioState);
     }
 
     this.getItemByServiceId(aClientId).updateRadioState(aRadioState);
   },
 
--- a/dom/mobileconnection/gonk/nsIGonkMobileConnectionService.idl
+++ b/dom/mobileconnection/gonk/nsIGonkMobileConnectionService.idl
@@ -4,17 +4,17 @@
 
 #include "nsIMobileConnectionService.idl"
 
 %{C++
 #define GONK_MOBILECONNECTION_SERVICE_CONTRACTID \
         "@mozilla.org/mobileconnection/gonkmobileconnectionservice;1"
 %}
 
-[scriptable, uuid(ef49b866-85a0-11e4-b023-f73e02752840)]
+[scriptable, uuid(3a7b8d47-d1c6-44c3-a312-df73fda1161e)]
 interface nsIGonkMobileConnectionService : nsIMobileConnectionService
 {
   void notifyNetworkInfoChanged(in unsigned long clientId, in jsval networkInfo);
 
   void notifyVoiceInfoChanged(in unsigned long clientId, in jsval voiceInfo);
 
   void notifyDataInfoChanged(in unsigned long clientId, in jsval dataInfo);
 
@@ -28,18 +28,16 @@ interface nsIGonkMobileConnectionService
 
   void notifyRadioStateChanged(in unsigned long clientId,
                                in long radioState);
 
   void notifyEmergencyCallbackModeChanged(in unsigned long clientId,
                                           in boolean active,
                                           in unsigned long timeoutMs);
 
-  void notifyIccChanged(in unsigned long clientId, in DOMString iccId);
-
   void notifyNetworkSelectModeChanged(in unsigned long clientId,
                                       in long mode);
 
   void notifySpnAvailable(in unsigned long clientId);
 
   void notifyLastHomeNetworkChanged(in unsigned long clientId,
                                     in DOMString network);
 
--- a/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl
+++ b/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl
@@ -7,17 +7,17 @@
 interface nsICellInfoListCallback;
 interface nsIMobileCallForwardingOptions;
 interface nsIMobileConnection;
 interface nsIMobileConnectionInfo;
 interface nsIMobileNetworkInfo;
 interface nsINeighboringCellIdsCallback;
 interface nsIVariant;
 
-[scriptable, uuid(6e6468a4-84fb-11e4-9b66-17dbe13c059e)]
+[scriptable, uuid(d6827b51-61a7-4b7c-8454-42d0cffc1829)]
 interface nsIMobileConnectionListener : nsISupports
 {
   /**
    * Notify when voice info is changed.
    */
   void notifyVoiceChanged();
 
   /**
@@ -71,21 +71,16 @@ interface nsIMobileConnectionListener : 
    *        Ota status. Possible values: 'spl_unlocked', 'spc_retries_exceeded',
    *        'a_key_exchanged', 'ssd_updated', 'nam_downloaded', 'mdn_downloaded',
    *        'imsi_downloaded', 'prl_downloaded', 'committed', 'otapa_started',
    *        'otapa_stopped', 'otapa_aborted'.
    */
   void notifyOtaStatusChanged(in DOMString status);
 
   /**
-   * Notify when icc id is changed.
-   */
-  void notifyIccChanged();
-
-  /**
    * Notify when radio state is changed.
    */
   void notifyRadioStateChanged();
 
   /**
    * Notify when clir mode is changed.
    *
    * @param mode
@@ -163,17 +158,17 @@ interface nsIMobileConnectionService : n
 
 %{C++
 template<typename T> struct already_AddRefed;
 
 already_AddRefed<nsIMobileConnectionService>
 NS_CreateMobileConnectionService();
 %}
 
-[scriptable, uuid(2b3d0122-8054-11e4-964e-c727f38fd7e6)]
+[scriptable, uuid(b9845f09-7cbb-46d0-b713-773d80844e0d)]
 interface nsIMobileConnection : nsISupports
 {
   /*
    * ICC service class.
    */
   const long ICC_SERVICE_CLASS_NONE       = 0; // not available
   const long ICC_SERVICE_CLASS_VOICE      = (1 << 0);
   const long ICC_SERVICE_CLASS_DATA       = (1 << 1);
@@ -304,21 +299,16 @@ interface nsIMobileConnection : nsISuppo
   readonly attribute nsIMobileConnectionInfo voice;
 
   /**
    * Connection information about the data.
    */
   readonly attribute nsIMobileConnectionInfo data;
 
   /**
-   * The integrated circuit card identifier of the SIM.
-   */
-  readonly attribute DOMString iccId;
-
-  /**
    * The selection mode of the voice and data networks. One of the
    * nsIMobileConnection.NETWORK_SELECTION_MODE_* values.
    */
   readonly attribute long networkSelectionMode;
 
   /**
    * Current radio state. One of the nsIMobileConnection.MOBILE_RADIO_STATE_*
    * values.
--- a/dom/mobileconnection/ipc/MobileConnectionChild.cpp
+++ b/dom/mobileconnection/ipc/MobileConnectionChild.cpp
@@ -21,17 +21,17 @@ MobileConnectionChild::MobileConnectionC
 }
 
 void
 MobileConnectionChild::Init()
 {
   nsIMobileConnectionInfo* rawVoice;
   nsIMobileConnectionInfo* rawData;
 
-  SendInit(&rawVoice, &rawData, &mLastNetwork, &mLastHomeNetwork, &mIccId,
+  SendInit(&rawVoice, &rawData, &mLastNetwork, &mLastHomeNetwork,
            &mNetworkSelectionMode, &mRadioState, &mSupportedNetworkTypes);
 
   // Use dont_AddRef here because this instances is already AddRef-ed in
   // MobileConnectionIPCSerializer.h
   nsCOMPtr<nsIMobileConnectionInfo> voice = dont_AddRef(rawVoice);
   mVoice = new MobileConnectionInfo(nullptr);
   mVoice->Update(voice);
 
@@ -94,23 +94,16 @@ NS_IMETHODIMP
 MobileConnectionChild::GetData(nsIMobileConnectionInfo** aData)
 {
   nsRefPtr<nsIMobileConnectionInfo> data(mData);
   data.forget(aData);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-MobileConnectionChild::GetIccId(nsAString& aIccId)
-{
-  aIccId = mIccId;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 MobileConnectionChild::GetRadioState(int32_t* aRadioState)
 {
   *aRadioState = mRadioState;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MobileConnectionChild::GetSupportedNetworkTypes(int32_t** aTypes,
@@ -443,28 +436,16 @@ MobileConnectionChild::RecvNotifyOtaStat
   for (int32_t i = 0; i < mListeners.Count(); i++) {
     mListeners[i]->NotifyOtaStatusChanged(aStatus);
   }
 
   return true;
 }
 
 bool
-MobileConnectionChild::RecvNotifyIccChanged(const nsString& aIccId)
-{
-  mIccId.Assign(aIccId);
-
-  for (int32_t i = 0; i < mListeners.Count(); i++) {
-    mListeners[i]->NotifyIccChanged();
-  }
-
-  return true;
-}
-
-bool
 MobileConnectionChild::RecvNotifyRadioStateChanged(const int32_t& aRadioState)
 {
   mRadioState = aRadioState;
 
   for (int32_t i = 0; i < mListeners.Count(); i++) {
     mListeners[i]->NotifyRadioStateChanged();
   }
 
--- a/dom/mobileconnection/ipc/MobileConnectionChild.h
+++ b/dom/mobileconnection/ipc/MobileConnectionChild.h
@@ -80,19 +80,16 @@ protected:
   virtual bool
   RecvNotifyEmergencyCbModeChanged(const bool& aActive,
                                    const uint32_t& aTimeoutMs) MOZ_OVERRIDE;
 
   virtual bool
   RecvNotifyOtaStatusChanged(const nsString& aStatus) MOZ_OVERRIDE;
 
   virtual bool
-  RecvNotifyIccChanged(const nsString& aIccId) MOZ_OVERRIDE;
-
-  virtual bool
   RecvNotifyRadioStateChanged(const int32_t& aRadioState) MOZ_OVERRIDE;
 
   virtual bool
   RecvNotifyClirModeChanged(const uint32_t& aMode) MOZ_OVERRIDE;
 
   virtual bool
   RecvNotifyLastNetworkChanged(const nsString& aNetwork) MOZ_OVERRIDE;
 
@@ -103,17 +100,16 @@ protected:
   RecvNotifyNetworkSelectionModeChanged(const int32_t& aMode) MOZ_OVERRIDE;
 
 private:
   uint32_t mServiceId;
   bool mLive;
   nsCOMArray<nsIMobileConnectionListener> mListeners;
   nsRefPtr<MobileConnectionInfo> mVoice;
   nsRefPtr<MobileConnectionInfo> mData;
-  nsString mIccId;
   int32_t mRadioState;
   nsString mLastNetwork;
   nsString mLastHomeNetwork;
   int32_t mNetworkSelectionMode;
   nsTArray<int32_t> mSupportedNetworkTypes;
 };
 
 /******************************************************************************
--- a/dom/mobileconnection/ipc/MobileConnectionParent.cpp
+++ b/dom/mobileconnection/ipc/MobileConnectionParent.cpp
@@ -119,28 +119,26 @@ MobileConnectionParent::DeallocPMobileCo
   return true;
 }
 
 bool
 MobileConnectionParent::RecvInit(nsMobileConnectionInfo* aVoice,
                                  nsMobileConnectionInfo* aData,
                                  nsString* aLastKnownNetwork,
                                  nsString* aLastKnownHomeNetwork,
-                                 nsString* aIccId,
                                  int32_t* aNetworkSelectionMode,
                                  int32_t* aRadioState,
                                  nsTArray<int32_t>* aSupportedNetworkTypes)
 {
   NS_ENSURE_TRUE(mMobileConnection, false);
 
   NS_ENSURE_SUCCESS(mMobileConnection->GetVoice(aVoice), false);
   NS_ENSURE_SUCCESS(mMobileConnection->GetData(aData), false);
   NS_ENSURE_SUCCESS(mMobileConnection->GetLastKnownNetwork(*aLastKnownNetwork), false);
   NS_ENSURE_SUCCESS(mMobileConnection->GetLastKnownHomeNetwork(*aLastKnownHomeNetwork), false);
-  NS_ENSURE_SUCCESS(mMobileConnection->GetIccId(*aIccId), false);
   NS_ENSURE_SUCCESS(mMobileConnection->GetNetworkSelectionMode(aNetworkSelectionMode), false);
   NS_ENSURE_SUCCESS(mMobileConnection->GetRadioState(aRadioState), false);
 
   int32_t* types = nullptr;
   uint32_t length = 0;
 
   nsresult rv = mMobileConnection->GetSupportedNetworkTypes(&types, &length);
   NS_ENSURE_SUCCESS(rv, false);
@@ -224,27 +222,16 @@ MobileConnectionParent::NotifyOtaStatusC
 {
   NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE);
 
   return SendNotifyOtaStatusChanged(nsAutoString(aStatus))
          ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
-MobileConnectionParent::NotifyIccChanged()
-{
-  NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE);
-
-  nsAutoString iccId;
-  mMobileConnection->GetIccId(iccId);
-
-  return SendNotifyIccChanged(iccId) ? NS_OK : NS_ERROR_FAILURE;
-}
-
-NS_IMETHODIMP
 MobileConnectionParent::NotifyRadioStateChanged()
 {
   NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE);
 
   nsresult rv;
   int32_t radioState;
   rv = mMobileConnection->GetRadioState(&radioState);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/mobileconnection/ipc/MobileConnectionParent.h
+++ b/dom/mobileconnection/ipc/MobileConnectionParent.h
@@ -46,18 +46,18 @@ protected:
   AllocPMobileConnectionRequestParent(const MobileConnectionRequest& request) MOZ_OVERRIDE;
 
   virtual bool
   DeallocPMobileConnectionRequestParent(PMobileConnectionRequestParent* aActor) MOZ_OVERRIDE;
 
   virtual bool
   RecvInit(nsMobileConnectionInfo* aVoice, nsMobileConnectionInfo* aData,
            nsString* aLastKnownNetwork, nsString* aLastKnownHomeNetwork,
-           nsString* aIccId, int32_t* aNetworkSelectionMode,
-           int32_t* aRadioState, nsTArray<int32_t>* aSupportedNetworkTypes) MOZ_OVERRIDE;
+           int32_t* aNetworkSelectionMode, int32_t* aRadioState,
+           nsTArray<int32_t>* aSupportedNetworkTypes) MOZ_OVERRIDE;
 
 private:
   nsCOMPtr<nsIMobileConnection> mMobileConnection;
   bool mLive;
 };
 
 /******************************************************************************
  * PMobileConnectionRequestParent
--- a/dom/mobileconnection/ipc/PMobileConnection.ipdl
+++ b/dom/mobileconnection/ipc/PMobileConnection.ipdl
@@ -20,17 +20,16 @@ sync protocol PMobileConnection
 child:
   NotifyVoiceInfoChanged(nsMobileConnectionInfo aInfo);
   NotifyDataInfoChanged(nsMobileConnectionInfo aInfo);
   NotifyDataError(nsString aMessage);
   NotifyCFStateChanged(uint16_t aAction, uint16_t aReason, nsString aNumber,
                        uint16_t aTimeSeconds, uint16_t aServiceClass);
   NotifyEmergencyCbModeChanged(bool aActive, uint32_t aTimeoutMs);
   NotifyOtaStatusChanged(nsString aStatus);
-  NotifyIccChanged(nsString aIccId);
   NotifyRadioStateChanged(int32_t aRadioState);
   NotifyClirModeChanged(uint32_t aMode);
   NotifyLastNetworkChanged(nsString aNetwork);
   NotifyLastHomeNetworkChanged(nsString aNetwork);
   NotifyNetworkSelectionModeChanged(int32_t aMode);
 
 parent:
   /**
@@ -44,18 +43,18 @@ parent:
   PMobileConnectionRequest(MobileConnectionRequest aRequest);
 
   /**
    * Sync call only be called once per child actor for initialization.
    */
   sync Init()
     returns (nsMobileConnectionInfo aVoice, nsMobileConnectionInfo aData,
              nsString aLastKnownNetwork, nsString aLastKnownHomeNetwork,
-             nsString aIccId, int32_t aNetworkSelectionMode,
-             int32_t aRadioState, int32_t[] aSupportedNetworkTypes);
+             int32_t aNetworkSelectionMode, int32_t aRadioState,
+             int32_t[] aSupportedNetworkTypes);
 };
 
 /**
  * MobileConnectionRequest
  */
 struct GetNetworksRequest
 {
 };
--- a/dom/mobileconnection/moz.build
+++ b/dom/mobileconnection/moz.build
@@ -64,15 +64,19 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk
         'gonk/nsIGonkMobileConnectionService.idl',
         'gonk/nsIMobileConnectionMessenger.idl',
     ]
     EXTRA_COMPONENTS += [
         'gonk/MobileConnectionService.js',
         'gonk/MobileConnectionService.manifest',
     ]
 
+LOCAL_INCLUDES += [
+    '/dom/system/gonk',
+]
+
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 XPIDL_MODULE = 'dom_mobileconnection'
--- a/dom/mobileconnection/tests/marionette/test_mobile_icc_change.js
+++ b/dom/mobileconnection/tests/marionette/test_mobile_icc_change.js
@@ -12,22 +12,26 @@ function setRadioEnabledAndWaitIccChange
   promises.push(waitForManagerEvent("iccchange"));
   promises.push(setRadioEnabled(aEnabled));
 
   return Promise.all(promises);
 }
 
 // Start tests
 startTestCommon(function() {
-  log("Test initial iccId");
-  is(mobileConnection.iccId, ICCID);
+  is(mobileConnection.iccId, ICCID, "test initial iccId");
 
   return setRadioEnabledAndWaitIccChange(false)
     .then(() => {
-      is(mobileConnection.iccId, null);
+      is(mobileConnection.iccId, null, "mobileConnection.iccId");
     })
 
     // Restore radio state.
     .then(() => setRadioEnabledAndWaitIccChange(true))
     .then(() => {
-      is(mobileConnection.iccId, ICCID);
+      is(mobileConnection.iccId, ICCID, "mobileConnection.iccId");
+
+      // ICC object should be ready in mozIccManager.
+      let icc = getMozIccByIccId(mobileConnection.iccId);
+      ok(icc instanceof MozIcc, "icc should be an instance of MozIcc");
+      is(icc.iccInfo.iccid, mobileConnection.iccId, "icc.iccInfo.iccid");
     });
 });
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -2223,16 +2223,22 @@ RadioInterface.prototype = {
     service.notifyStatusChanged(this.clientId, mwi.active, mwi.msgCount,
                                 null, null);
   },
 
   handleIccInfoChange: function(message) {
     let oldSpn = this.rilContext.iccInfo ? this.rilContext.iccInfo.spn : null;
 
     if (!message || !message.iccid) {
+      // If iccInfo is already `null`, don't have to clear it and send
+      // RIL:IccInfoChanged.
+      if (!this.rilContext.iccInfo) {
+        return;
+      }
+
       // Card is not detected, clear iccInfo to null.
       this.rilContext.iccInfo = null;
     } else {
       if (!this.rilContext.iccInfo) {
         if (message.iccType === "ruim" || message.iccType === "csim") {
           this.rilContext.iccInfo = new CdmaIccInfo();
         } else if (message.iccType === "sim" || message.iccType === "usim") {
           this.rilContext.iccInfo = new GsmIccInfo();
@@ -2249,21 +2255,16 @@ RadioInterface.prototype = {
     }
 
     // RIL:IccInfoChanged corresponds to a DOM event that gets fired only
     // when iccInfo has changed.
     gMessageManager.sendIccMessage("RIL:IccInfoChanged",
                                    this.clientId,
                                    message.iccid ? message : null);
 
-    // In bug 864489, icc related code will be move to gonk IccProvider, we may
-    // need a better way to notify icc change to MobileConnectionService.
-    gMobileConnectionService.notifyIccChanged(this.clientId,
-                                              message.iccid || null);
-
     // Update lastKnownSimMcc.
     if (message.mcc) {
       try {
         Services.prefs.setCharPref("ril.lastKnownSimMcc",
                                    message.mcc.toString());
       } catch (e) {}
     }