Bug 1114935 - Part 4.2: Add IPC Implementation of nsIIccService. r=echen
authorBevis Tseng <btseng@mozilla.com>
Wed, 07 Jan 2015 16:58:35 +0800
changeset 266481 ba5ae45ade56c24bf068b09b1e883ec0e2929c96
parent 266480 7b20a3e1a9bb45fbadb41983c5c02f94cadcf57f
child 266482 24fe79ca59f334656aab5e6e071782e7f3e40ebe
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersechen
bugs1114935
milestone39.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 1114935 - Part 4.2: Add IPC Implementation of nsIIccService. r=echen
dom/icc/ipc/IccChild.cpp
dom/icc/ipc/IccChild.h
dom/icc/ipc/IccIPCService.cpp
dom/icc/ipc/IccIPCService.h
dom/icc/ipc/IccParent.cpp
dom/icc/ipc/IccParent.h
dom/icc/moz.build
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
new file mode 100644
--- /dev/null
+++ b/dom/icc/ipc/IccChild.cpp
@@ -0,0 +1,310 @@
+/* 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/icc/IccChild.h"
+#include "IccInfo.h"
+
+using mozilla::dom::IccInfo;
+
+namespace mozilla {
+namespace dom {
+namespace icc {
+
+/**
+ * PIccChild Implementation.
+ */
+
+IccChild::IccChild()
+  : mCardState(nsIIcc::CARD_STATE_UNKNOWN)
+  , mIsAlive(true)
+{
+  MOZ_COUNT_CTOR(IccChild);
+}
+
+IccChild::~IccChild()
+{
+  MOZ_COUNT_DTOR(IccChild);
+}
+
+void
+IccChild::Init()
+{
+  OptionalIccInfoData infoData;
+
+  bool rv = SendInit(&infoData, &mCardState);
+  NS_ENSURE_TRUE_VOID(rv);
+
+  UpdateIccInfo(infoData);
+}
+
+void
+IccChild::Shutdown(){
+  if (mIsAlive) {
+    mIsAlive = false;
+    Send__delete__(this);
+  }
+
+  mListeners.Clear();
+  mIccInfo = nullptr;
+  mCardState = nsIIcc::CARD_STATE_UNKNOWN;
+}
+
+void
+IccChild::ActorDestroy(ActorDestroyReason why)
+{
+  mIsAlive = false;
+}
+
+bool
+IccChild::RecvNotifyCardStateChanged(const uint32_t& aCardState)
+{
+  mCardState = aCardState;
+
+  for (int32_t i = 0; i < mListeners.Count(); i++) {
+    mListeners[i]->NotifyCardStateChanged();
+  }
+
+  return true;
+}
+
+bool
+IccChild::RecvNotifyIccInfoChanged(const OptionalIccInfoData& aInfoData)
+{
+  UpdateIccInfo(aInfoData);
+
+  for (int32_t i = 0; i < mListeners.Count(); i++) {
+    mListeners[i]->NotifyIccInfoChanged();
+  }
+
+  return true;
+}
+
+PIccRequestChild*
+IccChild::AllocPIccRequestChild(const IccRequest& aRequest)
+{
+  MOZ_CRASH("Caller is supposed to manually construct a request!");
+}
+
+bool
+IccChild::DeallocPIccRequestChild(PIccRequestChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+bool
+IccChild::SendRequest(const IccRequest& aRequest, nsIIccCallback* aRequestReply)
+{
+  NS_ENSURE_TRUE(mIsAlive, false);
+
+  // Deallocated in IccChild::DeallocPIccRequestChild().
+  IccRequestChild* actor = new IccRequestChild(aRequestReply);
+  SendPIccRequestConstructor(actor, aRequest);
+
+  return true;
+}
+
+void
+IccChild::UpdateIccInfo(const OptionalIccInfoData& aInfoData) {
+  if (aInfoData.type() == OptionalIccInfoData::Tvoid_t) {
+    mIccInfo = nullptr;
+    return;
+  }
+
+  NS_ENSURE_TRUE_VOID(aInfoData.type() == OptionalIccInfoData::TIccInfoData);
+
+  nsRefPtr<IccInfo> iccInfo;
+  const IccInfoData& infoData = aInfoData.get_IccInfoData();
+  if (infoData.iccType().EqualsLiteral("sim")
+      || infoData.iccType().EqualsLiteral("usim")) {
+    iccInfo = new GsmIccInfo(infoData);
+  } else if (infoData.iccType().EqualsLiteral("ruim")
+             || infoData.iccType().EqualsLiteral("csim")){
+    iccInfo = new CdmaIccInfo(infoData);
+  } else {
+    iccInfo = new IccInfo(infoData);
+  }
+
+  // We update the orignal one instead of replacing with a new one
+  // if the IccType is the same.
+  if (mIccInfo) {
+    nsString oldIccType;
+    nsString newIccType;
+    mIccInfo->GetIccType(oldIccType);
+    iccInfo->GetIccType(newIccType);
+
+    if (oldIccType.Equals(newIccType)) {
+      mIccInfo->Update(iccInfo);
+      return;
+    }
+  }
+
+  mIccInfo = iccInfo;
+}
+
+/**
+ * nsIIcc Implementation.
+ */
+
+NS_IMPL_ISUPPORTS(IccChild, nsIIcc)
+
+NS_IMETHODIMP
+IccChild::RegisterListener(nsIIccListener *aListener)
+{
+  NS_ENSURE_TRUE(!mListeners.Contains(aListener), NS_ERROR_UNEXPECTED);
+
+  mListeners.AppendObject(aListener);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+IccChild::UnregisterListener(nsIIccListener *aListener)
+{
+  NS_ENSURE_TRUE(mListeners.Contains(aListener), NS_ERROR_UNEXPECTED);
+
+  mListeners.RemoveObject(aListener);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+IccChild::GetIccInfo(nsIIccInfo** aIccInfo)
+{
+  nsCOMPtr<nsIIccInfo> info(mIccInfo);
+  info.forget(aIccInfo);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+IccChild::GetCardState(uint32_t* aCardState)
+{
+  *aCardState = mCardState;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+IccChild::GetCardLockEnabled(uint32_t aLockType,
+                             nsIIccCallback* aRequestReply)
+{
+  return SendRequest(GetCardLockEnabledRequest(aLockType), aRequestReply)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+IccChild::UnlockCardLock(uint32_t aLockType,
+                         const nsAString& aPassword,
+                         const nsAString& aNewPin,
+                         nsIIccCallback* aRequestReply)
+{
+  return SendRequest(UnlockCardLockRequest(aLockType,
+                                           nsString(aPassword),
+                                           nsString(aNewPin)),
+                     aRequestReply)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+IccChild::SetCardLockEnabled(uint32_t aLockType,
+                             const nsAString& aPassword,
+                             bool aEnabled,
+                             nsIIccCallback* aRequestReply)
+{
+  return SendRequest(SetCardLockEnabledRequest(aLockType,
+                                               nsString(aPassword),
+                                               aEnabled),
+                     aRequestReply)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+IccChild::ChangeCardLockPassword(uint32_t aLockType,
+                                 const nsAString& aPassword,
+                                 const nsAString& aNewPassword,
+                                 nsIIccCallback* aRequestReply)
+{
+  return SendRequest(ChangeCardLockPasswordRequest(aLockType,
+                                                   nsString(aPassword),
+                                                   nsString(aNewPassword)),
+                     aRequestReply)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+IccChild::GetCardLockRetryCount(uint32_t aLockType,
+                                nsIIccCallback* aRequestReply)
+{
+  return SendRequest(GetCardLockRetryCountRequest(aLockType), aRequestReply)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+IccChild::MatchMvno(uint32_t aMvnoType,
+                    const nsAString& aMvnoData,
+                    nsIIccCallback* aRequestReply)
+{
+  return SendRequest(MatchMvnoRequest(aMvnoType, nsString(aMvnoData)),
+                     aRequestReply)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+IccChild::GetServiceStateEnabled(uint32_t aService,
+                                 nsIIccCallback* aRequestReply)
+{
+  return SendRequest(GetServiceStateEnabledRequest(aService),
+                     aRequestReply)
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+/**
+ * PIccRequestChild Implementation.
+ */
+
+IccRequestChild::IccRequestChild(nsIIccCallback* aRequestReply)
+  : mRequestReply(aRequestReply)
+{
+  MOZ_COUNT_CTOR(IccRequestChild);
+  MOZ_ASSERT(aRequestReply);
+}
+
+bool
+IccRequestChild::Recv__delete__(const IccReply& aResponse)
+{
+  MOZ_ASSERT(mRequestReply);
+
+  switch(aResponse.type()) {
+    case IccReply::TIccReplySuccess:
+      return NS_SUCCEEDED(mRequestReply->NotifySuccess());
+    case IccReply::TIccReplySuccessWithBoolean: {
+      const IccReplySuccessWithBoolean& resultWithBoolean
+        = aResponse.get_IccReplySuccessWithBoolean();
+      return NS_SUCCEEDED(
+        mRequestReply->NotifySuccessWithBoolean(resultWithBoolean.result()));
+    }
+    case IccReply::TIccReplyCardLockRetryCount: {
+      const IccReplyCardLockRetryCount& retryCount
+        = aResponse.get_IccReplyCardLockRetryCount();
+      return NS_SUCCEEDED(
+        mRequestReply->NotifyGetCardLockRetryCount(retryCount.count()));
+    }
+    case IccReply::TIccReplyError: {
+      const IccReplyError& error = aResponse.get_IccReplyError();
+      return NS_SUCCEEDED(mRequestReply->NotifyError(error.message()));
+    }
+    case IccReply::TIccReplyCardLockError: {
+      const IccReplyCardLockError& error
+        = aResponse.get_IccReplyCardLockError();
+      return NS_SUCCEEDED(
+        mRequestReply->NotifyCardLockError(error.message(),
+                                           error.retryCount()));
+    }
+    default:
+      MOZ_CRASH("Received invalid response type!");
+  }
+
+  return true;
+}
+
+} // namespace icc
+} // namespace dom
+} // namespace mozilla
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/icc/ipc/IccChild.h
@@ -0,0 +1,86 @@
+/* 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/. */
+
+#ifndef mozilla_dom_icc_IccChild_h
+#define mozilla_dom_icc_IccChild_h
+
+#include "mozilla/dom/icc/PIccChild.h"
+#include "mozilla/dom/icc/PIccRequestChild.h"
+#include "nsIIccService.h"
+
+namespace mozilla {
+namespace dom {
+
+class IccInfo;
+
+namespace icc {
+
+class IccChild final : public PIccChild
+                     , public nsIIcc
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIICC
+
+  explicit IccChild();
+
+void
+  Init();
+
+  void
+  Shutdown();
+
+protected:
+  virtual void
+  ActorDestroy(ActorDestroyReason why) override;
+
+  virtual PIccRequestChild*
+  AllocPIccRequestChild(const IccRequest& aRequest) override;
+
+  virtual bool
+  DeallocPIccRequestChild(PIccRequestChild* aActor) override;
+
+  virtual bool
+  RecvNotifyCardStateChanged(const uint32_t& aCardState) override;
+
+  virtual bool
+  RecvNotifyIccInfoChanged(const OptionalIccInfoData& aInfoData) override;
+
+private:
+  ~IccChild();
+
+  void
+  UpdateIccInfo(const OptionalIccInfoData& aInfoData);
+
+  bool
+  SendRequest(const IccRequest& aRequest, nsIIccCallback* aRequestReply);
+
+  nsCOMArray<nsIIccListener> mListeners;
+  nsRefPtr<IccInfo> mIccInfo;
+  uint32_t mCardState;
+  bool mIsAlive;
+};
+
+class IccRequestChild final : public PIccRequestChild
+{
+public:
+  explicit IccRequestChild(nsIIccCallback* aRequestReply);
+
+protected:
+  virtual bool
+  Recv__delete__(const IccReply& aReply) override;
+
+private:
+  virtual ~IccRequestChild() {
+    MOZ_COUNT_DTOR(IccRequestChild);
+  }
+
+  nsCOMPtr<nsIIccCallback> mRequestReply;
+};
+
+} // namespace icc
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_icc_IccChild_h
new file mode 100644
--- /dev/null
+++ b/dom/icc/ipc/IccIPCService.cpp
@@ -0,0 +1,56 @@
+/* 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 "IccIPCService.h"
+
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/Preferences.h"
+
+namespace mozilla {
+namespace dom {
+namespace icc {
+
+NS_IMPL_ISUPPORTS(IccIPCService, nsIIccService)
+
+IccIPCService::IccIPCService()
+{
+  int32_t numRil = Preferences::GetInt("ril.numRadioInterfaces", 1);
+  mIccs.SetLength(numRil);
+}
+
+IccIPCService::~IccIPCService()
+{
+  uint32_t count = mIccs.Length();
+  for (uint32_t i = 0; i < count; i++) {
+    if (mIccs[i]) {
+      mIccs[i]->Shutdown();
+    }
+  }
+}
+
+NS_IMETHODIMP
+IccIPCService::GetIccByServiceId(uint32_t aServiceId, nsIIcc** aIcc)
+{
+  NS_ENSURE_TRUE(aServiceId < mIccs.Length(), NS_ERROR_INVALID_ARG);
+
+  if (!mIccs[aServiceId]) {
+    nsRefPtr<IccChild> child = new IccChild();
+
+    // |SendPIccConstructor| adds another reference to the child
+    // actor and removes in |DeallocPIccChild|.
+    ContentChild::GetSingleton()->SendPIccConstructor(child, aServiceId);
+    child->Init();
+
+    mIccs[aServiceId] = child;
+  }
+
+  nsCOMPtr<nsIIcc> icc(mIccs[aServiceId]);
+  icc.forget(aIcc);
+
+  return NS_OK;
+}
+
+} // namespace icc
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/icc/ipc/IccIPCService.h
@@ -0,0 +1,35 @@
+/* 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/. */
+
+#ifndef mozilla_dom_icc_IccIPCService_h
+#define mozilla_dom_icc_IccIPCService_h
+
+#include "nsCOMPtr.h"
+#include "nsIIccService.h"
+
+namespace mozilla {
+namespace dom {
+namespace icc {
+
+class IccChild;
+
+class IccIPCService final : public nsIIccService
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIICCSERVICE
+
+  IccIPCService();
+
+private:
+  ~IccIPCService();
+
+  nsTArray<nsRefPtr<IccChild>> mIccs;
+};
+
+} // namespace icc
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_icc_IccIPCService_h
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/icc/ipc/IccParent.cpp
@@ -0,0 +1,320 @@
+/* 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/icc/IccParent.h"
+#include "nsIIccService.h"
+#include "IccInfo.h"
+
+using mozilla::dom::IccInfo;
+
+namespace mozilla {
+namespace dom {
+namespace icc {
+
+namespace {
+
+static void
+GetIccInfoDataFromIccInfo(nsIIccInfo* aInInfo, IccInfoData& aOutData) {
+  aInInfo->GetIccType(aOutData.iccType());
+  aInInfo->GetIccid(aOutData.iccid());
+  aInInfo->GetMcc(aOutData.mcc());
+  aInInfo->GetMnc(aOutData.mnc());
+  aInInfo->GetSpn(aOutData.spn());
+  aInInfo->GetIsDisplayNetworkNameRequired(
+    &aOutData.isDisplayNetworkNameRequired());
+  aInInfo->GetIsDisplaySpnRequired(
+    &aOutData.isDisplaySpnRequired());
+
+  nsCOMPtr<nsIGsmIccInfo> gsmIccInfo(do_QueryInterface(aInInfo));
+  if (gsmIccInfo) {
+    gsmIccInfo->GetMsisdn(aOutData.phoneNumber());
+  }
+
+  nsCOMPtr<nsICdmaIccInfo> cdmaIccInfo(do_QueryInterface(aInInfo));
+  if (cdmaIccInfo) {
+    cdmaIccInfo->GetMdn(aOutData.phoneNumber());
+    cdmaIccInfo->GetPrlVersion(&aOutData.prlVersion());
+  }
+}
+
+} // anonymous namespace
+
+/**
+ * PIccParent Implementation.
+ */
+
+IccParent::IccParent(uint32_t aServiceId)
+{
+  MOZ_COUNT_CTOR(IccParent);
+
+  nsCOMPtr<nsIIccService> service =
+    do_GetService(ICC_SERVICE_CONTRACTID);
+
+  NS_ASSERTION(service, "Failed to get IccService!");
+
+  service->GetIccByServiceId(aServiceId, getter_AddRefs(mIcc));
+
+  NS_ASSERTION(mIcc, "Failed to get Icc with specified serviceId.");
+
+  mIcc->RegisterListener(this);
+}
+
+void
+IccParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  if (mIcc) {
+    mIcc->UnregisterListener(this);
+    mIcc = nullptr;
+  }
+}
+
+bool
+IccParent::RecvInit(OptionalIccInfoData* aInfoData,
+                    uint32_t* aCardState)
+{
+  NS_ENSURE_TRUE(mIcc, false);
+
+  nsresult rv = mIcc->GetCardState(aCardState);
+  NS_ENSURE_SUCCESS(rv, false);
+
+  nsCOMPtr<nsIIccInfo> iccInfo;
+  rv = mIcc->GetIccInfo(getter_AddRefs(iccInfo));
+  NS_ENSURE_SUCCESS(rv, false);
+
+  if (iccInfo) {
+    IccInfoData data;
+    GetIccInfoDataFromIccInfo(iccInfo, data);
+    *aInfoData = OptionalIccInfoData(data);
+
+    return true;
+  }
+
+  *aInfoData = OptionalIccInfoData(void_t());
+
+  return true;
+}
+
+PIccRequestParent*
+IccParent::AllocPIccRequestParent(const IccRequest& aRequest)
+{
+  NS_ASSERTION(mIcc, "AllocPIccRequestParent after actor was destroyed!");
+
+  IccRequestParent* actor = new IccRequestParent(mIcc);
+  // Add an extra ref for IPDL. Will be released in
+  // IccParent::DeallocPIccRequestParent().
+  actor->AddRef();
+  return actor;
+}
+
+bool
+IccParent::DeallocPIccRequestParent(PIccRequestParent* aActor)
+{
+  // IccRequestParent is refcounted, must not be freed manually.
+  static_cast<IccRequestParent*>(aActor)->Release();
+  return true;
+}
+
+bool
+IccParent::RecvPIccRequestConstructor(PIccRequestParent* aActor,
+                                      const IccRequest& aRequest)
+{
+  NS_ASSERTION(mIcc, "RecvPIccRequestConstructor after actor was destroyed!");
+
+  IccRequestParent* actor = static_cast<IccRequestParent*>(aActor);
+
+  switch (aRequest.type()) {
+    case IccRequest::TGetCardLockEnabledRequest:
+      return actor->DoRequest(aRequest.get_GetCardLockEnabledRequest());
+    case IccRequest::TUnlockCardLockRequest:
+      return actor->DoRequest(aRequest.get_UnlockCardLockRequest());
+    case IccRequest::TSetCardLockEnabledRequest:
+      return actor->DoRequest(aRequest.get_SetCardLockEnabledRequest());
+    case IccRequest::TChangeCardLockPasswordRequest:
+      return actor->DoRequest(aRequest.get_ChangeCardLockPasswordRequest());
+    case IccRequest::TGetCardLockRetryCountRequest:
+      return actor->DoRequest(aRequest.get_GetCardLockRetryCountRequest());
+    case IccRequest::TMatchMvnoRequest:
+      return actor->DoRequest(aRequest.get_MatchMvnoRequest());
+    case IccRequest::TGetServiceStateEnabledRequest:
+      return actor->DoRequest(aRequest.get_GetServiceStateEnabledRequest());
+    default:
+      MOZ_CRASH("Received invalid request type!");
+  }
+
+  return true;
+}
+
+/**
+ * nsIIccListener Implementation.
+ */
+
+NS_IMPL_ISUPPORTS(IccParent, nsIIccListener)
+
+NS_IMETHODIMP
+IccParent::NotifyStkCommand(const nsAString & aMessage)
+{
+  // Bug 1114938 - [B2G][ICC] Refactor STK in MozIcc.webidl with IPDL.
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+IccParent::NotifyStkSessionEnd()
+{
+  // Bug 1114938 - [B2G][ICC] Refactor STK in MozIcc.webidl with IPDL.
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+IccParent::NotifyCardStateChanged()
+{
+  NS_ENSURE_TRUE(mIcc, NS_ERROR_FAILURE);
+
+  uint32_t cardState;
+  nsresult rv = mIcc->GetCardState(&cardState);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return SendNotifyCardStateChanged(cardState) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+IccParent::NotifyIccInfoChanged()
+{
+  NS_ENSURE_TRUE(mIcc, NS_ERROR_FAILURE);
+
+  nsCOMPtr<nsIIccInfo> iccInfo;
+  nsresult rv = mIcc->GetIccInfo(getter_AddRefs(iccInfo));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!iccInfo) {
+    return SendNotifyIccInfoChanged(OptionalIccInfoData(void_t()))
+      ? NS_OK : NS_ERROR_FAILURE;
+  }
+
+  IccInfoData data;
+  GetIccInfoDataFromIccInfo(iccInfo, data);
+
+  return SendNotifyIccInfoChanged(OptionalIccInfoData(data))
+    ? NS_OK : NS_ERROR_FAILURE;
+}
+
+/**
+ * PIccRequestParent Implementation.
+ */
+
+IccRequestParent::IccRequestParent(nsIIcc* aIcc)
+  : mIcc(aIcc)
+{
+  MOZ_COUNT_CTOR(IccRequestParent);
+}
+
+void
+IccRequestParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mIcc = nullptr;
+}
+
+bool
+IccRequestParent::DoRequest(const GetCardLockEnabledRequest& aRequest)
+{
+  return NS_SUCCEEDED(mIcc->GetCardLockEnabled(aRequest.lockType(),
+                                               this));
+}
+
+bool
+IccRequestParent::DoRequest(const UnlockCardLockRequest& aRequest)
+{
+  return NS_SUCCEEDED(mIcc->UnlockCardLock(aRequest.lockType(),
+                                           aRequest.password(),
+                                           aRequest.newPin(),
+                                           this));
+}
+
+bool
+IccRequestParent::DoRequest(const SetCardLockEnabledRequest& aRequest)
+{
+  return NS_SUCCEEDED(mIcc->SetCardLockEnabled(aRequest.lockType(),
+                                               aRequest.password(),
+                                               aRequest.enabled(),
+                                               this));
+}
+
+bool
+IccRequestParent::DoRequest(const ChangeCardLockPasswordRequest& aRequest)
+{
+  return NS_SUCCEEDED(mIcc->ChangeCardLockPassword(aRequest.lockType(),
+                                                   aRequest.password(),
+                                                   aRequest.newPassword(),
+                                                   this));
+}
+
+bool
+IccRequestParent::DoRequest(const GetCardLockRetryCountRequest& aRequest)
+{
+  return NS_SUCCEEDED(mIcc->GetCardLockRetryCount(aRequest.lockType(),
+                                                  this));
+}
+
+bool
+IccRequestParent::DoRequest(const MatchMvnoRequest& aRequest)
+{
+  return NS_SUCCEEDED(mIcc->MatchMvno(aRequest.mvnoType(),
+                                      aRequest.mvnoData(),
+                                      this));
+}
+
+bool
+IccRequestParent::DoRequest(const GetServiceStateEnabledRequest& aRequest)
+{
+  return NS_SUCCEEDED(mIcc->GetServiceStateEnabled(aRequest.service(),
+                                                   this));
+}
+
+nsresult
+IccRequestParent::SendReply(const IccReply& aReply)
+{
+  NS_ENSURE_TRUE(mIcc, NS_ERROR_FAILURE);
+
+  return Send__delete__(this, aReply) ? NS_OK : NS_ERROR_FAILURE;
+}
+
+/**
+ * nsIIccCallback Implementation.
+ */
+
+NS_IMPL_ISUPPORTS(IccRequestParent, nsIIccCallback)
+
+NS_IMETHODIMP
+IccRequestParent::NotifySuccess()
+{
+  return SendReply(IccReplySuccess());
+}
+
+NS_IMETHODIMP
+IccRequestParent::NotifySuccessWithBoolean(bool aResult)
+{
+  return SendReply(IccReplySuccessWithBoolean(aResult));
+}
+
+NS_IMETHODIMP
+IccRequestParent::NotifyGetCardLockRetryCount(int32_t aCount)
+{
+  return SendReply(IccReplyCardLockRetryCount(aCount));
+}
+
+NS_IMETHODIMP
+IccRequestParent::NotifyError(const nsAString & aErrorMsg)
+{
+  return SendReply(IccReplyError(nsString(aErrorMsg)));
+}
+
+NS_IMETHODIMP
+IccRequestParent::NotifyCardLockError(const nsAString & aErrorMsg,
+                                      int32_t aRetryCount)
+{
+  return SendReply(IccReplyCardLockError(aRetryCount, nsString(aErrorMsg)));
+}
+
+} // namespace icc
+} // namespace dom
+} // namespace mozilla
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/icc/ipc/IccParent.h
@@ -0,0 +1,107 @@
+/* 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/. */
+
+#ifndef mozilla_dom_icc_IccParent_h
+#define mozilla_dom_icc_IccParent_h
+
+#include "mozilla/dom/icc/PIccParent.h"
+#include "mozilla/dom/icc/PIccRequestParent.h"
+#include "nsIIccService.h"
+
+namespace mozilla {
+namespace dom {
+namespace icc {
+
+class IccParent final : public PIccParent
+                      , public nsIIccListener
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIICCLISTENER
+
+  explicit IccParent(uint32_t aServiceId);
+
+protected:
+  virtual
+  ~IccParent()
+  {
+    MOZ_COUNT_DTOR(IccParent);
+  }
+
+  virtual void
+  ActorDestroy(ActorDestroyReason aWhy) override;
+
+  virtual bool
+  RecvInit(
+          OptionalIccInfoData* aInfoData,
+          uint32_t* aCardState) override;
+
+  virtual PIccRequestParent*
+  AllocPIccRequestParent(const IccRequest& aRequest) override;
+
+  virtual bool
+  DeallocPIccRequestParent(PIccRequestParent* aActor) override;
+
+  virtual bool
+  RecvPIccRequestConstructor(PIccRequestParent* aActor,
+                             const IccRequest& aRequest) override;
+
+private:
+  IccParent();
+  nsCOMPtr<nsIIcc> mIcc;
+};
+
+class IccRequestParent final : public PIccRequestParent
+                             , public nsIIccCallback
+{
+  friend class IccParent;
+
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIICCCALLBACK
+
+  explicit IccRequestParent(nsIIcc* icc);
+
+protected:
+  virtual void
+  ActorDestroy(ActorDestroyReason why) override;
+
+private:
+  ~IccRequestParent()
+  {
+    MOZ_COUNT_DTOR(IccRequestParent);
+  }
+
+  bool
+  DoRequest(const GetCardLockEnabledRequest& aRequest);
+
+  bool
+  DoRequest(const UnlockCardLockRequest& aRequest);
+
+  bool
+  DoRequest(const SetCardLockEnabledRequest& aRequest);
+
+  bool
+  DoRequest(const ChangeCardLockPasswordRequest& aRequest);
+
+  bool
+  DoRequest(const GetCardLockRetryCountRequest& aRequest);
+
+  bool
+  DoRequest(const MatchMvnoRequest& aRequest);
+
+  bool
+  DoRequest(const GetServiceStateEnabledRequest& aRequest);
+
+  nsresult
+  SendReply(const IccReply& aReply);
+
+  nsCOMPtr<nsIIcc> mIcc;
+};
+
+} // namespace icc
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_icc_IccParent_h
--- a/dom/icc/moz.build
+++ b/dom/icc/moz.build
@@ -8,23 +8,31 @@ DIRS += ['interfaces']
 
 EXPORTS.mozilla.dom += [
     'Icc.h',
     'IccCardLockError.h',
     'IccInfo.h',
     'IccManager.h',
 ]
 
+EXPORTS.mozilla.dom.icc += [
+    'ipc/IccChild.h',
+    'ipc/IccParent.h',
+]
+
 UNIFIED_SOURCES += [
     'Assertions.cpp',
     'Icc.cpp',
     'IccCardLockError.cpp',
     "IccInfo.cpp",
     'IccListener.cpp',
     'IccManager.cpp',
+    'ipc/IccChild.cpp',
+    'ipc/IccIPCService.cpp',
+    'ipc/IccParent.cpp',
 ]
 
 IPDL_SOURCES += [
     'ipc/PIcc.ipdl',
     'ipc/PIccRequest.ipdl',
     'ipc/PIccTypes.ipdlh',
 ]
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -145,16 +145,17 @@
 
 #ifdef MOZ_NUWA_PROCESS
 #include <setjmp.h>
 #include "ipc/Nuwa.h"
 #endif
 
 #include "mozilla/dom/File.h"
 #include "mozilla/dom/cellbroadcast/CellBroadcastIPCService.h"
+#include "mozilla/dom/icc/IccChild.h"
 #include "mozilla/dom/mobileconnection/MobileConnectionChild.h"
 #include "mozilla/dom/mobilemessage/SmsChild.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
 #include "mozilla/dom/PFileSystemRequestChild.h"
 #include "mozilla/dom/FileSystemTaskBase.h"
 #include "mozilla/dom/bluetooth/PBluetoothChild.h"
 #include "mozilla/dom/PFMRadioChild.h"
 #include "mozilla/ipc/InputStreamUtils.h"
@@ -178,16 +179,17 @@
 #include "mozilla/net/NeckoMessageUtils.h"
 #include "mozilla/RemoteSpellCheckEngineChild.h"
 
 using namespace mozilla;
 using namespace mozilla::docshell;
 using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::cellbroadcast;
 using namespace mozilla::dom::devicestorage;
+using namespace mozilla::dom::icc;
 using namespace mozilla::dom::ipc;
 using namespace mozilla::dom::mobileconnection;
 using namespace mozilla::dom::mobilemessage;
 using namespace mozilla::dom::telephony;
 using namespace mozilla::dom::voicemail;
 using namespace mozilla::embedding;
 using namespace mozilla::hal_sandbox;
 using namespace mozilla::ipc;
@@ -1462,16 +1464,41 @@ ContentChild::AllocPHalChild()
 
 bool
 ContentChild::DeallocPHalChild(PHalChild* aHal)
 {
     delete aHal;
     return true;
 }
 
+PIccChild*
+ContentChild::SendPIccConstructor(PIccChild* aActor,
+                                  const uint32_t& aServiceId)
+{
+    // Add an extra ref for IPDL. Will be released in
+    // ContentChild::DeallocPIccChild().
+    static_cast<IccChild*>(aActor)->AddRef();
+    return PContentChild::SendPIccConstructor(aActor, aServiceId);
+}
+
+PIccChild*
+ContentChild::AllocPIccChild(const uint32_t& aServiceId)
+{
+    NS_NOTREACHED("No one should be allocating PIccChild actors");
+    return nullptr;
+}
+
+bool
+ContentChild::DeallocPIccChild(PIccChild* aActor)
+{
+    // IccChild is refcounted, must not be freed manually.
+    static_cast<IccChild*>(aActor)->Release();
+    return true;
+}
+
 asmjscache::PAsmJSCacheEntryChild*
 ContentChild::AllocPAsmJSCacheEntryChild(
                                     const asmjscache::OpenMode& aOpenMode,
                                     const asmjscache::WriteParams& aWriteParams,
                                     const IPC::Principal& aPrincipal)
 {
     NS_NOTREACHED("Should never get here!");
     return nullptr;
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -168,16 +168,23 @@ public:
     AllocPCrashReporterChild(const mozilla::dom::NativeThreadId& id,
                              const uint32_t& processType) override;
     virtual bool
     DeallocPCrashReporterChild(PCrashReporterChild*) override;
 
     virtual PHalChild* AllocPHalChild() override;
     virtual bool DeallocPHalChild(PHalChild*) override;
 
+    PIccChild*
+    SendPIccConstructor(PIccChild* aActor, const uint32_t& aServiceId);
+    virtual PIccChild*
+    AllocPIccChild(const uint32_t& aClientId) override;
+    virtual bool
+    DeallocPIccChild(PIccChild* aActor) override;
+
     virtual PMemoryReportRequestChild*
     AllocPMemoryReportRequestChild(const uint32_t& aGeneration,
                                    const bool& aAnonymize,
                                    const bool& aMinimizeMemoryUsage,
                                    const MaybeFileDesc& aDMDFile) override;
     virtual bool
     DeallocPMemoryReportRequestChild(PMemoryReportRequestChild* actor) override;
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -46,16 +46,17 @@
 #include "mozilla/dom/PContentBridgeParent.h"
 #include "mozilla/dom/PCycleCollectWithLogsParent.h"
 #include "mozilla/dom/PFMRadioParent.h"
 #include "mozilla/dom/PMemoryReportRequestParent.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/bluetooth/PBluetoothParent.h"
 #include "mozilla/dom/cellbroadcast/CellBroadcastParent.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
+#include "mozilla/dom/icc/IccParent.h"
 #include "mozilla/dom/mobileconnection/MobileConnectionParent.h"
 #include "mozilla/dom/mobilemessage/SmsParent.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/dom/telephony/TelephonyParent.h"
 #include "mozilla/dom/time/DateCacheCleaner.h"
 #include "mozilla/dom/voicemail/VoicemailParent.h"
 #include "mozilla/embedding/printingui/PrintingParent.h"
@@ -219,16 +220,17 @@ using base::ChildPrivileges;
 using base::KillProcess;
 
 #ifdef MOZ_CRASHREPORTER
 using namespace CrashReporter;
 #endif
 using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::cellbroadcast;
 using namespace mozilla::dom::devicestorage;
+using namespace mozilla::dom::icc;
 using namespace mozilla::dom::indexedDB;
 using namespace mozilla::dom::power;
 using namespace mozilla::dom::mobileconnection;
 using namespace mozilla::dom::mobilemessage;
 using namespace mozilla::dom::telephony;
 using namespace mozilla::dom::voicemail;
 using namespace mozilla::embedding;
 using namespace mozilla::hal;
@@ -3382,16 +3384,37 @@ ContentParent::AllocPHalParent()
 
 bool
 ContentParent::DeallocPHalParent(hal_sandbox::PHalParent* aHal)
 {
     delete aHal;
     return true;
 }
 
+PIccParent*
+ContentParent::AllocPIccParent(const uint32_t& aServiceId)
+{
+    if (!AssertAppProcessPermission(this, "mobileconnection")) {
+        return nullptr;
+    }
+    IccParent* parent = new IccParent(aServiceId);
+    // We release this ref in DeallocPIccParent().
+    parent->AddRef();
+
+    return parent;
+}
+
+bool
+ContentParent::DeallocPIccParent(PIccParent* aActor)
+{
+    // IccParent is refcounted, must not be freed manually.
+    static_cast<IccParent*>(aActor)->Release();
+    return true;
+}
+
 PMemoryReportRequestParent*
 ContentParent::AllocPMemoryReportRequestParent(const uint32_t& aGeneration,
                                                const bool &aAnonymize,
                                                const bool &aMinimizeMemoryUsage,
                                                const MaybeFileDesc &aDMDFile)
 {
     MemoryReportRequestParent* parent = new MemoryReportRequestParent();
     return parent;
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -545,16 +545,19 @@ private:
     virtual bool RecvGetRandomValues(const uint32_t& length,
                                      InfallibleTArray<uint8_t>* randomValues) override;
 
     virtual bool RecvIsSecureURI(const uint32_t& aType, const URIParams& aURI,
                                  const uint32_t& aFlags, bool* aIsSecureURI) override;
 
     virtual bool DeallocPHalParent(PHalParent*) override;
 
+    virtual PIccParent* AllocPIccParent(const uint32_t& aServiceId) override;
+    virtual bool DeallocPIccParent(PIccParent* aActor) override;
+
     virtual PMemoryReportRequestParent*
     AllocPMemoryReportRequestParent(const uint32_t& aGeneration,
                                     const bool &aAnonymize,
                                     const bool &aMinimizeMemoryUsage,
                                     const MaybeFileDesc &aDMDFile) override;
     virtual bool DeallocPMemoryReportRequestParent(PMemoryReportRequestParent* actor) override;
 
     virtual PCycleCollectWithLogsParent*
@@ -738,17 +741,17 @@ private:
     virtual bool RecvSetFakeVolumeState(const nsString& fsName, const int32_t& fsState) override;
 
     virtual bool RecvKeywordToURI(const nsCString& aKeyword,
                                   nsString* aProviderName,
                                   OptionalInputStreamParams* aPostData,
                                   OptionalURIParams* aURI) override;
 
     virtual bool RecvNotifyKeywordSearchLoading(const nsString &aProvider,
-                                                const nsString &aKeyword) override; 
+                                                const nsString &aKeyword) override;
 
     virtual void ProcessingError(Result aCode, const char* aMsgName) override;
 
     virtual bool RecvAllocateLayerTreeId(uint64_t* aId) override;
     virtual bool RecvDeallocateLayerTreeId(const uint64_t& aId) override;
 
     virtual bool RecvGetGraphicsFeatureStatus(const int32_t& aFeature,
                                               int32_t* aStatus,