Bug 1063304 - 3.b/3: implementation. r=echen
☠☠ backed out by a3fe8ac47f8a ☠ ☠
authorVicamo Yang <vyang@mozilla.com>
Tue, 16 Sep 2014 21:20:18 +0800
changeset 205505 11f7b314276295878aa12889a18d0601f4820452
parent 205504 32f15256799627720c2e1a2d56f6fd4e7482adaf
child 205506 9ff2889f236a420766dc4f60a3c7cd9ef2f6095b
push id10681
push uservyang@mozilla.com
push dateTue, 16 Sep 2014 13:20:43 +0000
treeherderb2g-inbound@69870df1c72f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersechen
bugs1063304
milestone35.0a1
Bug 1063304 - 3.b/3: implementation. r=echen
dom/mobileconnection/MobileConnection.cpp
dom/mobileconnection/MobileConnection.h
dom/mobileconnection/MobileConnectionArray.cpp
dom/mobileconnection/MobileConnectionArray.h
dom/mobileconnection/ipc/MobileConnectionChild.cpp
dom/mobileconnection/ipc/MobileConnectionChild.h
dom/mobileconnection/ipc/MobileConnectionIPCService.cpp
dom/mobileconnection/ipc/MobileConnectionIPCService.h
dom/mobileconnection/ipc/MobileConnectionParent.cpp
dom/mobileconnection/ipc/MobileConnectionParent.h
--- a/dom/mobileconnection/MobileConnection.cpp
+++ b/dom/mobileconnection/MobileConnection.cpp
@@ -73,18 +73,19 @@ private:
 
 NS_IMPL_ISUPPORTS(MobileConnection::Listener, nsIMobileConnectionListener)
 
 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 mService because
-  // it's an xpcom service and is only released at shutting down.
+  // MobileConnection but a raw pointer instead. Neither does mMobileConnection
+  // because it's an xpcom service owned object and is only released at shutting
+  // down.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoice)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MobileConnection,
                                                 DOMEventTargetHelper)
   tmp->Shutdown();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mVoice)
@@ -97,48 +98,55 @@ 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)
 {
   SetIsDOMBinding();
 
-  mService = do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID);
+  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 (!mService) {
+  if (!service) {
     NS_WARNING("Could not acquire nsIMobileConnectionService!");
     return;
   }
 
+  nsresult rv = service->GetItemByServiceId(aClientId,
+                                            getter_AddRefs(mMobileConnection));
+  if (NS_FAILED(rv) || !mMobileConnection) {
+    NS_WARNING("Could not acquire nsIMobileConnection!");
+    return;
+  }
+
   mListener = new Listener(this);
   mVoice = new MobileConnectionInfo(GetOwner());
   mData = new MobileConnectionInfo(GetOwner());
 
   if (CheckPermission("mobileconnection")) {
-    DebugOnly<nsresult> rv = mService->RegisterListener(mClientId, mListener);
+    DebugOnly<nsresult> rv = mMobileConnection->RegisterListener(mListener);
     NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
                      "Failed registering mobile connection messages with service");
     UpdateVoice();
     UpdateData();
   }
 }
 
 void
 MobileConnection::Shutdown()
 {
   if (mListener) {
-    if (mService) {
-      mService->UnregisterListener(mClientId, mListener);
+    if (mMobileConnection) {
+      mMobileConnection->UnregisterListener(mListener);
     }
 
     mListener->Disconnect();
     mListener = nullptr;
   }
 }
 
 MobileConnection::~MobileConnection()
@@ -171,61 +179,61 @@ MobileConnection::CheckPermission(const 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
   permMgr->TestPermissionFromWindow(GetOwner(), aType, &permission);
   return permission == nsIPermissionManager::ALLOW_ACTION;
 }
 
 void
 MobileConnection::UpdateVoice()
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     return;
   }
 
   nsCOMPtr<nsIMobileConnectionInfo> info;
-  mService->GetVoiceConnectionInfo(mClientId, getter_AddRefs(info));
+  mMobileConnection->GetVoice(getter_AddRefs(info));
   mVoice->Update(info);
 }
 
 void
 MobileConnection::UpdateData()
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     return;
   }
 
   nsCOMPtr<nsIMobileConnectionInfo> info;
