Bug 921991 - B2G BT: support multiple sim cards, r=echou, r=mrbkap
authorBen Tian <btian@mozilla.com>
Tue, 26 Nov 2013 14:11:06 +0800
changeset 157521 d293b47f58799b2e6df810d6d05fd9ddfeaa82af
parent 157520 70869a5eea0b7035b668cf3f8c106ff83188d0e0
child 157522 4e456bb4f31f18dcf8efdd47bf2b737918b95177
push id25715
push usercbook@mozilla.com
push dateTue, 26 Nov 2013 11:40:44 +0000
treeherdermozilla-central@34f431863037 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersechou, mrbkap
bugs921991
milestone28.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 921991 - B2G BT: support multiple sim cards, r=echou, r=mrbkap
dom/bluetooth/BluetoothRilListener.cpp
dom/bluetooth/BluetoothRilListener.h
dom/bluetooth/bluedroid/BluetoothHfpManager.cpp
dom/bluetooth/bluedroid/BluetoothHfpManager.h
dom/bluetooth/bluez/BluetoothHfpManager.cpp
dom/bluetooth/bluez/BluetoothHfpManager.h
dom/system/gonk/nsRadioInterfaceLayer.h
--- a/dom/bluetooth/BluetoothRilListener.cpp
+++ b/dom/bluetooth/BluetoothRilListener.cpp
@@ -2,46 +2,39 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* 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 "BluetoothRilListener.h"
 
 #include "BluetoothHfpManager.h"
-#include "nsIIccProvider.h"
-#include "nsIMobileConnectionProvider.h"
-#include "nsITelephonyProvider.h"
+#include "nsIDOMMobileConnection.h"
+#include "nsIRadioInterfaceLayer.h"
 #include "nsRadioInterfaceLayer.h"
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 
 USING_BLUETOOTH_NAMESPACE
 