-  mService->GetDataConnectionInfo(mClientId, getter_AddRefs(info));
+  mMobileConnection->GetData(getter_AddRefs(info));
   mData->Update(info);
 }
 
 // WebIDL interface
 
 void
 MobileConnection::GetLastKnownNetwork(nsString& aRetVal) const
 {
   aRetVal.SetIsVoid(true);
 
-  if (!mService) {
+  if (!mMobileConnection) {
     return;
   }
 
-  mService->GetLastKnownNetwork(mClientId, aRetVal);
+  mMobileConnection->GetLastKnownNetwork(aRetVal);
 }
 
 void
 MobileConnection::GetLastKnownHomeNetwork(nsString& aRetVal) const
 {
   aRetVal.SetIsVoid(true);
 
-  if (!mService) {
+  if (!mMobileConnection) {
     return;
   }
 
-  mService->GetLastKnownHomeNetwork(mClientId, aRetVal);
+  mMobileConnection->GetLastKnownHomeNetwork(aRetVal);
 }
 
 // All fields below require the "mobileconnection" permission.
 
 MobileConnectionInfo*
 MobileConnection::Voice() const
 {
   return mVoice;
@@ -237,362 +245,350 @@ MobileConnection::Data() const
   return mData;
 }
 
 void
 MobileConnection::GetIccId(nsString& aRetVal) const
 {
   aRetVal.SetIsVoid(true);
 
-  if (!mService) {
+  if (!mMobileConnection) {
     return;
   }
 
-  mService->GetIccId(mClientId, aRetVal);
+  mMobileConnection->GetIccId(aRetVal);
 }
 
 Nullable<MobileNetworkSelectionMode>
 MobileConnection::GetNetworkSelectionMode() const
 {
   Nullable<MobileNetworkSelectionMode> retVal =
     Nullable<MobileNetworkSelectionMode>();
 
-  if (!mService) {
+  if (!mMobileConnection) {
     return retVal;
   }
 
   nsAutoString mode;
-  mService->GetNetworkSelectionMode(mClientId, mode);
+  mMobileConnection->GetNetworkSelectionMode(mode);
   CONVERT_STRING_TO_NULLABLE_ENUM(mode, MobileNetworkSelectionMode, retVal);
 
   return retVal;
 }
 
 Nullable<MobileRadioState>
 MobileConnection::GetRadioState() const
 {
   Nullable<MobileRadioState> retVal = Nullable<MobileRadioState>();
 
-  if (!mService) {
+  if (!mMobileConnection) {
     return retVal;
   }
 
   nsAutoString state;
-  mService->GetRadioState(mClientId, state);
+  mMobileConnection->GetRadioState(state);
   CONVERT_STRING_TO_NULLABLE_ENUM(state, MobileRadioState, retVal);
 
   return retVal;
 }
 
 void
 MobileConnection::GetSupportedNetworkTypes(nsTArray<MobileNetworkType>& aTypes) const
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     return;
   }
 
-  nsCOMPtr<nsIVariant> variant;
-  mService->GetSupportedNetworkTypes(mClientId,
-                                     getter_AddRefs(variant));
+  char16_t** types = nullptr;
+  uint32_t length = 0;
+
+  nsresult rv = mMobileConnection->GetSupportedNetworkTypes(&types, &length);
+  NS_ENSURE_SUCCESS_VOID(rv);
 
-  uint16_t type;
-  nsIID iid;
-  uint32_t count;
-  void* data;
+  for (uint32_t i = 0; i < length; ++i) {
+    nsDependentString rawType(types[i]);
+    Nullable<MobileNetworkType> type = Nullable<MobileNetworkType>();
+    CONVERT_STRING_TO_NULLABLE_ENUM(rawType, MobileNetworkType, type);
 
-  // Convert the nsIVariant to an array.  We own the resulting buffer and its
-  // elements.
-  if (NS_FAILED(variant->GetAsArray(&type, &iid, &count, &data))) {
-    return;
+    if (!type.IsNull()) {
+      aTypes.AppendElement(type.Value());
+    }
   }
 
-  // We expect the element type is wstring.
-  if (type == nsIDataType::VTYPE_WCHAR_STR) {
-    char16_t** rawArray = reinterpret_cast<char16_t**>(data);
-    for (uint32_t i = 0; i < count; ++i) {
-      nsDependentString rawType(rawArray[i]);
-      Nullable<MobileNetworkType> type = Nullable<MobileNetworkType>();
-      CONVERT_STRING_TO_NULLABLE_ENUM(rawType, MobileNetworkType, type);
-
-      if (!type.IsNull()) {
-        aTypes.AppendElement(type.Value());
-      }
-    }
-  }
-  NS_Free(data);
+  NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(length, types);
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::GetNetworks(ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->GetNetworks(mClientId, requestCallback);
+  nsresult rv = mMobileConnection->GetNetworks(requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::SelectNetwork(MobileNetworkInfo& aNetwork, ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->SelectNetwork(mClientId, &aNetwork, requestCallback);
+  nsresult rv = mMobileConnection->SelectNetwork(&aNetwork, requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::SelectNetworkAutomatically(ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->SelectNetworkAutomatically(mClientId,
-                                                     requestCallback);
+  nsresult rv =
+    mMobileConnection->SelectNetworkAutomatically(requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::SetPreferredNetworkType(MobilePreferredNetworkType& aType,
                                           ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsAutoString type;
   CONVERT_ENUM_TO_STRING(MobilePreferredNetworkType, aType, type);
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->SetPreferredNetworkType(mClientId, type,
-                                                  requestCallback);
+  nsresult rv =
+    mMobileConnection->SetPreferredNetworkType(type, requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::GetPreferredNetworkType(ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->GetPreferredNetworkType(mClientId, requestCallback);
+  nsresult rv = mMobileConnection->GetPreferredNetworkType(requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::SetRoamingPreference(MobileRoamingMode& aMode,
                                        ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsAutoString mode;
   CONVERT_ENUM_TO_STRING(MobileRoamingMode, aMode, mode);
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->SetRoamingPreference(mClientId, mode, requestCallback);
+  nsresult rv = mMobileConnection->SetRoamingPreference(mode, requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::GetRoamingPreference(ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->GetRoamingPreference(mClientId, requestCallback);
+  nsresult rv = mMobileConnection->GetRoamingPreference(requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::SetVoicePrivacyMode(bool aEnabled, ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->SetVoicePrivacyMode(mClientId, aEnabled,
-                                              requestCallback);
+  nsresult rv =
+    mMobileConnection->SetVoicePrivacyMode(aEnabled, requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::GetVoicePrivacyMode(ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->GetVoicePrivacyMode(mClientId, requestCallback);
+  nsresult rv = mMobileConnection->GetVoicePrivacyMode(requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::SendMMI(const nsAString& aMMIString, ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->SendMMI(mClientId, aMMIString, requestCallback);
+  nsresult rv = mMobileConnection->SendMMI(aMMIString, requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::CancelMMI(ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->CancelMMI(mClientId, requestCallback);
+  nsresult rv = mMobileConnection->CancelMMI(requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::GetCallForwardingOption(uint16_t aReason, ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->GetCallForwarding(mClientId, aReason, requestCallback);
+  nsresult rv = mMobileConnection->GetCallForwarding(aReason, requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::SetCallForwardingOption(const MozCallForwardingOptions& aOptions,
                                           ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   AutoJSAPI jsapi;
   if (!NS_WARN_IF(jsapi.Init(GetOwner()))) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
@@ -604,30 +600,30 @@ MobileConnection::SetCallForwardingOptio
     aRv.Throw(NS_ERROR_TYPE_ERR);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->SetCallForwarding(mClientId, options, requestCallback);
+  nsresult rv = mMobileConnection->SetCallForwarding(options, requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::GetCallBarringOption(const MozCallBarringOptions& aOptions,
                                        ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   AutoJSAPI jsapi;
   if (!NS_WARN_IF(jsapi.Init(GetOwner()))) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
@@ -639,30 +635,30 @@ MobileConnection::GetCallBarringOption(c
     aRv.Throw(NS_ERROR_TYPE_ERR);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->GetCallBarring(mClientId, options, requestCallback);
+  nsresult rv = mMobileConnection->GetCallBarring(options, requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::SetCallBarringOption(const MozCallBarringOptions& aOptions,
                                        ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   AutoJSAPI jsapi;
   if (!NS_WARN_IF(jsapi.Init(GetOwner()))) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
@@ -674,30 +670,30 @@ MobileConnection::SetCallBarringOption(c
     aRv.Throw(NS_ERROR_TYPE_ERR);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->SetCallBarring(mClientId, options, requestCallback);
+  nsresult rv = mMobileConnection->SetCallBarring(options, requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::ChangeCallBarringPassword(const MozCallBarringOptions& aOptions,
                                             ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   AutoJSAPI jsapi;
   if (!NS_WARN_IF(jsapi.Init(GetOwner()))) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
@@ -709,147 +705,147 @@ MobileConnection::ChangeCallBarringPassw
     aRv.Throw(NS_ERROR_TYPE_ERR);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->ChangeCallBarringPassword(mClientId, options,
-                                                    requestCallback);
+  nsresult rv =
+    mMobileConnection->ChangeCallBarringPassword(options, requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::GetCallWaitingOption(ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->GetCallWaiting(mClientId, requestCallback);
+  nsresult rv = mMobileConnection->GetCallWaiting(requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::SetCallWaitingOption(bool aEnabled, ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->SetCallWaiting(mClientId, aEnabled, requestCallback);
+  nsresult rv = mMobileConnection->SetCallWaiting(aEnabled, requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::GetCallingLineIdRestriction(ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->GetCallingLineIdRestriction(mClientId,
-                                                      requestCallback);
+  nsresult rv =
+    mMobileConnection->GetCallingLineIdRestriction(requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::SetCallingLineIdRestriction(uint16_t aMode,
                                               ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->SetCallingLineIdRestriction(mClientId, aMode,
-                                                      requestCallback);
+  nsresult rv =
+    mMobileConnection->SetCallingLineIdRestriction(aMode, requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::ExitEmergencyCbMode(ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->ExitEmergencyCbMode(mClientId, requestCallback);
+  nsresult rv = mMobileConnection->ExitEmergencyCbMode(requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 MobileConnection::SetRadioEnabled(bool aEnabled, ErrorResult& aRv)
 {
-  if (!mService) {
+  if (!mMobileConnection) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
   nsRefPtr<MobileConnectionCallback> requestCallback =
     new MobileConnectionCallback(GetOwner(), request);
 
-  nsresult rv = mService->SetRadioEnabled(mClientId, aEnabled, requestCallback);
+  nsresult rv = mMobileConnection->SetRadioEnabled(aEnabled, requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
--- a/dom/mobileconnection/MobileConnection.h
+++ b/dom/mobileconnection/MobileConnection.h
@@ -158,18 +158,17 @@ public:
   IMPL_EVENT_HANDLER(iccchange)
   IMPL_EVENT_HANDLER(radiostatechange)
   IMPL_EVENT_HANDLER(clirmodechange)
 
 private:
   ~MobileConnection();
 
 private:
-  uint32_t mClientId;
-  nsCOMPtr<nsIMobileConnectionService> mService;
+  nsCOMPtr<nsIMobileConnection> mMobileConnection;
   nsRefPtr<Listener> mListener;
   nsRefPtr<MobileConnectionInfo> mVoice;
   nsRefPtr<MobileConnectionInfo> mData;
 
   bool
   CheckPermission(const char* aType) const;
 
   void
--- a/dom/mobileconnection/MobileConnectionArray.cpp
+++ b/dom/mobileconnection/MobileConnectionArray.cpp
@@ -2,58 +2,43 @@
 /* vim: set ts=8 sts=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 "mozilla/dom/MobileConnectionArray.h"
 #include "mozilla/dom/MozMobileConnectionArrayBinding.h"
 #include "mozilla/Preferences.h"
+#include "nsServiceManagerUtils.h"
 
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MobileConnectionArray,
                                       mWindow,
                                       mMobileConnections)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(MobileConnectionArray)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(MobileConnectionArray)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MobileConnectionArray)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 MobileConnectionArray::MobileConnectionArray(nsPIDOMWindow* aWindow)
-  : mInitialized(false)
+  : mLengthInitialized(false)
   , mWindow(aWindow)
 {
-  uint32_t numRil = mozilla::Preferences::GetUint("ril.numRadioInterfaces", 1);
-  MOZ_ASSERT(numRil > 0);
-
-  mMobileConnections.SetLength(numRil);
-
   SetIsDOMBinding();
 }
 
 MobileConnectionArray::~MobileConnectionArray()
 {
 }
 
-void
-MobileConnectionArray::Init()
-{
-  mInitialized = true;
-
-  for (uint32_t id = 0; id < mMobileConnections.Length(); id++) {
-    nsRefPtr<MobileConnection> mobileConnection = new MobileConnection(mWindow, id);
-    mMobileConnections[id] = mobileConnection;
-  }
-}
-
 nsPIDOMWindow*
 MobileConnectionArray::GetParentObject() const
 {
   MOZ_ASSERT(mWindow);
   return mWindow;
 }
 
 JSObject*
@@ -65,25 +50,42 @@ MobileConnectionArray::WrapObject(JSCont
 MobileConnection*
 MobileConnectionArray::Item(uint32_t aIndex)
 {
   bool unused;
   return IndexedGetter(aIndex, unused);
 }
 
 uint32_t
-MobileConnectionArray::Length() const
+MobileConnectionArray::Length()
 {
+  if (!mLengthInitialized) {
+    mLengthInitialized = true;
+
+    nsCOMPtr<nsIMobileConnectionService> service =
+      do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID);
+    NS_ENSURE_TRUE(service, 0);
+
+    uint32_t length = 0;
+    nsresult rv = service->GetNumItems(&length);
+    NS_ENSURE_SUCCESS(rv, 0);
+
+    mMobileConnections.SetLength(length);
+  }
+
   return mMobileConnections.Length();
 }
 
 MobileConnection*
 MobileConnectionArray::IndexedGetter(uint32_t aIndex, bool& aFound)
 {
-  if (!mInitialized) {
-    Init();
+
+  aFound = aIndex < Length();
+  if (!aFound) {
+    return nullptr;
   }
 
-  aFound = false;
-  aFound = aIndex < mMobileConnections.Length();
+  if (!mMobileConnections[aIndex]) {
+    mMobileConnections[aIndex] = new MobileConnection(mWindow, aIndex);
+  }
 
-  return aFound ? mMobileConnections[aIndex] : nullptr;
+  return mMobileConnections[aIndex];
 }
--- a/dom/mobileconnection/MobileConnectionArray.h
+++ b/dom/mobileconnection/MobileConnectionArray.h
@@ -29,28 +29,25 @@ public:
   virtual JSObject*
   WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   //  WebIDL
   MobileConnection*
   Item(uint32_t aIndex);
 
   uint32_t
-  Length() const;
+  Length();
 
   MobileConnection*
   IndexedGetter(uint32_t aIndex, bool& aFound);
 
 private:
   ~MobileConnectionArray();
 
-  void
-  Init();
-
-  bool mInitialized;
+  bool mLengthInitialized;
 
   nsCOMPtr<nsPIDOMWindow> mWindow;
   nsTArray<nsRefPtr<MobileConnection>> mMobileConnections;
 };
 
 } // namespace dom
 } // namespace mozilla
 
--- a/dom/mobileconnection/ipc/MobileConnectionChild.cpp
+++ b/dom/mobileconnection/ipc/MobileConnectionChild.cpp
@@ -6,152 +6,361 @@
 
 #include "MobileConnectionCallback.h"
 #include "mozilla/dom/MozMobileConnectionBinding.h"
 #include "nsComponentManagerUtils.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::dom::mobileconnection;
 
+NS_IMPL_ISUPPORTS(MobileConnectionChild, nsIMobileConnection)
+
+MobileConnectionChild::MobileConnectionChild(uint32_t aServiceId)
+  : mServiceId(aServiceId)
+  , mLive(true)
+{
+  MOZ_COUNT_CTOR(MobileConnectionChild);
+}
+
 void
 MobileConnectionChild::Init()
 {
   nsIMobileConnectionInfo* rawVoice;
   nsIMobileConnectionInfo* rawData;
-  nsTArray<nsString> types;
 
   SendInit(&rawVoice, &rawData, &mLastNetwork, &mLastHomeNetwork, &mIccId,
-           &mNetworkSelectionMode, &mRadioState, &types);
+           &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);
 
   // Use dont_AddRef here because this instances is already AddRef-ed in
   // MobileConnectionIPCSerializer.h
   nsCOMPtr<nsIMobileConnectionInfo> data = dont_AddRef(rawData);
   mData = new MobileConnectionInfo(nullptr);
   mData->Update(data);
-
-
-  // Initial SupportedNetworkTypes
-  nsresult rv;
-  mSupportedNetworkTypes = do_CreateInstance(NS_VARIANT_CONTRACTID, &rv);
-
-  if (NS_FAILED(rv)) {
-    return;
-  }
-
-  uint32_t arrayLen = types.Length();
-  if (arrayLen == 0) {
-    mSupportedNetworkTypes->SetAsEmptyArray();
-  } else {
-    // Note: The resulting nsIVariant dupes both the array and its elements.
-    const char16_t** array = reinterpret_cast<const char16_t**>
-                               (NS_Alloc(arrayLen * sizeof(const char16_t***)));
-    if (array) {
-      for (uint32_t i = 0; i < arrayLen; ++i) {
-        array[i] = types[i].get();
-      }
-
-      mSupportedNetworkTypes->SetAsArray(nsIDataType::VTYPE_WCHAR_STR,
-                                         nullptr,
-                                         arrayLen,
-                                         reinterpret_cast<void*>(array));
-      NS_Free(array);
-    }
-  }
 }
 
 void
 MobileConnectionChild::Shutdown()
 {
   if (mLive) {
     mLive = false;
     Send__delete__(this);
   }
 
   mListeners.Clear();
   mVoice = nullptr;
   mData = nullptr;
-  mSupportedNetworkTypes = nullptr;
 }
 
-void
+// nsIMobileConnection
+
+NS_IMETHODIMP
+MobileConnectionChild::GetServiceId(uint32_t* aServiceId)
+{
+  *aServiceId = mServiceId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 MobileConnectionChild::RegisterListener(nsIMobileConnectionListener* aListener)
 {
-  if (!mListeners.Contains(aListener)) {
-    mListeners.AppendObject(aListener);
-  }
+  NS_ENSURE_TRUE(!mListeners.Contains(aListener), NS_ERROR_UNEXPECTED);
+
+  mListeners.AppendObject(aListener);
+  return NS_OK;
 }
 
-void
+NS_IMETHODIMP
 MobileConnectionChild::UnregisterListener(nsIMobileConnectionListener* aListener)
 {
+  NS_ENSURE_TRUE(mListeners.Contains(aListener), NS_ERROR_UNEXPECTED);
+
   mListeners.RemoveObject(aListener);
+  return NS_OK;
 }
 
-MobileConnectionInfo*
-MobileConnectionChild::GetVoiceInfo()
+NS_IMETHODIMP
+MobileConnectionChild::GetVoice(nsIMobileConnectionInfo** aVoice)
 {
-  return mVoice;
+  nsRefPtr<nsIMobileConnectionInfo> voice(mVoice);
+  voice.forget(aVoice);
+  return NS_OK;
 }
 
-MobileConnectionInfo*
-MobileConnectionChild::GetDataInfo()
+NS_IMETHODIMP
+MobileConnectionChild::GetData(nsIMobileConnectionInfo** aData)
 {
-  return mData;
+  nsRefPtr<nsIMobileConnectionInfo> data(mData);
+  data.forget(aData);
+  return NS_OK;
 }
 
-void
+NS_IMETHODIMP
 MobileConnectionChild::GetIccId(nsAString& aIccId)
 {
   aIccId = mIccId;
+  return NS_OK;
 }
 
-void
+NS_IMETHODIMP
 MobileConnectionChild::GetRadioState(nsAString& aRadioState)
 {
   aRadioState = mRadioState;
-}
-
-nsIVariant*
-MobileConnectionChild::GetSupportedNetworkTypes()
-{
-  return mSupportedNetworkTypes;
+  return NS_OK;
 }
 
-void
-MobileConnectionChild::GetLastNetwork(nsAString& aNetwork)
+NS_IMETHODIMP
+MobileConnectionChild::GetSupportedNetworkTypes(char16_t*** aTypes,
+                                                uint32_t* aLength)
 {
-  aNetwork = mLastNetwork;
+  NS_ENSURE_ARG(aTypes);
+  NS_ENSURE_ARG(aLength);
+
+  *aLength = mSupportedNetworkTypes.Length();
+  *aTypes =
+    static_cast<char16_t**>(nsMemory::Alloc((*aLength) * sizeof(char16_t*)));
+  NS_ENSURE_TRUE(*aTypes, NS_ERROR_OUT_OF_MEMORY);
+
+  for (uint32_t i = 0; i < *aLength; i++) {
+    (*aTypes)[i] = ToNewUnicode(mSupportedNetworkTypes[i]);
+  }
+
+  return NS_OK;
 }
 
-void
-MobileConnectionChild::GetLastHomeNetwork(nsAString& aNetwork)
+NS_IMETHODIMP
+MobileConnectionChild::GetLastKnownNetwork(nsAString& aNetwork)
+{
+  aNetwork = mLastNetwork;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::GetLastKnownHomeNetwork(nsAString& aNetwork)
 {
   aNetwork = mLastHomeNetwork;
+  return NS_OK;
 }
 
-void
+NS_IMETHODIMP
 MobileConnectionChild::GetNetworkSelectionMode(nsAString& aMode)
 {
   aMode = mNetworkSelectionMode;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::GetNetworks(nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(GetNetworksRequest(), aCallback) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::SelectNetwork(nsIMobileNetworkInfo* aNetwork,
+                                     nsIMobileConnectionCallback* aCallback)
+{
+  nsCOMPtr<nsIMobileNetworkInfo> network = aNetwork;
+  // We release the ref after serializing process is finished in
+  // MobileConnectionIPCSerializer.
+  return SendRequest(SelectNetworkRequest(network.forget().take()), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::SelectNetworkAutomatically(nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(SelectNetworkAutoRequest(), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+
+NS_IMETHODIMP
+MobileConnectionChild::SetPreferredNetworkType(const nsAString& aType,
+                                               nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(SetPreferredNetworkTypeRequest(nsAutoString(aType)),
+                     aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::GetPreferredNetworkType(nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(GetPreferredNetworkTypeRequest(), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::SetRoamingPreference(const nsAString& aMode,
+                                            nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(SetRoamingPreferenceRequest(nsAutoString(aMode)),
+                     aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::GetRoamingPreference(nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(GetRoamingPreferenceRequest(), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::SetVoicePrivacyMode(bool aEnabled,
+                                           nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(SetVoicePrivacyModeRequest(aEnabled), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::GetVoicePrivacyMode(nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(GetVoicePrivacyModeRequest(), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::SendMMI(const nsAString& aMmi,
+                               nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(SendMmiRequest(nsAutoString(aMmi)), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::CancelMMI(nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(CancelMmiRequest(), aCallback) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::SetCallForwarding(JS::Handle<JS::Value> aOptions,
+                                         nsIMobileConnectionCallback* aCallback)
+{
+  AutoSafeJSContext cx;
+  IPC::MozCallForwardingOptions options;
+  if(!options.Init(cx, aOptions)) {
+    return NS_ERROR_TYPE_ERR;
+  }
+
+  return SendRequest(SetCallForwardingRequest(options), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::GetCallForwarding(uint16_t aReason,
+                                         nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(GetCallForwardingRequest(aReason), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::SetCallBarring(JS::Handle<JS::Value> aOptions,
+                                      nsIMobileConnectionCallback* aCallback)
+{
+  AutoSafeJSContext cx;
+  IPC::MozCallBarringOptions options;
+  if(!options.Init(cx, aOptions)) {
+    return NS_ERROR_TYPE_ERR;
+  }
+
+  return SendRequest(SetCallBarringRequest(options), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::GetCallBarring(JS::Handle<JS::Value> aOptions,
+                                      nsIMobileConnectionCallback* aCallback)
+{
+  AutoSafeJSContext cx;
+  IPC::MozCallBarringOptions options;
+  if(!options.Init(cx, aOptions)) {
+    return NS_ERROR_TYPE_ERR;
+  }
+
+  return SendRequest(GetCallBarringRequest(options), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::ChangeCallBarringPassword(JS::Handle<JS::Value> aOptions,
+                                                 nsIMobileConnectionCallback* aCallback)
+{
+  AutoSafeJSContext cx;
+  IPC::MozCallBarringOptions options;
+  if(!options.Init(cx, aOptions)) {
+    return NS_ERROR_TYPE_ERR;
+  }
+
+  return SendRequest(ChangeCallBarringPasswordRequest(options), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::SetCallWaiting(bool aEnabled,
+                                      nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(SetCallWaitingRequest(aEnabled), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::GetCallWaiting(nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(GetCallWaitingRequest(), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::SetCallingLineIdRestriction(uint16_t aMode,
+                                                   nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(SetCallingLineIdRestrictionRequest(aMode), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::GetCallingLineIdRestriction(nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(GetCallingLineIdRestrictionRequest(), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::ExitEmergencyCbMode(nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(ExitEmergencyCbModeRequest(), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+MobileConnectionChild::SetRadioEnabled(bool aEnabled,
+                                       nsIMobileConnectionCallback* aCallback)
+{
+  return SendRequest(SetRadioEnabledRequest(aEnabled), aCallback)
+    ? NS_OK : NS_ERROR_FAILURE;
 }
 
 bool
-MobileConnectionChild::SendRequest(MobileConnectionRequest aRequest,
-                                   nsIMobileConnectionCallback* aRequestCallback)
+MobileConnectionChild::SendRequest(const MobileConnectionRequest& aRequest,
+                                   nsIMobileConnectionCallback* aCallback)
 {
   NS_ENSURE_TRUE(mLive, false);
 
   // Deallocated in MobileConnectionChild::DeallocPMobileConnectionRequestChild().
-  MobileConnectionRequestChild* actor = new MobileConnectionRequestChild(aRequestCallback);
+  MobileConnectionRequestChild* actor =
+    new MobileConnectionRequestChild(aCallback);
   SendPMobileConnectionRequestConstructor(actor, aRequest);
 
   return true;
 }
 
 void
 MobileConnectionChild::ActorDestroy(ActorDestroyReason why)
 {
--- a/dom/mobileconnection/ipc/MobileConnectionChild.h
+++ b/dom/mobileconnection/ipc/MobileConnectionChild.h
@@ -20,75 +20,45 @@ namespace dom {
 namespace mobileconnection {
 
 /**
  * Child actor of PMobileConnection. The object is created by
  * MobileConnectionIPCService and destroyed after MobileConnectionIPCService is
  * shutdown. For multi-sim device, more than one instance will
  * be created and each instance represents a sim slot.
  */
-class MobileConnectionChild : public PMobileConnectionChild
+class MobileConnectionChild MOZ_FINAL : public PMobileConnectionChild
+                                      , public nsIMobileConnection
 {
-  NS_INLINE_DECL_REFCOUNTING(MobileConnectionChild)
-
 public:
-  MobileConnectionChild()
-    : mLive(true)
-  {
-    MOZ_COUNT_CTOR(MobileConnectionChild);
-  }
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIMOBILECONNECTION
+
+  MobileConnectionChild(uint32_t aServiceId);
 
   void
   Init();
 
   void
   Shutdown();
 
-  void
-  RegisterListener(nsIMobileConnectionListener* aListener);
-
-  void
-  UnregisterListener(nsIMobileConnectionListener* aListener);
-
-  MobileConnectionInfo*
-  GetVoiceInfo();
-
-  MobileConnectionInfo*
-  GetDataInfo();
-
-  void
-  GetIccId(nsAString& aIccId);
-
-  void
-  GetRadioState(nsAString& aRadioState);
+private:
+  MobileConnectionChild() MOZ_DELETE;
 
-  nsIVariant*
-  GetSupportedNetworkTypes();
-
-  void
-  GetLastNetwork(nsAString& aNetwork);
-
-  void
-  GetLastHomeNetwork(nsAString& aNetwork);
-
-  void
-  GetNetworkSelectionMode(nsAString& aMode);
-
-  bool
-  SendRequest(MobileConnectionRequest aRequest,
-              nsIMobileConnectionCallback* aRequestCallback);
-
-protected:
-  virtual
+  // MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
   ~MobileConnectionChild()
   {
     MOZ_COUNT_DTOR(MobileConnectionChild);
-    Shutdown();
   }
 
+protected:
+  bool
+  SendRequest(const MobileConnectionRequest& aRequest,
+              nsIMobileConnectionCallback* aCallback);
+
   virtual void
   ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
   virtual PMobileConnectionRequestChild*
   AllocPMobileConnectionRequestChild(const MobileConnectionRequest& request) MOZ_OVERRIDE;
 
   virtual bool
   DeallocPMobileConnectionRequestChild(PMobileConnectionRequestChild* aActor) MOZ_OVERRIDE;
@@ -132,26 +102,27 @@ protected:
 
   virtual bool
   RecvNotifyLastHomeNetworkChanged(const nsString& aNetwork) MOZ_OVERRIDE;
 
   virtual bool
   RecvNotifyNetworkSelectionModeChanged(const nsString& aMode) MOZ_OVERRIDE;
 
 private:
+  uint32_t mServiceId;
   bool mLive;
   nsCOMArray<nsIMobileConnectionListener> mListeners;
-  nsCOMPtr<nsIWritableVariant> mSupportedNetworkTypes;
   nsRefPtr<MobileConnectionInfo> mVoice;
   nsRefPtr<MobileConnectionInfo> mData;
   nsString mIccId;
   nsString mRadioState;
   nsString mLastNetwork;
   nsString mLastHomeNetwork;
   nsString mNetworkSelectionMode;
+  nsTArray<nsString> mSupportedNetworkTypes;
 };
 
 /******************************************************************************
  * PMobileConnectionRequestChild
  ******************************************************************************/
 
 /**
  * Child actor of PMobileConnectionRequest. The object is created when an
--- a/dom/mobileconnection/ipc/MobileConnectionIPCService.cpp
+++ b/dom/mobileconnection/ipc/MobileConnectionIPCService.cpp
@@ -27,368 +27,53 @@ MobileConnectionIPCService::GetSingleton
 
   sService = new MobileConnectionIPCService();
   return sService;
 }
 
 MobileConnectionIPCService::MobileConnectionIPCService()
 {
   int32_t numRil = Preferences::GetInt("ril.numRadioInterfaces", 1);
-  for (int32_t i = 0; i < numRil; i++) {
-    // Deallocated in ContentChild::DeallocPMobileConnectionChild().
-    nsRefPtr<MobileConnectionChild> client = new MobileConnectionChild();
-    NS_ASSERTION(client, "This shouldn't fail!");
-
-    ContentChild::GetSingleton()->SendPMobileConnectionConstructor(client, i);
-    client->Init();
-
-    mClients.AppendElement(client);
-  }
+  mItems.SetLength(numRil);
 }
 
 MobileConnectionIPCService::~MobileConnectionIPCService()
 {
-  uint32_t count = mClients.Length();
+  uint32_t count = mItems.Length();
   for (uint32_t i = 0; i < count; i++) {
-    mClients[i]->Shutdown();
+    if (mItems[i]) {
+      mItems[i]->Shutdown();
+    }
   }
-
-  mClients.Clear();
-}
-
-nsresult
-MobileConnectionIPCService::SendRequest(uint32_t aClientId,
-                                        MobileConnectionRequest aRequest,
-                                        nsIMobileConnectionCallback* aRequestCallback)
-{
-  if (aClientId >= mClients.Length()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  mClients[aClientId]->SendRequest(aRequest, aRequestCallback);
-  return NS_OK;
 }
 
 // nsIMobileConnectionService
 
 NS_IMETHODIMP
-MobileConnectionIPCService::RegisterListener(uint32_t aClientId,
-                                             nsIMobileConnectionListener* aListener)
-{
-  if (aClientId >= mClients.Length()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  mClients[aClientId]->RegisterListener(aListener);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::UnregisterListener(uint32_t aClientId,
-                                               nsIMobileConnectionListener* aListener)
-{
-  if (aClientId >= mClients.Length()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  mClients[aClientId]->UnregisterListener(aListener);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::GetLastKnownNetwork(uint32_t aClientId,
-                                                nsAString& aLastNetwork)
-{
-  if (aClientId >= mClients.Length()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  mClients[aClientId]->GetLastNetwork(aLastNetwork);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::GetLastKnownHomeNetwork(uint32_t aClientId,
-                                                    nsAString& aLastNetwork)
-{
-  if (aClientId >= mClients.Length()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  mClients[aClientId]->GetLastHomeNetwork(aLastNetwork);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::GetVoiceConnectionInfo(uint32_t aClientId,
-                                                   nsIMobileConnectionInfo** aInfo)
+MobileConnectionIPCService::GetNumItems(uint32_t* aNumItems)
 {
-  if (aClientId >= mClients.Length()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIMobileConnectionInfo> info = mClients[aClientId]->GetVoiceInfo();
-  info.forget(aInfo);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::GetDataConnectionInfo(uint32_t aClientId,
-                                                  nsIMobileConnectionInfo** aInfo)
-{
-  if (aClientId >= mClients.Length()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIMobileConnectionInfo> info = mClients[aClientId]->GetDataInfo();
-  info.forget(aInfo);
-
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::GetIccId(uint32_t aClientId, nsAString& aIccId)
-{
-  if (aClientId >= mClients.Length()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  mClients[aClientId]->GetIccId(aIccId);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::GetNetworkSelectionMode(uint32_t aClientId,
-                                                    nsAString& aNetworkSelectionMode)
-{
-  if (aClientId >= mClients.Length()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  mClients[aClientId]->GetNetworkSelectionMode(aNetworkSelectionMode);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::GetRadioState(uint32_t aClientId,
-                                          nsAString& aRadioState)
-{
-  if (aClientId >= mClients.Length()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  mClients[aClientId]->GetRadioState(aRadioState);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::GetSupportedNetworkTypes(uint32_t aClientId,
-                                                     nsIVariant** aSupportedTypes)
-{
-  if (aClientId >= mClients.Length()) {
-    return NS_ERROR_FAILURE;
-  }
-
-  nsCOMPtr<nsIVariant> supportedTypes = mClients[aClientId]->GetSupportedNetworkTypes();
-  supportedTypes.forget(aSupportedTypes);
-
+  *aNumItems = mItems.Length();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-MobileConnectionIPCService::GetNetworks(uint32_t aClientId,
-                                        nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId, GetNetworksRequest(), aRequest);
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::SelectNetwork(uint32_t aClientId,
-                                          nsIMobileNetworkInfo* aNetwork,
-                                          nsIMobileConnectionCallback* aRequest)
-{
-  nsCOMPtr<nsIMobileNetworkInfo> network = aNetwork;
-  // We release the ref after serializing process is finished in
-  // MobileConnectionIPCSerializer.
-  return SendRequest(aClientId, SelectNetworkRequest(network.forget().take()), aRequest);
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::SelectNetworkAutomatically(uint32_t aClientId,
-                                                       nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId, SelectNetworkAutoRequest(), aRequest);
-}
-
-
-NS_IMETHODIMP
-MobileConnectionIPCService::SetPreferredNetworkType(uint32_t aClientId,
-                                                    const nsAString& aType,
-                                                    nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId,
-                     SetPreferredNetworkTypeRequest(nsAutoString(aType)),
-                     aRequest);
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::GetPreferredNetworkType(uint32_t aClientId,
-                                                    nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId, GetPreferredNetworkTypeRequest(), aRequest);
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::SetRoamingPreference(uint32_t aClientId,
-                                                 const nsAString& aMode,
-                                                 nsIMobileConnectionCallback* aRequest)
+MobileConnectionIPCService::GetItemByServiceId(uint32_t aServiceId,
+                                               nsIMobileConnection** aItem)
 {
-  return SendRequest(aClientId,
-                     SetRoamingPreferenceRequest(nsAutoString(aMode)),
-                     aRequest);
-}
+  NS_ENSURE_TRUE(aServiceId < mItems.Length(), NS_ERROR_INVALID_ARG);
 
-NS_IMETHODIMP
-MobileConnectionIPCService::GetRoamingPreference(uint32_t aClientId,
-                                                 nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId, GetRoamingPreferenceRequest(), aRequest);
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::SetVoicePrivacyMode(uint32_t aClientId,
-                                                bool aEnabled,
-                                                nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId, SetVoicePrivacyModeRequest(aEnabled), aRequest);
-}
+  if (!mItems[aServiceId]) {
+    nsRefPtr<MobileConnectionChild> child = new MobileConnectionChild(aServiceId);
 
-NS_IMETHODIMP
-MobileConnectionIPCService::GetVoicePrivacyMode(uint32_t aClientId,
-                                                nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId, GetVoicePrivacyModeRequest(), aRequest);
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::SendMMI(uint32_t aClientId,
-                                    const nsAString& aMmi,
-                                    nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId, SendMmiRequest(nsAutoString(aMmi)), aRequest);
-}
+    // |SendPMobileConnectionConstructor| adds another reference to the child
+    // actor and removes in |DeallocPMobileConnectionChild|.
+    ContentChild::GetSingleton()->SendPMobileConnectionConstructor(child,
+                                                                   aServiceId);
+    child->Init();
 
-NS_IMETHODIMP
-MobileConnectionIPCService::CancelMMI(uint32_t aClientId,
-                                      nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId, CancelMmiRequest(), aRequest);
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::SetCallForwarding(uint32_t aClientId,
-                                              JS::Handle<JS::Value> aOptions,
-                                              nsIMobileConnectionCallback* aRequest)
-{
-  AutoSafeJSContext cx;
-  IPC::MozCallForwardingOptions options;
-  if(!options.Init(cx, aOptions)) {
-    return NS_ERROR_TYPE_ERR;
+    mItems[aServiceId] = child;
   }
 
-  return SendRequest(aClientId, SetCallForwardingRequest(options), aRequest);
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::GetCallForwarding(uint32_t aClientId,
-                                              uint16_t aReason,
-                                              nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId, GetCallForwardingRequest(aReason), aRequest);
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::SetCallBarring(uint32_t aClientId,
-                                           JS::Handle<JS::Value> aOptions,
-                                           nsIMobileConnectionCallback* aRequest)
-{
-  AutoSafeJSContext cx;
-  IPC::MozCallBarringOptions options;
-  if(!options.Init(cx, aOptions)) {
-    return NS_ERROR_TYPE_ERR;
-  }
-
-  return SendRequest(aClientId, SetCallBarringRequest(options), aRequest);
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::GetCallBarring(uint32_t aClientId,
-                                           JS::Handle<JS::Value> aOptions,
-                                           nsIMobileConnectionCallback* aRequest)
-{
-  AutoSafeJSContext cx;
-  IPC::MozCallBarringOptions options;
-  if(!options.Init(cx, aOptions)) {
-    return NS_ERROR_TYPE_ERR;
-  }
-
-  return SendRequest(aClientId, GetCallBarringRequest(options), aRequest);
-}
+  nsRefPtr<nsIMobileConnection> item(mItems[aServiceId]);
+  item.forget(aItem);
 
-NS_IMETHODIMP
-MobileConnectionIPCService::ChangeCallBarringPassword(uint32_t aClientId,
-                                                      JS::Handle<JS::Value> aOptions,
-                                                      nsIMobileConnectionCallback* aRequest)
-{
-  AutoSafeJSContext cx;
-  IPC::MozCallBarringOptions options;
-  if(!options.Init(cx, aOptions)) {
-    return NS_ERROR_TYPE_ERR;
-  }
-
-  return SendRequest(aClientId, ChangeCallBarringPasswordRequest(options), aRequest);
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::SetCallWaiting(uint32_t aClientId,
-                                           bool aEnabled,
-                                           nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId, SetCallWaitingRequest(aEnabled), aRequest);
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::GetCallWaiting(uint32_t aClientId,
-                                           nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId, GetCallWaitingRequest(), aRequest);
+  return NS_OK;
 }
-
-NS_IMETHODIMP
-MobileConnectionIPCService::SetCallingLineIdRestriction(uint32_t aClientId,
-                                                        uint16_t aMode,
-                                                        nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId, SetCallingLineIdRestrictionRequest(aMode), aRequest);
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::GetCallingLineIdRestriction(uint32_t aClientId,
-                                                        nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId, GetCallingLineIdRestrictionRequest(), aRequest);
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::ExitEmergencyCbMode(uint32_t aClientId,
-                                                nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId, ExitEmergencyCbModeRequest(), aRequest);
-}
-
-NS_IMETHODIMP
-MobileConnectionIPCService::SetRadioEnabled(uint32_t aClientId,
-                                            bool aEnabled,
-                                            nsIMobileConnectionCallback* aRequest)
-{
-  return SendRequest(aClientId, SetRadioEnabledRequest(aEnabled), aRequest);
-}
--- a/dom/mobileconnection/ipc/MobileConnectionIPCService.h
+++ b/dom/mobileconnection/ipc/MobileConnectionIPCService.h
@@ -20,23 +20,19 @@ public:
   NS_DECL_NSIMOBILECONNECTIONSERVICE
 
   static MobileConnectionIPCService*
   GetSingleton();
 
 private:
   MobileConnectionIPCService();
 
+  // MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
   ~MobileConnectionIPCService();
 
-  /** Send request */
-  nsresult
-  SendRequest(uint32_t aClientId, MobileConnectionRequest aRequest,
-              nsIMobileConnectionCallback* aRequestCallback);
-
-  nsTArray<nsRefPtr<MobileConnectionChild>> mClients;
+  nsTArray<nsRefPtr<MobileConnectionChild>> mItems;
 };
 
 } // namespace mobileconnection
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_mobileconnection_MobileConnectionIPCService_h
--- a/dom/mobileconnection/ipc/MobileConnectionParent.cpp
+++ b/dom/mobileconnection/ipc/MobileConnectionParent.cpp
@@ -12,36 +12,38 @@
 #include "nsIVariant.h"
 #include "nsJSUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::dom::mobileconnection;
 
 MobileConnectionParent::MobileConnectionParent(uint32_t aClientId)
-  : mClientId(aClientId)
-  , mLive(true)
+  : mLive(true)
 {
   MOZ_COUNT_CTOR(MobileConnectionParent);
 
-  mService = do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID);
-  NS_ASSERTION(mService, "This shouldn't fail!");
+  nsCOMPtr<nsIMobileConnectionService> service =
+    do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID);
+  NS_ASSERTION(service, "This shouldn't fail!");
 
-  if (mService) {
-    mService->RegisterListener(mClientId, this);
+  nsresult rv = service->GetItemByServiceId(aClientId,
+                                            getter_AddRefs(mMobileConnection));
+  if (NS_SUCCEEDED(rv) && mMobileConnection) {
+    mMobileConnection->RegisterListener(this);
   }
 }
 
 void
 MobileConnectionParent::ActorDestroy(ActorDestroyReason why)
 {
   mLive = false;
-  if (mService) {
-    mService->UnregisterListener(mClientId, this);
-    mService = nullptr;
+  if (mMobileConnection) {
+    mMobileConnection->UnregisterListener(this);
+    mMobileConnection = nullptr;
   }
 }
 
 bool
 MobileConnectionParent::RecvPMobileConnectionRequestConstructor(PMobileConnectionRequestParent* aActor,
                                                                 const MobileConnectionRequest& aRequest)
 {
   MobileConnectionRequestParent* actor = static_cast<MobileConnectionRequestParent*>(aActor);
@@ -100,17 +102,18 @@ MobileConnectionParent::RecvPMobileConne
 
 PMobileConnectionRequestParent*
 MobileConnectionParent::AllocPMobileConnectionRequestParent(const MobileConnectionRequest& request)
 {
   if (!AssertAppProcessPermission(Manager(), "mobileconnection")) {
     return nullptr;
   }
 
-  MobileConnectionRequestParent* actor = new MobileConnectionRequestParent(mClientId);
+  MobileConnectionRequestParent* actor =
+    new MobileConnectionRequestParent(mMobileConnection);
   // Add an extra ref for IPDL. Will be released in
   // MobileConnectionParent::DeallocPMobileConnectionRequestParent().
   actor->AddRef();
   return actor;
 }
 
 bool
 MobileConnectionParent::DeallocPMobileConnectionRequestParent(PMobileConnectionRequestParent* aActor)
@@ -125,77 +128,69 @@ MobileConnectionParent::RecvInit(nsMobil
                                  nsMobileConnectionInfo* aData,
                                  nsString* aLastKnownNetwork,
                                  nsString* aLastKnownHomeNetwork,
                                  nsString* aIccId,
                                  nsString* aNetworkSelectionMode,
                                  nsString* aRadioState,
                                  nsTArray<nsString>* aSupportedNetworkTypes)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  NS_ENSURE_SUCCESS(mService->GetVoiceConnectionInfo(mClientId, aVoice), false);
-  NS_ENSURE_SUCCESS(mService->GetDataConnectionInfo(mClientId, aData), false);
-  NS_ENSURE_SUCCESS(mService->GetLastKnownNetwork(mClientId, *aLastKnownNetwork), false);
-  NS_ENSURE_SUCCESS(mService->GetLastKnownHomeNetwork(mClientId, *aLastKnownHomeNetwork), false);
-  NS_ENSURE_SUCCESS(mService->GetIccId(mClientId, *aIccId), false);
-  NS_ENSURE_SUCCESS(mService->GetNetworkSelectionMode(mClientId, *aNetworkSelectionMode), false);
-  NS_ENSURE_SUCCESS(mService->GetRadioState(mClientId, *aRadioState), 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);
 
-  nsCOMPtr<nsIVariant> variant;
-  mService->GetSupportedNetworkTypes(mClientId, getter_AddRefs(variant));
+  char16_t** types = nullptr;
+  uint32_t length = 0;
 
-  uint16_t type;
-  nsIID iid;
-  uint32_t count;
-  void* data;
-  if (NS_FAILED(variant->GetAsArray(&type, &iid, &count, &data))) {
-    return false;
+  nsresult rv = mMobileConnection->GetSupportedNetworkTypes(&types, &length);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  for (uint32_t i = 0; i < length; ++i) {
+    nsDependentString type(types[i]);
+    aSupportedNetworkTypes->AppendElement(type);
   }
 
-  // We expect the element type is wstring.
-  if (type == nsIDataType::VTYPE_WCHAR_STR) {
-    char16_t** rawArray = reinterpret_cast<char16_t**>(data);
-    for (uint32_t i = 0; i < count; ++i) {
-      nsDependentString networkType(rawArray[i]);
-      aSupportedNetworkTypes->AppendElement(networkType);
-    }
-  }
-  NS_Free(data);
+  NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(length, types);
 
   return true;
 }
 
 // nsIMobileConnectionListener
 
 NS_IMPL_ISUPPORTS(MobileConnectionParent, nsIMobileConnectionListener)
 
 NS_IMETHODIMP
 MobileConnectionParent::NotifyVoiceChanged()
 {
   NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE);
 
   nsresult rv;
   nsCOMPtr<nsIMobileConnectionInfo> info;
-  rv = mService->GetVoiceConnectionInfo(mClientId, getter_AddRefs(info));
+  rv = mMobileConnection->GetVoice(getter_AddRefs(info));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // We release the ref after serializing process is finished in
   // MobileConnectionIPCSerializer.
   return SendNotifyVoiceInfoChanged(info.forget().take()) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 MobileConnectionParent::NotifyDataChanged()
 {
   NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE);
 
   nsresult rv;
   nsCOMPtr<nsIMobileConnectionInfo> info;
-  rv = mService->GetDataConnectionInfo(mClientId, getter_AddRefs(info));
+  rv = mMobileConnection->GetData(getter_AddRefs(info));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // We release the ref after serializing process is finished in
   // MobileConnectionIPCSerializer.
   return SendNotifyDataInfoChanged(info.forget().take()) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
@@ -251,29 +246,29 @@ MobileConnectionParent::NotifyOtaStatusC
 }
 
 NS_IMETHODIMP
 MobileConnectionParent::NotifyIccChanged()
 {
   NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE);
 
   nsAutoString iccId;
-  mService->GetIccId(mClientId, 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;
   nsAutoString radioState;
-  rv = mService->GetRadioState(mClientId, radioState);
+  rv = mMobileConnection->GetRadioState(radioState);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return SendNotifyRadioStateChanged(radioState) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 MobileConnectionParent::NotifyClirModeChanged(uint32_t aMode)
 {
@@ -284,264 +279,264 @@ MobileConnectionParent::NotifyClirModeCh
 
 NS_IMETHODIMP
 MobileConnectionParent::NotifyLastKnownNetworkChanged()
 {
   NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE);
 
   nsresult rv;
   nsAutoString network;
-  rv = mService->GetLastKnownNetwork(mClientId, network);
+  rv = mMobileConnection->GetLastKnownNetwork(network);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return SendNotifyLastNetworkChanged(network) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 MobileConnectionParent::NotifyLastKnownHomeNetworkChanged()
 {
   NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE);
 
   nsresult rv;
   nsAutoString network;
-  rv = mService->GetLastKnownHomeNetwork(mClientId, network);
+  rv = mMobileConnection->GetLastKnownHomeNetwork(network);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return SendNotifyLastHomeNetworkChanged(network) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 MobileConnectionParent::NotifyNetworkSelectionModeChanged()
 {
   NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE);
 
   nsresult rv;
   nsAutoString mode;
-  rv = mService->GetNetworkSelectionMode(mClientId, mode);
+  rv = mMobileConnection->GetNetworkSelectionMode(mode);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return SendNotifyNetworkSelectionModeChanged(mode) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 /******************************************************************************
  * PMobileConnectionRequestParent
  ******************************************************************************/
 
 void
 MobileConnectionRequestParent::ActorDestroy(ActorDestroyReason why)
 {
   mLive = false;
-  mService = nullptr;
+  mMobileConnection = nullptr;
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const GetNetworksRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->GetNetworks(mClientId, this));
+  return NS_SUCCEEDED(mMobileConnection->GetNetworks(this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const SelectNetworkRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
   // Use dont_AddRef here because this instances is already AddRef-ed in
   // MobileConnectionIPCSerializer.h
   nsCOMPtr<nsIMobileNetworkInfo> network = dont_AddRef(aRequest.network());
-  return NS_SUCCEEDED(mService->SelectNetwork(mClientId, network, this));
+  return NS_SUCCEEDED(mMobileConnection->SelectNetwork(network, this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const SelectNetworkAutoRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->SelectNetworkAutomatically(mClientId, this));
+  return NS_SUCCEEDED(mMobileConnection->SelectNetworkAutomatically(this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const SetPreferredNetworkTypeRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->SetPreferredNetworkType(mClientId, aRequest.type(), this));
+  return NS_SUCCEEDED(mMobileConnection->SetPreferredNetworkType(aRequest.type(), this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const GetPreferredNetworkTypeRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->GetPreferredNetworkType(mClientId, this));
+  return NS_SUCCEEDED(mMobileConnection->GetPreferredNetworkType(this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const SetRoamingPreferenceRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->SetRoamingPreference(mClientId, aRequest.mode(), this));
+  return NS_SUCCEEDED(mMobileConnection->SetRoamingPreference(aRequest.mode(), this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const GetRoamingPreferenceRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->GetRoamingPreference(mClientId, this));
+  return NS_SUCCEEDED(mMobileConnection->GetRoamingPreference(this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const SetVoicePrivacyModeRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->SetVoicePrivacyMode(mClientId, aRequest.enabled(), this));
+  return NS_SUCCEEDED(mMobileConnection->SetVoicePrivacyMode(aRequest.enabled(), this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const GetVoicePrivacyModeRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->GetVoicePrivacyMode(mClientId, this));
+  return NS_SUCCEEDED(mMobileConnection->GetVoicePrivacyMode(this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const SendMmiRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->SendMMI(mClientId, aRequest.mmi(), this));
+  return NS_SUCCEEDED(mMobileConnection->SendMMI(aRequest.mmi(), this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const CancelMmiRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->CancelMMI(mClientId, this));
+  return NS_SUCCEEDED(mMobileConnection->CancelMMI(this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const SetCallForwardingRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
   AutoSafeJSContext cx;
   JS::Rooted<JS::Value> options(cx);
   if (!ToJSValue(cx, aRequest.options(), &options)) {
     JS_ClearPendingException(cx);
     return false;
   }
 
-  return NS_SUCCEEDED(mService->SetCallForwarding(mClientId, options, this));
+  return NS_SUCCEEDED(mMobileConnection->SetCallForwarding(options, this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const GetCallForwardingRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->GetCallForwarding(mClientId, aRequest.reason(), this));
+  return NS_SUCCEEDED(mMobileConnection->GetCallForwarding(aRequest.reason(), this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const SetCallBarringRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
   AutoSafeJSContext cx;
   JS::Rooted<JS::Value> options(cx);
   if (!ToJSValue(cx, aRequest.options(), &options)) {
     JS_ClearPendingException(cx);
     return false;
   }
 
-  return NS_SUCCEEDED(mService->SetCallBarring(mClientId, options, this));
+  return NS_SUCCEEDED(mMobileConnection->SetCallBarring(options, this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const GetCallBarringRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
   AutoSafeJSContext cx;
   JS::Rooted<JS::Value> options(cx);
   if (!ToJSValue(cx, aRequest.options(), &options)) {
     JS_ClearPendingException(cx);
     return false;
   }
 
-  return NS_SUCCEEDED(mService->GetCallBarring(mClientId, options, this));
+  return NS_SUCCEEDED(mMobileConnection->GetCallBarring(options, this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const ChangeCallBarringPasswordRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
   AutoSafeJSContext cx;
   JS::Rooted<JS::Value> options(cx);
   if (!ToJSValue(cx, aRequest.options(), &options)) {
     JS_ClearPendingException(cx);
     return false;
   }
 
-  return NS_SUCCEEDED(mService->ChangeCallBarringPassword(mClientId, options, this));
+  return NS_SUCCEEDED(mMobileConnection->ChangeCallBarringPassword(options, this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const SetCallWaitingRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->SetCallWaiting(mClientId, aRequest.enabled(), this));
+  return NS_SUCCEEDED(mMobileConnection->SetCallWaiting(aRequest.enabled(), this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const GetCallWaitingRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->GetCallWaiting(mClientId, this));
+  return NS_SUCCEEDED(mMobileConnection->GetCallWaiting(this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const SetCallingLineIdRestrictionRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->SetCallingLineIdRestriction(mClientId, aRequest.mode(), this));
+  return NS_SUCCEEDED(mMobileConnection->SetCallingLineIdRestriction(aRequest.mode(), this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const GetCallingLineIdRestrictionRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->GetCallingLineIdRestriction(mClientId, this));
+  return NS_SUCCEEDED(mMobileConnection->GetCallingLineIdRestriction(this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const ExitEmergencyCbModeRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->ExitEmergencyCbMode(mClientId, this));
+  return NS_SUCCEEDED(mMobileConnection->ExitEmergencyCbMode(this));
 }
 
 bool
 MobileConnectionRequestParent::DoRequest(const SetRadioEnabledRequest& aRequest)
 {
-  NS_ENSURE_TRUE(mService, false);
+  NS_ENSURE_TRUE(mMobileConnection, false);
 
-  return NS_SUCCEEDED(mService->SetRadioEnabled(mClientId, aRequest.enabled(), this));
+  return NS_SUCCEEDED(mMobileConnection->SetRadioEnabled(aRequest.enabled(), this));
 }
 
 nsresult
 MobileConnectionRequestParent::SendReply(const MobileConnectionReply& aReply)
 {
   NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE);
 
   return Send__delete__(this, aReply) ? NS_OK : NS_ERROR_FAILURE;
--- a/dom/mobileconnection/ipc/MobileConnectionParent.h
+++ b/dom/mobileconnection/ipc/MobileConnectionParent.h
@@ -50,19 +50,18 @@ protected:
 
   virtual bool
   RecvInit(nsMobileConnectionInfo* aVoice, nsMobileConnectionInfo* aData,
            nsString* aLastKnownNetwork, nsString* aLastKnownHomeNetwork,
            nsString* aIccId, nsString* aNetworkSelectionMode,
            nsString* aRadioState, nsTArray<nsString>* aSupportedNetworkTypes) MOZ_OVERRIDE;
 
 private:
-  uint32_t mClientId;
+  nsCOMPtr<nsIMobileConnection> mMobileConnection;
   bool mLive;
-  nsCOMPtr<nsIMobileConnectionService> mService;
 };
 
 /******************************************************************************
  * PMobileConnectionRequestParent
  ******************************************************************************/
 
 /**
  * Parent actor of PMobileConnectionRequestParent. The object is created along
@@ -73,24 +72,21 @@ private:
  */
 class MobileConnectionRequestParent : public PMobileConnectionRequestParent
                                     , public nsIMobileConnectionCallback
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIMOBILECONNECTIONCALLBACK
 
-  explicit MobileConnectionRequestParent(uint32_t aClientId)
-    : mClientId(aClientId)
+  explicit MobileConnectionRequestParent(nsIMobileConnection* aMobileConnection)
+    : mMobileConnection(aMobileConnection)
     , mLive(true)
   {
     MOZ_COUNT_CTOR(MobileConnectionRequestParent);
-
-    mService = do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID);
-    NS_ASSERTION(mService, "This shouldn't fail!");
   }
 
   bool
   DoRequest(const GetNetworksRequest& aRequest);
 
   bool
   DoRequest(const SelectNetworkRequest& aRequest);
 
@@ -163,18 +159,17 @@ protected:
 
   virtual void
   ActorDestroy(ActorDestroyReason why);
 
   nsresult
   SendReply(const MobileConnectionReply& aReply);
 
 private:
-  uint32_t mClientId;
+  nsCOMPtr<nsIMobileConnection> mMobileConnection;
   bool mLive;
-  nsCOMPtr<nsIMobileConnectionService> mService;
 };
 
 } // namespace mobileconnection
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_mobileconnection_MobileConnectionParent_h