-namespace {
-
 /**
  *  IccListener
  */
-class IccListener : public nsIIccListener
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIICCLISTENER
-
-  IccListener() { }
-};
-
 NS_IMPL_ISUPPORTS1(IccListener, nsIIccListener)
 
 NS_IMETHODIMP
 IccListener::NotifyIccInfoChanged()
 {
+  // mOwner would be set to nullptr only in the dtor of BluetoothRilListener
+  NS_ENSURE_TRUE(mOwner, NS_ERROR_FAILURE);
+
   BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
-  hfp->HandleIccInfoChanged();
+  NS_ENSURE_TRUE(hfp, NS_ERROR_FAILURE);
+
+  hfp->HandleIccInfoChanged(mOwner->mClientId);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IccListener::NotifyStkCommand(const nsAString & aMessage)
 {
   return NS_OK;
@@ -54,35 +47,53 @@ IccListener::NotifyStkSessionEnd()
 }
 
 NS_IMETHODIMP
 IccListener::NotifyCardStateChanged()
 {
   return NS_OK;
 }
 
+bool
+IccListener::Listen(bool aStart)
+{
+  NS_ENSURE_TRUE(mOwner, false);
+
+  nsCOMPtr<nsIIccProvider> provider =
+    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
+  NS_ENSURE_TRUE(provider, false);
+
+  nsresult rv;
+  if (aStart) {
+    rv = provider->RegisterIccMsg(mOwner->mClientId, this);
+  } else {
+    rv = provider->UnregisterIccMsg(mOwner->mClientId, this);
+  }
+
+  return NS_SUCCEEDED(rv);
+}
+
+void
+IccListener::SetOwner(BluetoothRilListener *aOwner)
+{
+  mOwner = aOwner;
+}
+
 /**
  *  MobileConnectionListener
  */
-class MobileConnectionListener : public nsIMobileConnectionListener
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIMOBILECONNECTIONLISTENER
-
-  MobileConnectionListener() { }
-};
-
 NS_IMPL_ISUPPORTS1(MobileConnectionListener, nsIMobileConnectionListener)
 
 NS_IMETHODIMP
 MobileConnectionListener::NotifyVoiceChanged()
 {
   BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
-  hfp->HandleVoiceConnectionChanged();
+  NS_ENSURE_TRUE(hfp, NS_OK);
+
+  hfp->HandleVoiceConnectionChanged(mClientId);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MobileConnectionListener::NotifyDataChanged()
 {
   return NS_OK;
@@ -132,71 +143,81 @@ MobileConnectionListener::NotifyIccChang
 }
 
 NS_IMETHODIMP
 MobileConnectionListener::NotifyRadioStateChanged()
 {
   return NS_OK;
 }
 
+bool
+MobileConnectionListener::Listen(bool aStart)
+{
+  nsCOMPtr<nsIMobileConnectionProvider> provider =
+    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
+  NS_ENSURE_TRUE(provider, false);
+
+  nsresult rv;
+  if (aStart) {
+    rv = provider->RegisterMobileConnectionMsg(mClientId, this);
+  } else {
+    rv = provider->UnregisterMobileConnectionMsg(mClientId, this);
+  }
+
+  return NS_SUCCEEDED(rv);
+}
+
 /**
  *  TelephonyListener Implementation
- *
- *  TODO: Bug 921991 - B2G BT: support multiple sim cards
  */
-class TelephonyListener : public nsITelephonyListener
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSITELEPHONYLISTENER
-
-  TelephonyListener() { }
-};
-
 NS_IMPL_ISUPPORTS1(TelephonyListener, nsITelephonyListener)
 
 NS_IMETHODIMP
 TelephonyListener::CallStateChanged(uint32_t aServiceId,
                                     uint32_t aCallIndex,
                                     uint16_t aCallState,
                                     const nsAString& aNumber,
                                     bool aIsActive,
                                     bool aIsOutgoing,
                                     bool aIsEmergency,
                                     bool aIsConference)
 {
   BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
+  NS_ENSURE_TRUE(hfp, NS_ERROR_FAILURE);
+
   hfp->HandleCallStateChanged(aCallIndex, aCallState, EmptyString(), aNumber,
                               aIsOutgoing, true);
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TelephonyListener::EnumerateCallState(uint32_t aServiceId,
                                       uint32_t aCallIndex,
                                       uint16_t aCallState,
                                       const nsAString_internal& aNumber,
                                       bool aIsActive,
                                       bool aIsOutgoing,
                                       bool aIsEmergency,
                                       bool aIsConference)
 {
   BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
+  NS_ENSURE_TRUE(hfp, NS_ERROR_FAILURE);
+
   hfp->HandleCallStateChanged(aCallIndex, aCallState, EmptyString(), aNumber,
                               aIsOutgoing, false);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TelephonyListener::NotifyError(uint32_t aServiceId,
                                int32_t aCallIndex,
                                const nsAString& aError)
 {
   BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
+  NS_ENSURE_TRUE(hfp, NS_ERROR_FAILURE);
 
   if (aCallIndex > 0) {
     // In order to not miss any related call state transition.
     // It's possible that 3G network signal lost for unknown reason.
     // If a call is released abnormally, NotifyError() will be called,
     // instead of CallStateChanged(). We need to reset the call array state
     // via setting CALL_STATE_DISCONNECTED
     hfp->HandleCallStateChanged(aCallIndex,
@@ -239,127 +260,163 @@ TelephonyListener::NotifyConferenceError
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TelephonyListener::NotifyCdmaCallWaiting(uint32_t aServiceId,
                                          const nsAString& aNumber)
 {
   BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
+  NS_ENSURE_TRUE(hfp, NS_ERROR_FAILURE);
+
   hfp->UpdateSecondNumber(aNumber);
 
   return NS_OK;
 }
 
-} // anonymous namespace
+bool
+TelephonyListener::Listen(bool aStart)
+{
+  nsCOMPtr<nsITelephonyProvider> provider =
+    do_GetService(TELEPHONY_PROVIDER_CONTRACTID);
+  NS_ENSURE_TRUE(provider, false);
+
+  nsresult rv;
+  if (aStart) {
+    rv = provider->RegisterListener(this);
+  } else {
+    rv = provider->UnregisterListener(this);
+  }
+
+  return NS_SUCCEEDED(rv);
+}
 
 /**
  *  BluetoothRilListener
  */
 BluetoothRilListener::BluetoothRilListener()
 {
+  // Query number of total clients (sim slots)
+  uint32_t numOfClients;
+  nsCOMPtr<nsIRadioInterfaceLayer> radioInterfaceLayer =
+    do_GetService(NS_RADIOINTERFACELAYER_CONTRACTID);
+  NS_ENSURE_TRUE_VOID(radioInterfaceLayer);
+
+  radioInterfaceLayer->GetNumRadioInterfaces(&numOfClients);
+
+  // Init MobileConnectionListener array and IccInfoListener
+  for (uint32_t i = 0; i < numOfClients; i++) {
+    mMobileConnListeners.AppendElement(new MobileConnectionListener(i));
+  }
+
+  mTelephonyListener = new TelephonyListener();
   mIccListener = new IccListener();
-  mMobileConnectionListener = new MobileConnectionListener();
-  mTelephonyListener = new TelephonyListener();
+  mIccListener->SetOwner(this);
+
+  // Probe for available client
+  SelectClient();
+}
+
+BluetoothRilListener::~BluetoothRilListener()
+{
+  mIccListener->SetOwner(nullptr);
 }
 
 bool
-BluetoothRilListener::StartListening()
+BluetoothRilListener::Listen(bool aStart)
 {
-  NS_ENSURE_TRUE(StartIccListening(), false);
-  NS_ENSURE_TRUE(StartMobileConnectionListening(), false);
-  NS_ENSURE_TRUE(StartTelephonyListening(), false);
+  NS_ENSURE_TRUE(ListenMobileConnAndIccInfo(aStart), false);
+  NS_ENSURE_TRUE(mTelephonyListener->Listen(aStart), false);
 
   return true;
 }
 
-bool
-BluetoothRilListener::StopListening()
+void
+BluetoothRilListener::SelectClient()
 {
-  NS_ENSURE_TRUE(StopIccListening(), false);
-  NS_ENSURE_TRUE(StopMobileConnectionListening(), false);
-  NS_ENSURE_TRUE(StopTelephonyListening(), false);
+  // Reset mClientId
+  mClientId = mMobileConnListeners.Length();
+
+  nsCOMPtr<nsIMobileConnectionProvider> connection =
+    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
+  NS_ENSURE_TRUE_VOID(connection);
+
+  for (uint32_t i = 0; i < mMobileConnListeners.Length(); i++) {
+    nsCOMPtr<nsIDOMMozMobileConnectionInfo> voiceInfo;
+    connection->GetVoiceConnectionInfo(i, getter_AddRefs(voiceInfo));
+    if (!voiceInfo) {
+      BT_WARNING("%s: Failed to get voice connection info", __FUNCTION__);
+      continue;
+    }
+
+    nsString regState;
+    voiceInfo->GetState(regState);
+    if (regState.EqualsLiteral("registered")) {
+      // Found available client
+      mClientId = i;
+      return;
+    }
+  }
+}
 
-  return true;
+void
+BluetoothRilListener::ServiceChanged(uint32_t aClientId, bool aRegistered)
+{
+  // Stop listening
+  ListenMobileConnAndIccInfo(false);
+
+  /**
+   * aRegistered:
+   * - TRUE:  service becomes registered. We were listening to all clients
+   *          and one of them becomes available. Select it to listen.
+   * - FALSE: service becomes un-registered. The client we were listening
+   *          becomes unavailable. Select another registered one to listen.
+   */
+  if (aRegistered) {
+    mClientId = aClientId;
+  } else {
+    SelectClient();
+  }
+
+  // Restart listening
+  ListenMobileConnAndIccInfo(true);
+
+  BT_LOGR("%s: %d client %d. new mClientId %d",
+          __FUNCTION__, aRegistered, aClientId,
+          (mClientId < mMobileConnListeners.Length()) ? mClientId : -1);
 }
 
 void
 BluetoothRilListener::EnumerateCalls()
 {
   nsCOMPtr<nsITelephonyProvider> provider =
     do_GetService(TELEPHONY_PROVIDER_CONTRACTID);
   NS_ENSURE_TRUE_VOID(provider);
 
-  provider->EnumerateCalls(mTelephonyListener);
-}
-
-// private
-bool
-BluetoothRilListener::StartIccListening()
-{
-  nsCOMPtr<nsIIccProvider> provider =
-    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
-  NS_ENSURE_TRUE(provider, false);
+  nsCOMPtr<nsITelephonyListener> listener(
+    do_QueryObject(mTelephonyListener));
 
-  // TODO: Bug 921991 - B2G BT: support multiple sim cards
-  nsresult rv = provider->RegisterIccMsg(0, mIccListener);
-  return NS_SUCCEEDED(rv);
-}
-
-bool
-BluetoothRilListener::StopIccListening()
-{
-  nsCOMPtr<nsIIccProvider> provider =
-    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
-  NS_ENSURE_TRUE(provider, false);
-
-  // TODO: Bug 921991 - B2G BT: support multiple sim cards
-  nsresult rv = provider->UnregisterIccMsg(0, mIccListener);
-  return NS_SUCCEEDED(rv);
+  provider->EnumerateCalls(listener);
 }
 
 bool
-BluetoothRilListener::StartMobileConnectionListening()
+BluetoothRilListener::ListenMobileConnAndIccInfo(bool aStart)
 {
-  nsCOMPtr<nsIMobileConnectionProvider> provider =
-    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
-  NS_ENSURE_TRUE(provider, false);
-
-  // TODO: Bug 921991 - B2G BT: support multiple sim cards
-  nsresult rv = provider->
-                  RegisterMobileConnectionMsg(0, mMobileConnectionListener);
-  return NS_SUCCEEDED(rv);
-}
-
-bool
-BluetoothRilListener::StopMobileConnectionListening()
-{
-  nsCOMPtr<nsIMobileConnectionProvider> provider =
-    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
-  NS_ENSURE_TRUE(provider, false);
+  /**
+   * mClientId < number of total clients:
+   *   The client with mClientId is available. Start/Stop listening
+   *   mobile connection and icc info of this client only.
+   *
+   * mClientId >= number of total clients:
+   *   All clients are unavailable. Start/Stop listening mobile
+   *   connections of all clients.
+   */
+  if (mClientId < mMobileConnListeners.Length()) {
+    NS_ENSURE_TRUE(mMobileConnListeners[mClientId]->Listen(aStart), false);
+    NS_ENSURE_TRUE(mIccListener->Listen(aStart), false);
+  } else {
+    for (uint32_t i = 0; i < mMobileConnListeners.Length(); i++) {
+      NS_ENSURE_TRUE(mMobileConnListeners[i]->Listen(aStart), false);
+    }
+  }
 
-  // TODO: Bug 921991 - B2G BT: support multiple sim cards
-  nsresult rv = provider->
-                  UnregisterMobileConnectionMsg(0, mMobileConnectionListener);
-  return NS_SUCCEEDED(rv);
+  return true;
 }
-
-bool
-BluetoothRilListener::StartTelephonyListening()
-{
-  nsCOMPtr<nsITelephonyProvider> provider =
-    do_GetService(TELEPHONY_PROVIDER_CONTRACTID);
-  NS_ENSURE_TRUE(provider, false);
-
-  nsresult rv = provider->RegisterListener(mTelephonyListener);
-  return NS_SUCCEEDED(rv);
-}
-
-bool
-BluetoothRilListener::StopTelephonyListening()
-{
-  nsCOMPtr<nsITelephonyProvider> provider =
-    do_GetService(TELEPHONY_PROVIDER_CONTRACTID);
-  NS_ENSURE_TRUE(provider, false);
-
-  nsresult rv = provider->UnregisterListener(mTelephonyListener);
-  return NS_SUCCEEDED(rv);
-}
--- a/dom/bluetooth/BluetoothRilListener.h
+++ b/dom/bluetooth/BluetoothRilListener.h
@@ -4,44 +4,124 @@
  * 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/. */
 
 #ifndef mozilla_dom_bluetooth_bluetoothrillistener_h__
 #define mozilla_dom_bluetooth_bluetoothrillistener_h__
 
 #include "BluetoothCommon.h"
 
-#include "nsCOMPtr.h"
+#include "nsAutoPtr.h"
 
-class nsIIccListener;
-class nsIMobileConnectionListener;
-class nsITelephonyListener;
+#include "nsIIccProvider.h"
+#include "nsIMobileConnectionProvider.h"
+#include "nsITelephonyProvider.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
+class BluetoothRilListener;
+
+class IccListener : public nsIIccListener
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIICCLISTENER
+
+  IccListener() { }
+
+  bool Listen(bool aStart);
+  void SetOwner(BluetoothRilListener *aOwner);
+
+private:
+  BluetoothRilListener* mOwner;
+};
+
+class MobileConnectionListener : public nsIMobileConnectionListener
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIMOBILECONNECTIONLISTENER
+
+  MobileConnectionListener(uint32_t aClientId)
+  : mClientId(aClientId) { }
+
+  bool Listen(bool aStart);
+
+private:
+  uint32_t mClientId;
+};
+
+class TelephonyListener : public nsITelephonyListener
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSITELEPHONYLISTENER
+
+  TelephonyListener() { }
+
+  bool Listen(bool aStart);
+};
+
 class BluetoothRilListener
 {
 public:
   BluetoothRilListener();
+  ~BluetoothRilListener();
 
-  bool StartListening();
-  bool StopListening();
+  /**
+   * Start/Stop listening.
+   *
+   * @param aStart [in] whether to start/stop listening
+   */
+  bool Listen(bool aStart);
 
+  /**
+   * Be informed that certain client's service has changed.
+   *
+   * @param aClientId   [in] the client id with service change
+   * @param aRegistered [in] whether changed service is registered
+   */
+  void ServiceChanged(uint32_t aClientId, bool aRegistered);
+
+  /**
+   * Enumerate current calls.
+   */
   void EnumerateCalls();
 
+  /**
+   * The id of client that mobile connection and icc info listeners
+   * are listening to.
+   *
+   * mClientId equals to number of total clients (array length of
+   * mobile connection listeners) if there is no available client to listen.
+   */
+  uint32_t mClientId;
+
 private:
-  bool StartIccListening();
-  bool StopIccListening();
-
-  bool StartMobileConnectionListening();
-  bool StopMobileConnectionListening();
+  /**
+   * Start/Stop listening of mobile connection and icc info.
+   *
+   * @param aStart [in] whether to start/stop listening
+   */
+  bool ListenMobileConnAndIccInfo(bool aStart);
 
-  bool StartTelephonyListening();
-  bool StopTelephonyListening();
+  /**
+   * Select available client to listen and assign mClientId.
+   *
+   * mClientId is assigned to number of total clients (array length of
+   * mobile connection listeners) if there is no available client to listen.
+   */
+  void SelectClient();
 
-  nsCOMPtr<nsIIccListener> mIccListener;
-  nsCOMPtr<nsIMobileConnectionListener> mMobileConnectionListener;
-  nsCOMPtr<nsITelephonyListener> mTelephonyListener;
+  /**
+   * Array of mobile connection listeners.
+   *
+   * The length equals to number of total clients.
+   */
+  nsTArray<nsRefPtr<MobileConnectionListener> > mMobileConnListeners;
+
+  nsRefPtr<IccListener> mIccListener;
+  nsRefPtr<TelephonyListener> mTelephonyListener;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/bluedroid/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothHfpManager.cpp
@@ -381,17 +381,17 @@ BluetoothHfpManager::Init()
       NS_FAILED(obs->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false))) {
     BT_WARNING("Failed to add observers!");
     return false;
   }
 
   hal::RegisterBatteryObserver(this);
 
   mListener = new BluetoothRilListener();
-  NS_ENSURE_TRUE(mListener->StartListening(), false);
+  NS_ENSURE_TRUE(mListener->Listen(true), false);
 
   nsCOMPtr<nsISettingsService> settings =
     do_GetService("@mozilla.org/settingsService;1");
   NS_ENSURE_TRUE(settings, false);
 
   nsCOMPtr<nsISettingsServiceLock> settingsLock;
   nsresult rv = settings->CreateLock(getter_AddRefs(settingsLock));
   NS_ENSURE_SUCCESS(rv, false);
@@ -422,17 +422,17 @@ BluetoothHfpManager::InitHfpInterface()
     interface->init(&sBluetoothHfpCallbacks), false);
   sBluetoothHfpInterface = interface;
 
   return true;
 }
 
 BluetoothHfpManager::~BluetoothHfpManager()
 {
-  if (!mListener->StopListening()) {
+  if (!mListener->Listen(false)) {
     BT_WARNING("Failed to stop listening RIL");
   }
   mListener = nullptr;
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   NS_ENSURE_TRUE_VOID(obs);
 
   if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) ||
@@ -810,27 +810,30 @@ BluetoothHfpManager::HandleVolumeChanged
     NS_ENSURE_TRUE_VOID(sBluetoothHfpInterface);
     NS_ENSURE_TRUE_VOID(BT_STATUS_SUCCESS ==
       sBluetoothHfpInterface->volume_control(BTHF_VOLUME_TYPE_SPK,
                                              mCurrentVgs));
   }
 }
 
 void
-BluetoothHfpManager::HandleVoiceConnectionChanged()
+BluetoothHfpManager::HandleVoiceConnectionChanged(uint32_t aClientId)
 {
   nsCOMPtr<nsIMobileConnectionProvider> connection =
     do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
   NS_ENSURE_TRUE_VOID(connection);
 
   nsCOMPtr<nsIDOMMozMobileConnectionInfo> voiceInfo;
-  connection->GetVoiceConnectionInfo(0, getter_AddRefs(voiceInfo));
+  connection->GetVoiceConnectionInfo(aClientId, getter_AddRefs(voiceInfo));
   NS_ENSURE_TRUE_VOID(voiceInfo);
 
-  // Roam
+  nsString type;
+  voiceInfo->GetType(type);
+  mPhoneType = GetPhoneType(type);
+
   bool roaming;
   voiceInfo->GetRoaming(&roaming);
   mRoam = (roaming) ? 1 : 0;
 
   // Service
   nsString regState;
   voiceInfo->GetState(regState);
   mService = (regState.EqualsLiteral("registered")) ? 1 : 0;
@@ -862,24 +865,24 @@ BluetoothHfpManager::HandleVoiceConnecti
   // Please see Bug 871366 for more information.
   if (mOperatorName.Length() > 16) {
     BT_WARNING("The operator name was longer than 16 characters. We cut it.");
     mOperatorName.Left(mOperatorName, 16);
   }
 }
 
 void
-BluetoothHfpManager::HandleIccInfoChanged()
+BluetoothHfpManager::HandleIccInfoChanged(uint32_t aClientId)
 {
   nsCOMPtr<nsIIccProvider> icc =
     do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
   NS_ENSURE_TRUE_VOID(icc);
 
   nsCOMPtr<nsIDOMMozIccInfo> iccInfo;
-  icc->GetIccInfo(0, getter_AddRefs(iccInfo));
+  icc->GetIccInfo(aClientId, getter_AddRefs(iccInfo));
   NS_ENSURE_TRUE_VOID(iccInfo);
 
   nsCOMPtr<nsIDOMMozGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
   NS_ENSURE_TRUE_VOID(gsmIccInfo);
   gsmIccInfo->GetMsisdn(mMsisdn);
 }
 
 void
--- a/dom/bluetooth/bluedroid/BluetoothHfpManager.h
+++ b/dom/bluetooth/bluedroid/BluetoothHfpManager.h
@@ -91,18 +91,18 @@ public:
   bool IsScoConnected();
 
   /**
    * @param aSend A boolean indicates whether we need to notify headset or not
    */
   void HandleCallStateChanged(uint32_t aCallIndex, uint16_t aCallState,
                               const nsAString& aError, const nsAString& aNumber,
                               const bool aIsOutgoing, bool aSend);
-  void HandleIccInfoChanged();
-  void HandleVoiceConnectionChanged();
+  void HandleIccInfoChanged(uint32_t aClientId);
+  void HandleVoiceConnectionChanged(uint32_t aClientId);
 
   // Bluedroid hfp callback handlers
   void ProcessConnectionState(bthf_connection_state_t aState, bt_bdaddr_t* aBdAddress);
   void ProcessAudioState(bthf_audio_state_t aState, bt_bdaddr_t* aBdAddress);
   void ProcessAnswerCall();
   void ProcessHangupCall();
   void ProcessVolumeControl(bthf_volume_type_t aType, int aVolume);
   void ProcessDialCall(char *aNumber);
--- a/dom/bluetooth/bluez/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/bluez/BluetoothHfpManager.cpp
@@ -411,17 +411,17 @@ BluetoothHfpManager::Init()
     BT_WARNING("Failed to add observers!");
     return false;
   }
 
   hal::RegisterBatteryObserver(this);
 
 #ifdef MOZ_B2G_RIL
   mListener = new BluetoothRilListener();
-  if (!mListener->StartListening()) {
+  if (!mListener->Listen(true)) {
     BT_WARNING("Failed to start listening RIL");
     return false;
   }
 #endif
 
   nsCOMPtr<nsISettingsService> settings =
     do_GetService("@mozilla.org/settingsService;1");
   NS_ENSURE_TRUE(settings, false);
@@ -443,17 +443,17 @@ BluetoothHfpManager::Init()
   mScoSocketStatus = mScoSocket->GetConnectionStatus();
   ListenSco();
   return true;
 }
 
 BluetoothHfpManager::~BluetoothHfpManager()
 {
 #ifdef MOZ_B2G_RIL
-  if (!mListener->StopListening()) {
+  if (!mListener->Listen(false)) {
     BT_WARNING("Failed to stop listening RIL");
   }
   mListener = nullptr;
 #endif
 
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   NS_ENSURE_TRUE_VOID(obs);
 
@@ -582,40 +582,40 @@ BluetoothHfpManager::HandleVolumeChanged
   // Only send volume back when there's a connected headset
   if (IsConnected()) {
     SendCommand("+VGS: ", mCurrentVgs);
   }
 }
 
 #ifdef MOZ_B2G_RIL
 void
-BluetoothHfpManager::HandleVoiceConnectionChanged()
+BluetoothHfpManager::HandleVoiceConnectionChanged(uint32_t aClientId)
 {
   nsCOMPtr<nsIMobileConnectionProvider> connection =
     do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
   NS_ENSURE_TRUE_VOID(connection);
 
   nsCOMPtr<nsIDOMMozMobileConnectionInfo> voiceInfo;
-  // TODO: Bug 921991 - B2G BT: support multiple sim cards
-  connection->GetVoiceConnectionInfo(0, getter_AddRefs(voiceInfo));
+  connection->GetVoiceConnectionInfo(aClientId, getter_AddRefs(voiceInfo));
   NS_ENSURE_TRUE_VOID(voiceInfo);
 
   nsString type;
   voiceInfo->GetType(type);
   mPhoneType = GetPhoneType(type);
 
   bool roaming;
   voiceInfo->GetRoaming(&roaming);
   UpdateCIND(CINDType::ROAM, roaming);
 
-  bool service = false;
   nsString regState;
   voiceInfo->GetState(regState);
-  if (regState.EqualsLiteral("registered")) {
-    service = true;
+  bool service = regState.EqualsLiteral("registered");
+  if (service != sCINDItems[CINDType::SERVICE].value) {
+    // Notify BluetoothRilListener of service change
+    mListener->ServiceChanged(aClientId, service);
   }
   UpdateCIND(CINDType::SERVICE, service);
 
   uint8_t signal;
   JS::Value value;
   voiceInfo->GetRelSignalStrength(&value);
   if (!value.isNumber()) {
     BT_WARNING("Failed to get relSignalStrength in BluetoothHfpManager");
@@ -626,18 +626,17 @@ BluetoothHfpManager::HandleVoiceConnecti
 
   /**
    * Possible return values for mode are:
    * - null (unknown): set mNetworkSelectionMode to 0 (auto)
    * - automatic: set mNetworkSelectionMode to 0 (auto)
    * - manual: set mNetworkSelectionMode to 1 (manual)
    */
   nsString mode;
-  // TODO: Bug 921991 - B2G BT: support multiple sim cards
-  connection->GetNetworkSelectionMode(0, mode);
+  connection->GetNetworkSelectionMode(aClientId, mode);
   if (mode.EqualsLiteral("manual")) {
     mNetworkSelectionMode = 1;
   } else {
     mNetworkSelectionMode = 0;
   }
 
   nsCOMPtr<nsIDOMMozMobileNetworkInfo> network;
   voiceInfo->GetNetwork(getter_AddRefs(network));
@@ -654,25 +653,24 @@ BluetoothHfpManager::HandleVoiceConnecti
   // Please see Bug 871366 for more information.
   if (mOperatorName.Length() > 16) {
     BT_WARNING("The operator name was longer than 16 characters. We cut it.");
     mOperatorName.Left(mOperatorName, 16);
   }
 }
 
 void
-BluetoothHfpManager::HandleIccInfoChanged()
+BluetoothHfpManager::HandleIccInfoChanged(uint32_t aClientId)
 {
   nsCOMPtr<nsIIccProvider> icc =
     do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
   NS_ENSURE_TRUE_VOID(icc);
 
   nsCOMPtr<nsIDOMMozIccInfo> iccInfo;
-  // TODO: Bug 921991 - B2G BT: support multiple sim cards
-  icc->GetIccInfo(0, getter_AddRefs(iccInfo));
+  icc->GetIccInfo(aClientId, getter_AddRefs(iccInfo));
   NS_ENSURE_TRUE_VOID(iccInfo);
 
   nsCOMPtr<nsIDOMMozGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
   NS_ENSURE_TRUE_VOID(gsmIccInfo);
   gsmIccInfo->GetMsisdn(mMsisdn);
 }
 #endif // MOZ_B2G_RIL
 
--- a/dom/bluetooth/bluez/BluetoothHfpManager.h
+++ b/dom/bluetooth/bluez/BluetoothHfpManager.h
@@ -116,18 +116,18 @@ public:
 
 #ifdef MOZ_B2G_RIL
   /**
    * @param aSend A boolean indicates whether we need to notify headset or not
    */
   void HandleCallStateChanged(uint32_t aCallIndex, uint16_t aCallState,
                               const nsAString& aError, const nsAString& aNumber,
                               const bool aIsOutgoing, bool aSend);
-  void HandleIccInfoChanged();
-  void HandleVoiceConnectionChanged();
+  void HandleIccInfoChanged(uint32_t aClientId);
+  void HandleVoiceConnectionChanged(uint32_t aClientId);
 
   // CDMA-specific functions
   void UpdateSecondNumber(const nsAString& aNumber);
   void AnswerWaitingCall();
   void IgnoreWaitingCall();
   void ToggleCalls();
 #endif
 
--- a/dom/system/gonk/nsRadioInterfaceLayer.h
+++ b/dom/system/gonk/nsRadioInterfaceLayer.h
@@ -6,9 +6,11 @@
 
 #define NS_RADIOINTERFACELAYER_CID \
     { 0x2d831c8d, 0x6017, 0x435b, \
       { 0xa8, 0x0c, 0xe5, 0xd4, 0x22, 0x81, 0x0c, 0xea } }
 
 #define NS_RILCONTENTHELPER_CID \
     { 0x472816e1, 0x1fd6, 0x4405, \
       { 0x99, 0x6c, 0x80, 0x6f, 0x9e, 0xa6, 0x81, 0x74 } }
+
+#define NS_RADIOINTERFACELAYER_CONTRACTID "@mozilla.org/ril;1"
 #define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1"