Merge m-c to inbound a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 27 Mar 2015 17:31:19 -0700
changeset 266656 21aa17588defe40c117cd4a47ad8d91008a720f6
parent 266655 1628ecf1c71fb80533e39245a255d69554927d69 (current diff)
parent 266497 ad587ca628cfc317941aa2c61b447226fbbd214a (diff)
child 266657 8183a5fa421db468925be3b4dedc53afd5c6d3dd
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)
reviewersmerge
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
Merge m-c to inbound a=merge
dom/base/Navigator.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/mobileconnection/MobileConnection.cpp
dom/mobileconnection/MobileConnection.h
dom/plugins/ipc/PluginModuleChild.cpp
js/src/jscntxt.cpp
js/src/jsexn.cpp
--- a/b2g/components/PaymentProviderStrategy.js
+++ b/b2g/components/PaymentProviderStrategy.js
@@ -6,19 +6,19 @@
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 const PREF_DEBUG = "dom.payment.debug";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
-XPCOMUtils.defineLazyServiceGetter(this, "iccProvider",
-                                   "@mozilla.org/ril/content-helper;1",
-                                   "nsIIccProvider");
+XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
+                                   "@mozilla.org/icc/iccservice;1",
+                                   "nsIIccService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gRil",
                                    "@mozilla.org/ril;1",
                                    "nsIRadioInterfaceLayer");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
                                    "@mozilla.org/settingsService;1",
                                    "nsISettingsService");
@@ -143,17 +143,18 @@ PaymentProviderStrategy.prototype = {
   set paymentServiceId(aServiceId) {
     this._settings.paymentServiceId = aServiceId;
   },
 
   get iccInfo() {
     if (!this._iccInfo) {
       this._iccInfo = [];
       for (let i = 0; i < gRil.numRadioInterfaces; i++) {
-        let info = iccProvider.getIccInfo(i);
+        let icc = gIccService.getIccByServiceId(i);
+        let info = icc && icc.iccInfo;
         if (!info) {
           LOGE("Tried to get the ICC info for an invalid service ID " + i);
           continue;
         }
 
         this._iccInfo.push({
           iccId: info.iccid,
           mcc: info.mcc,
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="9cc496cecc37d7a29f9279827cdf6e4891211f67"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0e7c8ade48129b3e03c5de8ae0452fd1f756535c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f5de61a5d8fdaa2db3d4e17e0c4212ec4d54a365"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="173b3104bfcbd23fc9dccd4b0035fc49aae3d444">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="9cc496cecc37d7a29f9279827cdf6e4891211f67"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0e7c8ade48129b3e03c5de8ae0452fd1f756535c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="527d1c939ee57deb7192166e56e2a3fffa8cb087"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4efd19d199ae52656604f794c5a77518400220fd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="9cc496cecc37d7a29f9279827cdf6e4891211f67"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0e7c8ade48129b3e03c5de8ae0452fd1f756535c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f5de61a5d8fdaa2db3d4e17e0c4212ec4d54a365"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="9cc496cecc37d7a29f9279827cdf6e4891211f67"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0e7c8ade48129b3e03c5de8ae0452fd1f756535c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f5de61a5d8fdaa2db3d4e17e0c4212ec4d54a365"/>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="9cc496cecc37d7a29f9279827cdf6e4891211f67"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0e7c8ade48129b3e03c5de8ae0452fd1f756535c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f5de61a5d8fdaa2db3d4e17e0c4212ec4d54a365"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="173b3104bfcbd23fc9dccd4b0035fc49aae3d444">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="9cc496cecc37d7a29f9279827cdf6e4891211f67"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="0e7c8ade48129b3e03c5de8ae0452fd1f756535c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="93f9ba577f68d772093987c2f1c0a4ae293e1802"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="527d1c939ee57deb7192166e56e2a3fffa8cb087"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="ef937d1aca7c4cf89ecb5cc43ae8c21c2000a9db">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="9cc496cecc37d7a29f9279827cdf6e4891211f67"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0e7c8ade48129b3e03c5de8ae0452fd1f756535c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f5de61a5d8fdaa2db3d4e17e0c4212ec4d54a365"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4efd19d199ae52656604f794c5a77518400220fd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="9cc496cecc37d7a29f9279827cdf6e4891211f67"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0e7c8ade48129b3e03c5de8ae0452fd1f756535c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f5de61a5d8fdaa2db3d4e17e0c4212ec4d54a365"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "9cc496cecc37d7a29f9279827cdf6e4891211f67", 
+        "git_revision": "0e7c8ade48129b3e03c5de8ae0452fd1f756535c", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "9e79307fd6bcade07847b92d42948a6a6a334f79", 
+    "revision": "97a01eae94361363300254b54e53e2ac0f0b9d38", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4efd19d199ae52656604f794c5a77518400220fd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="9cc496cecc37d7a29f9279827cdf6e4891211f67"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0e7c8ade48129b3e03c5de8ae0452fd1f756535c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f5de61a5d8fdaa2db3d4e17e0c4212ec4d54a365"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="52775e03a2d8532429dff579cb2cd56718e488c3">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="9cc496cecc37d7a29f9279827cdf6e4891211f67"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="0e7c8ade48129b3e03c5de8ae0452fd1f756535c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2aa4a75c63cd6e93870a8bddbba45f863cbfd9a3"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="ed2cf97a6c37a4bbd0bbbbffe06ec7136d8c79ff"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="f5de61a5d8fdaa2db3d4e17e0c4212ec4d54a365"/>
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -173,17 +173,16 @@
 @RESPATH@/components/dom_audiochannel.xpt
 @RESPATH@/components/dom_base.xpt
 @RESPATH@/components/dom_system.xpt
 #ifdef MOZ_WIDGET_GONK
 @RESPATH@/components/dom_wifi.xpt
 @RESPATH@/components/dom_system_gonk.xpt
 #endif
 #ifdef MOZ_B2G_RIL
-@RESPATH@/components/dom_icc.xpt
 @RESPATH@/components/dom_wappush.xpt
 @RESPATH@/components/dom_mobileconnection.xpt
 #endif
 #ifdef MOZ_B2G_BT
 @RESPATH@/components/dom_bluetooth.xpt
 #endif
 #ifdef MOZ_B2G_CAMERA
 @BINPATH@/components/dom_camera.xpt
@@ -213,16 +212,17 @@
 @RESPATH@/components/dom_power.xpt
 @RESPATH@/components/dom_quota.xpt
 @RESPATH@/components/dom_range.xpt
 @RESPATH@/components/dom_security.xpt
 @RESPATH@/components/dom_settings.xpt
 @RESPATH@/components/dom_permissionsettings.xpt
 @RESPATH@/components/dom_sidebar.xpt
 @RESPATH@/components/dom_cellbroadcast.xpt
+@RESPATH@/components/dom_icc.xpt
 @RESPATH@/components/dom_mobilemessage.xpt
 @RESPATH@/components/dom_storage.xpt
 @RESPATH@/components/dom_stylesheets.xpt
 @RESPATH@/components/dom_telephony.xpt
 @RESPATH@/components/dom_threads.xpt
 @RESPATH@/components/dom_traversal.xpt
 @RESPATH@/components/dom_tv.xpt
 @RESPATH@/components/dom_views.xpt
@@ -478,16 +478,18 @@
 @RESPATH@/components/ResourceStatsManager.js
 @RESPATH@/components/ResourceStatsManager.manifest
 #endif // MOZ_WIDGET_GONK
 
 ; RIL
 #if defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
 @RESPATH@/components/CellBroadcastService.js
 @RESPATH@/components/CellBroadcastService.manifest
+@BINPATH@/components/IccService.js
+@BINPATH@/components/IccService.manifest
 @RESPATH@/components/MmsService.js
 @RESPATH@/components/MmsService.manifest
 @RESPATH@/components/MobileMessageDatabaseService.js
 @RESPATH@/components/MobileMessageDatabaseService.manifest
 #ifndef DISABLE_MOZ_RIL_GEOLOC
 @RESPATH@/components/MobileConnectionService.js
 @RESPATH@/components/MobileConnectionService.manifest
 @RESPATH@/components/RadioInterfaceLayer.js
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -41,16 +41,22 @@
 #main-window[customize-entered] {
   min-width: -moz-fit-content;
 }
 
 searchbar {
   -moz-binding: url("chrome://browser/content/search/search.xml#searchbar");
 }
 
+/* Prevent shrinking the page content to 0 height and width */
+.browserStack > browser {
+  min-height: 25px;
+  min-width: 25px;
+}
+
 .browserStack > browser {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-browser");
 }
 
 .browserStack > browser[remote="true"] {
   -moz-binding: url("chrome://browser/content/tabbrowser.xml#tabbrowser-remote-browser");
 }
 
--- a/browser/base/content/test/general/browser_tab_dragdrop.js
+++ b/browser/base/content/test/general/browser_tab_dragdrop.js
@@ -27,16 +27,65 @@ let clickTest = Task.async(function*(tab
   is(newClicks, clicks + 1, "adding 1 more click on BODY");
 });
 
 function loadURI(tab, url) {
   tab.linkedBrowser.loadURI(url);
   return BrowserTestUtils.browserLoaded(tab.linkedBrowser);
 }
 
+// Creates a framescript which caches the current object value from the plugin
+// in the page. checkObjectValue below verifies that the framescript is still
+// active for the browser and that the cached value matches that from the plugin
+// in the page which tells us the plugin hasn't been reinitialized.
+function cacheObjectValue(browser) {
+  let frame_script = function() {
+    let plugin = content.document.wrappedJSObject.body.firstChild;
+    let objectValue = plugin.getObjectValue();
+
+    addMessageListener("Test:CheckObjectValue", () => {
+      try {
+        let plugin = content.document.wrappedJSObject.body.firstChild;
+        sendAsyncMessage("Test:CheckObjectValue", {
+          result: plugin.checkObjectValue(objectValue)
+        });
+      }
+      catch (e) {
+        sendAsyncMessage("Test:CheckObjectValue", {
+          result: null,
+          exception: e.toString()
+        });
+      }
+    });
+  };
+
+  browser.messageManager.loadFrameScript("data:,(" + frame_script.toString() + ")();", false)
+}
+
+// See the notes for cacheObjectValue above.
+function checkObjectValue(browser) {
+  let mm = browser.messageManager;
+
+  return new Promise((resolve, reject) => {
+    let listener  = ({ data }) => {
+      mm.removeMessageListener("Test:CheckObjectValue", listener);
+      if (data.result === null) {
+        ok(false, "checkObjectValue threw an exception: " + data.exception);
+        reject(data.exception);
+      }
+      else {
+        resolve(data.result);
+      }
+    };
+
+    mm.addMessageListener("Test:CheckObjectValue", listener);
+    mm.sendAsyncMessage("Test:CheckObjectValue");
+  });
+}
+
 add_task(function*() {
   let embed = '<embed type="application/x-test" allowscriptaccess="always" allowfullscreen="true" wmode="window" width="640" height="480"></embed>'
   setTestPluginEnabledState(Ci.nsIPluginTag.STATE_ENABLED);
 
   // create a few tabs
   let tabs = [
     gBrowser.tabs[0],
     gBrowser.addTab("about:blank", {skipAnimation: true}),
@@ -52,39 +101,34 @@ add_task(function*() {
   yield loadURI(tabs[4], "data:text/html;charset=utf-8,<body onload='clicks=0' onclick='++clicks'>"+embed);
   gBrowser.selectedTab = tabs[3];
 
   swapTabsAndCloseOther(2, 3); // now: 0 1 2 4
   is(gBrowser.tabs[1], tabs[1], "tab1");
   is(gBrowser.tabs[2], tabs[3], "tab3");
   is(gBrowser.tabs[3], tabs[4], "tab4");
 
-  let plugin = tabs[4].linkedBrowser.contentDocument.wrappedJSObject.body.firstChild;
-  let tab4_plugin_object = plugin.getObjectValue();
+  cacheObjectValue(tabs[4].linkedBrowser);
 
   swapTabsAndCloseOther(3, 2); // now: 0 1 4
   gBrowser.selectedTab = gBrowser.tabs[2];
 
-  let doc = gBrowser.tabs[2].linkedBrowser.contentDocument.wrappedJSObject;
-  plugin = doc.body.firstChild;
-  ok(plugin && plugin.checkObjectValue(tab4_plugin_object), "same plugin instance");
+  ok((yield checkObjectValue(gBrowser.tabs[2].linkedBrowser)), "same plugin instance");
 
   is(gBrowser.tabs[1], tabs[1], "tab1");
   is(gBrowser.tabs[2], tabs[3], "tab4");
 
   let clicks = yield getClicks(gBrowser.tabs[2]);
   is(clicks, 0, "no click on BODY so far");
   yield clickTest(gBrowser.tabs[2]);
 
   swapTabsAndCloseOther(2, 1); // now: 0 4
   is(gBrowser.tabs[1], tabs[1], "tab1");
 
-  doc = gBrowser.tabs[1].linkedBrowser.contentDocument.wrappedJSObject;
-  plugin = doc.body.firstChild;
-  ok(plugin && plugin.checkObjectValue(tab4_plugin_object), "same plugin instance");
+  ok((yield checkObjectValue(gBrowser.tabs[1].linkedBrowser)), "same plugin instance");
 
   yield clickTest(gBrowser.tabs[1]);
 
   // Load a new document (about:blank) in tab4, then detach that tab into a new window.
   // In the new window, navigate back to the original document and click on its <body>,
   // verify that its onclick was called.
   gBrowser.selectedTab = tabs[1];
   yield loadURI(tabs[1], "about:blank");
--- a/browser/devtools/framework/test/browser_toolbox_hosts_size.js
+++ b/browser/devtools/framework/test/browser_toolbox_hosts_size.js
@@ -20,22 +20,22 @@ add_task(function*() {
   let nbox = gBrowser.getNotificationBox();
   let {clientHeight: nboxHeight, clientWidth: nboxWidth} = nbox;
   let toolbox = yield gDevTools.showToolbox(TargetFactory.forTab(tab));
 
   is (nbox.clientHeight, nboxHeight, "Opening the toolbox hasn't changed the height of the nbox");
   is (nbox.clientWidth, nboxWidth, "Opening the toolbox hasn't changed the width of the nbox");
 
   let iframe = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-bottom-iframe");
-  is (iframe.clientHeight, nboxHeight - 10, "The iframe fits within the available space ");
+  is (iframe.clientHeight, nboxHeight - 25, "The iframe fits within the available space");
 
   yield toolbox.switchHost(devtools.Toolbox.HostType.SIDE);
   iframe = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-side-iframe");
   iframe.style.minWidth = "1px"; // Disable the min width set in css
-  is (iframe.clientWidth, nboxWidth - 10, "The iframe fits within the available space");
+  is (iframe.clientWidth, nboxWidth - 25, "The iframe fits within the available space");
 
   yield cleanup(toolbox);
 });
 
 add_task(function*() {
   // Set size prefs to something reasonable, so we can check to make sure
   // they are being set properly.
   Services.prefs.setIntPref("devtools.toolbox.footer.height", 100);
--- a/browser/devtools/framework/toolbox-hosts.js
+++ b/browser/devtools/framework/toolbox-hosts.js
@@ -5,16 +5,22 @@
 "use strict";
 
 const {Cu} = require("chrome");
 const EventEmitter = require("devtools/toolkit/event-emitter");
 const {Promise: promise} = require("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
 
+/* A host should always allow this much space for the page to be displayed.
+ * There is also a min-height on the browser, but we still don't want to set
+ * frame.height to be larger than that, since it can cause problems with
+ * resizing the toolbox and panel layout. */
+const MIN_PAGE_SIZE = 25;
+
 /**
  * A toolbox host represents an object that contains a toolbox (e.g. the
  * sidebar or a separate window). Any host object should implement the
  * following functions:
  *
  * create() - create the UI and emit a 'ready' event when the UI is ready to use
  * destroy() - destroy the host's UI
  */
@@ -52,17 +58,17 @@ BottomHost.prototype = {
 
     this._splitter = ownerDocument.createElement("splitter");
     this._splitter.setAttribute("class", "devtools-horizontal-splitter");
 
     this.frame = ownerDocument.createElement("iframe");
     this.frame.className = "devtools-toolbox-bottom-iframe";
     this.frame.height = Math.min(
       Services.prefs.getIntPref(this.heightPref),
-      this._nbox.clientHeight - 10 // Always show at least some page content
+      this._nbox.clientHeight - MIN_PAGE_SIZE
     );
 
     this._nbox.appendChild(this._splitter);
     this._nbox.appendChild(this.frame);
 
     let frameLoad = () => {
       this.emit("ready", this.frame);
       deferred.resolve(this.frame);
@@ -139,17 +145,17 @@ SidebarHost.prototype = {
     this._splitter = ownerDocument.createElement("splitter");
     this._splitter.setAttribute("class", "devtools-side-splitter");
 
     this.frame = ownerDocument.createElement("iframe");
     this.frame.className = "devtools-toolbox-side-iframe";
 
     this.frame.width = Math.min(
       Services.prefs.getIntPref(this.widthPref),
-      this._sidebar.clientWidth - 10 // Always show at least some page content
+      this._sidebar.clientWidth - MIN_PAGE_SIZE
     );
 
     this._sidebar.appendChild(this._splitter);
     this._sidebar.appendChild(this.frame);
 
     let frameLoad = () => {
       this.emit("ready", this.frame);
       deferred.resolve(this.frame);
--- a/browser/devtools/markupview/markup-view.js
+++ b/browser/devtools/markupview/markup-view.js
@@ -2323,17 +2323,17 @@ TextEditor.prototype = {
  */
 function ElementEditor(aContainer, aNode) {
   this.container = aContainer;
   this.node = aNode;
   this.markup = this.container.markup;
   this.template = this.markup.template.bind(this.markup);
   this.doc = this.markup.doc;
 
-  this.attrs = {};
+  this.attrElements = new Map();
   this.animationTimers = {};
 
   // The templates will fill the following properties
   this.elt = null;
   this.tag = null;
   this.closeTag = null;
   this.attrList = null;
   this.newAttr = null;
@@ -2403,67 +2403,80 @@ ElementEditor.prototype = {
       flashElementOff(this.getAttributeElement(attrName));
     }, this.markup.CONTAINER_FLASHING_DURATION);
   },
 
   /**
    * Update the state of the editor from the node.
    */
   update: function() {
-    let attrs = this.node.attributes || [];
-    let attrsToRemove = new Set(this.attrList.querySelectorAll(".attreditor"));
-
-    // Only loop through the current attributes on the node, anything that's
-    // been removed will be removed from this DOM because it will be part of
-    // the attrsToRemove set.
-    for (let attr of attrs) {
-      let el = this.attrs[attr.name];
+    let nodeAttributes = this.node.attributes || [];
+
+    // Keep the data model in sync with attributes on the node.
+    let currentAttributes = new Set(nodeAttributes.map(a=>a.name));
+    for (let name of this.attrElements.keys()) {
+      if (!currentAttributes.has(name)) {
+        this.removeAttribute(name);
+      }
+    }
+
+    // Only loop through the current attributes on the node.  Missing
+    // attributes have already been removed at this point.
+    for (let attr of nodeAttributes) {
+      let el = this.attrElements.get(attr.name);
       let valueChanged = el && el.querySelector(".attr-value").innerHTML !== attr.value;
       let isEditing = el && el.querySelector(".editable").inplaceEditor;
       let canSimplyShowEditor = el && (!valueChanged || isEditing);
 
       if (canSimplyShowEditor) {
         // Element already exists and doesn't need to be recreated.
         // Just show it (it's hidden by default due to the template).
-        attrsToRemove.delete(el);
         el.style.removeProperty("display");
       } else {
         // Create a new editor, because the value of an existing attribute
         // has changed.
         let attribute = this._createAttribute(attr);
         attribute.style.removeProperty("display");
 
         // Temporarily flash the attribute to highlight the change.
         // But not if this is the first time the editor instance has
         // been created.
         if (this.initialized) {
           this.flashAttribute(attr.name);
         }
       }
     }
-
-    for (let el of attrsToRemove) {
-      el.remove();
-    }
   },
 
   _startModifyingAttributes: function() {
     return this.node.startModifyingAttributes();
   },
 
   /**
    * Get the element used for one of the attributes of this element
    * @param string attrName The name of the attribute to get the element for
    * @return DOMElement
    */
   getAttributeElement: function(attrName) {
     return this.attrList.querySelector(
       ".attreditor[data-attr=" + attrName + "] .attr-value");
   },
 
+  /**
+   * Remove an attribute from the attrElements object and the DOM
+   * @param string attrName The name of the attribute to remove
+   */
+  removeAttribute: function(attrName) {
+    let attr = this.attrElements.get(attrName);
+    if (attr) {
+      this.attrElements.delete(attrName);
+      attr.remove();
+    }
+  },
+
   _createAttribute: function(aAttr, aBefore = null) {
     // Create the template editor, which will save some variables here.
     let data = {
       attrName: aAttr.name,
     };
     this.template("attribute", data);
     var {attr, inner, name, val} = data;
 
@@ -2536,28 +2549,23 @@ ElementEditor.prototype = {
       }
     });
 
     // Figure out where we should place the attribute.
     let before = aBefore;
     if (aAttr.name == "id") {
       before = this.attrList.firstChild;
     } else if (aAttr.name == "class") {
-      let idNode = this.attrs["id"];
+      let idNode = this.attrElements.get("id");
       before = idNode ? idNode.nextSibling : this.attrList.firstChild;
     }
     this.attrList.insertBefore(attr, before);
 
-    // Remove the old version of this attribute from the DOM.
-    let oldAttr = this.attrs[aAttr.name];
-    if (oldAttr && oldAttr.parentNode) {
-      oldAttr.parentNode.removeChild(oldAttr);
-    }
-
-    this.attrs[aAttr.name] = attr;
+    this.removeAttribute(aAttr.name);
+    this.attrElements.set(aAttr.name, attr);
 
     let collapsedValue;
     if (aAttr.value.match(COLLAPSE_DATA_URL_REGEX)) {
       collapsedValue = truncateString(aAttr.value, COLLAPSE_DATA_URL_LENGTH);
     } else {
       collapsedValue = truncateString(aAttr.value, COLLAPSE_ATTRIBUTE_LENGTH);
     }
 
--- a/browser/devtools/markupview/test/browser_markupview_css_completion_style_attribute.js
+++ b/browser/devtools/markupview/test/browser_markupview_css_completion_style_attribute.js
@@ -135,12 +135,12 @@ function* checkData(index, editor, inspe
       ok(editor.popup.isOpen, "Popup is open");
     } else {
       ok(editor.popup._panel.state != "open" && editor.popup._panel.state != "showing",
         "Popup is closed");
     }
   } else {
     let nodeFront = yield getNodeFront("#node14", inspector);
     let editor = getContainerForNodeFront(nodeFront, inspector).editor;
-    let attr = editor.attrs["style"].querySelector(".editable");
+    let attr = editor.attrElements.get("style").querySelector(".editable");
     is(attr.textContent, completion, "Correct value is persisted after pressing Enter");
   }
 }
--- a/browser/devtools/markupview/test/browser_markupview_mutation_01.js
+++ b/browser/devtools/markupview/test/browser_markupview_mutation_01.js
@@ -35,16 +35,42 @@ const TEST_DATA = [
     check: function*(inspector) {
       let {editor} = yield getContainerForSelector("#node1", inspector);
       ok(![...editor.attrList.querySelectorAll(".attreditor")].some(attr => {
         return attr.textContent.trim() === "newattr=\"newattrval\"";
       }), "newattr attribute removed");
     }
   },
   {
+    desc: "Re-adding an attribute",
+    test: () => {
+      let node1 = getNode("#node1");
+      node1.setAttribute("newattr", "newattrval");
+    },
+    check: function*(inspector) {
+      let {editor} = yield getContainerForSelector("#node1", inspector);
+      ok([...editor.attrList.querySelectorAll(".attreditor")].some(attr => {
+        return attr.textContent.trim() === "newattr=\"newattrval\"";
+      }), "newattr attribute found");
+    }
+  },
+  {
+    desc: "Changing an attribute",
+    test: () => {
+      let node1 = getNode("#node1");
+      node1.setAttribute("newattr", "newattrchanged");
+    },
+    check: function*(inspector) {
+      let {editor} = yield getContainerForSelector("#node1", inspector);
+      ok([...editor.attrList.querySelectorAll(".attreditor")].some(attr => {
+        return attr.textContent.trim() === "newattr=\"newattrchanged\"";
+      }), "newattr attribute found");
+    }
+  },
+  {
     desc: "Updating the text-content",
     test: () => {
       let node1 = getNode("#node1");
       node1.textContent = "newtext";
     },
     check: function*(inspector) {
       let {children} = yield getContainerForSelector("#node1", inspector);
       is(children.querySelector(".text").textContent.trim(), "newtext",
--- a/browser/devtools/markupview/test/browser_markupview_mutation_02.js
+++ b/browser/devtools/markupview/test/browser_markupview_mutation_02.js
@@ -118,17 +118,17 @@ function* assertNodeFlashing(nodeFront, 
   clearTimeout(container._flashMutationTimer);
   container._flashMutationTimer = null;
   container.tagState.classList.remove("theme-bg-contrast");
 }
 
 function* assertAttributeFlashing(nodeFront, attribute, inspector) {
   let container = getContainerForNodeFront(nodeFront, inspector);
   ok(container, "Markup container for node found");
-  ok(container.editor.attrs[attribute], "Attribute exists on editor");
+  ok(container.editor.attrElements.get(attribute), "Attribute exists on editor");
 
   let attributeElement = container.editor.getAttributeElement(attribute);
 
   ok(attributeElement.classList.contains("theme-bg-contrast"),
     "Element for " + attribute + " attribute is flashing");
 
   attributeElement.classList.remove("theme-bg-contrast");
 }
--- a/browser/devtools/markupview/test/browser_markupview_tag_edit_02.js
+++ b/browser/devtools/markupview/test/browser_markupview_tag_edit_02.js
@@ -17,17 +17,17 @@ add_task(function*() {
 
   info("Verify attributes, only ID should be there for now");
   yield assertAttributes("#test-div", {
     id: "test-div"
   });
 
   info("Focus the ID attribute and change its content");
   let {editor} = yield getContainerForSelector("#test-div", inspector);
-  let attr = editor.attrs["id"].querySelector(".editable");
+  let attr = editor.attrElements.get("id").querySelector(".editable");
   let mutated = inspector.once("markupmutation");
   setEditableFieldValue(attr,
     attr.textContent + ' class="newclass" style="color:green"', inspector);
   yield mutated;
 
   info("Verify attributes, should have ID, class and style");
   yield assertAttributes("#test-div", {
     id: "test-div",
--- a/browser/devtools/markupview/test/browser_markupview_tag_edit_07.js
+++ b/browser/devtools/markupview/test/browser_markupview_tag_edit_07.js
@@ -42,39 +42,39 @@ let TEST_DATA = [{
 }, {
   desc: "Try to add long data URL to make sure it is collapsed in attribute editor.",
   text: "style='"+DATA_URL_INLINE_STYLE+"'",
   expectedAttributes: {
     'style': DATA_URL_INLINE_STYLE
   },
   validate: (element, container, inspector) => {
     let editor = container.editor;
-    let visibleAttrText = editor.attrs["style"].querySelector(".attr-value").textContent;
+    let visibleAttrText = editor.attrElements.get("style").querySelector(".attr-value").textContent;
     is (visibleAttrText, DATA_URL_INLINE_STYLE_COLLAPSED);
   }
 }, {
   desc: "Try to add long attribute to make sure it is collapsed in attribute editor.",
   text: 'data-long="'+LONG_ATTRIBUTE+'"',
   expectedAttributes: {
     'data-long':LONG_ATTRIBUTE
   },
   validate: (element, container, inspector) => {
     let editor = container.editor;
-    let visibleAttrText = editor.attrs["data-long"].querySelector(".attr-value").textContent;
+    let visibleAttrText = editor.attrElements.get("data-long").querySelector(".attr-value").textContent;
     is (visibleAttrText, LONG_ATTRIBUTE_COLLAPSED)
   }
 }, {
   desc: "Try to add long data URL to make sure it is collapsed in attribute editor.",
   text: 'src="'+DATA_URL_ATTRIBUTE+'"',
   expectedAttributes: {
     "src": DATA_URL_ATTRIBUTE
   },
   validate: (element, container, inspector) => {
     let editor = container.editor;
-    let visibleAttrText = editor.attrs["src"].querySelector(".attr-value").textContent;
+    let visibleAttrText = editor.attrElements.get("src").querySelector(".attr-value").textContent;
     is (visibleAttrText, DATA_URL_ATTRIBUTE_COLLAPSED);
   }
 }];
 
 add_task(function*() {
   let {inspector} = yield addTab(TEST_URL).then(openInspector);
   yield runAddAttributesTests(TEST_DATA, "div", inspector)
 });
--- a/browser/devtools/markupview/test/browser_markupview_tag_edit_08.js
+++ b/browser/devtools/markupview/test/browser_markupview_tag_edit_08.js
@@ -31,29 +31,29 @@ function* testCollapsedLongAttribute(ins
 
   yield assertAttributes("#node24", {
     id: "node24",
     "class": "",
     "data-long": LONG_ATTRIBUTE
   });
 
   let {editor} = yield getContainerForSelector("#node24", inspector);
-  let attr = editor.attrs["data-long"].querySelector(".editable");
+  let attr = editor.attrElements.get("data-long").querySelector(".editable");
 
   // Check to make sure it has expanded after focus
   attr.focus();
   EventUtils.sendKey("return", inspector.panelWin);
   let input = inplaceEditor(attr).input;
   is (input.value, 'data-long="' + LONG_ATTRIBUTE + '"');
   EventUtils.sendKey("escape", inspector.panelWin);
 
   setEditableFieldValue(attr, input.value + ' data-short="ABC"', inspector);
   yield inspector.once("markupmutation");
 
-  let visibleAttrText = editor.attrs["data-long"].querySelector(".attr-value").textContent;
+  let visibleAttrText = editor.attrElements.get("data-long").querySelector(".attr-value").textContent;
   is (visibleAttrText, LONG_ATTRIBUTE_COLLAPSED)
 
   yield assertAttributes("#node24", {
     id: "node24",
     class: "",
     'data-long': LONG_ATTRIBUTE,
     "data-short": "ABC"
   });
@@ -64,17 +64,17 @@ function* testModifyInlineStyleWithQuote
 
   yield assertAttributes("#node26", {
     id: "node26",
     style: 'background-image: url("moz-page-thumb://thumbnail?url=http%3A%2F%2Fwww.mozilla.org%2F");'
   });
 
   let onMutated = inspector.once("markupmutation");
   let {editor} = yield getContainerForSelector("#node26", inspector);
-  let attr = editor.attrs["style"].querySelector(".editable");
+  let attr = editor.attrElements.get("style").querySelector(".editable");
 
   attr.focus();
   EventUtils.sendKey("return", inspector.panelWin);
 
   let input = inplaceEditor(attr).input;
   let value = input.value;
 
   is (value,
@@ -100,17 +100,17 @@ function* testEditingAttributeWithMixedQ
 
   yield assertAttributes("#node27", {
     "id": "node27",
     "class": 'Double " and single \''
   });
 
   let onMutated = inspector.once("markupmutation");
   let {editor} = yield getContainerForSelector("#node27", inspector);
-  let attr = editor.attrs["class"].querySelector(".editable");
+  let attr = editor.attrElements.get("class").querySelector(".editable");
 
   attr.focus();
   EventUtils.sendKey("return", inspector.panelWin);
 
   let input = inplaceEditor(attr).input;
   let value = input.value;
 
   is (value, "class=\"Double &quot; and single '\"", "Value contains &quot;");
--- a/browser/devtools/markupview/test/browser_markupview_tag_edit_09.js
+++ b/browser/devtools/markupview/test/browser_markupview_tag_edit_09.js
@@ -22,17 +22,17 @@ function* testWellformedMixedCase(inspec
   info("Modifying a mixed-case attribute, " +
     "expecting the attribute's case to be preserved");
 
   info("Listening to markup mutations");
   let onMutated = inspector.once("markupmutation");
 
   info("Focusing the viewBox attribute editor");
   let {editor} = yield getContainerForSelector("svg", inspector);
-  let attr = editor.attrs["viewBox"].querySelector(".editable");
+  let attr = editor.attrElements.get("viewBox").querySelector(".editable");
   attr.focus();
   EventUtils.sendKey("return", inspector.panelWin);
 
   info("Editing the attribute value and waiting for the mutation event");
   let input = inplaceEditor(attr).input;
   input.value = "viewBox=\"0 0 1 1\"";
   EventUtils.sendKey("return", inspector.panelWin);
   yield onMutated;
@@ -48,17 +48,17 @@ function* testMalformedMixedCase(inspect
   info("Modifying a malformed, mixed-case attribute, " +
     "expecting the attribute's case to be preserved");
 
   info("Listening to markup mutations");
   let onMutated = inspector.once("markupmutation");
 
   info("Focusing the viewBox attribute editor");
   let {editor} = yield getContainerForSelector("svg", inspector);
-  let attr = editor.attrs["viewBox"].querySelector(".editable");
+  let attr = editor.attrElements.get("viewBox").querySelector(".editable");
   attr.focus();
   EventUtils.sendKey("return", inspector.panelWin);
 
   info("Editing the attribute value and waiting for the mutation event");
   let input = inplaceEditor(attr).input;
   input.value = "viewBox=\"<>\"";
   EventUtils.sendKey("return", inspector.panelWin);
   yield onMutated;
--- a/browser/devtools/markupview/test/helper_attributes_test_runner.js
+++ b/browser/devtools/markupview/test/helper_attributes_test_runner.js
@@ -128,17 +128,17 @@ function* runEditAttributesTest(test, in
   info("Editing attribute " + test.name + " with value " + test.value);
 
   let container = yield getContainerForSelector(test.node, inspector);
   ok(container && container.editor, "The markup-container for " + test.node +
     " was found");
 
   info("Listening for the markupmutation event");
   let nodeMutated = inspector.once("markupmutation");
-  let attr = container.editor.attrs[test.name].querySelector(".editable");
+  let attr = container.editor.attrElements.get(test.name).querySelector(".editable");
   setEditableFieldValue(attr, test.value, inspector);
   yield nodeMutated;
 
   info("Asserting the new attributes after edition");
   yield assertAttributes(test.node, test.expectedAttributes);
 
   info("Undo the change and assert that the attributes have been changed back");
   yield undoChange(inspector);
--- a/browser/devtools/netmonitor/test/browser.ini
+++ b/browser/devtools/netmonitor/test/browser.ini
@@ -52,17 +52,16 @@ skip-if= buildapp == 'mulet'
 [browser_net_copy_image_as_data_uri.js]
 [browser_net_copy_url.js]
 [browser_net_copy_as_curl.js]
 skip-if = e10s # Bug 1091596
 [browser_net_cyrillic-01.js]
 [browser_net_cyrillic-02.js]
 [browser_net_details-no-duplicated-content.js]
 [browser_net_filter-01.js]
-skip-if = e10s # Bug 1091603
 [browser_net_filter-02.js]
 [browser_net_filter-03.js]
 [browser_net_filter-04.js]
 [browser_net_footer-summary.js]
 [browser_net_html-preview.js]
 [browser_net_icon-preview.js]
 [browser_net_image-tooltip.js]
 [browser_net_json-long.js]
--- a/browser/devtools/performance/modules/front.js
+++ b/browser/devtools/performance/modules/front.js
@@ -292,18 +292,20 @@ PerformanceFront.prototype = {
     // for all targets and interacts with the whole platform, so we don't want
     // to affect other clients by stopping (or restarting) it.
     let profilerStatus = yield this._request("profiler", "isActive");
     if (profilerStatus.isActive) {
       this.emit("profiler-already-active");
       return profilerStatus.currentTime;
     }
 
-    // Extend the profiler options so that protocol.js doesn't modify the original.
-    let profilerOptions = extend({}, this._customProfilerOptions);
+    // If this._customProfilerOptions is defined, use those to pass in
+    // to the profiler actor. The profiler actor handles all the defaults
+    // now, so this should only be used for tests.
+    let profilerOptions = this._customProfilerOptions || {};
     yield this._request("profiler", "startProfiler", profilerOptions);
 
     this.emit("profiler-activated");
     return 0;
   }),
 
   /**
    * Starts the timeline actor.
@@ -396,29 +398,16 @@ PerformanceFront.prototype = {
 
     let delay = DEFAULT_ALLOCATION_SITES_PULL_TIMEOUT;
     this._sitesPullTimeout = setTimeout(this._pullAllocationSites, delay);
 
     deferred.resolve();
   }),
 
   /**
-   * Overrides the options sent to the built-in profiler module when activating,
-   * such as the maximum entries count, the sampling interval etc.
-   *
-   * Used in tests and for older backend implementations.
-   */
-  _customProfilerOptions: {
-    entries: 1000000,
-    interval: 1,
-    features: ["js"],
-    threadFilters: ["GeckoMain"]
-  },
-
-  /**
    * Returns an object indicating if mock actors are being used or not.
    */
   getMocksInUse: function () {
     return {
       memory: this._usingMockMemory,
       timeline: this._usingMockTimeline
     };
   }
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -210,16 +210,17 @@
 @RESPATH@/components/dom_css.xpt
 @RESPATH@/components/dom_devicestorage.xpt
 @RESPATH@/components/dom_events.xpt
 @RESPATH@/components/dom_geolocation.xpt
 @RESPATH@/components/dom_media.xpt
 @RESPATH@/components/dom_network.xpt
 @RESPATH@/components/dom_notification.xpt
 @RESPATH@/components/dom_html.xpt
+@RESPATH@/components/dom_icc.xpt
 @RESPATH@/components/dom_offline.xpt
 @RESPATH@/components/dom_json.xpt
 @RESPATH@/components/dom_power.xpt
 @RESPATH@/components/dom_quota.xpt
 @RESPATH@/components/dom_range.xpt
 @RESPATH@/components/dom_security.xpt
 @RESPATH@/components/dom_settings.xpt
 @RESPATH@/components/dom_permissionsettings.xpt
--- a/docshell/base/TimelineMarker.h
+++ b/docshell/base/TimelineMarker.h
@@ -28,19 +28,19 @@ public:
                  TracingMetadata aMetaData,
                  const nsAString& aCause);
 
   virtual ~TimelineMarker();
 
   // Check whether two markers should be considered the same,
   // for the purpose of pairing start and end markers.  Normally
   // this definition suffices.
-  virtual bool Equals(const TimelineMarker* aOther)
+  virtual bool Equals(const TimelineMarker& aOther)
   {
-    return strcmp(mName, aOther->mName) == 0;
+    return strcmp(mName, aOther.mName) == 0;
   }
 
   // Add details specific to this marker type to aMarker.  The
   // standard elements have already been set.  This method is
   // called on both the starting and ending markers of a pair.
   // Ordinarily the ending marker doesn't need to do anything
   // here.
   virtual void AddDetails(mozilla::dom::ProfileTimelineMarker& aMarker) {}
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -2972,20 +2972,20 @@ nsDocShell::PopProfileTimelineMarkers(
 
   nsTArray<mozilla::dom::ProfileTimelineMarker> profileTimelineMarkers;
   SequenceRooter<mozilla::dom::ProfileTimelineMarker> rooter(
     aCx, &profileTimelineMarkers);
 
   // If we see an unpaired START, we keep it around for the next call
   // to PopProfileTimelineMarkers.  We store the kept START objects in
   // this array.
-  nsTArray<TimelineMarker*> keptMarkers;
+  nsTArray<UniquePtr<TimelineMarker>> keptMarkers;
 
   for (uint32_t i = 0; i < mProfileTimelineMarkers.Length(); ++i) {
-    TimelineMarker* startPayload = mProfileTimelineMarkers[i];
+    UniquePtr<TimelineMarker>& startPayload = mProfileTimelineMarkers[i];
     const char* startMarkerName = startPayload->GetName();
 
     bool hasSeenPaintedLayer = false;
     bool isPaint = strcmp(startMarkerName, "Paint") == 0;
 
     // If we are processing a Paint marker, we append information from
     // all the embedded Layer markers to this array.
     dom::Sequence<dom::ProfileTimelineLayerRect> layerRectangles;
@@ -2997,26 +2997,26 @@ nsDocShell::PopProfileTimelineMarkers(
       // for the matching end.  It doesn't hurt to apply this logic to
       // all event types.
       uint32_t markerDepth = 0;
 
       // The assumption is that the devtools timeline flushes markers frequently
       // enough for the amount of markers to always be small enough that the
       // nested for loop isn't going to be a performance problem.
       for (uint32_t j = i + 1; j < mProfileTimelineMarkers.Length(); ++j) {
-        TimelineMarker* endPayload = mProfileTimelineMarkers[j];
+        UniquePtr<TimelineMarker>& endPayload = mProfileTimelineMarkers[j];
         const char* endMarkerName = endPayload->GetName();
 
         // Look for Layer markers to stream out paint markers.
         if (isPaint && strcmp(endMarkerName, "Layer") == 0) {
           hasSeenPaintedLayer = true;
           endPayload->AddLayerRectangles(layerRectangles);
         }
 
-        if (!startPayload->Equals(endPayload)) {
+        if (!startPayload->Equals(*endPayload)) {
           continue;
         }
 
         // Pair start and end markers.
         if (endPayload->GetMetaData() == TRACING_INTERVAL_START) {
           ++markerDepth;
         } else if (endPayload->GetMetaData() == TRACING_INTERVAL_END) {
           if (markerDepth > 0) {
@@ -3043,24 +3043,23 @@ nsDocShell::PopProfileTimelineMarkers(
 
             break;
           }
         }
       }
 
       // If we did not see the corresponding END, keep the START.
       if (!hasSeenEnd) {
-        keptMarkers.AppendElement(mProfileTimelineMarkers[i]);
+        keptMarkers.AppendElement(Move(mProfileTimelineMarkers[i]));
         mProfileTimelineMarkers.RemoveElementAt(i);
         --i;
       }
     }
   }
 
-  ClearProfileTimelineMarkers();
   mProfileTimelineMarkers.SwapElements(keptMarkers);
 
   if (!ToJSValue(aCx, profileTimelineMarkers, aProfileTimelineMarkers)) {
     JS_ClearPendingException(aCx);
     return NS_ERROR_UNEXPECTED;
   }
 
   return NS_OK;
@@ -3081,20 +3080,20 @@ nsDocShell::AddProfileTimelineMarker(con
 {
   if (mProfileTimelineRecording) {
     TimelineMarker* marker = new TimelineMarker(this, aName, aMetaData);
     mProfileTimelineMarkers.AppendElement(marker);
   }
 }
 
 void
-nsDocShell::AddProfileTimelineMarker(UniquePtr<TimelineMarker>& aMarker)
+nsDocShell::AddProfileTimelineMarker(UniquePtr<TimelineMarker>&& aMarker)
 {
   if (mProfileTimelineRecording) {
-    mProfileTimelineMarkers.AppendElement(aMarker.release());
+    mProfileTimelineMarkers.AppendElement(Move(aMarker));
   }
 }
 
 NS_IMETHODIMP
 nsDocShell::SetWindowDraggingAllowed(bool aValue)
 {
   nsRefPtr<nsDocShell> parent = GetParentDocshell();
   if (!aValue && mItemType == typeChrome && !parent) {
@@ -3120,19 +3119,16 @@ nsDocShell::GetWindowDraggingAllowed(boo
     *aValue = mWindowDraggingAllowed;
   }
   return NS_OK;
 }
 
 void
 nsDocShell::ClearProfileTimelineMarkers()
 {
-  for (uint32_t i = 0; i < mProfileTimelineMarkers.Length(); ++i) {
-    delete mProfileTimelineMarkers[i];
-  }
   mProfileTimelineMarkers.Clear();
 }
 
 nsIDOMStorageManager*
 nsDocShell::TopSessionStorageManager()
 {
   nsresult rv;
 
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -267,17 +267,17 @@ public:
   // is no longer applied
   void NotifyAsyncPanZoomStopped();
 
   // Add new profile timeline markers to this docShell. This will only add
   // markers if the docShell is currently recording profile timeline markers.
   // See nsIDocShell::recordProfileTimelineMarkers
   void AddProfileTimelineMarker(const char* aName,
                                 TracingMetadata aMetaData);
-  void AddProfileTimelineMarker(mozilla::UniquePtr<TimelineMarker>& aMarker);
+  void AddProfileTimelineMarker(mozilla::UniquePtr<TimelineMarker>&& aMarker);
 
   // Global counter for how many docShells are currently recording profile
   // timeline markers
   static unsigned long gProfileTimelineRecordingsCount;
 
 protected:
   // Object Management
   virtual ~nsDocShell();
@@ -979,17 +979,17 @@ private:
 
   // A depth count of how many times NotifyRunToCompletionStart
   // has been called without a matching NotifyRunToCompletionStop.
   uint32_t mJSRunToCompletionDepth;
 
   // True if recording profiles.
   bool mProfileTimelineRecording;
 
-  nsTArray<TimelineMarker*> mProfileTimelineMarkers;
+  nsTArray<mozilla::UniquePtr<TimelineMarker>> mProfileTimelineMarkers;
 
   // Get rid of all the timeline markers accumulated so far
   void ClearProfileTimelineMarkers();
 
   // Separate function to do the actual name (i.e. not _top, _self etc.)
   // searching for FindItemWithName.
   nsresult DoFindItemWithName(const char16_t* aName,
                               nsISupports* aRequestor,
--- a/dom/apps/OperatorApps.jsm
+++ b/dom/apps/OperatorApps.jsm
@@ -16,19 +16,19 @@ Cu.import("resource://gre/modules/Webapp
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 
 let Path = OS.Path;
 
 #ifdef MOZ_B2G_RIL
-XPCOMUtils.defineLazyServiceGetter(this, "iccProvider",
-                                   "@mozilla.org/ril/content-helper;1",
-                                   "nsIIccProvider");
+XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
+                                   "@mozilla.org/icc/iccservice;1",
+                                   "nsIIccService");
 #endif
 
 function debug(aMsg) {
   //dump("-*-*- OperatorApps.jsm : " + aMsg + "\n");
 }
 
 // Single Variant source dir will be set in PREF_SINGLE_VARIANT_DIR
 // preference.
@@ -64,27 +64,28 @@ let iccListener = {
   notifyStkCommand: function() {},
 
   notifyStkSessionEnd: function() {},
 
   notifyCardStateChanged: function() {},
 
   notifyIccInfoChanged: function() {
     // TODO: Bug 927709 - OperatorApps for multi-sim
-    // In Multi-sim, there is more than one client in iccProvider. Each
-    // client represents a icc service. To maintain the backward compatibility
+    // In Multi-sim, there is more than one client in IccService. Each
+    // client represents a icc handle. To maintain the backward compatibility
     // with single sim, we always use client 0 for now. Adding support for
     // multiple sim will be addressed in bug 927709, if needed.
     let clientId = 0;
-    let iccInfo = iccProvider.getIccInfo(clientId);
+    let icc = gIccService.getIccByServiceId(clientId);
+    let iccInfo = icc && icc.iccInfo;
     if (iccInfo && iccInfo.mcc && iccInfo.mnc) {
       let mcc = iccInfo.mcc;
       let mnc = iccInfo.mnc;
       debug("******* iccListener cardIccInfo MCC-MNC: " + mcc + "-" + mnc);
-      iccProvider.unregisterIccMsg(clientId, this);
+      icc.unregisterListener(this);
       OperatorAppsRegistry._installOperatorApps(mcc, mnc);
 
       debug("Broadcast message first-run-with-sim");
       let messenger = Cc["@mozilla.org/system-message-internal;1"]
                         .getService(Ci.nsISystemMessagesInternal);
       messenger.broadcastMessage("first-run-with-sim", { mcc: mcc,
                                                          mnc: mnc });
     }
@@ -100,40 +101,41 @@ this.OperatorAppsRegistry = {
     debug("init");
 #ifdef MOZ_B2G_RIL
     if (isFirstRunWithSIM()) {
       debug("First Run with SIM");
       Task.spawn(function() {
         try {
           yield this._initializeSourceDir();
           // TODO: Bug 927709 - OperatorApps for multi-sim
-          // In Multi-sim, there is more than one client in iccProvider. Each
-          // client represents a icc service. To maintain the backward
+          // In Multi-sim, there is more than one client in IccService. Each
+          // client represents a icc handle. To maintain the backward
           // compatibility with single sim, we always use client 0 for now.
           // Adding support for multiple sim will be addressed in bug 927709, if
           // needed.
           let clientId = 0;
-          let iccInfo = iccProvider.getIccInfo(clientId);
+          let icc = gIccService.getIccByServiceId(clientId);
+          let iccInfo = icc && icc.iccInfo;
           let mcc = 0;
           let mnc = 0;
           if (iccInfo && iccInfo.mcc) {
             mcc = iccInfo.mcc;
           }
           if (iccInfo && iccInfo.mnc) {
             mnc = iccInfo.mnc;
           }
           if (mcc && mnc) {
             this._installOperatorApps(mcc, mnc);
             let messenger = Cc["@mozilla.org/system-message-internal;1"]
                               .getService(Ci.nsISystemMessagesInternal);
             messenger.broadcastMessage("first-run-with-sim", { mcc: mcc,
                                                                mnc: mnc });
 
           } else {
-            iccProvider.registerIccMsg(clientId, iccListener);
+            icc.registerListener(iccListener);
           }
         } catch (e) {
           debug("Error Initializing OperatorApps. " + e);
         }
       }.bind(this));
     } else {
       debug("No First Run with SIM");
     }
--- a/dom/base/Console.cpp
+++ b/dom/base/Console.cpp
@@ -929,23 +929,23 @@ public:
                         const nsAString& aCause)
     : TimelineMarker(aDocShell, "ConsoleTime", aMetaData, aCause)
   {
     if (aMetaData == TRACING_INTERVAL_END) {
       CaptureStack();
     }
   }
 
-  virtual bool Equals(const TimelineMarker* aOther) override
+  virtual bool Equals(const TimelineMarker& aOther) override
   {
     if (!TimelineMarker::Equals(aOther)) {
       return false;
     }
     // Console markers must have matching causes as well.
-    return GetCause() == aOther->GetCause();
+    return GetCause() == aOther.GetCause();
   }
 
   virtual void AddDetails(mozilla::dom::ProfileTimelineMarker& aMarker) override
   {
     if (GetMetaData() == TRACING_INTERVAL_START) {
       aMarker.mCauseName.Construct(GetCause());
     } else {
       aMarker.mEndStack = GetStack();
@@ -1052,17 +1052,17 @@ Console::Method(JSContext* aCx, MethodNa
         JS::Rooted<JSString*> jsString(aCx, JS::ToString(aCx, value));
         if (jsString) {
           nsAutoJSString key;
           if (key.init(aCx, jsString)) {
             mozilla::UniquePtr<TimelineMarker> marker =
               MakeUnique<ConsoleTimelineMarker>(docShell,
                                                 aMethodName == MethodTime ? TRACING_INTERVAL_START : TRACING_INTERVAL_END,
                                                 key);
-            docShell->AddProfileTimelineMarker(marker);
+            docShell->AddProfileTimelineMarker(Move(marker));
           }
         }
       }
 
     } else {
       WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
       MOZ_ASSERT(workerPrivate);
 
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -31,16 +31,17 @@
 #include "nsUnicharUtils.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "BatteryManager.h"
 #include "mozilla/dom/PowerManager.h"
 #include "mozilla/dom/WakeLock.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/CellBroadcast.h"
+#include "mozilla/dom/IccManager.h"
 #include "mozilla/dom/MobileMessageManager.h"
 #include "mozilla/dom/ServiceWorkerContainer.h"
 #include "mozilla/dom/Telephony.h"
 #include "mozilla/dom/Voicemail.h"
 #include "mozilla/dom/TVManager.h"
 #include "mozilla/dom/VRDevice.h"
 #include "mozilla/Hal.h"
 #include "nsISiteSpecificUserAgent.h"
@@ -48,17 +49,16 @@
 #include "mozilla/StaticPtr.h"
 #include "Connection.h"
 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
 #include "nsGlobalWindow.h"
 #ifdef MOZ_B2G
 #include "nsIMobileIdentityService.h"
 #endif
 #ifdef MOZ_B2G_RIL
-#include "mozilla/dom/IccManager.h"
 #include "mozilla/dom/MobileConnectionArray.h"
 #endif
 #include "nsIIdleObserver.h"
 #include "nsIPermissionManager.h"
 #include "nsMimeTypes.h"
 #include "nsNetUtil.h"
 #include "nsIHttpChannel.h"
 #include "nsIHttpChannelInternal.h"
@@ -172,24 +172,24 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlugins)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMimeTypes)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileMessageManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTVManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
 #ifdef MOZ_B2G_RIL
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
 #endif
 #ifdef MOZ_B2G_BT
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBluetooth)
 #endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelManager)
 #endif
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCameraManager)
@@ -245,16 +245,21 @@ Navigator::Invalidate()
     mPowerManager->Shutdown();
     mPowerManager = nullptr;
   }
 
   if (mCellBroadcast) {
     mCellBroadcast = nullptr;
   }
 
+  if (mIccManager) {
+    mIccManager->Shutdown();
+    mIccManager = nullptr;
+  }
+
   if (mMobileMessageManager) {
     mMobileMessageManager->Shutdown();
     mMobileMessageManager = nullptr;
   }
 
   if (mTelephony) {
     mTelephony = nullptr;
   }
@@ -272,21 +277,16 @@ Navigator::Invalidate()
     mConnection->Shutdown();
     mConnection = nullptr;
   }
 
 #ifdef MOZ_B2G_RIL
   if (mMobileConnections) {
     mMobileConnections = nullptr;
   }
-
-  if (mIccManager) {
-    mIccManager->Shutdown();
-    mIccManager = nullptr;
-  }
 #endif
 
 #ifdef MOZ_B2G_BT
   if (mBluetooth) {
     mBluetooth = nullptr;
   }
 #endif
 
@@ -1702,34 +1702,31 @@ Navigator::GetMozVoicemail(ErrorResult& 
     }
 
     mVoicemail = Voicemail::Create(mWindow, aRv);
   }
 
   return mVoicemail;
 }
 
-#ifdef MOZ_B2G_RIL
-
 IccManager*
 Navigator::GetMozIccManager(ErrorResult& aRv)
 {
   if (!mIccManager) {
     if (!mWindow) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
     NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
 
     mIccManager = new IccManager(mWindow);
   }
 
   return mIccManager;
 }
-#endif // MOZ_B2G_RIL
 
 #ifdef MOZ_GAMEPAD
 void
 Navigator::GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads,
                        ErrorResult& aRv)
 {
   if (!mWindow) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -39,20 +39,16 @@ class MediaDevices;
 struct MediaStreamConstraints;
 class WakeLock;
 class ArrayBufferViewOrBlobOrStringOrFormData;
 struct MobileIdOptions;
 class ServiceWorkerContainer;
 }
 }
 
-#ifdef MOZ_B2G_RIL
-class nsIDOMMozIccManager;
-#endif // MOZ_B2G_RIL
-
 //*****************************************************************************
 // Navigator: Script "navigator" object
 //*****************************************************************************
 
 namespace mozilla {
 namespace dom {
 
 namespace battery {
@@ -83,22 +79,22 @@ class Connection;
 
 #ifdef MOZ_B2G_BT
 namespace bluetooth {
 class BluetoothManager;
 } // namespace bluetooth
 #endif // MOZ_B2G_BT
 
 #ifdef MOZ_B2G_RIL
-class IccManager;
 class MobileConnectionArray;
 #endif
 
 class PowerManager;
 class CellBroadcast;
+class IccManager;
 class Telephony;
 class Voicemail;
 class TVManager;
 
 namespace time {
 class TimeManager;
 } // namespace time
 
@@ -219,16 +215,17 @@ public:
                                              ErrorResult& aRv);
   nsDOMDeviceStorage* GetDeviceStorage(const nsAString& aType,
                                        ErrorResult& aRv);
   void GetDeviceStorages(const nsAString& aType,
                          nsTArray<nsRefPtr<nsDOMDeviceStorage> >& aStores,
                          ErrorResult& aRv);
   DesktopNotificationCenter* GetMozNotification(ErrorResult& aRv);
   CellBroadcast* GetMozCellBroadcast(ErrorResult& aRv);
+  IccManager* GetMozIccManager(ErrorResult& aRv);
   MobileMessageManager* GetMozMobileMessage();
   Telephony* GetMozTelephony(ErrorResult& aRv);
   Voicemail* GetMozVoicemail(ErrorResult& aRv);
   TVManager* GetTv();
   network::Connection* GetConnection(ErrorResult& aRv);
   nsDOMCameraManager* GetMozCameras(ErrorResult& aRv);
   MediaDevices* GetMediaDevices(ErrorResult& aRv);
   void MozSetMessageHandler(const nsAString& aType,
@@ -238,17 +235,16 @@ public:
   void MozSetMessageHandlerPromise(Promise& aPromise, ErrorResult& aRv);
 
 #ifdef MOZ_B2G
   already_AddRefed<Promise> GetMobileIdAssertion(const MobileIdOptions& options,
                                                  ErrorResult& aRv);
 #endif
 #ifdef MOZ_B2G_RIL
   MobileConnectionArray* GetMozMobileConnections(ErrorResult& aRv);
-  IccManager* GetMozIccManager(ErrorResult& aRv);
 #endif // MOZ_B2G_RIL
 #ifdef MOZ_GAMEPAD
   void GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads, ErrorResult& aRv);
 #endif // MOZ_GAMEPAD
   already_AddRefed<Promise> GetVRDevices(ErrorResult& aRv);
 #ifdef MOZ_B2G_FM
   FMRadio* GetMozFMRadio(ErrorResult& aRv);
 #endif
@@ -348,24 +344,24 @@ private:
   nsRefPtr<Geolocation> mGeolocation;
   nsRefPtr<DesktopNotificationCenter> mNotification;
   nsRefPtr<battery::BatteryManager> mBatteryManager;
 #ifdef MOZ_B2G_FM
   nsRefPtr<FMRadio> mFMRadio;
 #endif
   nsRefPtr<PowerManager> mPowerManager;
   nsRefPtr<CellBroadcast> mCellBroadcast;
+  nsRefPtr<IccManager> mIccManager;
   nsRefPtr<MobileMessageManager> mMobileMessageManager;
   nsRefPtr<Telephony> mTelephony;
   nsRefPtr<Voicemail> mVoicemail;
   nsRefPtr<TVManager> mTVManager;
   nsRefPtr<network::Connection> mConnection;
 #ifdef MOZ_B2G_RIL
   nsRefPtr<MobileConnectionArray> mMobileConnections;
-  nsRefPtr<IccManager> mIccManager;
 #endif
 #ifdef MOZ_B2G_BT
   nsRefPtr<bluetooth::BluetoothManager> mBluetooth;
 #endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   nsRefPtr<system::AudioChannelManager> mAudioChannelManager;
 #endif
   nsRefPtr<nsDOMCameraManager> mCameraManager;
--- a/dom/base/ScriptSettings.cpp
+++ b/dom/base/ScriptSettings.cpp
@@ -307,17 +307,16 @@ AutoJSAPI::AutoJSAPI()
   , mOldAutoJSAPIOwnsErrorReporting(false)
 {
 }
 
 AutoJSAPI::~AutoJSAPI()
 {
   if (mOwnErrorReporting) {
     MOZ_ASSERT(NS_IsMainThread(), "See corresponding assertion in TakeOwnershipOfErrorReporting()");
-    JS::ContextOptionsRef(cx()).setAutoJSAPIOwnsErrorReporting(mOldAutoJSAPIOwnsErrorReporting);
 
     if (HasException()) {
 
       // AutoJSAPI uses a JSAutoNullableCompartment, and may be in a null
       // compartment when the destructor is called. However, the JS engine
       // requires us to be in a compartment when we fetch the pending exception.
       // In this case, we enter the privileged junk scope and don't dispatch any
       // error events.
@@ -337,16 +336,23 @@ AutoJSAPI::~AutoJSAPI()
           DispatchScriptErrorEvent(win, JS_GetRuntime(cx()), xpcReport, exn);
         } else {
           xpcReport->LogToConsole();
         }
       } else {
         NS_WARNING("OOMed while acquiring uncaught exception from JSAPI");
       }
     }
+
+    // We need to do this _after_ processing the existing exception, because the
+    // JS engine can throw while doing that, and uses this bit to determine what
+    // to do in that case: squelch the exception if the bit is set, otherwise
+    // call the error reporter. Calling WarningOnlyErrorReporter with a
+    // non-warning will assert, so we need to make sure we do the former.
+    JS::ContextOptionsRef(cx()).setAutoJSAPIOwnsErrorReporting(mOldAutoJSAPIOwnsErrorReporting);
   }
 
   if (mOldErrorReporter.isSome()) {
     JS_SetErrorReporter(JS_GetRuntime(cx()), mOldErrorReporter.value());
   }
 }
 
 void
--- a/dom/bluetooth/BluetoothRilListener.cpp
+++ b/dom/bluetooth/BluetoothRilListener.cpp
@@ -2,22 +2,21 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BluetoothRilListener.h"
 
 #include "BluetoothHfpManager.h"
-#include "nsIIccProvider.h"
+#include "nsIIccService.h"
 #include "nsIMobileConnectionInfo.h"
 #include "nsIMobileConnectionService.h"
 #include "nsITelephonyCallInfo.h"
 #include "nsITelephonyService.h"
-#include "nsRadioInterfaceLayer.h" // For NS_RILCONTENTHELPER_CONTRACTID.
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 
 USING_BLUETOOTH_NAMESPACE
 
 /**
  *  IccListener
  */
@@ -55,25 +54,29 @@ IccListener::NotifyCardStateChanged()
   return NS_OK;
 }
 
 bool
 IccListener::Listen(bool aStart)
 {
   NS_ENSURE_TRUE(mOwner, false);
 
-  nsCOMPtr<nsIIccProvider> provider =
-    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
-  NS_ENSURE_TRUE(provider, false);
+  nsCOMPtr<nsIIccService> service =
+    do_GetService(ICC_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(service, false);
+
+  nsCOMPtr<nsIIcc> icc;
+  service->GetIccByServiceId(mOwner->mClientId, getter_AddRefs(icc));
+  NS_ENSURE_TRUE(icc, false);
 
   nsresult rv;
   if (aStart) {
-    rv = provider->RegisterIccMsg(mOwner->mClientId, this);
+    rv = icc->RegisterListener(this);
   } else {
-    rv = provider->UnregisterIccMsg(mOwner->mClientId, this);
+    rv = icc->UnregisterListener(this);
   }
 
   return NS_SUCCEEDED(rv);
 }
 
 void
 IccListener::SetOwner(BluetoothRilListener *aOwner)
 {
--- a/dom/bluetooth/BluetoothRilListener.h
+++ b/dom/bluetooth/BluetoothRilListener.h
@@ -6,17 +6,17 @@
 
 #ifndef mozilla_dom_bluetooth_bluetoothrillistener_h__
 #define mozilla_dom_bluetooth_bluetoothrillistener_h__
 
 #include "BluetoothCommon.h"
 
 #include "nsAutoPtr.h"
 
-#include "nsIIccProvider.h"
+#include "nsIIccService.h"
 #include "nsIMobileConnectionService.h"
 #include "nsITelephonyCallInfo.h"
 #include "nsITelephonyService.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothRilListener;
 
--- a/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
@@ -21,16 +21,18 @@
 
 using namespace mozilla;
 USING_BLUETOOTH_NAMESPACE
 // AVRC_ID op code follows bluedroid avrc_defs.h
 #define AVRC_ID_REWIND  0x48
 #define AVRC_ID_FAST_FOR 0x49
 #define AVRC_KEY_PRESS_STATE  1
 #define AVRC_KEY_RELEASE_STATE  0
+// bluedroid bt_rc.h
+#define AVRC_MAX_ATTR_STR_LEN 255
 
 namespace {
   StaticRefPtr<BluetoothA2dpManager> sBluetoothA2dpManager;
   bool sInShutdown = false;
   static BluetoothA2dpInterface* sBtA2dpInterface;
   static BluetoothAvrcpInterface* sBtAvrcpInterface;
 } // anonymous namespace
 
@@ -42,22 +44,37 @@ ConvertAttributeString(BluetoothAvrcpMed
                        nsAString& aAttrStr)
 {
   BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
   NS_ENSURE_TRUE_VOID(a2dp);
 
   switch (aAttrId) {
     case AVRCP_MEDIA_ATTRIBUTE_TITLE:
       a2dp->GetTitle(aAttrStr);
+      /*
+       * bluedroid can only send string length AVRC_MAX_ATTR_STR_LEN - 1
+       */
+      if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
+        aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
+        BT_WARNING("Truncate media item attribute title, length is over 255");
+      }
       break;
     case AVRCP_MEDIA_ATTRIBUTE_ARTIST:
       a2dp->GetArtist(aAttrStr);
+      if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
+        aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
+        BT_WARNING("Truncate media item attribute artist, length is over 255");
+      }
       break;
     case AVRCP_MEDIA_ATTRIBUTE_ALBUM:
       a2dp->GetAlbum(aAttrStr);
+      if (aAttrStr.Length() >= AVRC_MAX_ATTR_STR_LEN) {
+        aAttrStr.Truncate(AVRC_MAX_ATTR_STR_LEN - 1);
+        BT_WARNING("Truncate media item attribute album, length is over 255");
+      }
       break;
     case AVRCP_MEDIA_ATTRIBUTE_TRACK_NUM:
       aAttrStr.AppendInt(a2dp->GetMediaNumber());
       break;
     case AVRCP_MEDIA_ATTRIBUTE_NUM_TRACKS:
       aAttrStr.AppendInt(a2dp->GetTotalMediaNumber());
       break;
     case AVRCP_MEDIA_ATTRIBUTE_GENRE:
--- a/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp
@@ -12,24 +12,23 @@
 
 #include "jsapi.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsContentUtils.h"
 #include "nsIAudioManager.h"
 #include "nsIIccInfo.h"
-#include "nsIIccProvider.h"
+#include "nsIIccService.h"
 #include "nsIMobileConnectionInfo.h"
 #include "nsIMobileConnectionService.h"
 #include "nsIMobileNetworkInfo.h"
 #include "nsIObserverService.h"
 #include "nsISettingsService.h"
 #include "nsITelephonyService.h"
-#include "nsRadioInterfaceLayer.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #define MOZSETTINGS_CHANGED_ID               "mozsettings-changed"
 #define AUDIO_VOLUME_BT_SCO_ID               "audio.volume.bt_sco"
 
@@ -721,22 +720,26 @@ BluetoothHfpManager::HandleVoiceConnecti
     BT_WARNING("The operator name was longer than 16 characters. We cut it.");
     mOperatorName.Left(mOperatorName, 16);
   }
 }
 
 void
 BluetoothHfpManager::HandleIccInfoChanged(uint32_t aClientId)
 {
-  nsCOMPtr<nsIIccProvider> icc =
-    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
+  nsCOMPtr<nsIIccService> service =
+    do_GetService(ICC_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE_VOID(service);
+
+  nsCOMPtr<nsIIcc> icc;
+  service->GetIccByServiceId(aClientId, getter_AddRefs(icc));
   NS_ENSURE_TRUE_VOID(icc);
 
   nsCOMPtr<nsIIccInfo> iccInfo;
-  icc->GetIccInfo(aClientId, getter_AddRefs(iccInfo));
+  icc->GetIccInfo(getter_AddRefs(iccInfo));
   NS_ENSURE_TRUE_VOID(iccInfo);
 
   nsCOMPtr<nsIGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
   NS_ENSURE_TRUE_VOID(gsmIccInfo);
   gsmIccInfo->GetMsisdn(mMsisdn);
 }
 
 void
--- a/dom/bluetooth/bluez/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/bluez/BluetoothHfpManager.cpp
@@ -23,22 +23,21 @@
 #include "nsIObserverService.h"
 #include "nsISettingsService.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #ifdef MOZ_B2G_RIL
 #include "nsIIccInfo.h"
-#include "nsIIccProvider.h"
+#include "nsIIccService.h"
 #include "nsIMobileConnectionInfo.h"
 #include "nsIMobileConnectionService.h"
 #include "nsIMobileNetworkInfo.h"
 #include "nsITelephonyService.h"
-#include "nsRadioInterfaceLayer.h"
 #endif
 
 /**
  * BRSF bitmask of AG supported features. See 4.34.1 "Bluetooth Defined AT
  * Capabilities" in Bluetooth hands-free profile 1.6
  */
 #define BRSF_BIT_THREE_WAY_CALLING         1
 #define BSRF_BIT_EC_NR_FUNCTION            (1 << 1)
@@ -659,22 +658,26 @@ BluetoothHfpManager::HandleVoiceConnecti
     BT_WARNING("The operator name was longer than 16 characters. We cut it.");
     mOperatorName.Left(mOperatorName, 16);
   }
 }
 
 void
 BluetoothHfpManager::HandleIccInfoChanged(uint32_t aClientId)
 {
-  nsCOMPtr<nsIIccProvider> icc =
-    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
+  nsCOMPtr<nsIIccService> service =
+    do_GetService(ICC_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE_VOID(service);
+
+  nsCOMPtr<nsIIcc> icc;
+  service->GetIccByServiceId(aClientId, getter_AddRefs(icc));
   NS_ENSURE_TRUE_VOID(icc);
 
   nsCOMPtr<nsIIccInfo> iccInfo;
-  icc->GetIccInfo(aClientId, getter_AddRefs(iccInfo));
+  icc->GetIccInfo(getter_AddRefs(iccInfo));
   NS_ENSURE_TRUE_VOID(iccInfo);
 
   nsCOMPtr<nsIGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
   NS_ENSURE_TRUE_VOID(gsmIccInfo);
   gsmIccInfo->GetMsisdn(mMsisdn);
 }
 #endif // MOZ_B2G_RIL
 
--- a/dom/bluetooth2/BluetoothRilListener.cpp
+++ b/dom/bluetooth2/BluetoothRilListener.cpp
@@ -2,21 +2,20 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BluetoothRilListener.h"
 
 #include "BluetoothHfpManager.h"
-#include "nsIIccProvider.h"
+#include "nsIIccService.h"
 #include "nsIMobileConnectionInfo.h"
 #include "nsIMobileConnectionService.h"
 #include "nsITelephonyService.h"
-#include "nsRadioInterfaceLayer.h" // For NS_RILCONTENTHELPER_CONTRACTID.
 #include "nsServiceManagerUtils.h"
 #include "nsString.h"
 
 USING_BLUETOOTH_NAMESPACE
 
 /**
  *  IccListener
  */
@@ -54,25 +53,29 @@ IccListener::NotifyCardStateChanged()
   return NS_OK;
 }
 
 bool
 IccListener::Listen(bool aStart)
 {
   NS_ENSURE_TRUE(mOwner, false);
 
-  nsCOMPtr<nsIIccProvider> provider =
-    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
-  NS_ENSURE_TRUE(provider, false);
+  nsCOMPtr<nsIIccService> service =
+    do_GetService(ICC_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(service, false);
+
+  nsCOMPtr<nsIIcc> icc;
+  service->GetIccByServiceId(mOwner->mClientId, getter_AddRefs(icc));
+  NS_ENSURE_TRUE(icc, false);
 
   nsresult rv;
   if (aStart) {
-    rv = provider->RegisterIccMsg(mOwner->mClientId, this);
+    rv = icc->RegisterListener(this);
   } else {
-    rv = provider->UnregisterIccMsg(mOwner->mClientId, this);
+    rv = icc->UnregisterListener(this);
   }
 
   return NS_SUCCEEDED(rv);
 }
 
 void
 IccListener::SetOwner(BluetoothRilListener *aOwner)
 {
--- a/dom/bluetooth2/BluetoothRilListener.h
+++ b/dom/bluetooth2/BluetoothRilListener.h
@@ -6,17 +6,17 @@
 
 #ifndef mozilla_dom_bluetooth_bluetoothrillistener_h__
 #define mozilla_dom_bluetooth_bluetoothrillistener_h__
 
 #include "BluetoothCommon.h"
 
 #include "nsAutoPtr.h"
 
-#include "nsIIccProvider.h"
+#include "nsIIccService.h"
 #include "nsIMobileConnectionService.h"
 #include "nsITelephonyCallInfo.h"
 #include "nsITelephonyService.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothRilListener;
 
--- a/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp
+++ b/dom/bluetooth2/bluedroid/hfp/BluetoothHfpManager.cpp
@@ -12,24 +12,23 @@
 
 #include "jsapi.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "nsContentUtils.h"
 #include "nsIAudioManager.h"
 #include "nsIIccInfo.h"
-#include "nsIIccProvider.h"
+#include "nsIIccService.h"
 #include "nsIMobileConnectionInfo.h"
 #include "nsIMobileConnectionService.h"
 #include "nsIMobileNetworkInfo.h"
 #include "nsIObserverService.h"
 #include "nsISettingsService.h"
 #include "nsITelephonyService.h"
-#include "nsRadioInterfaceLayer.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #define MOZSETTINGS_CHANGED_ID               "mozsettings-changed"
 #define AUDIO_VOLUME_BT_SCO_ID               "audio.volume.bt_sco"
 
@@ -705,22 +704,26 @@ BluetoothHfpManager::HandleVoiceConnecti
     BT_WARNING("The operator name was longer than 16 characters. We cut it.");
     mOperatorName.Left(mOperatorName, 16);
   }
 }
 
 void
 BluetoothHfpManager::HandleIccInfoChanged(uint32_t aClientId)
 {
-  nsCOMPtr<nsIIccProvider> icc =
-    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
+  nsCOMPtr<nsIIccService> service =
+    do_GetService(ICC_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE_VOID(service);
+
+  nsCOMPtr<nsIIcc> icc;
+  service->GetIccByServiceId(aClientId, getter_AddRefs(icc));
   NS_ENSURE_TRUE_VOID(icc);
 
   nsCOMPtr<nsIIccInfo> iccInfo;
-  icc->GetIccInfo(aClientId, getter_AddRefs(iccInfo));
+  icc->GetIccInfo(getter_AddRefs(iccInfo));
   NS_ENSURE_TRUE_VOID(iccInfo);
 
   nsCOMPtr<nsIGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
   NS_ENSURE_TRUE_VOID(gsmIccInfo);
   gsmIccInfo->GetMsisdn(mMsisdn);
 }
 
 void
--- a/dom/bluetooth2/bluez/BluetoothHfpManager.cpp
+++ b/dom/bluetooth2/bluez/BluetoothHfpManager.cpp
@@ -23,22 +23,21 @@
 #include "nsIObserverService.h"
 #include "nsISettingsService.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/SettingChangeNotificationBinding.h"
 
 #ifdef MOZ_B2G_RIL
 #include "nsIIccInfo.h"
-#include "nsIIccProvider.h"
+#include "nsIIccService.h"
 #include "nsIMobileConnectionInfo.h"
 #include "nsIMobileConnectionService.h"
 #include "nsIMobileNetworkInfo.h"
 #include "nsITelephonyService.h"
-#include "nsRadioInterfaceLayer.h"
 #endif
 
 /**
  * BRSF bitmask of AG supported features. See 4.34.1 "Bluetooth Defined AT
  * Capabilities" in Bluetooth hands-free profile 1.6
  */
 #define BRSF_BIT_THREE_WAY_CALLING         1
 #define BSRF_BIT_EC_NR_FUNCTION            (1 << 1)
@@ -659,22 +658,26 @@ BluetoothHfpManager::HandleVoiceConnecti
     BT_WARNING("The operator name was longer than 16 characters. We cut it.");
     mOperatorName.Left(mOperatorName, 16);
   }
 }
 
 void
 BluetoothHfpManager::HandleIccInfoChanged(uint32_t aClientId)
 {
-  nsCOMPtr<nsIIccProvider> icc =
-    do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
+  nsCOMPtr<nsIIccService> service =
+    do_GetService(ICC_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE_VOID(service);
+
+  nsCOMPtr<nsIIcc> icc;
+  service->GetIccByServiceId(aClientId, getter_AddRefs(icc));
   NS_ENSURE_TRUE_VOID(icc);
 
   nsCOMPtr<nsIIccInfo> iccInfo;
-  icc->GetIccInfo(aClientId, getter_AddRefs(iccInfo));
+  icc->GetIccInfo(getter_AddRefs(iccInfo));
   NS_ENSURE_TRUE_VOID(iccInfo);
 
   nsCOMPtr<nsIGsmIccInfo> gsmIccInfo = do_QueryInterface(iccInfo);
   NS_ENSURE_TRUE_VOID(gsmIccInfo);
   gsmIccInfo->GetMsisdn(mMsisdn);
 }
 #endif // MOZ_B2G_RIL
 
--- a/dom/events/EventListenerManager.cpp
+++ b/dom/events/EventListenerManager.cpp
@@ -1089,17 +1089,17 @@ EventListenerManager::HandleEventInterna
               nsDocShell* ds = static_cast<nsDocShell*>(docShell.get());
               nsAutoString typeStr;
               (*aDOMEvent)->GetType(typeStr);
               uint16_t phase;
               (*aDOMEvent)->GetEventPhase(&phase);
               mozilla::UniquePtr<TimelineMarker> marker =
                 MakeUnique<EventTimelineMarker>(ds, TRACING_INTERVAL_START,
                                                 phase, typeStr);
-              ds->AddProfileTimelineMarker(marker);
+              ds->AddProfileTimelineMarker(Move(marker));
             }
           }
 
           if (NS_FAILED(HandleEventSubType(listener, *aDOMEvent,
                                            aCurrentTarget))) {
             aEvent->mFlags.mExceptionHasBeenRisen = true;
           }
 
--- a/dom/icc/Assertions.cpp
+++ b/dom/icc/Assertions.cpp
@@ -1,22 +1,22 @@
 /* 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/MozIccBinding.h"
-#include "nsIIccProvider.h"
+#include "nsIIccService.h"
 
 namespace mozilla {
 namespace dom {
 namespace icc {
 
 #define ASSERT_EQUALITY(webidlType, webidlState, xpidlState) \
-  static_assert(static_cast<uint32_t>(webidlType::webidlState) == nsIIccProvider::xpidlState, \
-  #webidlType "::" #webidlState " should equal to nsIIccProvider::" #xpidlState)
+  static_assert(static_cast<uint32_t>(webidlType::webidlState) == nsIIcc::xpidlState, \
+  #webidlType "::" #webidlState " should equal to nsIIccService::" #xpidlState)
 
 /**
  * Enum IccCardState
  */
 #define ASSERT_ICC_CARD_STATE_EQUALITY(webidlState, xpidlState) \
   ASSERT_EQUALITY(IccCardState, webidlState, xpidlState)
 
 ASSERT_ICC_CARD_STATE_EQUALITY(Unknown, CARD_STATE_UNKNOWN);
--- a/dom/icc/Icc.cpp
+++ b/dom/icc/Icc.cpp
@@ -1,25 +1,29 @@
 /* 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.h"
 
+#include "IccCallback.h"
 #include "mozilla/dom/DOMRequest.h"
 #include "mozilla/dom/IccInfo.h"
 #include "mozilla/dom/MozStkCommandEvent.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "nsIIccInfo.h"
 #include "nsIIccProvider.h"
+#include "nsIIccService.h"
 #include "nsJSON.h"
 #include "nsRadioInterfaceLayer.h"
 #include "nsServiceManagerUtils.h"
 
+using mozilla::dom::icc::IccCallback;
+
 namespace mozilla {
 namespace dom {
 
 namespace {
 
 bool
 IsPukCardLockType(IccLockType aLockType)
 {
@@ -45,19 +49,20 @@ IsPukCardLockType(IccLockType aLockType)
 NS_IMPL_CYCLE_COLLECTION_INHERITED(Icc, DOMEventTargetHelper, mIccInfo)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(Icc)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(Icc, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(Icc, DOMEventTargetHelper)
 
-Icc::Icc(nsPIDOMWindow* aWindow, long aClientId, nsIIccInfo* aIccInfo)
+Icc::Icc(nsPIDOMWindow* aWindow, long aClientId, nsIIcc* aHandler, nsIIccInfo* aIccInfo)
   : mLive(true)
   , mClientId(aClientId)
+  , mHandler(aHandler)
 {
   BindToOwner(aWindow);
 
   mProvider = do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
 
   if (aIccInfo) {
     aIccInfo->GetIccid(mIccId);
     UpdateIccInfo(aIccInfo);
@@ -74,16 +79,17 @@ Icc::~Icc()
 {
 }
 
 void
 Icc::Shutdown()
 {
   mIccInfo.SetNull();
   mProvider = nullptr;
+  mHandler = nullptr;
   mLive = false;
 }
 
 nsresult
 Icc::NotifyEvent(const nsAString& aName)
 {
   return DispatchTrustedEvent(aName);
 }
@@ -165,20 +171,20 @@ Icc::GetIccInfo(Nullable<OwningMozIccInf
   aIccInfo = mIccInfo;
 }
 
 Nullable<IccCardState>
 Icc::GetCardState() const
 {
   Nullable<IccCardState> result;
 
-  uint32_t cardState = nsIIccProvider::CARD_STATE_UNDETECTED;
-  if (mProvider &&
-      NS_SUCCEEDED(mProvider->GetCardState(mClientId, &cardState)) &&
-      cardState != nsIIccProvider::CARD_STATE_UNDETECTED) {
+  uint32_t cardState = nsIIcc::CARD_STATE_UNDETECTED;
+  if (mHandler &&
+      NS_SUCCEEDED(mHandler->GetCardState(&cardState)) &&
+      cardState != nsIIcc::CARD_STATE_UNDETECTED) {
     MOZ_ASSERT(cardState < static_cast<uint32_t>(IccCardState::EndGuard_));
     result.SetValue(static_cast<IccCardState>(cardState));
   }
 
   return result;
 }
 
 void
@@ -244,110 +250,117 @@ Icc::SendStkEventDownload(const JSContex
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
   }
 }
 
 already_AddRefed<DOMRequest>
 Icc::GetCardLock(IccLockType aLockType, ErrorResult& aRv)
 {
-  if (!mProvider) {
+  if (!mHandler) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
-  nsRefPtr<nsIDOMDOMRequest> request;
-  nsresult rv = mProvider->GetCardLockEnabled(mClientId, GetOwner(),
-                                              static_cast<uint32_t>(aLockType),
-                                              getter_AddRefs(request));
+  nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
+  // TODO: Bug 1125018 - Simplify The Result of GetCardLock and
+  // getCardLockRetryCount in MozIcc.webidl without a wrapper object.
+  nsRefPtr<IccCallback> requestCallback =
+    new IccCallback(GetOwner(), request, true);
+  nsresult rv = mHandler->GetCardLockEnabled(static_cast<uint32_t>(aLockType),
+                                             requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
-  return request.forget().downcast<DOMRequest>();
+  return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 Icc::UnlockCardLock(const IccUnlockCardLockOptions& aOptions, ErrorResult& aRv)
 {
-  if (!mProvider) {
+  if (!mHandler) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
-  nsRefPtr<nsIDOMDOMRequest> request;
+  nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
+  nsRefPtr<IccCallback> requestCallback =
+    new IccCallback(GetOwner(), request);
   const nsString& password = IsPukCardLockType(aOptions.mLockType)
                            ? aOptions.mPuk : aOptions.mPin;
-  nsresult rv = mProvider->UnlockCardLock(mClientId, GetOwner(),
-                                          static_cast<uint32_t>(aOptions.mLockType),
-                                          password, aOptions.mNewPin,
-                                          getter_AddRefs(request));
+  nsresult rv =
+    mHandler->UnlockCardLock(static_cast<uint32_t>(aOptions.mLockType),
+                             password, aOptions.mNewPin, requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
-  return request.forget().downcast<DOMRequest>();
+  return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 Icc::SetCardLock(const IccSetCardLockOptions& aOptions, ErrorResult& aRv)
 {
-  if (!mProvider) {
+  if (!mHandler) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
   nsresult rv;
-  nsRefPtr<nsIDOMDOMRequest> request;
+  nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
+  nsRefPtr<IccCallback> requestCallback =
+    new IccCallback(GetOwner(), request);
 
   if (aOptions.mEnabled.WasPassed()) {
     // Enable card lock.
     const nsString& password = (aOptions.mLockType == IccLockType::Fdn) ?
                                aOptions.mPin2 : aOptions.mPin;
 
-    rv = mProvider->SetCardLockEnabled(mClientId, GetOwner(),
-                                       static_cast<uint32_t>(aOptions.mLockType),
-                                       password, aOptions.mEnabled.Value(),
-                                       getter_AddRefs(request));
+    rv =
+      mHandler->SetCardLockEnabled(static_cast<uint32_t>(aOptions.mLockType),
+                                   password, aOptions.mEnabled.Value(),
+                                   requestCallback);
   } else {
     // Change card lock password.
-    rv = mProvider->ChangeCardLockPassword(mClientId, GetOwner(),
-                                           static_cast<uint32_t>(aOptions.mLockType),
-                                           aOptions.mPin, aOptions.mNewPin,
-                                           getter_AddRefs(request));
+    rv =
+      mHandler->ChangeCardLockPassword(static_cast<uint32_t>(aOptions.mLockType),
+                                       aOptions.mPin, aOptions.mNewPin,
+                                       requestCallback);
   }
 
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
-  return request.forget().downcast<DOMRequest>();
+  return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 Icc::GetCardLockRetryCount(IccLockType aLockType, ErrorResult& aRv)
 {
-  if (!mProvider) {
+  if (!mHandler) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
-  nsRefPtr<nsIDOMDOMRequest> request;
-  nsresult rv = mProvider->GetCardLockRetryCount(mClientId, GetOwner(),
-                                                 static_cast<uint32_t>(aLockType),
-                                                 getter_AddRefs(request));
+  nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
+  nsRefPtr<IccCallback> requestCallback =
+    new IccCallback(GetOwner(), request);
+  nsresult rv = mHandler->GetCardLockRetryCount(static_cast<uint32_t>(aLockType),
+                                                requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
-  return request.forget().downcast<DOMRequest>();
+  return request.forget();
 }
 
 already_AddRefed<DOMRequest>
 Icc::ReadContacts(IccContactType aContactType, ErrorResult& aRv)
 {
   if (!mProvider) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
@@ -387,48 +400,61 @@ Icc::UpdateContact(const JSContext* aCx,
 
   return request.forget().downcast<DOMRequest>();
 }
 
 already_AddRefed<DOMRequest>
 Icc::MatchMvno(IccMvnoType aMvnoType, const nsAString& aMvnoData,
                ErrorResult& aRv)
 {
-  if (!mProvider) {
+  if (!mHandler) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
-  nsRefPtr<nsIDOMDOMRequest> request;
-  nsresult rv = mProvider->MatchMvno(mClientId, GetOwner(),
-                                     static_cast<uint32_t>(aMvnoType),
-                                     aMvnoData, getter_AddRefs(request));
+  nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner());
+  nsRefPtr<IccCallback> requestCallback =
+    new IccCallback(GetOwner(), request);
+  nsresult rv = mHandler->MatchMvno(static_cast<uint32_t>(aMvnoType),
+                                    aMvnoData, requestCallback);
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
-  return request.forget().downcast<DOMRequest>();
+  return request.forget();
 }
 
 already_AddRefed<Promise>
 Icc::GetServiceState(IccService aService, ErrorResult& aRv)
 {
-  if (!mProvider) {
+  if (!mHandler) {
     aRv.Throw(NS_ERROR_FAILURE);
     return nullptr;
   }
 
-  nsCOMPtr<nsISupports> supports;
-  nsresult rv = mProvider->GetServiceState(mClientId, GetOwner(),
-                                           static_cast<uint32_t>(aService),
-                                           getter_AddRefs(supports));
-  if (NS_FAILED(rv)) {
-    aRv.Throw(rv);
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
+  if (!global) {
+    return nullptr;
+  }
+
+  nsRefPtr<Promise> promise = Promise::Create(global, aRv);
+  if (aRv.Failed()) {
     return nullptr;
   }
 
-  nsCOMPtr<Promise> promise = do_QueryInterface(supports);
+  nsRefPtr<IccCallback> requestCallback =
+    new IccCallback(GetOwner(), promise);
+
+  nsresult rv =
+    mHandler->GetServiceStateEnabled(static_cast<uint32_t>(aService),
+                                     requestCallback);
+
+  if (NS_FAILED(rv)) {
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
+    // fall-through to return promise.
+  }
+
   return promise.forget();
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/icc/Icc.h
+++ b/dom/icc/Icc.h
@@ -3,16 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_Icc_h
 #define mozilla_dom_Icc_h
 
 #include "mozilla/dom/MozIccBinding.h"
 #include "mozilla/DOMEventTargetHelper.h"
 
+class nsIIcc;
 class nsIIccInfo;
 class nsIIccProvider;
 
 namespace mozilla {
 namespace dom {
 
 class DOMRequest;
 class OwningMozIccInfoOrMozGsmIccInfoOrMozCdmaIccInfo;
@@ -20,17 +21,18 @@ class Promise;
 
 class Icc final : public DOMEventTargetHelper
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Icc, DOMEventTargetHelper)
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
 
-  Icc(nsPIDOMWindow* aWindow, long aClientId, nsIIccInfo* aIccInfo);
+  Icc(nsPIDOMWindow* aWindow, long aClientId,
+      nsIIcc* aHandler, nsIIccInfo* aIccInfo);
 
   void
   Shutdown();
 
   nsresult
   NotifyEvent(const nsAString& aName);
 
   nsresult
@@ -106,23 +108,29 @@ public:
   GetServiceState(IccService aService, ErrorResult& aRv);
 
   IMPL_EVENT_HANDLER(iccinfochange)
   IMPL_EVENT_HANDLER(cardstatechange)
   IMPL_EVENT_HANDLER(stkcommand)
   IMPL_EVENT_HANDLER(stksessionend)
 
 private:
+  // Put definition of the destructor in Icc.cpp to ensure forward declaration
+  // of nsIIccProvider, nsIIcc for the auto-generated .cpp file (i.e.,
+  // MozIccManagerBinding.cpp) that includes this header.
   ~Icc();
 
   bool mLive;
   uint32_t mClientId;
   nsString mIccId;
-  // mProvider is a xpcom service and will be released at shutdown, so it
+  // mProvider is a xpcom service and will be released at Shutdown(), so it
   // doesn't need to be cycle collected.
   nsCOMPtr<nsIIccProvider> mProvider;
+  // mHandler will be released at Shutdown(), so there is no need to join cycle
+  // collection.
+  nsCOMPtr<nsIIcc> mHandler;
   Nullable<OwningMozIccInfoOrMozGsmIccInfoOrMozCdmaIccInfo> mIccInfo;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_icc_Icc_h
new file mode 100644
--- /dev/null
+++ b/dom/icc/IccCallback.cpp
@@ -0,0 +1,135 @@
+/* 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 "IccCallback.h"
+
+#include "mozilla/dom/IccCardLockError.h"
+#include "mozilla/dom/MozIccBinding.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/dom/ToJSValue.h"
+#include "nsJSUtils.h"
+#include "nsServiceManagerUtils.h"
+
+namespace mozilla {
+namespace dom {
+namespace icc {
+
+NS_IMPL_ISUPPORTS(IccCallback, nsIIccCallback)
+
+IccCallback::IccCallback(nsPIDOMWindow* aWindow, DOMRequest* aRequest,
+                         bool aIsCardLockEnabled)
+  : mWindow(aWindow)
+  , mRequest(aRequest)
+  , mIsCardLockEnabled(aIsCardLockEnabled)
+{
+}
+
+IccCallback::IccCallback(nsPIDOMWindow* aWindow, Promise* aPromise)
+  : mWindow(aWindow)
+  , mPromise(aPromise)
+{
+}
+
+nsresult
+IccCallback::NotifySuccess(JS::Handle<JS::Value> aResult)
+{
+  nsCOMPtr<nsIDOMRequestService> rs =
+    do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
+
+  return rs->FireSuccessAsync(mRequest, aResult);
+}
+
+nsresult
+IccCallback::NotifyGetCardLockEnabled(bool aResult)
+{
+  IccCardLockStatus result;
+  result.mEnabled.Construct(aResult);
+
+  AutoJSAPI jsapi;
+  if (NS_WARN_IF(!jsapi.Init(mWindow))) {
+    return NS_ERROR_FAILURE;
+  }
+
+  JSContext* cx = jsapi.cx();
+  JS::Rooted<JS::Value> jsResult(cx);
+  if (!ToJSValue(cx, result, &jsResult)) {
+    JS_ClearPendingException(cx);
+    return NS_ERROR_TYPE_ERR;
+  }
+
+  return NotifySuccess(jsResult);
+}
+
+NS_IMETHODIMP
+IccCallback::NotifySuccess()
+{
+  return NotifySuccess(JS::UndefinedHandleValue);
+}
+
+NS_IMETHODIMP
+IccCallback::NotifySuccessWithBoolean(bool aResult)
+{
+  if (mPromise) {
+    mPromise->MaybeResolve(aResult ? JS::TrueHandleValue : JS::FalseHandleValue);
+    return NS_OK;
+  }
+
+  return mIsCardLockEnabled
+    ? NotifyGetCardLockEnabled(aResult)
+    : NotifySuccess(aResult ? JS::TrueHandleValue : JS::FalseHandleValue);
+}
+
+NS_IMETHODIMP
+IccCallback::NotifyGetCardLockRetryCount(int32_t aCount)
+{
+  // TODO: Bug 1125018 - Simplify The Result of GetCardLock and
+  // getCardLockRetryCount in MozIcc.webidl without a wrapper object.
+  IccCardLockRetryCount result;
+  result.mRetryCount.Construct(aCount);
+
+  AutoJSAPI jsapi;
+  if (NS_WARN_IF(!jsapi.Init(mWindow))) {
+    return NS_ERROR_FAILURE;
+  }
+
+  JSContext* cx = jsapi.cx();
+  JS::Rooted<JS::Value> jsResult(cx);
+  if (!ToJSValue(cx, result, &jsResult)) {
+    JS_ClearPendingException(cx);
+    return NS_ERROR_TYPE_ERR;
+  }
+
+  return NotifySuccess(jsResult);
+}
+
+NS_IMETHODIMP
+IccCallback::NotifyError(const nsAString & aErrorMsg)
+{
+  if (mPromise) {
+    mPromise->MaybeRejectBrokenly(aErrorMsg);
+    return NS_OK;
+  }
+
+  nsCOMPtr<nsIDOMRequestService> rs =
+    do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
+
+  return rs->FireErrorAsync(mRequest, aErrorMsg);
+}
+
+NS_IMETHODIMP
+IccCallback::NotifyCardLockError(const nsAString & aErrorMsg,
+                                 int32_t aRetryCount)
+{
+  nsRefPtr<IccCardLockError> error =
+    new IccCardLockError(mWindow, aErrorMsg, aRetryCount);
+  mRequest->FireDetailedError(error);
+
+  return NS_OK;
+}
+
+} // namespace icc
+} // namespace dom
+} // namespace mozilla
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/icc/IccCallback.h
@@ -0,0 +1,64 @@
+/* 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_IccCallback_h
+#define mozilla_dom_icc_IccCallback_h
+
+#include "nsCOMPtr.h"
+#include "nsIIccService.h"
+
+namespace mozilla {
+namespace dom {
+
+class DOMRequest;
+class Promise;
+
+namespace icc {
+
+/**
+ * A callback object for handling asynchronous request/response. This object is
+ * created when an asynchronous request is made and should be destroyed after
+ * Notify*Success/Error is called.
+ * The modules hold the reference of IccCallback in OOP mode and non-OOP mode
+ * are different.
+ * - OOP mode: IccRequestChild
+ * - non-OOP mode: IccService
+ * The reference should be released after Notify*Success/Error is called.
+ */
+class IccCallback final : public nsIIccCallback
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIICCCALLBACK
+
+  // TODO: Bug 1125018 - Simplify The Result of GetCardLock and
+  // getCardLockRetryCount in MozIcc.webidl without a wrapper object.
+  IccCallback(nsPIDOMWindow* aWindow, DOMRequest* aRequest,
+              bool aIsCardLockEnabled = false);
+  IccCallback(nsPIDOMWindow* aWindow, Promise* aPromise);
+
+private:
+  ~IccCallback() {}
+
+  nsresult
+  NotifySuccess(JS::Handle<JS::Value> aResult);
+
+  // TODO: Bug 1125018 - Simplify The Result of GetCardLock and
+  // getCardLockRetryCount in MozIcc.webidl without a wrapper object.
+  nsresult
+  NotifyGetCardLockEnabled(bool aResult);
+
+  nsCOMPtr<nsPIDOMWindow> mWindow;
+  nsRefPtr<DOMRequest> mRequest;
+  nsRefPtr<Promise> mPromise;
+  // TODO: Bug 1125018 - Simplify The Result of GetCardLock and
+  // getCardLockRetryCount in MozIcc.webidl without a wrapper object.
+  bool mIsCardLockEnabled;
+};
+
+} // namespace icc
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_icc_IccCallback_h
--- a/dom/icc/IccInfo.cpp
+++ b/dom/icc/IccInfo.cpp
@@ -1,233 +1,295 @@
 /* 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/IccInfo.h"
 
+#include "mozilla/dom/icc/PIccTypes.h"
 #include "nsPIDOMWindow.h"
 
 #define CONVERT_STRING_TO_NULLABLE_ENUM(_string, _enumType, _enum)      \
 {                                                                       \
   uint32_t i = 0;                                                       \
   for (const EnumEntry* entry = _enumType##Values::strings;             \
        entry->value;                                                    \
        ++entry, ++i) {                                                  \
     if (_string.EqualsASCII(entry->value)) {                            \
       _enum.SetValue(static_cast<_enumType>(i));                        \
     }                                                                   \
   }                                                                     \
 }
 
 using namespace mozilla::dom;
 
+using mozilla::dom::icc::IccInfoData;
+
 // IccInfo
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(IccInfo, mWindow, mIccInfo)
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(IccInfo, mWindow)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(IccInfo)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(IccInfo)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IccInfo)
+  NS_INTERFACE_MAP_ENTRY(nsIIccInfo)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 IccInfo::IccInfo(nsPIDOMWindow* aWindow)
   : mWindow(aWindow)
 {
+  mIccType.SetIsVoid(true);
+  mIccid.SetIsVoid(true);
+  mMcc.SetIsVoid(true);
+  mMnc.SetIsVoid(true);
+  mSpn.SetIsVoid(true);
+}
+
+IccInfo::IccInfo(const IccInfoData& aData)
+{
+  mIccType = aData.iccType();
+  mIccid = aData.iccid();
+  mMcc = aData.mcc();
+  mMnc = aData.mnc();
+  mSpn = aData.spn();
+  mIsDisplayNetworkNameRequired = aData.isDisplayNetworkNameRequired();
+  mIsDisplaySpnRequired = aData.isDisplaySpnRequired();
+}
+
+// nsIIccInfo
+
+NS_IMETHODIMP
+IccInfo::GetIccType(nsAString & aIccType)
+{
+  aIccType = mIccType;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+IccInfo::GetIccid(nsAString & aIccid)
+{
+  aIccid = mIccid;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+IccInfo::GetMcc(nsAString & aMcc)
+{
+  aMcc = mMcc;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+IccInfo::GetMnc(nsAString & aMnc)
+{
+  aMnc = mMnc;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+IccInfo::GetSpn(nsAString & aSpn)
+{
+  aSpn = mSpn;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+IccInfo::GetIsDisplayNetworkNameRequired(bool *aIsDisplayNetworkNameRequired)
+{
+  *aIsDisplayNetworkNameRequired = mIsDisplayNetworkNameRequired;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+IccInfo::GetIsDisplaySpnRequired(bool *aIsDisplaySpnRequired)
+{
+  *aIsDisplaySpnRequired = mIsDisplaySpnRequired;
+  return NS_OK;
 }
 
 void
 IccInfo::Update(nsIIccInfo* aInfo)
 {
-  mIccInfo = aInfo;
+  NS_ASSERTION(aInfo, "aInfo is null");
+
+  aInfo->GetIccType(mIccType);
+  aInfo->GetIccid(mIccid);
+  aInfo->GetMcc(mMcc);
+  aInfo->GetMnc(mMnc);
+  aInfo->GetSpn(mSpn);
+  aInfo->GetIsDisplayNetworkNameRequired(
+    &mIsDisplayNetworkNameRequired);
+  aInfo->GetIsDisplaySpnRequired(
+    &mIsDisplaySpnRequired);
 }
 
+// WebIDL implementation
+
 JSObject*
 IccInfo::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return MozIccInfoBinding::Wrap(aCx, this, aGivenProto);
 }
 
 Nullable<IccType>
 IccInfo::GetIccType() const
 {
-  if (!mIccInfo) {
-    return Nullable<IccType>();
-  }
-
-  nsAutoString type;
   Nullable<IccType> iccType;
 
-  mIccInfo->GetIccType(type);
-  CONVERT_STRING_TO_NULLABLE_ENUM(type, IccType, iccType);
+  CONVERT_STRING_TO_NULLABLE_ENUM(mIccType, IccType, iccType);
 
   return iccType;
 }
 
 void
 IccInfo::GetIccid(nsAString& aIccId) const
 {
-  if (!mIccInfo) {
-    aIccId.SetIsVoid(true);
-    return;
-  }
-
-  mIccInfo->GetIccid(aIccId);
+  aIccId = mIccid;
 }
 
 void
 IccInfo::GetMcc(nsAString& aMcc) const
 {
-  if (!mIccInfo) {
-    aMcc.SetIsVoid(true);
-    return;
-  }
-
-  mIccInfo->GetMcc(aMcc);
+  aMcc = mMcc;
 }
 
 void
 IccInfo::GetMnc(nsAString& aMnc) const
 {
-  if (!mIccInfo) {
-    aMnc.SetIsVoid(true);
-    return;
-  }
-
-  mIccInfo->GetMnc(aMnc);
+  aMnc = mMnc;
 }
 
 void
 IccInfo::GetSpn(nsAString& aSpn) const
 {
-  if (!mIccInfo) {
-    aSpn.SetIsVoid(true);
-    return;
-  }
-
-  mIccInfo->GetSpn(aSpn);
+  aSpn = mSpn;
 }
 
 bool
 IccInfo::IsDisplayNetworkNameRequired() const
 {
-  if (!mIccInfo) {
-    return false;
-  }
-
-  bool isDisplayNetworkNameRequired;
-  mIccInfo->GetIsDisplayNetworkNameRequired(&isDisplayNetworkNameRequired);
-
-  return isDisplayNetworkNameRequired;
+  return mIsDisplayNetworkNameRequired;
 }
 
 bool
 IccInfo::IsDisplaySpnRequired() const
 {
-  if (!mIccInfo) {
-    return false;
-  }
-
-  bool isDisplaySpnRequired;
-  mIccInfo->GetIsDisplaySpnRequired(&isDisplaySpnRequired);
-
-  return isDisplaySpnRequired;
+  return mIsDisplaySpnRequired;
 }
 
 // GsmIccInfo
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED(GsmIccInfo, IccInfo, mGsmIccInfo)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(GsmIccInfo)
-NS_INTERFACE_MAP_END_INHERITING(IccInfo)
-
-NS_IMPL_ADDREF_INHERITED(GsmIccInfo, IccInfo)
-NS_IMPL_RELEASE_INHERITED(GsmIccInfo, IccInfo)
+NS_IMPL_ISUPPORTS_INHERITED(GsmIccInfo, IccInfo, nsIGsmIccInfo)
 
 GsmIccInfo::GsmIccInfo(nsPIDOMWindow* aWindow)
   : IccInfo(aWindow)
 {
+  mPhoneNumber.SetIsVoid(true);
 }
 
+GsmIccInfo::GsmIccInfo(const IccInfoData& aData)
+  : IccInfo(aData)
+{
+  mPhoneNumber = aData.phoneNumber();
+}
+
+// nsIGsmIccInfo
+
+NS_IMETHODIMP
+GsmIccInfo::GetMsisdn(nsAString & aMsisdn)
+{
+  aMsisdn = mPhoneNumber;
+  return NS_OK;
+}
+
+// WebIDL implementation
+
 void
 GsmIccInfo::Update(nsIGsmIccInfo* aInfo)
 {
+  MOZ_ASSERT(aInfo);
   nsCOMPtr<nsIIccInfo> iccInfo = do_QueryInterface(aInfo);
   MOZ_ASSERT(iccInfo);
 
   IccInfo::Update(iccInfo);
-  mGsmIccInfo = aInfo;
+
+  aInfo->GetMsisdn(mPhoneNumber);
 }
 
 JSObject*
 GsmIccInfo::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return MozGsmIccInfoBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
 GsmIccInfo::GetMsisdn(nsAString& aMsisdn) const
 {
-  if (!mGsmIccInfo) {
-    aMsisdn.SetIsVoid(true);
-    return;
-  }
-
-  mGsmIccInfo->GetMsisdn(aMsisdn);
+  aMsisdn = mPhoneNumber;
 }
 
 // CdmaIccInfo
 
-NS_IMPL_CYCLE_COLLECTION_INHERITED(CdmaIccInfo, IccInfo, mCdmaIccInfo)
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(CdmaIccInfo)
-NS_INTERFACE_MAP_END_INHERITING(IccInfo)
-
-NS_IMPL_ADDREF_INHERITED(CdmaIccInfo, IccInfo)
-NS_IMPL_RELEASE_INHERITED(CdmaIccInfo, IccInfo)
+NS_IMPL_ISUPPORTS_INHERITED(CdmaIccInfo, IccInfo, nsICdmaIccInfo)
 
 CdmaIccInfo::CdmaIccInfo(nsPIDOMWindow* aWindow)
   : IccInfo(aWindow)
 {
+  mPhoneNumber.SetIsVoid(true);
+}
+
+CdmaIccInfo::CdmaIccInfo(const IccInfoData& aData)
+  : IccInfo(aData)
+{
+  mPhoneNumber = aData.phoneNumber();
+  mPrlVersion = aData.prlVersion();
+}
+
+// nsICdmaIccInfo
+
+NS_IMETHODIMP
+CdmaIccInfo::GetMdn(nsAString & aMdn)
+{
+  aMdn = mPhoneNumber;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+CdmaIccInfo::GetPrlVersion(int32_t *aPrlVersion)
+{
+  *aPrlVersion = mPrlVersion;
+  return NS_OK;
 }
 
 void
 CdmaIccInfo::Update(nsICdmaIccInfo* aInfo)
 {
+  MOZ_ASSERT(aInfo);
   nsCOMPtr<nsIIccInfo> iccInfo = do_QueryInterface(aInfo);
   MOZ_ASSERT(iccInfo);
 
   IccInfo::Update(iccInfo);
-  mCdmaIccInfo = aInfo;
+
+  aInfo->GetMdn(mPhoneNumber);
+  aInfo->GetPrlVersion(&mPrlVersion);
 }
 
+// WebIDL implementation
+
 JSObject*
 CdmaIccInfo::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return MozCdmaIccInfoBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
 CdmaIccInfo::GetMdn(nsAString& aMdn) const
 {
-  if (!mCdmaIccInfo) {
-    aMdn.SetIsVoid(true);
-    return;
-  }
-
-  mCdmaIccInfo->GetMdn(aMdn);
+  aMdn = mPhoneNumber;
 }
 
 int32_t
 CdmaIccInfo::PrlVersion() const
 {
-  if (!mCdmaIccInfo) {
-    return 0;
-  }
-
-  int32_t prlVersion;
-  mCdmaIccInfo->GetPrlVersion(&prlVersion);
-
-  return prlVersion;
+  return mPrlVersion;
 }
--- a/dom/icc/IccInfo.h
+++ b/dom/icc/IccInfo.h
@@ -9,24 +9,30 @@
 #include "nsIIccInfo.h"
 #include "nsWrapperCache.h"
 
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
-class IccInfo : public nsISupports
+namespace icc {
+class IccInfoData;
+} // namespace icc
+
+class IccInfo : public nsIIccInfo
               , public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(IccInfo)
+  NS_DECL_NSIICCINFO
 
   explicit IccInfo(nsPIDOMWindow* aWindow);
+  explicit IccInfo(const icc::IccInfoData& aData);
 
   void
   Update(nsIIccInfo* aInfo);
 
   nsPIDOMWindow*
   GetParentObject() const
   {
     return mWindow;
@@ -56,54 +62,68 @@ public:
   IsDisplayNetworkNameRequired() const;
 
   bool
   IsDisplaySpnRequired() const;
 
 protected:
   virtual ~IccInfo() {}
 
-protected:
   nsCOMPtr<nsPIDOMWindow> mWindow;
-  nsCOMPtr<nsIIccInfo> mIccInfo;
+  // To prevent compiling error in OS_WIN in auto-generated UnifiedBindingsXX.cpp,
+  // we have all data fields expended here instead of having a data member of
+  // |IccInfoData| defined in PIccTypes.h which indirectly includes "windows.h"
+  // See 925382 for the restriction of including "windows.h" in UnifiedBindings.cpp.
+  nsString mIccType;
+  nsString mIccid;
+  nsString mMcc;
+  nsString mMnc;
+  nsString mSpn;
+  bool mIsDisplayNetworkNameRequired;
+  bool mIsDisplaySpnRequired;
 };
 
 class GsmIccInfo final : public IccInfo
+                       , public nsIGsmIccInfo
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(GsmIccInfo, IccInfo)
+  NS_FORWARD_NSIICCINFO(IccInfo::)
+  NS_DECL_NSIGSMICCINFO
 
   explicit GsmIccInfo(nsPIDOMWindow* aWindow);
+  explicit GsmIccInfo(const icc::IccInfoData& aData);
 
   void
   Update(nsIGsmIccInfo* aInfo);
 
   // WrapperCache
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   // MozCdmaIccInfo WebIDL
   void
   GetMsisdn(nsAString& aMsisdn) const;
 
 private:
   ~GsmIccInfo() {}
 
-private:
-  nsCOMPtr<nsIGsmIccInfo> mGsmIccInfo;
+  nsString mPhoneNumber;
 };
 
 class CdmaIccInfo final : public IccInfo
+                        , public nsICdmaIccInfo
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CdmaIccInfo, IccInfo)
+  NS_FORWARD_NSIICCINFO(IccInfo::)
+  NS_DECL_NSICDMAICCINFO
 
   explicit CdmaIccInfo(nsPIDOMWindow* aWindow);
+  explicit CdmaIccInfo(const icc::IccInfoData& aData);
 
   void
   Update(nsICdmaIccInfo* aInfo);
 
   // WrapperCache
   virtual JSObject*
   WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
@@ -112,17 +132,17 @@ public:
   GetMdn(nsAString& aMdn) const;
 
   int32_t
   PrlVersion() const;
 
 private:
   ~CdmaIccInfo() {}
 
-private:
-  nsCOMPtr<nsICdmaIccInfo> mCdmaIccInfo;
+  nsString mPhoneNumber;
+  int32_t mPrlVersion;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_IccInfo_h
 
--- a/dom/icc/IccListener.cpp
+++ b/dom/icc/IccListener.cpp
@@ -15,51 +15,77 @@ using namespace mozilla::dom;
 NS_IMPL_ISUPPORTS(IccListener, nsIIccListener)
 
 IccListener::IccListener(IccManager* aIccManager, uint32_t aClientId)
   : mClientId(aClientId)
   , mIccManager(aIccManager)
 {
   MOZ_ASSERT(mIccManager);
 
+  // TODO: Bug 1114938, Refactor STK in MozIcc.webidl with IPDL.
+  //       Remove the registration to IccProvider.
   mProvider = do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
 
   if (!mProvider) {
     NS_WARNING("Could not acquire nsIIccProvider!");
     return;
   }
 
+  nsCOMPtr<nsIIccService> iccService = do_GetService(ICC_SERVICE_CONTRACTID);
+
+  if (!iccService) {
+    NS_WARNING("Could not acquire nsIIccService!");
+    return;
+  }
+
+  iccService->GetIccByServiceId(mClientId, getter_AddRefs(mHandler));
+  if (!mHandler) {
+    NS_WARNING("Could not acquire nsIIcc!");
+    return;
+  }
+
   nsCOMPtr<nsIIccInfo> iccInfo;
-  mProvider->GetIccInfo(mClientId, getter_AddRefs(iccInfo));
+  mHandler->GetIccInfo(getter_AddRefs(iccInfo));
   if (iccInfo) {
     nsString iccId;
     iccInfo->GetIccid(iccId);
     if (!iccId.IsEmpty()) {
-      mIcc = new Icc(mIccManager->GetOwner(), mClientId, iccInfo);
+      mIcc = new Icc(mIccManager->GetOwner(), mClientId, mHandler, iccInfo);
     }
   }
 
-  DebugOnly<nsresult> rv = mProvider->RegisterIccMsg(mClientId, this);
+  DebugOnly<nsresult> rv = mHandler->RegisterListener(this);
+  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
+                   "Failed registering icc listener with Icc Handler");
+
+  rv = mProvider->RegisterIccMsg(mClientId, this);
   NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
                    "Failed registering icc messages with provider");
 }
 
 IccListener::~IccListener()
 {
   Shutdown();
 }
 
 void
 IccListener::Shutdown()
 {
+  // TODO: Bug 1114938, Refactor STK in MozIcc.webidl with IPDL.
+  //       Remove the unregistration to IccProvider.
   if (mProvider) {
     mProvider->UnregisterIccMsg(mClientId, this);
     mProvider = nullptr;
   }
 
+  if (mHandler) {
+    mHandler->UnregisterListener(this);
+    mHandler = nullptr;
+  }
+
   if (mIcc) {
     mIcc->Shutdown();
     mIcc = nullptr;
   }
 
   mIccManager = nullptr;
 }
 
@@ -93,30 +119,34 @@ IccListener::NotifyCardStateChanged()
   }
 
   return mIcc->NotifyEvent(NS_LITERAL_STRING("cardstatechange"));
 }
 
 NS_IMETHODIMP
 IccListener::NotifyIccInfoChanged()
 {
+  if (!mHandler) {
+    return NS_OK;
+  }
+
   nsCOMPtr<nsIIccInfo> iccInfo;
-  mProvider->GetIccInfo(mClientId, getter_AddRefs(iccInfo));
+  mHandler->GetIccInfo(getter_AddRefs(iccInfo));
 
   // Create/delete icc object based on current iccInfo.
   // 1. If the mIcc is nullptr and iccInfo has valid data, create icc object and
   //    notify mIccManager a new icc is added.
   // 2. If the mIcc is not nullptr and iccInfo becomes to null, delete existed
   //    icc object and notify mIccManager the icc is removed.
   if (!mIcc) {
     if (iccInfo) {
       nsString iccId;
       iccInfo->GetIccid(iccId);
       if (!iccId.IsEmpty()) {
-        mIcc = new Icc(mIccManager->GetOwner(), mClientId, iccInfo);
+        mIcc = new Icc(mIccManager->GetOwner(), mClientId, mHandler, iccInfo);
         mIccManager->NotifyIccAdd(iccId);
         mIcc->NotifyEvent(NS_LITERAL_STRING("iccinfochange"));
       }
     }
   } else {
     mIcc->UpdateIccInfo(iccInfo);
     mIcc->NotifyEvent(NS_LITERAL_STRING("iccinfochange"));
     if (!iccInfo) {
--- a/dom/icc/IccListener.h
+++ b/dom/icc/IccListener.h
@@ -2,16 +2,17 @@
  * 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_IccListener_h
 #define mozilla_dom_IccListener_h
 
 #include "nsAutoPtr.h"
 #include "nsIIccProvider.h"
+#include "nsIIccService.h"
 
 namespace mozilla {
 namespace dom {
 
 class IccManager;
 class Icc;
 
 class IccListener final : public nsIIccListener
@@ -37,17 +38,20 @@ private:
 private:
   uint32_t mClientId;
   // We did not setup 'mIcc' and 'mIccManager' being a participant of cycle
   // collection is because in Navigator->Invalidate() it will call
   // mIccManager->Shutdown(), then IccManager will call Shutdown() of each
   // IccListener, this will release the reference and break the cycle.
   nsRefPtr<Icc> mIcc;
   nsRefPtr<IccManager> mIccManager;
-  // mProvider is a xpcom service and will be released at shutdown, so it
+  // mProvider is a xpcom service and will be released at Shutdown(), so it
   // doesn't need to be cycle collected.
   nsCOMPtr<nsIIccProvider> mProvider;
+  // mHandler will be released at Shutdown(), there is no need to join cycle
+  // collection.
+  nsCOMPtr<nsIIcc> mHandler;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_IccListener_h
--- a/dom/icc/IccManager.cpp
+++ b/dom/icc/IccManager.cpp
@@ -5,16 +5,25 @@
 #include "IccManager.h"
 #include "mozilla/dom/MozIccManagerBinding.h"
 #include "Icc.h"
 #include "IccListener.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/dom/IccChangeEvent.h"
 #include "mozilla/Preferences.h"
 #include "nsIIccInfo.h"
+// Service instantiation
+#include "ipc/IccIPCService.h"
+#if defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
+// TODO: Bug 815526, deprecate RILContentHelper.
+#include "nsIRadioInterfaceLayer.h"
+#include "nsRadioInterfaceLayer.h"
+#include "nsIGonkIccService.h"
+#endif
+#include "nsXULAppAPI.h" // For XRE_GetProcessType()
 
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(IccManager)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IccManager,
                                                   DOMEventTargetHelper)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@@ -124,8 +133,30 @@ IccManager::GetIccById(const nsAString& 
   for (i = 0; i < mIccListeners.Length(); ++i) {
     Icc* icc = mIccListeners[i]->GetIcc();
     if (icc && aIccId == icc->GetIccId()) {
       return icc;
     }
   }
   return nullptr;
 }
+
+already_AddRefed<nsIIccService>
+NS_CreateIccService()
+{
+  nsCOMPtr<nsIIccService> service;
+
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    service = new mozilla::dom::icc::IccIPCService();
+#if defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
+  } else {
+    // TODO: Bug 815526, deprecate RILContentHelper.
+    nsCOMPtr <nsIRadioInterfaceLayer> ril =
+      do_GetService(NS_RADIOINTERFACELAYER_CONTRACTID);
+    nsCOMPtr <nsIRadioInterfaceLayer_new> ril_new(do_QueryInterface(ril));
+
+    service = (ril_new) ? do_GetService(GONK_ICC_SERVICE_CONTRACTID)
+                        : do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
+#endif
+  }
+
+  return service.forget();
+}
--- a/dom/icc/IccManager.h
+++ b/dom/icc/IccManager.h
@@ -2,17 +2,16 @@
  * 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_IccManager_h
 #define mozilla_dom_IccManager_h
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "nsCycleCollectionParticipant.h"
-#include "nsIIccProvider.h"
 #include "nsTArrayHelpers.h"
 
 namespace mozilla {
 namespace dom {
 
 class Icc;
 class IccListener;
 
@@ -20,17 +19,17 @@ class IccManager final : public DOMEvent
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
 
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IccManager, DOMEventTargetHelper)
 
-  IccManager(nsPIDOMWindow* aWindow);
+  explicit IccManager(nsPIDOMWindow* aWindow);
 
   void
   Shutdown();
 
   nsresult
   NotifyIccAdd(const nsAString& aIccId);
 
   nsresult
new file mode 100644
--- /dev/null
+++ b/dom/icc/gonk/IccService.js
@@ -0,0 +1,437 @@
+/* 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/. */
+
+"use strict";
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+var RIL = {};
+Cu.import("resource://gre/modules/ril_consts.js", RIL);
+
+const GONK_ICCSERVICE_CONTRACTID = "@mozilla.org/icc/gonkiccservice;1";
+const GONK_ICCSERVICE_CID = Components.ID("{df854256-9554-11e4-a16c-c39e8d106c26}");
+
+const NS_XPCOM_SHUTDOWN_OBSERVER_ID      = "xpcom-shutdown";
+const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID  = "nsPref:changed";
+
+const kPrefRilDebuggingEnabled = "ril.debugging.enabled";
+const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
+
+XPCOMUtils.defineLazyServiceGetter(this, "gRadioInterfaceLayer",
+                                   "@mozilla.org/ril;1",
+                                   "nsIRadioInterfaceLayer");
+
+let DEBUG = RIL.DEBUG_RIL;
+function debug(s) {
+  dump("IccService: " + s);
+}
+
+function IccInfo() {}
+IccInfo.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccInfo]),
+
+  // nsIIccInfo
+
+  iccType: null,
+  iccid: null,
+  mcc: null,
+  mnc: null,
+  spn: null,
+  isDisplayNetworkNameRequired: false,
+  isDisplaySpnRequired: false
+};
+
+function GsmIccInfo() {}
+GsmIccInfo.prototype = {
+  __proto__: IccInfo.prototype,
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIGsmIccInfo,
+                                         Ci.nsIIccInfo]),
+
+  // nsIGsmIccInfo
+
+  msisdn: null
+};
+
+function CdmaIccInfo() {}
+CdmaIccInfo.prototype = {
+  __proto__: IccInfo.prototype,
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsICdmaIccInfo,
+                                         Ci.nsIIccInfo]),
+
+  // nsICdmaIccInfo
+
+  mdn: null,
+  prlVersion: 0
+};
+
+function IccService() {
+  this._iccs = [];
+
+  let numClients = gRadioInterfaceLayer.numRadioInterfaces;
+  for (let i = 0; i < numClients; i++) {
+    this._iccs.push(new Icc(gRadioInterfaceLayer.getRadioInterface(i)));
+  }
+
+  this._updateDebugFlag();
+
+  Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false);
+  Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
+}
+IccService.prototype = {
+  classID: GONK_ICCSERVICE_CID,
+
+  classInfo: XPCOMUtils.generateCI({classID: GONK_ICCSERVICE_CID,
+                                    contractID: GONK_ICCSERVICE_CONTRACTID,
+                                    classDescription: "IccService",
+                                    interfaces: [Ci.nsIIccService,
+                                                 Ci.nsIGonkIccService],
+                                    flags: Ci.nsIClassInfo.SINGLETON}),
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccService,
+                                         Ci.nsIGonkIccService,
+                                         Ci.nsIObserver]),
+
+  // An array of Icc instances.
+  _iccs: null,
+
+  _updateDebugFlag: function() {
+    try {
+      DEBUG = DEBUG ||
+              Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
+    } catch (e) {}
+  },
+
+  /**
+   * nsIIccService interface.
+   */
+  getIccByServiceId: function(aServiceId) {
+    let icc = this._iccs[aServiceId];
+    if (!icc) {
+      throw Cr.NS_ERROR_UNEXPECTED;
+    }
+
+    return icc;
+  },
+
+  /**
+   * nsIGonkIccService interface.
+   */
+  notifyCardStateChanged: function(aServiceId, aCardState) {
+    if (DEBUG) {
+      debug("notifyCardStateChanged for service Id: " + aServiceId +
+            ", CardState: " + aCardState);
+    }
+
+    this.getIccByServiceId(aServiceId)._updateCardState(aCardState);
+  },
+
+  notifyIccInfoChanged: function(aServiceId, aIccInfo) {
+    if (DEBUG) {
+      debug("notifyIccInfoChanged for service Id: " + aServiceId +
+            ", IccInfo: " + JSON.stringify(aIccInfo));
+    }
+
+    this.getIccByServiceId(aServiceId)._updateIccInfo(aIccInfo);
+  },
+
+  notifyImsiChanged: function(aServiceId, aImsi) {
+    if (DEBUG) {
+      debug("notifyImsiChanged for service Id: " + aServiceId +
+            ", Imsi: " + aImsi);
+    }
+
+    let icc = this.getIccByServiceId(aServiceId);
+    icc._imsi = aImsi;
+  },
+
+  /**
+   * nsIObserver interface.
+   */
+  observe: function(aSubject, aTopic, aData) {
+    switch (aTopic) {
+      case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
+        if (aData === kPrefRilDebuggingEnabled) {
+          this._updateDebugFlag();
+        }
+        break;
+      case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
+        Services.prefs.removeObserver(kPrefRilDebuggingEnabled, this);
+        Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
+        break;
+    }
+  }
+};
+
+function Icc(aRadioInterface) {
+  this._radioInterface = aRadioInterface;
+  this._listeners = [];
+}
+Icc.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIIcc]),
+
+  _radioInterface: null,
+  _imsi: null,
+  _listeners: null,
+
+  _updateCardState: function(aCardState) {
+    if (this.cardState != aCardState) {
+      this.cardState = aCardState;
+    }
+
+    this._deliverListenerEvent("notifyCardStateChanged");
+  },
+
+  // An utility function to copy objects.
+  _updateInfo: function(aSrcInfo, aDestInfo) {
+    for (let key in aSrcInfo) {
+      aDestInfo[key] = aSrcInfo[key];
+    }
+  },
+
+  /**
+   * We need to consider below cases when update iccInfo:
+   * 1. Should clear iccInfo to null if there is no card detected.
+   * 2. Need to create corresponding object based on iccType.
+   */
+  _updateIccInfo: function(aIccInfo) {
+    // Card is not detected, clear iccInfo to null.
+    if (!aIccInfo || !aIccInfo.iccid) {
+      if (this.iccInfo) {
+        if (DEBUG) {
+          debug("Card is not detected, clear iccInfo to null.");
+        }
+        this.iccInfo = null;
+        this._deliverListenerEvent("notifyIccInfoChanged");
+      }
+      return;
+    }
+
+    // If iccInfo is null, new corresponding object based on iccType.
+    if (!this.iccInfo ||
+        this.iccInfo.iccType != aIccInfo.iccType) {
+      if (aIccInfo.iccType === "ruim" || aIccInfo.iccType === "csim") {
+        this.iccInfo = new CdmaIccInfo();
+      } else if (aIccInfo.iccType === "sim" || aIccInfo.iccType === "usim") {
+        this.iccInfo = new GsmIccInfo();
+      } else {
+        this.iccInfo = new IccInfo();
+      }
+    }
+
+    this._updateInfo(aIccInfo, this.iccInfo);
+
+    this._deliverListenerEvent("notifyIccInfoChanged");
+
+    // Update lastKnownSimMcc.
+    if (aIccInfo.mcc) {
+      try {
+        Services.prefs.setCharPref("ril.lastKnownSimMcc",
+                                   aIccInfo.mcc.toString());
+      } catch (e) {}
+    }
+  },
+
+  _deliverListenerEvent: function(aName, aArgs) {
+    let listeners = this._listeners.slice();
+    for (let listener of listeners) {
+      if (this._listeners.indexOf(listener) === -1) {
+        continue;
+      }
+      let handler = listener[aName];
+      if (typeof handler != "function") {
+        throw new Error("No handler for " + aName);
+      }
+      try {
+        handler.apply(listener, aArgs);
+      } catch (e) {
+        if (DEBUG) {
+          debug("listener for " + aName + " threw an exception: " + e);
+        }
+      }
+    }
+  },
+
+  _modifyCardLock: function(aOperation, aOptions, aCallback) {
+    this._radioInterface.sendWorkerMessage(aOperation,
+                                           aOptions,
+                                           (aResponse) => {
+      if (aResponse.errorMsg) {
+        let retryCount =
+          (aResponse.retryCount !== undefined) ? aResponse.retryCount : -1;
+        aCallback.notifyCardLockError(aResponse.errorMsg, retryCount);
+        return;
+      }
+
+      aCallback.notifySuccess();
+    });
+  },
+
+  /**
+   * Helper to match the MVNO pattern with IMSI.
+   *
+   * Note: Characters 'x' and 'X' in MVNO are skipped and not compared.
+   *       E.g., if the aMvnoData passed is '310260x10xxxxxx', then the
+   *       function returns true only if imsi has the same first 6 digits, 8th
+   *       and 9th digit.
+   *
+   * @param aMvnoData
+   *        MVNO pattern.
+   * @param aImsi
+   *        IMSI of this ICC.
+   *
+   * @return true if matched.
+   */
+  _isImsiMatches: function(aMvnoData, aImsi) {
+    // This should not be an error, but a mismatch.
+    if (aMvnoData.length > aImsi.length) {
+      return false;
+    }
+
+    for (let i = 0; i < aMvnoData.length; i++) {
+      let c = aMvnoData[i];
+      if ((c !== 'x') && (c !== 'X') && (c !== aImsi[i])) {
+        return false;
+      }
+    }
+    return true;
+  },
+
+  /**
+   * nsIIcc interface.
+   */
+  iccInfo: null,
+  cardState: Ci.nsIIcc.CARD_STATE_UNKNOWN,
+
+  registerListener: function(aListener) {
+    if (this._listeners.indexOf(aListener) >= 0) {
+      throw Cr.NS_ERROR_UNEXPECTED;
+    }
+
+    this._listeners.push(aListener);
+  },
+
+  unregisterListener: function(aListener) {
+    let index = this._listeners.indexOf(aListener);
+    if (index >= 0) {
+      this._listeners.splice(index, 1);
+    }
+  },
+
+  getCardLockEnabled: function(aLockType, aCallback) {
+    this._radioInterface.sendWorkerMessage("iccGetCardLockEnabled",
+                                           { lockType: aLockType },
+                                           (aResponse) => {
+      if (aResponse.errorMsg) {
+        aCallback.notifyError(aResponse.errorMsg);
+        return;
+      }
+
+      aCallback.notifySuccessWithBoolean(aResponse.enabled);
+    });
+  },
+
+  unlockCardLock: function(aLockType, aPassword, aNewPin, aCallback) {
+    this._modifyCardLock("iccUnlockCardLock",
+                         { lockType: aLockType,
+                           password: aPassword,
+                           newPin: aNewPin },
+                         aCallback);
+  },
+
+  setCardLockEnabled: function(aLockType, aPassword, aEnabled, aCallback) {
+    this._modifyCardLock("iccSetCardLockEnabled",
+                         { lockType: aLockType,
+                           password: aPassword,
+                           enabled: aEnabled },
+                         aCallback);
+  },
+
+  changeCardLockPassword: function(aLockType, aPassword, aNewPassword, aCallback) {
+    this._modifyCardLock("iccChangeCardLockPassword",
+                         { lockType: aLockType,
+                           password: aPassword,
+                           newPassword: aNewPassword, },
+                         aCallback);
+  },
+
+  getCardLockRetryCount: function(aLockType, aCallback) {
+    this._radioInterface.sendWorkerMessage("iccGetCardLockRetryCount",
+                                           { lockType: aLockType },
+                                           (aResponse) => {
+      if (aResponse.errorMsg) {
+        aCallback.notifyError(aResponse.errorMsg);
+        return;
+      }
+
+      aCallback.notifyGetCardLockRetryCount(aResponse.retryCount);
+    });
+  },
+
+  matchMvno: function(aMvnoType, aMvnoData, aCallback) {
+    if (!aMvnoData) {
+      aCallback.notifyError(RIL.GECKO_ERROR_INVALID_PARAMETER);
+      return;
+    }
+
+    switch (aMvnoType) {
+      case Ci.nsIIcc.CARD_MVNO_TYPE_IMSI:
+        let imsi = this._imsi;
+        if (!imsi) {
+          aCallback.notifyError(RIL.GECKO_ERROR_GENERIC_FAILURE);
+          break;
+        }
+        aCallback.notifySuccessWithBoolean(
+          this._isImsiMatches(aMvnoData, imsi));
+        break;
+      case Ci.nsIIcc.CARD_MVNO_TYPE_SPN:
+        let spn = this.iccInfo && this.iccInfo.spn;
+        if (!spn) {
+          aCallback.notifyError(RIL.GECKO_ERROR_GENERIC_FAILURE);
+          break;
+        }
+        aCallback.notifySuccessWithBoolean(spn == aMvnoData);
+        break;
+      case Ci.nsIIcc.CARD_MVNO_TYPE_GID:
+        this._radioInterface.sendWorkerMessage("getGID1",
+                                               null,
+                                               (aResponse) => {
+          let gid = aResponse.gid1;
+          let mvnoDataLength = aMvnoData.length;
+
+          if (!gid) {
+            aCallback.notifyError(RIL.GECKO_ERROR_GENERIC_FAILURE);
+          } else if (mvnoDataLength > gid.length) {
+            aCallback.notifySuccessWithBoolean(false);
+          } else {
+            let result =
+              gid.substring(0, mvnoDataLength).toLowerCase() ==
+              aMvnoData.toLowerCase();
+            aCallback.notifySuccessWithBoolean(result);
+          }
+        });
+        break;
+      default:
+        aCallback.notifyError(RIL.GECKO_ERROR_MODE_NOT_SUPPORTED);
+        break;
+    }
+  },
+
+  getServiceStateEnabled: function(aService, aCallback) {
+    this._radioInterface.sendWorkerMessage("getIccServiceState",
+                                           { service: aService },
+                                           (aResponse) => {
+      if (aResponse.errorMsg) {
+        aCallback.notifyError(aResponse.errorMsg);
+        return;
+      }
+
+      aCallback.notifySuccessWithBoolean(aResponse.result);
+    });
+  }
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([IccService]);
new file mode 100644
--- /dev/null
+++ b/dom/icc/gonk/IccService.manifest
@@ -0,0 +1,6 @@
+# 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/.
+
+component {df854256-9554-11e4-a16c-c39e8d106c26} IccService.js
+contract @mozilla.org/icc/gonkiccservice;1 {df854256-9554-11e4-a16c-c39e8d106c26}
\ No newline at end of file
--- a/dom/icc/interfaces/moz.build
+++ b/dom/icc/interfaces/moz.build
@@ -1,17 +1,19 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
     'nsIIccInfo.idl',
-    'nsIIccProvider.idl',
+    'nsIIccProvider.idl', # TODO: Bug 815526, deprecate RILContentHelper.
+    'nsIIccService.idl',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_B2G_RIL']:
     XPIDL_SOURCES += [
+        'nsIGonkIccService.idl',
         'nsIIccMessenger.idl',
     ]
 
 XPIDL_MODULE = 'dom_icc'
new file mode 100644
--- /dev/null
+++ b/dom/icc/interfaces/nsIGonkIccService.idl
@@ -0,0 +1,21 @@
+/* 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 "nsIIccService.idl"
+
+%{C++
+#define GONK_ICC_SERVICE_CONTRACTID \
+        "@mozilla.org/icc/gonkiccservice;1"
+%}
+
+[scriptable, uuid(a037b8a2-b027-11e4-9496-c3b7af59a512)]
+interface nsIGonkIccService : nsIIccService
+{
+  // TODO: Bug 1114938 - Refactor STK in MozIcc.webidl with IPDL:
+  // void notifyStkCommand(in unsigned long aServiceId, in jsval aStkcommand);
+  // void notifyStkSessionEnd(in unsigned long aServiceId);
+  void notifyCardStateChanged(in unsigned long aServiceId, in unsigned long aCardState);
+  void notifyIccInfoChanged(in unsigned long aServiceId, in jsval aIccInfo);
+  void notifyImsiChanged(in unsigned long aServiceId, in DOMString aImsi);
+};
--- a/dom/icc/interfaces/nsIIccProvider.idl
+++ b/dom/icc/interfaces/nsIIccProvider.idl
@@ -2,25 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
 interface nsIDOMDOMRequest;
 interface nsIDOMWindow;
 interface nsIIccInfo;
-
-[scriptable, uuid(7c0ada3d-d8d4-493e-9243-fa3df39855e4)]
-interface nsIIccListener : nsISupports
-{
-  void notifyStkCommand(in DOMString aMessage);
-  void notifyStkSessionEnd();
-  void notifyCardStateChanged();
-  void notifyIccInfoChanged();
-};
+interface nsIIccListener;
 
 [scriptable, uuid(6136acab-b50e-494a-a86d-df392a032897)]
 interface nsIIccChannelCallback : nsISupports
 {
   /**
    * Callback function to notify on successfully opening a logical channel.
    *
    * @param channel
@@ -53,114 +45,28 @@ interface nsIIccChannelCallback : nsISup
    *
    */
   void notifyError(in DOMString error);
 };
 
 /**
  * XPCOM component (in the content process) that provides the ICC information.
  */
-[scriptable, uuid(a203cd2e-2280-4d8e-a687-42b745d322c1)]
+[scriptable, uuid(7dd6e186-b007-11e4-9b7e-7717d7863cb8)]
 interface nsIIccProvider : nsISupports
 {
-  // MUST match enum IccCardState in MozIcc.webidl!
-  const unsigned long CARD_STATE_UNKNOWN = 0;
-  const unsigned long CARD_STATE_READY = 1;
-  const unsigned long CARD_STATE_PIN_REQUIRED = 2;
-  const unsigned long CARD_STATE_PUK_REQUIRED = 3;
-  const unsigned long CARD_STATE_PERMANENT_BLOCKED = 4;
-  const unsigned long CARD_STATE_PERSONALIZATION_IN_PROGRESS = 5;
-  const unsigned long CARD_STATE_PERSONALIZATION_READY = 6;
-  const unsigned long CARD_STATE_NETWORK_LOCKED = 7;
-  const unsigned long CARD_STATE_NETWORK_SUBSET_LOCKED = 8;
-  const unsigned long CARD_STATE_CORPORATE_LOCKED = 9;
-  const unsigned long CARD_STATE_SERVICE_PROVIDER_LOCKED = 10;
-  const unsigned long CARD_STATE_SIM_LOCKED = 11;
-  const unsigned long CARD_STATE_NETWORK_PUK_REQUIRED = 12;
-  const unsigned long CARD_STATE_NETWORK_SUBSET_PUK_REQUIRED = 13;
-  const unsigned long CARD_STATE_CORPORATE_PUK_REQUIRED = 14;
-  const unsigned long CARD_STATE_SERVICE_PROVIDER_PUK_REQUIRED = 15;
-  const unsigned long CARD_STATE_SIM_PUK_REQUIRED = 16;
-  const unsigned long CARD_STATE_NETWORK1_LOCKED = 17;
-  const unsigned long CARD_STATE_NETWORK2_LOCKED = 18;
-  const unsigned long CARD_STATE_HRPD_NETWORK_LOCKED = 19;
-  const unsigned long CARD_STATE_RUIM_CORPORATE_LOCKED = 20;
-  const unsigned long CARD_STATE_RUIM_SERVICE_PROVIDER_LOCKED = 21;
-  const unsigned long CARD_STATE_RUIM_LOCKED = 22;
-  const unsigned long CARD_STATE_NETWORK1_PUK_REQUIRED = 23;
-  const unsigned long CARD_STATE_NETWORK2_PUK_REQUIRED = 24;
-  const unsigned long CARD_STATE_HRPD_NETWORK_PUK_REQUIRED = 25;
-  const unsigned long CARD_STATE_RUIM_CORPORATE_PUK_REQUIRED = 26;
-  const unsigned long CARD_STATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED = 27;
-  const unsigned long CARD_STATE_RUIM_PUK_REQUIRED = 28;
-  const unsigned long CARD_STATE_ILLEGAL = 29;
-
-  const unsigned long CARD_STATE_UNDETECTED = 4294967295; // UINT32_MAX
-
-  // MUST match with enum IccLockType in MozIcc.webidl
-  const unsigned long CARD_LOCK_TYPE_PIN = 0;
-  const unsigned long CARD_LOCK_TYPE_PIN2 = 1;
-  const unsigned long CARD_LOCK_TYPE_PUK = 2;
-  const unsigned long CARD_LOCK_TYPE_PUK2 = 3;
-  const unsigned long CARD_LOCK_TYPE_NCK = 4;
-  const unsigned long CARD_LOCK_TYPE_NSCK = 5;
-  const unsigned long CARD_LOCK_TYPE_NCK1 = 6;
-  const unsigned long CARD_LOCK_TYPE_NCK2 = 7;
-  const unsigned long CARD_LOCK_TYPE_HNCK = 8;
-  const unsigned long CARD_LOCK_TYPE_CCK = 9;
-  const unsigned long CARD_LOCK_TYPE_SPCK = 10;
-  const unsigned long CARD_LOCK_TYPE_PCK = 11;
-  const unsigned long CARD_LOCK_TYPE_RCCK = 12;
-  const unsigned long CARD_LOCK_TYPE_RSPCK = 13;
-  const unsigned long CARD_LOCK_TYPE_NCK_PUK = 14;
-  const unsigned long CARD_LOCK_TYPE_NSCK_PUK = 15;
-  const unsigned long CARD_LOCK_TYPE_NCK1_PUK = 16;
-  const unsigned long CARD_LOCK_TYPE_NCK2_PUK = 17;
-  const unsigned long CARD_LOCK_TYPE_HNCK_PUK = 18;
-  const unsigned long CARD_LOCK_TYPE_CCK_PUK = 19;
-  const unsigned long CARD_LOCK_TYPE_SPCK_PUK = 20;
-  const unsigned long CARD_LOCK_TYPE_PCK_PUK = 21;
-  const unsigned long CARD_LOCK_TYPE_RCCK_PUK = 22;
-  const unsigned long CARD_LOCK_TYPE_RSPCK_PUK = 23;
-  const unsigned long CARD_LOCK_TYPE_FDN = 24;
-
-  // MUST match with enum IccContactType in MozIcc.webidl
-  const unsigned long CARD_CONTACT_TYPE_ADN = 0;
-  const unsigned long CARD_CONTACT_TYPE_FDN = 1;
-  const unsigned long CARD_CONTACT_TYPE_SDN = 2;
-
-  // MUST match with enum IccMvnoType in MozIcc.webidl
-  const unsigned long CARD_MVNO_TYPE_IMSI = 0;
-  const unsigned long CARD_MVNO_TYPE_SPN = 1;
-  const unsigned long CARD_MVNO_TYPE_GID = 2;
-
-  // MUST match with enum IccService in MozIcc.webidl
-  const unsigned long CARD_SERVICE_FDN = 0;
-
   /**
    * Called when a content process registers receiving unsolicited messages from
    * RadioInterfaceLayer in the chrome process. Only a content process that has
    * the 'mobileconnection' permission is allowed to register.
    */
   void registerIccMsg(in unsigned long clientId, in nsIIccListener listener);
   void unregisterIccMsg(in unsigned long clientId, in nsIIccListener listener);
 
   /**
-   * UICC Information
-   */
-  nsIIccInfo getIccInfo(in unsigned long clientId);
-
-  /**
-   * Card State
-   *
-   * One of the nsIIccProvider.CARD_STATE_* values.
-   */
-  unsigned long getCardState(in unsigned long clientId);
-
-  /**
    * STK interfaces.
    */
   void sendStkResponse(in unsigned long clientId,
                        in nsIDOMWindow window,
                        in jsval command,
                        in jsval response);
   void sendStkMenuSelection(in unsigned long clientId,
                             in nsIDOMWindow window,
@@ -169,54 +75,29 @@ interface nsIIccProvider : nsISupports
   void sendStkTimerExpiration(in unsigned long clientId,
                               in nsIDOMWindow window,
                               in jsval timer);
   void sendStkEventDownload(in unsigned long clientId,
                             in nsIDOMWindow window,
                             in jsval event);
 
   /**
-   * Card lock interfaces.
-   */
-  nsIDOMDOMRequest getCardLockEnabled(in unsigned long clientId,
-                                      in nsIDOMWindow window,
-                                      in unsigned long lockType);
-  nsIDOMDOMRequest unlockCardLock(in unsigned long clientId,
-                                  in nsIDOMWindow window,
-                                  in unsigned long lockType,
-                                  in DOMString password,
-                                  [optional] in DOMString newPin);
-  nsIDOMDOMRequest setCardLockEnabled(in unsigned long clientId,
-                                      in nsIDOMWindow window,
-                                      in unsigned long lockType,
-                                      in DOMString password,
-                                      in boolean enabled);
-  nsIDOMDOMRequest changeCardLockPassword(in unsigned long clientId,
-                                          in nsIDOMWindow window,
-                                          in unsigned long lockType,
-                                          in DOMString password,
-                                          in DOMString newPassword);
-  nsIDOMDOMRequest getCardLockRetryCount(in unsigned long clientId,
-                                         in nsIDOMWindow window,
-                                         in unsigned long lockType);
-
-  /**
    * Phonebook interfaces.
    */
   nsIDOMDOMRequest readContacts(in unsigned long clientId,
                                 in nsIDOMWindow window,
                                 in unsigned long contactType);
 
   nsIDOMDOMRequest updateContact(in unsigned long clientId,
                                  in nsIDOMWindow window,
                                  in unsigned long contactType,
                                  in jsval contact,
                                  in DOMString pin2);
 
-/**
+  /**
    * Secure Card Icc communication channel
    */
   void iccOpenChannel(in unsigned long clientId,
                       in DOMString aid,
                       in nsIIccChannelCallback callback);
 
   /**
    * Exchange Command APDU (C-APDU) with SIM on the given logical channel.
@@ -233,21 +114,9 @@ interface nsIIccProvider : nsISupports
                        in octet p2,
                        in short p3,
                        in DOMString data,
                        in nsIIccChannelCallback callback);
 
   void iccCloseChannel(in unsigned long clientId,
                        in long channel,
                        in nsIIccChannelCallback callback);
-
-  /**
-   * Helpers
-   */
-  nsIDOMDOMRequest matchMvno(in unsigned long clientId,
-                             in nsIDOMWindow window,
-                             in unsigned long mvnoType,
-                             in DOMString mvnoData);
-
-  nsISupports getServiceState(in unsigned long clientId,
-                              in nsIDOMWindow window,
-                              in unsigned long service);
 };
new file mode 100644
--- /dev/null
+++ b/dom/icc/interfaces/nsIIccService.idl
@@ -0,0 +1,329 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+interface nsIIcc;
+interface nsIIccInfo;
+
+[scriptable, uuid(7c0ada3d-d8d4-493e-9243-fa3df39855e4)]
+interface nsIIccListener : nsISupports
+{
+  void notifyStkCommand(in DOMString aMessage);
+  void notifyStkSessionEnd();
+  void notifyCardStateChanged();
+  void notifyIccInfoChanged();
+};
+
+/**
+ * A callback interface for handling asynchronous response.
+ */
+[scriptable, uuid(b0e2899a-adc3-11e4-89cf-1b60eaa35b06)]
+interface nsIIccCallback : nsISupports
+{
+  /**
+   * The success callback with no result required:
+   * |unlockCardLock|, |setCardLockEnabled| and |changeCardLockPassword|.
+   */
+  void notifySuccess();
+
+  /**
+   * The success callback with boolean response:
+   * |getCardLockEnabled|, |matchMvno|, and |getServiceStateEnabled|.
+   */
+  void notifySuccessWithBoolean(in boolean aResult);
+
+  /**
+   * The success callback of |getCardLockRetryCount|.
+   *
+   * @param aCount
+   *        The number of remaining retries. -1 if unknown.
+   */
+  void notifyGetCardLockRetryCount(in long aCount);
+
+  /**
+   * The error callback of |getCardLockEnabled|, |getCardLockRetryCount|,
+   * |matchMvno|, and |getServiceStateEnabled|.
+   *
+   * @param aErrorMsg
+   *        The error message.
+   */
+  void notifyError(in DOMString aErrorMsg);
+
+  /**
+   * The error callback of |unlockCardLock|, |setCardLockEnabled| and
+   * |changeCardLockPassword|.
+   *
+   * @param aErrorMsg
+   *        The error message.
+   * @param aRetryCount
+   *        The number of remaining retries. -1 if unknown.
+   */
+  void notifyCardLockError(in DOMString aErrorMsg, in long aRetryCount);
+};
+
+%{C++
+#define ICC_SERVICE_CID \
+  { 0xbab0277a, 0x900e, 0x11e4, { 0x80, 0xc7, 0xdb, 0xd7, 0xad, 0x05, 0x24, 0x01 } }
+#define ICC_SERVICE_CONTRACTID \
+  "@mozilla.org/icc/iccservice;1"
+
+template<typename T> struct already_AddRefed;
+%}
+
+/**
+ * XPCOM Service for the selection of the ICC to be accessed.
+ */
+[scriptable, uuid(6590a04c-9ca4-11e4-ae95-570876ecc428)]
+interface nsIIccService : nsISupports
+{
+  /**
+   * Get Icc instance with specified Service Id.
+   *
+   * @param aServiceId
+   *        Started from 0 to nsIMobileConnectionService.numItems - 1;
+   *
+   * @return a nsIcc instance.
+   */
+  nsIIcc getIccByServiceId(in unsigned long aServiceId);
+};
+
+%{C++
+already_AddRefed<nsIIccService>
+NS_CreateIccService();
+%}
+
+/**
+ * XPCOM component that provides the access to the selected ICC.
+ */
+[scriptable, uuid(38a5bbe2-add6-11e4-ba9e-e390d1d19195)]
+interface nsIIcc : nsISupports
+{
+  /**
+   * Card State Constants
+   *
+   * Note: MUST be matched with enum IccCardState in MozIcc.webidl!
+   */
+  const unsigned long CARD_STATE_UNKNOWN = 0;
+  const unsigned long CARD_STATE_READY = 1;
+  const unsigned long CARD_STATE_PIN_REQUIRED = 2;
+  const unsigned long CARD_STATE_PUK_REQUIRED = 3;
+  const unsigned long CARD_STATE_PERMANENT_BLOCKED = 4;
+  const unsigned long CARD_STATE_PERSONALIZATION_IN_PROGRESS = 5;
+  const unsigned long CARD_STATE_PERSONALIZATION_READY = 6;
+  const unsigned long CARD_STATE_NETWORK_LOCKED = 7;
+  const unsigned long CARD_STATE_NETWORK_SUBSET_LOCKED = 8;
+  const unsigned long CARD_STATE_CORPORATE_LOCKED = 9;
+  const unsigned long CARD_STATE_SERVICE_PROVIDER_LOCKED = 10;
+  const unsigned long CARD_STATE_SIM_LOCKED = 11;
+  const unsigned long CARD_STATE_NETWORK_PUK_REQUIRED = 12;
+  const unsigned long CARD_STATE_NETWORK_SUBSET_PUK_REQUIRED = 13;
+  const unsigned long CARD_STATE_CORPORATE_PUK_REQUIRED = 14;
+  const unsigned long CARD_STATE_SERVICE_PROVIDER_PUK_REQUIRED = 15;
+  const unsigned long CARD_STATE_SIM_PUK_REQUIRED = 16;
+  const unsigned long CARD_STATE_NETWORK1_LOCKED = 17;
+  const unsigned long CARD_STATE_NETWORK2_LOCKED = 18;
+  const unsigned long CARD_STATE_HRPD_NETWORK_LOCKED = 19;
+  const unsigned long CARD_STATE_RUIM_CORPORATE_LOCKED = 20;
+  const unsigned long CARD_STATE_RUIM_SERVICE_PROVIDER_LOCKED = 21;
+  const unsigned long CARD_STATE_RUIM_LOCKED = 22;
+  const unsigned long CARD_STATE_NETWORK1_PUK_REQUIRED = 23;
+  const unsigned long CARD_STATE_NETWORK2_PUK_REQUIRED = 24;
+  const unsigned long CARD_STATE_HRPD_NETWORK_PUK_REQUIRED = 25;
+  const unsigned long CARD_STATE_RUIM_CORPORATE_PUK_REQUIRED = 26;
+  const unsigned long CARD_STATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED = 27;
+  const unsigned long CARD_STATE_RUIM_PUK_REQUIRED = 28;
+  const unsigned long CARD_STATE_ILLEGAL = 29;
+
+  const unsigned long CARD_STATE_UNDETECTED = 4294967295; // UINT32_MAX
+
+  /**
+   * Card Lock Constants
+   *
+   * Note: MUST be matched with enum IccLockType in MozIcc.webidl!
+   */
+  const unsigned long CARD_LOCK_TYPE_PIN = 0;
+  const unsigned long CARD_LOCK_TYPE_PIN2 = 1;
+  const unsigned long CARD_LOCK_TYPE_PUK = 2;
+  const unsigned long CARD_LOCK_TYPE_PUK2 = 3;
+  const unsigned long CARD_LOCK_TYPE_NCK = 4;
+  const unsigned long CARD_LOCK_TYPE_NSCK = 5;
+  const unsigned long CARD_LOCK_TYPE_NCK1 = 6;
+  const unsigned long CARD_LOCK_TYPE_NCK2 = 7;
+  const unsigned long CARD_LOCK_TYPE_HNCK = 8;
+  const unsigned long CARD_LOCK_TYPE_CCK = 9;
+  const unsigned long CARD_LOCK_TYPE_SPCK = 10;
+  const unsigned long CARD_LOCK_TYPE_PCK = 11;
+  const unsigned long CARD_LOCK_TYPE_RCCK = 12;
+  const unsigned long CARD_LOCK_TYPE_RSPCK = 13;
+  const unsigned long CARD_LOCK_TYPE_NCK_PUK = 14;
+  const unsigned long CARD_LOCK_TYPE_NSCK_PUK = 15;
+  const unsigned long CARD_LOCK_TYPE_NCK1_PUK = 16;
+  const unsigned long CARD_LOCK_TYPE_NCK2_PUK = 17;
+  const unsigned long CARD_LOCK_TYPE_HNCK_PUK = 18;
+  const unsigned long CARD_LOCK_TYPE_CCK_PUK = 19;
+  const unsigned long CARD_LOCK_TYPE_SPCK_PUK = 20;
+  const unsigned long CARD_LOCK_TYPE_PCK_PUK = 21;
+  const unsigned long CARD_LOCK_TYPE_RCCK_PUK = 22;
+  const unsigned long CARD_LOCK_TYPE_RSPCK_PUK = 23;
+  const unsigned long CARD_LOCK_TYPE_FDN = 24;
+
+  /**
+   * Contact Type Constants
+   *
+   * Note: MUST be matched with enum IccContactType in MozIcc.webidl!
+   */
+  const unsigned long CARD_CONTACT_TYPE_ADN = 0;
+  const unsigned long CARD_CONTACT_TYPE_FDN = 1;
+  const unsigned long CARD_CONTACT_TYPE_SDN = 2;
+
+  /**
+   * MVNO Type Constants
+   *
+   * Note: MUST be matched with enum IccMvnoType in MozIcc.webidl!
+   */
+  const unsigned long CARD_MVNO_TYPE_IMSI = 0;
+  const unsigned long CARD_MVNO_TYPE_SPN = 1;
+  const unsigned long CARD_MVNO_TYPE_GID = 2;
+
+  /**
+   * Card Service Constants
+   *
+   * Note: MUST be matched with enum IccService in MozIcc.webidl!
+   */
+  const unsigned long CARD_SERVICE_FDN = 0;
+
+  /**
+   * Called to register icc-related changes.
+   *
+   * 'mobileconnection' permission is required to register.
+   */
+  void registerListener(in nsIIccListener aListener);
+  void unregisterListener(in nsIIccListener aListener);
+
+  /**
+   * Information stored in this ICC.
+   */
+  readonly attribute nsIIccInfo iccInfo;
+
+  /**
+   * Indicates the state of this ICC.
+   *
+   * One of the CARD_STATE_* values.
+   */
+  readonly attribute unsigned long cardState;
+
+  /**
+   * Get the status of an ICC lock (e.g. the PIN lock).
+   *
+   * @param aLockType
+   *        One of the CARD_LOCK_TYPE_* values.
+   * @param aCallback
+   *        An instance of nsIIccCallback:
+   *        nsIIccCallback::notifySuccessWithBoolean() if success.
+   *        nsIIccCallback::notifyError(), otherwise.
+   */
+  void getCardLockEnabled(in unsigned long aLockType,
+                          in nsIIccCallback aCallback);
+
+  /**
+   * Unlock a card lock.
+   *
+   * @param aLockType
+   *        One of the CARD_LOCK_TYPE_* values.
+   * @param aPassword
+   *        The password of this lock.
+   * @param aNewPin (Optional)
+   *        The new PIN to be set after PUK/PUK2 is unlock.
+   * @param aCallback
+   *        An instance of nsIIccCallback:
+   *        nsIIccCallback::notifySuccess() if success.
+   *        nsIIccCallback::notifyCardLockError(), otherwise.
+   */
+  void unlockCardLock(in unsigned long aLockType,
+                      in DOMString aPassword,
+                      in DOMString aNewPin,
+                      in nsIIccCallback aCallback);
+
+  /**
+   * Enable/Disable a card lock.
+   *
+   * @param aLockType
+   *        One of the CARD_LOCK_TYPE_* values.
+   * @param aPassword
+   *        The password of this lock.
+   * @param aEnabled.
+   *        True to enable the lock. False to disable, otherwise.
+   * @param aCallback
+   *        An instance of nsIIccCallback:
+   *        nsIIccCallback::notifySuccess() if success.
+   *        nsIIccCallback::notifyCardLockError(), otherwise.
+   */
+  void setCardLockEnabled(in unsigned long aLockType,
+                          in DOMString aPassword,
+                          in boolean aEnabled,
+                          in nsIIccCallback aCallback);
+
+  /**
+   * Change the password of a card lock.
+   *
+   * @param aLockType
+   *        One of the CARD_LOCK_TYPE_* values.
+   * @param aPassword
+   *        The password of this lock.
+   * @param aNewPassword.
+   *        The new password of this lock.
+   * @param aCallback
+   *        An instance of nsIIccCallback:
+   *        nsIIccCallback::notifySuccess() if success.
+   *        nsIIccCallback::notifyCardLockError(), otherwise.
+   */
+  void changeCardLockPassword(in unsigned long aLockType,
+                              in DOMString aPassword,
+                              in DOMString aNewPassword,
+                              in nsIIccCallback aCallback);
+
+  /**
+   * Get the number of remaining tries of a lock.
+   *
+   * @param aLockType
+   *        One of the CARD_LOCK_TYPE_* values.
+   * @param aCallback
+   *        An instance of nsIIccCallback:
+   *        nsIIccCallback::notifyGetCardLockRetryCount() if success.
+   *        nsIIccCallback::notifyError(), otherwise.
+   */
+  void getCardLockRetryCount(in unsigned long aLockType,
+                             in nsIIccCallback aCallback);
+
+  /**
+   * Verify whether the passed data (matchData) matches with some ICC's field
+   * according to the mvno type (mvnoType).
+   *
+   * @param aMvnoType
+   *        One of CARD_MVNO_TYPE_* values.
+   * @param aMvnoData
+   *        Data to be compared with ICC's field.
+   * @param aCallback
+   *        An instance of nsIIccCallback:
+   *        nsIIccCallback::notifySuccessWithBoolean() if success.
+   *        nsIIccCallback::notifyError(), otherwise.
+   */
+  void matchMvno(in unsigned long aMvnoType,
+                 in DOMString aMvnoData,
+                 in nsIIccCallback aCallback);
+
+  /**
+   * Retrieve the the availability of an icc service.
+   *
+   * @param aService
+   *        One of CARD_SERVICE_* values.
+   * @param aCallback
+   *        An instance of nsIIccCallback:
+   *        nsIIccCallback::notifySuccessWithBoolean() if success.
+   *        nsIIccCallback::notifyError(), otherwise.
+   */
+  void getServiceStateEnabled(in unsigned long aService,
+                              in nsIIccCallback aCallback);
+};
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
new file mode 100644
--- /dev/null
+++ b/dom/icc/ipc/PIcc.ipdl
@@ -0,0 +1,111 @@
+/* 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 protocol PContent;
+include protocol PIccRequest;
+include PIccTypes;
+
+using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
+
+namespace mozilla {
+namespace dom {
+namespace icc {
+
+union OptionalIccInfoData
+{
+  void_t;
+  IccInfoData;
+};
+
+struct GetCardLockEnabledRequest
+{
+  uint32_t lockType;
+};
+
+struct UnlockCardLockRequest
+{
+  uint32_t lockType;
+  nsString password;
+  nsString newPin;
+};
+
+struct SetCardLockEnabledRequest
+{
+  uint32_t lockType;
+  nsString password;
+  bool enabled;
+};
+
+struct ChangeCardLockPasswordRequest
+{
+  uint32_t lockType;
+  nsString password;
+  nsString newPassword;
+};
+
+struct GetCardLockRetryCountRequest
+{
+  uint32_t lockType;
+};
+
+struct MatchMvnoRequest
+{
+  uint32_t mvnoType;
+  nsString mvnoData;
+};
+
+struct GetServiceStateEnabledRequest
+{
+  uint32_t service;
+};
+
+union IccRequest
+{
+  GetCardLockEnabledRequest;
+  UnlockCardLockRequest;
+  SetCardLockEnabledRequest;
+  ChangeCardLockPasswordRequest;
+  GetCardLockRetryCountRequest;
+  MatchMvnoRequest;
+  GetServiceStateEnabledRequest;
+};
+
+sync protocol PIcc
+{
+  manager PContent;
+  manages PIccRequest;
+
+child:
+  /**
+   * Notify CardStateChanged with updated CardState.
+   */
+  NotifyCardStateChanged(uint32_t aCardState);
+
+  /**
+   * Notify IccInfoChanged with updated IccInfo.
+   */
+  NotifyIccInfoChanged(OptionalIccInfoData aInfoData);
+
+parent:
+  /**
+   * Sent when the child no longer needs to use PIcc.
+   */
+  __delete__();
+
+  /**
+   * Sent when the child makes an asynchronous request to the parent.
+   */
+  PIccRequest(IccRequest aRequest);
+
+  /**
+   * Sync call to initialize the updated IccInfo/CardState.
+   */
+  sync Init()
+     returns (OptionalIccInfoData aInfoData, uint32_t aCardState);
+
+};
+
+} // namespace icc
+} // namespace dom
+} // namespace mozilla
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/icc/ipc/PIccRequest.ipdl
@@ -0,0 +1,61 @@
+/* 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 protocol PIcc;
+include PIccTypes;
+
+namespace mozilla {
+namespace dom {
+namespace icc {
+
+struct IccReplySuccess
+{
+};
+
+struct IccReplySuccessWithBoolean
+{
+  bool result;
+};
+
+struct IccReplyCardLockRetryCount
+{
+  int32_t count;
+};
+
+struct IccReplyError
+{
+  nsString message;
+};
+
+struct IccReplyCardLockError
+{
+  int32_t retryCount;
+  nsString message;
+};
+
+union IccReply
+{
+  // Success
+  IccReplySuccess;
+  IccReplySuccessWithBoolean;
+  IccReplyCardLockRetryCount;
+  // Error
+  IccReplyError;
+  IccReplyCardLockError;
+};
+
+protocol PIccRequest
+{
+  manager PIcc;
+
+child:
+  /**
+   * Sent when the asynchronous request has completed.
+   */
+  __delete__(IccReply response);
+};
+
+} // namespace icc
+} // namespace dom
+} // namespace mozilla
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/icc/ipc/PIccTypes.ipdlh
@@ -0,0 +1,24 @@
+/* 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/. */
+
+namespace mozilla {
+namespace dom {
+namespace icc {
+
+struct IccInfoData
+{
+  nsString  iccType;
+  nsString  iccid;
+  nsString  mcc;
+  nsString  mnc;
+  nsString  spn;
+  bool      isDisplayNetworkNameRequired;
+  bool      isDisplaySpnRequired;
+  nsString  phoneNumber;
+  int32_t   prlVersion;
+};
+
+} // namespace icc
+} // namespace dom
+} // namespace mozilla
\ No newline at end of file
--- a/dom/icc/moz.build
+++ b/dom/icc/moz.build
@@ -8,29 +8,48 @@ 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',
+    'IccCallback.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',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_B2G_RIL']:
     EXTRA_JS_MODULES += [
         'gonk/StkProactiveCmdFactory.jsm',
     ]
+    EXTRA_COMPONENTS += [
+        'gonk/IccService.js',
+        'gonk/IccService.manifest',
+    ]
 
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
 LOCAL_INCLUDES += [
--- 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,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -16,16 +16,17 @@ include protocol PCycleCollectWithLogs;
 include protocol PCrashReporter;
 include protocol PDocAccessible;
 include protocol PExternalHelperApp;
 include protocol PDeviceStorageRequest;
 include protocol PFileDescriptorSet;
 include protocol PFMRadio;
 include protocol PFileSystemRequest;
 include protocol PHal;
+include protocol PIcc;
 include protocol PProcessHangMonitor;
 include protocol PImageBridge;
 include protocol PMemoryReportRequest;
 include protocol PMobileConnection;
 include protocol PNecko;
 include protocol PPluginModule;
 include protocol PPrinting;
 include protocol POfflineCacheUpdate;
@@ -374,16 +375,17 @@ prio(normal upto urgent) sync protocol P
     manages PCycleCollectWithLogs;
     manages PDocAccessible;
     manages PDeviceStorageRequest;
     manages PFileSystemRequest;
     manages PExternalHelperApp;
     manages PFileDescriptorSet;
     manages PFMRadio;
     manages PHal;
+    manages PIcc;
     manages PMemoryReportRequest;
     manages PMobileConnection;
     manages PNecko;
     manages POfflineCacheUpdate;
     manages PPrinting;
     manages PScreenManager;
     manages PSms;
     manages PSpeechSynthesis;
@@ -650,16 +652,18 @@ parent:
 
     async GetSystemMemory(uint64_t getterId);
 
     sync IsSecureURI(uint32_t type, URIParams uri, uint32_t flags)
         returns (bool isSecureURI);
 
     PHal();
 
+    PIcc(uint32_t serviceId);
+
     PMobileConnection(uint32_t clientId);
 
     PNecko();
 
     PPrinting();
 
     prio(high) sync PScreenManager()
         returns (uint32_t numberOfScreens,
--- a/dom/mobileconnection/MobileConnection.cpp
+++ b/dom/mobileconnection/MobileConnection.cpp
@@ -10,27 +10,24 @@
 #include "mozilla/dom/DataErrorEvent.h"
 #include "mozilla/dom/MozClirModeEvent.h"
 #include "mozilla/dom/MozEmergencyCbModeEvent.h"
 #include "mozilla/dom/MozOtaStatusEvent.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "nsIDOMDOMRequest.h"
+#include "nsIIccInfo.h"
 #include "nsIPermissionManager.h"
 #include "nsIVariant.h"
 #include "nsJSON.h"
 #include "nsJSUtils.h"
 #include "nsRadioInterfaceLayer.h"
 #include "nsServiceManagerUtils.h"
 
-#ifdef MOZ_B2G_RIL
-#include "nsIIccInfo.h"
-#endif // MOZ_B2G_RIL
-
 #define MOBILECONN_ERROR_INVALID_PARAMETER NS_LITERAL_STRING("InvalidParameter")
 #define MOBILECONN_ERROR_INVALID_PASSWORD  NS_LITERAL_STRING("InvalidPassword")
 
 #ifdef CONVERT_STRING_TO_NULLABLE_ENUM
 #undef CONVERT_STRING_TO_NULLABLE_ENUM
 #endif
 #define CONVERT_STRING_TO_NULLABLE_ENUM(_string, _enumType, _enum)      \
 {                                                                       \
@@ -44,28 +41,24 @@
   }                                                                     \
 }
 
 using mozilla::ErrorResult;
 using namespace mozilla::dom;
 using namespace mozilla::dom::mobileconnection;
 
 class MobileConnection::Listener final : public nsIMobileConnectionListener
-#ifdef MOZ_B2G_RIL
                                        , public nsIIccListener
-#endif // MOZ_B2G_RIL
 {
   MobileConnection* mMobileConnection;
 
 public:
   NS_DECL_ISUPPORTS
   NS_FORWARD_SAFE_NSIMOBILECONNECTIONLISTENER(mMobileConnection)
-#ifdef MOZ_B2G_RIL
   NS_FORWARD_SAFE_NSIICCLISTENER(mMobileConnection)
-#endif // MOZ_B2G_RIL
 
   explicit Listener(MobileConnection* aMobileConnection)
     : mMobileConnection(aMobileConnection)
   {
     MOZ_ASSERT(mMobileConnection);
   }
 
   void Disconnect()
@@ -76,40 +69,38 @@ public:
 
 private:
   ~Listener()
   {
     MOZ_ASSERT(!mMobileConnection);
   }
 };
 
-#ifdef MOZ_B2G_RIL
 NS_IMPL_ISUPPORTS(MobileConnection::Listener, nsIMobileConnectionListener,
                   nsIIccListener)
-#else
-NS_IMPL_ISUPPORTS(MobileConnection::Listener, nsIMobileConnectionListener)
-#endif // MOZ_B2G_RIL
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(MobileConnection)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MobileConnection,
                                                   DOMEventTargetHelper)
   // Don't traverse mListener because it doesn't keep any reference to
   // MobileConnection but a raw pointer instead. Neither does mMobileConnection
   // because it's an xpcom service owned object and is only released at shutting
   // down.
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoice)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccHandler)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MobileConnection,
                                                 DOMEventTargetHelper)
   tmp->Shutdown();
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mVoice)
   NS_IMPL_CYCLE_COLLECTION_UNLINK(mData)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mIccHandler)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MobileConnection)
   // MobileConnection does not expose nsIMobileConnectionListener. mListener is
   // the exposed nsIMobileConnectionListener and forwards the calls it receives
   // to us.
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
@@ -131,61 +122,62 @@ MobileConnection::MobileConnection(nsPID
   // for it explicitly below.
   if (!service) {
     NS_WARNING("Could not acquire nsIMobileConnectionService!");
     return;
   }
 
   nsresult rv = service->GetItemByServiceId(mClientId,
                                             getter_AddRefs(mMobileConnection));
-#ifdef MOZ_B2G_RIL
-  mIcc = do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
 
-  if (NS_FAILED(rv) || !mMobileConnection || !mIcc) {
-    NS_WARNING("Could not acquire nsIMobileConnection or nsIIccProvider!");
-#else
   if (NS_FAILED(rv) || !mMobileConnection) {
     NS_WARNING("Could not acquire nsIMobileConnection!");
-#endif // MOZ_B2G_RIL
     return;
   }
 
   mListener = new Listener(this);
   mVoice = new MobileConnectionInfo(GetOwner());
   mData = new MobileConnectionInfo(GetOwner());
 
   if (CheckPermission("mobileconnection")) {
     DebugOnly<nsresult> rv = mMobileConnection->RegisterListener(mListener);
     NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
                      "Failed registering mobile connection messages with service");
     UpdateVoice();
     UpdateData();
 
-#ifdef MOZ_B2G_RIL
-    rv = mIcc->RegisterIccMsg(mClientId, mListener);
+    nsCOMPtr<nsIIccService> iccService = do_GetService(ICC_SERVICE_CONTRACTID);
+
+    if (iccService) {
+      iccService->GetIccByServiceId(mClientId, getter_AddRefs(mIccHandler));
+    }
+
+    if (!mIccHandler) {
+      NS_WARNING("Could not acquire nsIMobileConnection or nsIIcc!");
+      return;
+    }
+
+    rv = mIccHandler->RegisterListener(mListener);
     NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
                      "Failed registering icc messages with service");
     UpdateIccId();
-#endif // MOZ_B2G_RIL
   }
 }
 
 void
 MobileConnection::Shutdown()
 {
   if (mListener) {
     if (mMobileConnection) {
       mMobileConnection->UnregisterListener(mListener);
     }
 
-#ifdef MOZ_B2G_RIL
-    if (mIcc) {
-      mIcc->UnregisterIccMsg(mClientId, mListener);
+    if (mIccHandler) {
+      mIccHandler->UnregisterListener(mListener);
     }
-#endif // MOZ_B2G_RIL
 
     mListener->Disconnect();
     mListener = nullptr;
   }
 }
 
 MobileConnection::~MobileConnection()
 {
@@ -241,32 +233,30 @@ MobileConnection::UpdateData()
   nsCOMPtr<nsIMobileConnectionInfo> info;
   mMobileConnection->GetData(getter_AddRefs(info));
   mData->Update(info);
 }
 
 bool
 MobileConnection::UpdateIccId()
 {
-#ifdef MOZ_B2G_RIL
   nsAutoString iccId;
   nsCOMPtr<nsIIccInfo> iccInfo;
-  if (mIcc &&
-      NS_SUCCEEDED(mIcc->GetIccInfo(mClientId, getter_AddRefs(iccInfo))) &&
+  if (mIccHandler &&
+      NS_SUCCEEDED(mIccHandler->GetIccInfo(getter_AddRefs(iccInfo))) &&
       iccInfo) {
     iccInfo->GetIccid(iccId);
   } else {
     iccId.SetIsVoid(true);
   }
 
   if (!mIccId.Equals(iccId)) {
     mIccId = iccId;
     return true;
   }
-#endif // MOZ_B2G_RIL
 
   return false;
 }
 
 nsresult
 MobileConnection::NotifyError(nsIDOMDOMRequest* aRequest, const nsAString& aMessage)
 {
   nsCOMPtr<nsIDOMRequestService> rs = do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
@@ -1129,17 +1119,16 @@ MobileConnection::NotifyLastKnownHomeNet
 }
 
 NS_IMETHODIMP
 MobileConnection::NotifyNetworkSelectionModeChanged()
 {
   return NS_OK;
 }
 
-#ifdef MOZ_B2G_RIL
 // nsIIccListener
 
 NS_IMETHODIMP
 MobileConnection::NotifyStkCommand(const nsAString& aMessage)
 {
   return NS_OK;
 }
 
@@ -1166,9 +1155,8 @@ MobileConnection::NotifyIccInfoChanged()
     return NS_OK;
   }
 
   nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
     new AsyncEventDispatcher(this, NS_LITERAL_STRING("iccchange"), false);
 
   return asyncDispatcher->PostDOMEvent();
 }
-#endif // MOZ_B2G_RIL
--- a/dom/mobileconnection/MobileConnection.h
+++ b/dom/mobileconnection/MobileConnection.h
@@ -6,48 +6,41 @@
 #define mozilla_dom_MobileConnection_h
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/DOMRequest.h"
 #include "mozilla/dom/MobileConnectionInfo.h"
 #include "mozilla/dom/MobileNetworkInfo.h"
 #include "mozilla/dom/MozMobileConnectionBinding.h"
 #include "nsCycleCollectionParticipant.h"
+#include "nsIIccService.h"
 #include "nsIMobileConnectionService.h"
 #include "nsWeakPtr.h"
 
-#ifdef MOZ_B2G_RIL
-#include "nsIIccProvider.h"
-#endif // MOZ_B2G_RIL
-
 namespace mozilla {
 namespace dom {
 
 class MobileConnection final : public DOMEventTargetHelper
                              , private nsIMobileConnectionListener
-#ifdef MOZ_B2G_RIL
                              , private nsIIccListener
-#endif // MOZ_B2G_RIL
 {
   /**
    * Class MobileConnection doesn't actually expose
    * nsIMobileConnectionListener. Instead, it owns an
    * nsIMobileConnectionListener derived instance mListener and passes it to
    * nsIMobileConnectionService. The onreceived events are first delivered to
    * mListener and then forwarded to its owner, MobileConnection. See also bug
    * 775997 comment #51.
    */
   class Listener;
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIMOBILECONNECTIONLISTENER
-#ifdef MOZ_B2G_RIL
   NS_DECL_NSIICCLISTENER
-#endif // MOZ_B2G_RIL
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MobileConnection,
                                            DOMEventTargetHelper)
 
   MobileConnection(nsPIDOMWindow *aWindow, uint32_t aClientId);
 
   void
   Shutdown();
@@ -164,19 +157,17 @@ public:
 
 private:
   ~MobileConnection();
 
 private:
   uint32_t mClientId;
   nsString mIccId;
   nsCOMPtr<nsIMobileConnection> mMobileConnection;
-#ifdef MOZ_B2G_RIL
-  nsCOMPtr<nsIIccProvider> mIcc;
-#endif // MOZ_B2G_RIL
+  nsCOMPtr<nsIIcc> mIccHandler;
   nsRefPtr<Listener> mListener;
   nsRefPtr<MobileConnectionInfo> mVoice;
   nsRefPtr<MobileConnectionInfo> mData;
 
   bool
   CheckPermission(const char* aType) const;
 
   void
--- a/dom/mobilemessage/gonk/MmsService.js
+++ b/dom/mobilemessage/gonk/MmsService.js
@@ -401,17 +401,17 @@ MmsConnection.prototype = {
     if (!this.connected) {
       this.pendingCallbacks.push(callback);
 
       let errorStatus;
       if (getRadioDisabledState()) {
         if (DEBUG) debug("Error! Radio is disabled when sending MMS.");
         errorStatus = _HTTP_STATUS_RADIO_DISABLED;
       } else if (this.radioInterface.rilContext.cardState !=
-                 Ci.nsIIccProvider.CARD_STATE_READY) {
+                 Ci.nsIIcc.CARD_STATE_READY) {
         if (DEBUG) debug("Error! SIM card is not ready when sending MMS.");
         errorStatus = _HTTP_STATUS_NO_SIM_CARD;
       }
       if (errorStatus != null) {
         this.flushPendingCallbacks(errorStatus);
         return true;
       }
 
--- a/dom/mobilemessage/gonk/SmsService.js
+++ b/dom/mobilemessage/gonk/SmsService.js
@@ -881,17 +881,17 @@ SmsService.prototype = {
       if (!gPhoneNumberUtils.isPlainPhoneNumber(options.number)) {
         if (DEBUG) debug("Error! Address is invalid when sending SMS: " + options.number);
         errorCode = Ci.nsIMobileMessageCallback.INVALID_ADDRESS_ERROR;
       } else if (radioState == Ci.nsIMobileConnection.MOBILE_RADIO_STATE_UNKNOWN ||
                  radioState == Ci.nsIMobileConnection.MOBILE_RADIO_STATE_DISABLED) {
         if (DEBUG) debug("Error! Radio is disabled when sending SMS.");
         errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR;
       } else if (gRadioInterfaces[aServiceId].rilContext.cardState !=
-                 Ci.nsIIccProvider.CARD_STATE_READY) {
+                 Ci.nsIIcc.CARD_STATE_READY) {
         if (DEBUG) debug("Error! SIM card is not ready when sending SMS.");
         errorCode = Ci.nsIMobileMessageCallback.NO_SIM_CARD_ERROR;
       }
       if (errorCode) {
         if (aSilent) {
           aRequest.notifySendMessageFailed(errorCode, aSendingMessage);
           return;
         }
--- a/dom/moz.build
+++ b/dom/moz.build
@@ -59,16 +59,17 @@ DIRS += [
     'encoding',
     'events',
     'fetch',
     'filehandle',
     'filesystem',
     'fmradio',
     'geolocation',
     'html',
+    'icc',
     'json',
     'jsurl',
     'asmjscache',
     'mathml',
     'media',
     'messages',
     'mobileconnection',
     'notification',
@@ -117,17 +118,16 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk
     DIRS += [
         'speakermanager',
         'tethering',
         'wifi',
     ]
 
 if CONFIG['MOZ_B2G_RIL']:
     DIRS += [
-        'icc',
         'wappush',
     ]
 
 if CONFIG['MOZ_PAY']:
     DIRS += ['payment']
 
 if CONFIG['MOZ_GAMEPAD']:
     DIRS += ['gamepad']
--- a/dom/phonenumberutils/PhoneNumberUtils.jsm
+++ b/dom/phonenumberutils/PhoneNumberUtils.jsm
@@ -18,19 +18,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/PhoneNumberNormalizer.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "MCC_ISO3166_TABLE",
                                   "resource://gre/modules/mcc_iso3166_table.jsm");
 
 #ifdef MOZ_B2G_RIL
 XPCOMUtils.defineLazyServiceGetter(this, "mobileConnection",
                                    "@mozilla.org/mobileconnection/mobileconnectionservice;1",
                                    "nsIMobileConnectionService");
-XPCOMUtils.defineLazyServiceGetter(this, "icc",
-                                   "@mozilla.org/ril/content-helper;1",
-                                   "nsIIccProvider");
+XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
+                                   "@mozilla.org/icc/iccservice;1",
+                                   "nsIIccService");
 #endif
 
 this.PhoneNumberUtils = {
   init: function() {
     ppmm.addMessageListener(["PhoneNumberService:FuzzyMatch"], this);
   },
   //  1. See whether we have a network mcc
   //  2. If we don't have that, look for the simcard mcc
@@ -41,32 +41,33 @@ this.PhoneNumberUtils = {
   _mcc: '724',
 
   getCountryName: function getCountryName() {
     let mcc;
     let countryName;
 
 #ifdef MOZ_B2G_RIL
     // TODO: Bug 926740 - PhoneNumberUtils for multisim
-    // In Multi-sim, there is more than one client in 
-    // iccProvider/mobileConnectionProvider. Each client represents a
+    // In Multi-sim, there is more than one client in
+    // iccService/mobileConnectionService. Each client represents a
     // icc/mobileConnection service. To maintain the backward compatibility with
     // single sim, we always use client 0 for now. Adding support for multiple
     // sim will be addressed in bug 926740, if needed.
     let clientId = 0;
 
     // Get network mcc
     let connection = mobileConnection.getItemByServiceId(clientId);
     let voice = connection && connection.voice;
     if (voice && voice.network && voice.network.mcc) {
       mcc = voice.network.mcc;
     }
 
     // Get SIM mcc
-    let iccInfo = icc.getIccInfo(clientId);
+    let icc = gIccService.getIccByServiceId(clientId);
+    let iccInfo = icc && icc.iccInfo;
     if (!mcc && iccInfo && iccInfo.mcc) {
       mcc = iccInfo.mcc;
     }
 
     // Attempt to grab last known sim mcc from prefs
     if (!mcc) {
       try {
         mcc = Services.prefs.getCharPref("ril.lastKnownSimMcc");
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -1810,17 +1810,17 @@ NPError
 
     NPBool success = _convertpoint(instance, 
                                   pluginX,  pluginY, NPCoordinateSpacePlugin, 
                                  &screenX, &screenY, NPCoordinateSpaceScreen);
 
     if (success) {
         return mozilla::plugins::PluginUtilsOSX::ShowCocoaContextMenu(menu,
                                     screenX, screenY,
-                                    PluginModuleChild::GetChrome(),
+                                    InstCast(instance)->Manager(),
                                     ProcessBrowserEvents);
     } else {
         NS_WARNING("Convertpoint failed, could not created contextmenu.");
         return NPERR_GENERIC_ERROR;
     }
 
 #else
     NS_WARNING("Not supported on this platform!");
--- a/dom/push/PushService.jsm
+++ b/dom/push/PushService.jsm
@@ -1770,24 +1770,25 @@ this.PushService = {
     try {
       if (!prefs.get("udp.wakeupEnabled")) {
         debug("UDP support disabled, we do not send any carrier info");
         throw new Error("UDP disabled");
       }
 
       let nm = Cc["@mozilla.org/network/manager;1"].getService(Ci.nsINetworkManager);
       if (nm.active && nm.active.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE) {
-        let icc = Cc["@mozilla.org/ril/content-helper;1"].getService(Ci.nsIIccProvider);
+        let iccService = Cc["@mozilla.org/icc/iccservice;1"].getService(Ci.nsIIccService);
         // TODO: Bug 927721 - PushService for multi-sim
-        // In Multi-sim, there is more than one client in iccProvider. Each
-        // client represents a icc service. To maintain backward compatibility
+        // In Multi-sim, there is more than one client in iccService. Each
+        // client represents a icc handle. To maintain backward compatibility
         // with single sim, we always use client 0 for now. Adding support
         // for multiple sim will be addressed in bug 927721, if needed.
         let clientId = 0;
-        let iccInfo = icc.getIccInfo(clientId);
+        let icc = iccService.getIccByServiceId(clientId);
+        let iccInfo = icc && icc.iccInfo;
         if (iccInfo) {
           debug("Running on mobile data");
 
           let ips = {};
           let prefixLengths = {};
           nm.active.getAddresses(ips, prefixLengths);
 
           return {
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -93,18 +93,18 @@ IccInfo.prototype = {
 
   // nsIIccInfo
 
   iccType: null,
   iccid: null,
   mcc: null,
   mnc: null,
   spn: null,
-  isDisplayNetworkNameRequired: null,
-  isDisplaySpnRequired: null
+  isDisplayNetworkNameRequired: false,
+  isDisplaySpnRequired: false
 };
 
 function GsmIccInfo() {}
 GsmIccInfo.prototype = {
   __proto__: IccInfo.prototype,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIGsmIccInfo,
                                          Ci.nsIIccInfo]),
 
@@ -126,44 +126,49 @@ CdmaIccInfo.prototype = {
 };
 
 function RILContentHelper() {
   this.updateDebugFlag();
 
   this.numClients = gNumRadioInterfaces;
   if (DEBUG) debug("Number of clients: " + this.numClients);
 
+  this._iccs = [];
   this.rilContexts = [];
   for (let clientId = 0; clientId < this.numClients; clientId++) {
+    this._iccs.push(new Icc(this, clientId));
     this.rilContexts[clientId] = {
-      cardState: Ci.nsIIccProvider.CARD_STATE_UNKNOWN,
+      cardState: Ci.nsIIcc.CARD_STATE_UNKNOWN,
       iccInfo: null
     };
   }
 
   this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES);
   this._windowsMap = [];
+  this._requestMap = [];
   this._iccListeners = [];
   this._iccChannelCallback = [];
 
   Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
 
   Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false);
 }
 
 RILContentHelper.prototype = {
   __proto__: DOMRequestIpcHelper.prototype,
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccProvider,
+                                         Ci.nsIIccService,
                                          Ci.nsIObserver,
                                          Ci.nsISupportsWeakReference]),
   classID:   RILCONTENTHELPER_CID,
   classInfo: XPCOMUtils.generateCI({classID: RILCONTENTHELPER_CID,
                                     classDescription: "RILContentHelper",
-                                    interfaces: [Ci.nsIIccProvider]}),
+                                    interfaces: [Ci.nsIIccProvider,
+                                                 Ci.nsIIccService]}),
 
   updateDebugFlag: function() {
     try {
       DEBUG = RIL.DEBUG_CONTENT_HELPER ||
               Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
     } catch (e) {}
   },
 
@@ -201,16 +206,18 @@ RILContentHelper.prototype = {
       }
     }
 
     this.updateInfo(newInfo, rilContext.iccInfo);
   },
 
   _windowsMap: null,
 
+  _requestMap: null,
+
   rilContexts: null,
 
   getRilContext: function(clientId) {
     // Update ril contexts by sending IPC message to chrome only when the first
     // time we require it. The information will be updated by following info
     // changed messages.
     this.getRilContext = function getRilContext(clientId) {
       return this.rilContexts[clientId];
@@ -229,152 +236,16 @@ RILContentHelper.prototype = {
 
     return this.rilContexts[clientId];
   },
 
   /**
    * nsIIccProvider
    */
 
-  getIccInfo: function(clientId) {
-    let context = this.getRilContext(clientId);
-    return context && context.iccInfo;
-  },
-
-  getCardState: function(clientId) {
-    let context = this.getRilContext(clientId);
-    return context && context.cardState;
-  },
-
-  matchMvno: function(clientId, window, mvnoType, mvnoData) {
-    if (window == null) {
-      throw Components.Exception("Can't get window object",
-                                  Cr.NS_ERROR_UNEXPECTED);
-    }
-
-    let request = Services.DOMRequest.createRequest(window);
-    let requestId = this.getRequestId(request);
-
-    cpmm.sendAsyncMessage("RIL:MatchMvno", {
-      clientId: clientId,
-      data: {
-        requestId: requestId,
-        mvnoType: mvnoType,
-        mvnoData: mvnoData
-      }
-    });
-    return request;
-  },
-
-  getCardLockEnabled: function(clientId, window, lockType) {
-    if (window == null) {
-      throw Components.Exception("Can't get window object",
-                                  Cr.NS_ERROR_UNEXPECTED);
-    }
-
-    let request = Services.DOMRequest.createRequest(window);
-    let requestId = this.getRequestId(request);
-    this._windowsMap[requestId] = window;
-
-    cpmm.sendAsyncMessage("RIL:GetCardLockEnabled", {
-      clientId: clientId,
-      data: {
-        lockType: lockType,
-        requestId: requestId
-      }
-    });
-    return request;
-  },
-
-  unlockCardLock: function(clientId, window, lockType, password, newPin) {
-    if (window == null) {
-      throw Components.Exception("Can't get window object",
-                                  Cr.NS_ERROR_UNEXPECTED);
-    }
-
-    let request = Services.DOMRequest.createRequest(window);
-    let requestId = this.getRequestId(request);
-    this._windowsMap[requestId] = window;
-
-    cpmm.sendAsyncMessage("RIL:UnlockCardLock", {
-      clientId: clientId,
-      data: {
-        lockType: lockType,
-        password: password,
-        newPin: newPin,
-        requestId: requestId
-      }
-    });
-    return request;
-  },
-
-  setCardLockEnabled: function(clientId, window, lockType, password, enabled) {
-    if (window == null) {
-      throw Components.Exception("Can't get window object",
-                                  Cr.NS_ERROR_UNEXPECTED);
-    }
-
-    let request = Services.DOMRequest.createRequest(window);
-    let requestId = this.getRequestId(request);
-    this._windowsMap[requestId] = window;
-
-    cpmm.sendAsyncMessage("RIL:SetCardLockEnabled", {
-      clientId: clientId,
-      data: {
-        lockType: lockType,
-        password: password,
-        enabled: enabled,
-        requestId: requestId
-      }
-    });
-    return request;
-  },
-
-  changeCardLockPassword: function(clientId, window, lockType, password,
-                                   newPassword) {
-    if (window == null) {
-      throw Components.Exception("Can't get window object",
-                                  Cr.NS_ERROR_UNEXPECTED);
-    }
-
-    let request = Services.DOMRequest.createRequest(window);
-    let requestId = this.getRequestId(request);
-    this._windowsMap[requestId] = window;
-
-    cpmm.sendAsyncMessage("RIL:ChangeCardLockPassword", {
-      clientId: clientId,
-      data: {
-        lockType: lockType,
-        password: password,
-        newPassword: newPassword,
-        requestId: requestId
-      }
-    });
-    return request;
-  },
-
-  getCardLockRetryCount: function(clientId, window, lockType) {
-    if (window == null) {
-      throw Components.Exception("Can't get window object",
-                                  Cr.NS_ERROR_UNEXPECTED);
-    }
-    let request = Services.DOMRequest.createRequest(window);
-    let requestId = this.getRequestId(request);
-    this._windowsMap[requestId] = window;
-
-    cpmm.sendAsyncMessage("RIL:GetCardLockRetryCount", {
-      clientId: clientId,
-      data: {
-        lockType: lockType,
-        requestId: requestId
-      }
-    });
-    return request;
-  },
-
   sendStkResponse: function(clientId, window, command, response) {
     if (window == null) {
       throw Components.Exception("Can't get window object",
                                   Cr.NS_ERROR_UNEXPECTED);
     }
     response.command = command;
     cpmm.sendAsyncMessage("RIL:SendStkResponse", {
       clientId: clientId,
@@ -540,37 +411,16 @@ RILContentHelper.prototype = {
         contact: iccContact,
         pin2: pin2
       }
     });
 
     return request;
   },
 
-  getServiceState: function(clientId, window, service) {
-    if (window == null) {
-      throw Components.Exception("Can't get window object",
-                                  Cr.NS_ERROR_UNEXPECTED);
-    }
-
-    return new window.Promise((resolve, reject) => {
-      let requestId =
-        this.getPromiseResolverId({resolve: resolve, reject: reject});
-      this._windowsMap[requestId] = window;
-
-      cpmm.sendAsyncMessage("RIL:GetServiceState", {
-        clientId: clientId,
-        data: {
-          requestId: requestId,
-          service: service
-        }
-      });
-    });
-  },
-
   _iccListeners: null,
 
   registerListener: function(listenerType, clientId, listener) {
     if (!this[listenerType]) {
       return;
     }
     let listeners = this[listenerType][clientId];
     if (!listeners) {
@@ -716,72 +566,66 @@ RILContentHelper.prototype = {
     }
 
     let data = msg.json.data;
     let clientId = msg.json.clientId;
     switch (msg.name) {
       case "RIL:CardStateChanged":
         if (this.rilContexts[clientId].cardState != data.cardState) {
           this.rilContexts[clientId].cardState = data.cardState;
-          this._deliverEvent(clientId,
-                             "_iccListeners",
-                             "notifyCardStateChanged",
-                             null);
+          this._deliverIccEvent(clientId,
+                                "notifyCardStateChanged",
+                                null);
         }
         break;
       case "RIL:IccInfoChanged":
         this.updateIccInfo(clientId, data);
-        this._deliverEvent(clientId,
-                           "_iccListeners",
-                           "notifyIccInfoChanged",
-                           null);
+        this._deliverIccEvent(clientId,
+                              "notifyIccInfoChanged",
+                              null);
         break;
       case "RIL:GetCardLockResult": {
         let requestId = data.requestId;
-        let requestWindow = this._windowsMap[requestId];
-        delete this._windowsMap[requestId];
+        let callback = this._requestMap[requestId];
+        delete this._requestMap[requestId];
 
         if (data.errorMsg) {
-          this.fireRequestError(requestId, data.errorMsg);
+          callback.notifyError(data.errorMsg);
           break;
         }
 
-        this.fireRequestSuccess(requestId,
-                                Cu.cloneInto({ enabled: data.enabled },
-                                             requestWindow));
+        callback.notifySuccessWithBoolean(data.enabled);
         break;
       }
       case "RIL:SetUnlockCardLockResult": {
         let requestId = data.requestId;
-        let requestWindow = this._windowsMap[requestId];
-        delete this._windowsMap[requestId];
+        let callback = this._requestMap[requestId];
+        delete this._requestMap[requestId];
 
         if (data.errorMsg) {
-          let cardLockError = new requestWindow.IccCardLockError(data.errorMsg,
-                                                                 data.retryCount);
-          this.fireRequestDetailedError(requestId, cardLockError);
+          let retryCount =
+            (data.retryCount !== undefined) ? data.retryCount : -1;
+          callback.notifyCardLockError(data.errorMsg, retryCount);
           break;
         }
 
-        this.fireRequestSuccess(requestId, null);
+        callback.notifySuccess();
         break;
       }
       case "RIL:CardLockRetryCount": {
         let requestId = data.requestId;
-        let requestWindow = this._windowsMap[requestId];
-        delete this._windowsMap[requestId];
+        let callback = this._requestMap[requestId];
+        delete this._requestMap[requestId];
 
         if (data.errorMsg) {
-          this.fireRequestError(data.requestId, data.errorMsg);
+          callback.notifyError(data.errorMsg);
           break;
         }
 
-        this.fireRequestSuccess(data.requestId,
-                                Cu.cloneInto({ retryCount: data.retryCount },
-                                             requestWindow));
+        callback.notifyGetCardLockRetryCount(data.retryCount);
         break;
       }
       case "RIL:StkCommand":
         this._deliverEvent(clientId, "_iccListeners", "notifyStkCommand",
                            [JSON.stringify(data)]);
         break;
       case "RIL:StkSessionEnd":
         this._deliverEvent(clientId, "_iccListeners", "notifyStkSessionEnd", null);
@@ -796,22 +640,40 @@ RILContentHelper.prototype = {
         this.handleIccExchangeAPDU(data);
         break;
       case "RIL:ReadIccContacts":
         this.handleReadIccContacts(data);
         break;
       case "RIL:UpdateIccContact":
         this.handleUpdateIccContact(data);
         break;
-      case "RIL:MatchMvno":
-        this.handleSimpleRequest(data.requestId, data.errorMsg, data.result);
+      case "RIL:MatchMvno": {
+        let requestId = data.requestId;
+        let callback = this._requestMap[requestId];
+        delete this._requestMap[requestId];
+
+        if (data.errorMsg) {
+          callback.notifyError(data.errorMsg);
+          break;
+        }
+        callback.notifySuccessWithBoolean(data.result);
         break;
-      case "RIL:GetServiceState":
-        this.handleGetServiceState(data);
+      }
+      case "RIL:GetServiceState": {
+        let requestId = data.requestId;
+        let callback = this._requestMap[requestId];
+        delete this._requestMap[requestId];
+
+        if (data.errorMsg) {
+          callback.notifyError(data.errorMsg);
+          break;
+        }
+        callback.notifySuccessWithBoolean(data.result);
         break;
+      }
     }
   },
 
   handleSimpleRequest: function(requestId, errorMsg, result) {
     if (errorMsg) {
       this.fireRequestError(requestId, errorMsg);
     } else {
       this.fireRequestSuccess(requestId, result);
@@ -904,30 +766,16 @@ RILContentHelper.prototype = {
     }
 
     let contact = new window.mozContact(prop);
     contact.id = iccContact.contactId;
 
     this.fireRequestSuccess(message.requestId, contact);
   },
 
-  handleGetServiceState: function(message) {
-    let requestId = message.requestId;
-    let requestWindow = this._windowsMap[requestId];
-    delete this._windowsMap[requestId];
-
-    let resolver = this.takePromiseResolver(requestId);
-    if (message.errorMsg) {
-      resolver.reject(new requestWindow.DOMError(message.errorMsg));
-      return;
-    }
-
-    resolver.resolve(message.result);
-  },
-
   _deliverEvent: function(clientId, listenerType, name, args) {
     if (!this[listenerType]) {
       return;
     }
     let thisListeners = this[listenerType][clientId];
     if (!thisListeners) {
       return;
     }
@@ -942,12 +790,241 @@ RILContentHelper.prototype = {
         throw new Error("No handler for " + name);
       }
       try {
         handler.apply(listener, args);
       } catch (e) {
         if (DEBUG) debug("listener for " + name + " threw an exception: " + e);
       }
     }
+  },
+
+  /**
+   * nsIIccService interface.
+   */
+
+  _iccs: null, // An array of Icc instances.
+
+  getIccByServiceId: function(serviceId) {
+    let icc = this._iccs[serviceId];
+    if (!icc) {
+      throw Cr.NS_ERROR_UNEXPECTED;
+    }
+
+    return icc;
+  },
+
+  /**
+   * Bridge APIs from nsIIccService to nsIIccProvider
+   */
+
+  _deliverIccEvent: function(clientId, name, args) {
+    let icc = this._iccs[clientId];
+    if (!icc) {
+      if (DEBUG) debug("_deliverIccEvent: Invalid clientId: " + clientId);
+      return;
+    }
+
+    icc.deliverListenerEvent(name, args);
+  },
+
+  getIccInfo: function(clientId) {
+    let context = this.getRilContext(clientId);
+    return context && context.iccInfo;
+  },
+
+  getCardState: function(clientId) {
+    let context = this.getRilContext(clientId);
+    return context && context.cardState;
+  },
+
+  matchMvno: function(clientId, mvnoType, mvnoData, callback) {
+    let requestId = UUIDGenerator.generateUUID().toString();
+    this._requestMap[requestId] = callback;
+
+    cpmm.sendAsyncMessage("RIL:MatchMvno", {
+      clientId: clientId,
+      data: {
+        requestId: requestId,
+        mvnoType: mvnoType,
+        mvnoData: mvnoData
+      }
+    });
+  },
+
+  getCardLockEnabled: function(clientId, lockType, callback) {
+    let requestId = UUIDGenerator.generateUUID().toString();
+    this._requestMap[requestId] = callback;
+
+    cpmm.sendAsyncMessage("RIL:GetCardLockEnabled", {
+      clientId: clientId,
+      data: {
+        lockType: lockType,
+        requestId: requestId
+      }
+    });
+  },
+
+  unlockCardLock: function(clientId, lockType, password, newPin, callback) {
+    let requestId = UUIDGenerator.generateUUID().toString();
+    this._requestMap[requestId] = callback;
+
+    cpmm.sendAsyncMessage("RIL:UnlockCardLock", {
+      clientId: clientId,
+      data: {
+        lockType: lockType,
+        password: password,
+        newPin: newPin,
+        requestId: requestId
+      }
+    });
+  },
+
+  setCardLockEnabled: function(clientId, lockType, password, enabled, callback) {
+    let requestId = UUIDGenerator.generateUUID().toString();
+    this._requestMap[requestId] = callback;
+
+    cpmm.sendAsyncMessage("RIL:SetCardLockEnabled", {
+      clientId: clientId,
+      data: {
+        lockType: lockType,
+        password: password,
+        enabled: enabled,
+        requestId: requestId
+      }
+    });
+  },
+
+  changeCardLockPassword: function(clientId, lockType, password, newPassword,
+                                   callback) {
+    let requestId = UUIDGenerator.generateUUID().toString();
+    this._requestMap[requestId] = callback;
+
+    cpmm.sendAsyncMessage("RIL:ChangeCardLockPassword", {
+      clientId: clientId,
+      data: {
+        lockType: lockType,
+        password: password,
+        newPassword: newPassword,
+        requestId: requestId
+      }
+    });
+  },
+
+  getCardLockRetryCount: function(clientId, lockType, callback) {
+    let requestId = UUIDGenerator.generateUUID().toString();
+    this._requestMap[requestId] = callback;
+
+    cpmm.sendAsyncMessage("RIL:GetCardLockRetryCount", {
+      clientId: clientId,
+      data: {
+        lockType: lockType,
+        requestId: requestId
+      }
+    });
+  },
+
+  getServiceStateEnabled: function(clientId, service, callback) {
+    let requestId = UUIDGenerator.generateUUID().toString();
+    this._requestMap[requestId] = callback;
+
+    cpmm.sendAsyncMessage("RIL:GetServiceState", {
+      clientId: clientId,
+      data: {
+        requestId: requestId,
+        service: service
+      }
+    });
+  }
+};
+
+function Icc(aIccProvider, aClientId) {
+  this._iccProvider = aIccProvider;
+  this._clientId = aClientId;
+  this._listeners = [];
+}
+Icc.prototype = {
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIIcc]),
+
+  _iccProvider: null,
+  _clientId: -1,
+  _listeners: null,
+
+  deliverListenerEvent: function(aName, aArgs) {
+    let listeners = this._listeners.slice();
+    for (let listener of listeners) {
+      if (this._listeners.indexOf(listener) === -1) {
+        continue;
+      }
+      let handler = listener[aName];
+      if (typeof handler != "function") {
+        throw new Error("No handler for " + aName);
+      }
+      try {
+        handler.apply(listener, aArgs);
+      } catch (e) {
+        if (DEBUG) {
+          debug("listener for " + aName + " threw an exception: " + e);
+        }
+      }
+    }
+  },
+
+  /**
+   * nsIIcc interface.
+   */
+  registerListener: function(aListener) {
+    if (this._listeners.indexOf(aListener) >= 0) {
+      throw Cr.NS_ERROR_UNEXPECTED;
+    }
+
+    this._listeners.push(aListener);
+    cpmm.sendAsyncMessage("RIL:RegisterIccMsg");
+  },
+
+  unregisterListener: function(aListener) {
+    let index = this._listeners.indexOf(aListener);
+    if (index >= 0) {
+      this._listeners.splice(index, 1);
+    }
+  },
+
+  get iccInfo() {
+    return this._iccProvider.getIccInfo(this._clientId);
+  },
+
+  get cardState() {
+    return this._iccProvider.getCardState(this._clientId);
+  },
+
+  getCardLockEnabled: function(aLockType, aCallback) {
+    this._iccProvider.getCardLockEnabled(this._clientId, aLockType, aCallback);
+  },
+
+  unlockCardLock: function(aLockType, aPassword, aNewPin, aCallback) {
+    this._iccProvider.unlockCardLock(this._clientId, aLockType,
+                                     aPassword, aNewPin, aCallback);
+  },
+
+  setCardLockEnabled: function(aLockType, aPassword, aEnabled, aCallback) {
+    this._iccProvider.setCardLockEnabled(this._clientId, aLockType,
+                                         aPassword, aEnabled, aCallback);
+  },
+
+  changeCardLockPassword: function(aLockType, aPassword, aNewPassword, aCallback) {
+    this._iccProvider.changeCardLockPassword(this._clientId, aLockType,
+                                             aPassword, aNewPassword, aCallback);
+  },
+
+  getCardLockRetryCount: function(aLockType, aCallback) {
+    this._iccProvider.getCardLockRetryCount(this._clientId, aLockType, aCallback);
+  },
+
+  matchMvno: function(aMvnoType, aMvnoData, aCallback) {
+    this._iccProvider.matchMvno(this._clientId, aMvnoType, aMvnoData, aCallback);
+  },
+
+  getServiceStateEnabled: function(aService, aCallback) {
+    this._iccProvider.getServiceStateEnabled(this._clientId, aService, aCallback);
   }
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RILContentHelper]);
--- a/dom/system/gonk/RILContentHelper.manifest
+++ b/dom/system/gonk/RILContentHelper.manifest
@@ -8,11 +8,13 @@
 #
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 # RILContentHelper.js
+# TODO: Bug 815526, deprecate RILContentHelper:
+#       To be removed from b2g/installer/package-manifest.in as well.
 component {472816e1-1fd6-4405-996c-806f9ea68174} RILContentHelper.js
 contract @mozilla.org/ril/content-helper;1 {472816e1-1fd6-4405-996c-806f9ea68174}
 category profile-after-change RILContentHelper @mozilla.org/ril/content-helper;1
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -82,16 +82,17 @@ const INT32_MAX = 2147483647;
 const NETWORK_TYPE_UNKNOWN     = Ci.nsINetworkInterface.NETWORK_TYPE_UNKNOWN;
 const NETWORK_TYPE_WIFI        = Ci.nsINetworkInterface.NETWORK_TYPE_WIFI;
 const NETWORK_TYPE_MOBILE      = Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE;
 const NETWORK_TYPE_MOBILE_MMS  = Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS;
 const NETWORK_TYPE_MOBILE_SUPL = Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL;
 const NETWORK_TYPE_MOBILE_IMS  = Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_IMS;
 const NETWORK_TYPE_MOBILE_DUN  = Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN;
 
+// TODO: Bug 815526, deprecate RILContentHelper.
 const RIL_IPC_ICCMANAGER_MSG_NAMES = [
   "RIL:GetRilContext",
   "RIL:SendStkResponse",
   "RIL:SendStkMenuSelection",
   "RIL:SendStkTimerExpiration",
   "RIL:SendStkEventDownload",
   "RIL:GetCardLockEnabled",
   "RIL:UnlockCardLock",
@@ -122,16 +123,20 @@ function updateDebugFlag() {
   DEBUG = RIL.DEBUG_RIL || debugPref;
 }
 updateDebugFlag();
 
 function debug(s) {
   dump("-*- RadioInterfaceLayer: " + s + "\n");
 }
 
+XPCOMUtils.defineLazyServiceGetter(this, "gIccService",
+                                   "@mozilla.org/icc/gonkiccservice;1",
+                                   "nsIGonkIccService");
+
 XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageService",
                                    "@mozilla.org/mobilemessage/mobilemessageservice;1",
                                    "nsIMobileMessageService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gSmsService",
                                    "@mozilla.org/sms/gonksmsservice;1",
                                    "nsIGonkSmsService");
 
@@ -172,16 +177,17 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "nsIIccMessenger");
 
 XPCOMUtils.defineLazyGetter(this, "gStkCmdFactory", function() {
   let stk = {};
   Cu.import("resource://gre/modules/StkProactiveCmdFactory.jsm", stk);
   return stk.StkProactiveCmdFactory;
 });
 
+// TODO: Bug 815526, deprecate RILContentHelper.
 XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
   return {
     QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
                                            Ci.nsIObserver]),
 
     ril: null,
 
     // Manage message targets in terms of topic. Only the authorized and
@@ -881,18 +887,18 @@ IccInfo.prototype = {
 
   // nsIIccInfo
 
   iccType: null,
   iccid: null,
   mcc: null,
   mnc: null,
   spn: null,
-  isDisplayNetworkNameRequired: null,
-  isDisplaySpnRequired: null
+  isDisplayNetworkNameRequired: false,
+  isDisplaySpnRequired: false
 };
 
 function GsmIccInfo() {}
 GsmIccInfo.prototype = {
   __proto__: IccInfo.prototype,
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIGsmIccInfo,
                                          Ci.nsIIccInfo]),
 
@@ -1418,28 +1424,29 @@ function RadioInterfaceLayer() {
   this.radioInterfaces = [];
   for (let clientId = 0; clientId < numIfaces; clientId++) {
     this.radioInterfaces.push(new RadioInterface(clientId, workerMessenger));
   }
 
   Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
   Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false);
 
-  gMessageManager.init(this);
+  gMessageManager.init(this); // TODO: Bug 815526, deprecate RILContentHelper.
   gRadioEnabledController.init(this);
   gDataConnectionManager.init(this);
 }
 RadioInterfaceLayer.prototype = {
 
   classID:   RADIOINTERFACELAYER_CID,
   classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACELAYER_CID,
                                     classDescription: "RadioInterfaceLayer",
                                     interfaces: [Ci.nsIRadioInterfaceLayer]}),
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIRadioInterfaceLayer,
+                                         Ci.nsIRadioInterfaceLayer_new, // TODO: Bug 815526, deprecate RILContentHelper.
                                          Ci.nsIObserver]),
 
   /**
    * nsIObserver interface methods.
    */
 
   observe: function(subject, topic, data) {
     switch (topic) {
@@ -1671,23 +1678,24 @@ WorkerMessenger.prototype = {
     }).bind(this));
   }
 };
 
 function RadioInterface(aClientId, aWorkerMessenger) {
   this.clientId = aClientId;
   this.workerMessenger = {
     send: aWorkerMessenger.send.bind(aWorkerMessenger, aClientId),
+    // TODO: Bug 815526, deprecate RILContentHelper.
     sendWithIPCMessage:
       aWorkerMessenger.sendWithIPCMessage.bind(aWorkerMessenger, aClientId),
   };
   aWorkerMessenger.registerClient(aClientId, this);
 
   this.rilContext = {
-    cardState:      Ci.nsIIccProvider.CARD_STATE_UNKNOWN,
+    cardState:      Ci.nsIIcc.CARD_STATE_UNKNOWN,
     iccInfo:        null,
     imsi:           null
   };
 
   this.operatorInfo = {};
 
   let lock = gSettingsService.createLock();
 
@@ -1775,22 +1783,24 @@ RadioInterface.prototype = {
       }
     }
 
     return false;
   },
 
   isCardPresent: function() {
     let cardState = this.rilContext.cardState;
-    return cardState !== Ci.nsIIccProvider.CARD_STATE_UNDETECTED &&
-      cardState !== Ci.nsIIccProvider.CARD_STATE_UNKNOWN;
+    return cardState !== Ci.nsIIcc.CARD_STATE_UNDETECTED &&
+      cardState !== Ci.nsIIcc.CARD_STATE_UNKNOWN;
   },
 
   /**
    * Process a message from the content process.
+   *
+   * TODO: Bug 815526, deprecate RILContentHelper
    */
   receiveMessage: function(msg) {
     switch (msg.name) {
       case "RIL:GetRilContext":
         // This message is sync.
         return this.rilContext;
       case "RIL:GetCardLockEnabled":
         this.workerMessenger.sendWithIPCMessage(msg, "iccGetCardLockEnabled",
@@ -1911,16 +1921,19 @@ RadioInterface.prototype = {
         // gRadioEnabledController should know the radio state for each client,
         // so notify gRadioEnabledController here.
         gRadioEnabledController.notifyRadioStateChanged(this.clientId,
                                                         message.radioState);
         break;
       case "cardstatechange":
         this.rilContext.cardState = message.cardState;
         gRadioEnabledController.receiveCardState(this.clientId);
+        gIccService.notifyCardStateChanged(this.clientId,
+                                           this.rilContext.cardState);
+        // TODO: Bug 815526, deprecate RILContentHelper.
         gMessageManager.sendIccMessage("RIL:CardStateChanged",
                                        this.clientId, message);
         break;
       case "sms-received":
         this.handleSmsReceived(message);
         break;
       case "cellbroadcast-received":
         this.handleCellbroadcastMessageReceived(message);
@@ -1928,42 +1941,45 @@ RadioInterface.prototype = {
       case "nitzTime":
         this.handleNitzTime(message);
         break;
       case "iccinfochange":
         this.handleIccInfoChange(message);
         break;
       case "iccimsi":
         this.rilContext.imsi = message.imsi;
+        gIccService.notifyImsiChanged(this.clientId, this.rilContext.imsi);
         break;
       case "iccmbdn":
         this.handleIccMbdn(message);
         break;
       case "iccmwis":
         this.handleIccMwis(message.mwi);
         break;
       case "stkcommand":
         this.handleStkProactiveCommand(message);
         break;
       case "stksessionend":
+        // TODO: Bug 815526, deprecate RILContentHelper.
         gMessageManager.sendIccMessage("RIL:StkSessionEnd", this.clientId, null);
         break;
       case "cdma-info-rec-received":
         this.handleCdmaInformationRecords(message.records);
         break;
       default:
         throw new Error("Don't know about this message type: " +
                         message.rilMessageType);
     }
   },
 
   // Matches the mvnoData pattern with imsi. Characters 'x' and 'X' are skipped
   // and not compared. E.g., if the mvnoData passed is '310260x10xxxxxx',
   // then the function returns true only if imsi has the same first 6 digits,
   // 8th and 9th digit.
+  // TODO: Bug 815526, deprecate RILContentHelper.
   isImsiMatches: function(mvnoData) {
     let imsi = this.rilContext.imsi;
 
     // This should not be an error, but a mismatch.
     if (mvnoData.length > imsi.length) {
       return false;
     }
 
@@ -1971,16 +1987,17 @@ RadioInterface.prototype = {
       let c = mvnoData[i];
       if ((c !== 'x') && (c !== 'X') && (c !== imsi[i])) {
         return false;
       }
     }
     return true;
   },
 
+  // TODO: Bug 815526, deprecate RILContentHelper.
   matchMvno: function(target, message) {
     if (DEBUG) this.debug("matchMvno: " + JSON.stringify(message));
 
     if (!message || !message.mvnoData) {
       message.errorMsg = RIL.GECKO_ERROR_INVALID_PARAMETER;
     }
 
     if (!message.errorMsg) {
@@ -2208,16 +2225,18 @@ RadioInterface.prototype = {
     // Note: returnNumber and returnMessage is not available from UICC.
     service.notifyStatusChanged(this.clientId, mwi.active, mwi.msgCount,
                                 null, null);
   },
 
   handleIccInfoChange: function(message) {
     let oldSpn = this.rilContext.iccInfo ? this.rilContext.iccInfo.spn : null;
 
+    // TODO: Bug 815526, deprecate RILContentHelper:
+    //       Move the logic of updating iccInfo to IccService.js.
     if (!message || !message.iccid) {
       // If iccInfo is already `null`, don't have to clear it and send
       // RIL:IccInfoChanged.
       if (!this.rilContext.iccInfo) {
         return;
       }
 
       // Card is not detected, clear iccInfo to null.
@@ -2237,27 +2256,21 @@ RadioInterface.prototype = {
         return;
       }
 
       this.updateInfo(message, this.rilContext.iccInfo);
     }
 
     // RIL:IccInfoChanged corresponds to a DOM event that gets fired only
     // when iccInfo has changed.
+    // TODO: Bug 815526, deprecate RILContentHelper.
     gMessageManager.sendIccMessage("RIL:IccInfoChanged",
                                    this.clientId,
                                    message.iccid ? message : null);
-
-    // Update lastKnownSimMcc.
-    if (message.mcc) {
-      try {
-        Services.prefs.setCharPref("ril.lastKnownSimMcc",
-                                   message.mcc.toString());
-      } catch (e) {}
-    }
+    gIccService.notifyIccInfoChanged(this.clientId, this.rilContext.iccInfo);
 
     // Update lastKnownHomeNetwork.
     if (message.mcc && message.mnc) {
       let lastKnownHomeNetwork = message.mcc + "-" + message.mnc;
       // Append spn information if available.
       if (message.spn) {
         lastKnownHomeNetwork += "-" + message.spn;
       }
@@ -2275,16 +2288,17 @@ RadioInterface.prototype = {
   handleStkProactiveCommand: function(message) {
     if (DEBUG) this.debug("handleStkProactiveCommand " + JSON.stringify(message));
     let iccId = this.rilContext.iccInfo && this.rilContext.iccInfo.iccid;
     if (iccId) {
       gIccMessenger
         .notifyStkProactiveCommand(iccId,
                                    gStkCmdFactory.createCommand(message));
     }
+    // TODO: Bug 815526, deprecate RILContentHelper.
     gMessageManager.sendIccMessage("RIL:StkCommand", this.clientId, message);
   },
 
   _convertCbGsmGeographicalScope: function(aGeographicalScope) {
     return (aGeographicalScope != null)
       ? aGeographicalScope
       : Ci.nsICellBroadcastService.GSM_GEOGRAPHICAL_SCOPE_INVALID;
   },
--- a/dom/system/gonk/moz.build
+++ b/dom/system/gonk/moz.build
@@ -84,18 +84,18 @@ EXTRA_JS_MODULES += [
     'systemlibs.js',
 ]
 
 if CONFIG['MOZ_B2G_RIL']:
     XPIDL_SOURCES += [
         'nsIRadioInterfaceLayer.idl',
     ]
     EXTRA_COMPONENTS += [
-        'RILContentHelper.js',
-        'RILContentHelper.manifest',
+        'RILContentHelper.js', # TODO: Bug 815526, deprecate RILContentHelper.
+        'RILContentHelper.manifest', # TODO: Bug 815526, deprecate RILContentHelper.
         'RILSystemMessengerHelper.js',
         'RILSystemMessengerHelper.manifest',
     ]
     EXTRA_JS_MODULES += [
         'ril_consts.js',
         'ril_worker.js',
         'ril_worker_buf_object.js',
         'RILSystemMessenger.jsm',
--- a/dom/system/gonk/nsIRadioInterfaceLayer.idl
+++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl
@@ -20,17 +20,17 @@ interface nsIRilNetworkInterface : nsINe
   readonly attribute DOMString mmsProxy; // Empty string if not set.
   readonly attribute long      mmsPort;  // -1 if not set.
 };
 
 [scriptable, uuid(4441e660-4ad0-11e4-916c-0800200c9a66)]
 interface nsIRilContext : nsISupports
 {
   /**
-   * One of the nsIIccProvider.CARD_STATE_* values.
+   * One of the nsIIcc.CARD_STATE_* values.
    */
   readonly attribute unsigned long cardState;
 
   readonly attribute DOMString imsi;
 
   readonly attribute nsIIccInfo iccInfo;
 };
 
@@ -74,8 +74,18 @@ interface nsIRadioInterfaceLayer : nsISu
    * Select a proper client for dialing emergency call.
    *
    * @return clientId or -1 if none of the clients are avaialble.
    */
   unsigned long getClientIdForEmergencyCall();
 
   void setMicrophoneMuted(in boolean muted);
 };
+
+
+/**
+ * Helper Interface to define new APIs of nsIRadioInterfaceLayer during
+ * ril-interfaces frozen phase.
+ */
+[scriptable, uuid(f8ec63da-c22e-11e4-89f3-b767dae42a13)]
+interface nsIRadioInterfaceLayer_new : nsIRadioInterfaceLayer
+{
+};
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -2572,17 +2572,17 @@ this.CALL_FAIL_ERROR_UNSPECIFIED = 0xfff
 
 // See nsIMobileConnection::MOBILE_RADIO_STATE_*
 this.GECKO_RADIOSTATE_UNKNOWN   = -1;
 this.GECKO_RADIOSTATE_ENABLED   = 0;
 this.GECKO_RADIOSTATE_DISABLED  = 1;
 
 // Only used in ril_worker.js
 this.GECKO_CARDSTATE_UNINITIALIZED = 4294967294; // UINT32_MAX - 1
-// See nsIIccProvider::CARD_STATE_*
+// See nsIIcc::CARD_STATE_*
 this.GECKO_CARDSTATE_UNDETECTED = 4294967295; // UINT32_MAX
 this.GECKO_CARDSTATE_UNKNOWN = 0;
 this.GECKO_CARDSTATE_READY = 1;
 this.GECKO_CARDSTATE_PIN_REQUIRED = 2;
 this.GECKO_CARDSTATE_PUK_REQUIRED = 3;
 this.GECKO_CARDSTATE_PERMANENT_BLOCKED = 4;
 this.GECKO_CARDSTATE_PERSONALIZATION_IN_PROGRESS = 5;
 this.GECKO_CARDSTATE_PERSONALIZATION_READY = 6;
@@ -2605,17 +2605,17 @@ this.GECKO_CARDSTATE_RUIM_LOCKED = 22;
 this.GECKO_CARDSTATE_NETWORK1_PUK_REQUIRED = 23;
 this.GECKO_CARDSTATE_NETWORK2_PUK_REQUIRED = 24;
 this.GECKO_CARDSTATE_HRPD_NETWORK_PUK_REQUIRED = 25;
 this.GECKO_CARDSTATE_RUIM_CORPORATE_PUK_REQUIRED = 26;
 this.GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED = 27;
 this.GECKO_CARDSTATE_RUIM_PUK_REQUIRED = 28;
 this.GECKO_CARDSTATE_ILLEGAL = 29;
 
-// See nsIIccProvider::CARD_LOCK_TYPE_*
+// See nsIIcc::CARD_LOCK_TYPE_*
 this.GECKO_CARDLOCK_PIN = 0;
 this.GECKO_CARDLOCK_PIN2 = 1;
 this.GECKO_CARDLOCK_PUK = 2;
 this.GECKO_CARDLOCK_PUK2 = 3;
 this.GECKO_CARDLOCK_NCK = 4;
 this.GECKO_CARDLOCK_NSCK = 5;
 this.GECKO_CARDLOCK_NCK1 = 6;
 this.GECKO_CARDLOCK_NCK2 = 7;
@@ -2648,27 +2648,27 @@ GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOC
 GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_PUK2] = ICC_SEL_CODE_SIM_PUK2;
 GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_NCK] = ICC_SEL_CODE_PH_NET_PIN;
 GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_NSCK] = ICC_SEL_CODE_PH_NETSUB_PIN;
 GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_CCK] = ICC_SEL_CODE_PH_CORP_PIN;
 GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_SPCK] = ICC_SEL_CODE_PH_SP_PIN;
 // TODO: Bug 1116072: identify the mapping between RIL_PERSOSUBSTATE_SIM_SIM @
 //       ril.h and TS 27.007, clause 8.65 for GECKO_CARDLOCK_PCK.
 
-// See nsIIccProvider::CARD_CONTACT_TYPE_*
+// See nsIIcc::CARD_CONTACT_TYPE_*
 this.GECKO_CARDCONTACT_TYPE_ADN = 0;
 this.GECKO_CARDCONTACT_TYPE_FDN = 1;
 this.GECKO_CARDCONTACT_TYPE_SDN = 2;
 
-// See nsIIccProvider::CARD_MVNO_TYPE_*
+// See nsIIcc::CARD_MVNO_TYPE_*
 this.GECKO_CARDMVNO_TYPE_IMSI = 0;
 this.GECKO_CARDMVNO_TYPE_SPN = 1;
 this.GECKO_CARDMVNO_TYPE_GID = 2;
 
-// See nsIIccProvider::CARD_MVNO_TYPE_*
+// See nsIIcc::CARD_SERVICE_*
 this.GECKO_CARDSERVICE_FDN = 0;
 
 // See ril.h RIL_PersoSubstate
 this.PERSONSUBSTATE = {};
 PERSONSUBSTATE[CARD_PERSOSUBSTATE_UNKNOWN] = GECKO_CARDSTATE_UNKNOWN;
 PERSONSUBSTATE[CARD_PERSOSUBSTATE_IN_PROGRESS] = GECKO_CARDSTATE_PERSONALIZATION_IN_PROGRESS;
 PERSONSUBSTATE[CARD_PERSOSUBSTATE_READY] = GECKO_CARDSTATE_PERSONALIZATION_READY;
 PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_NETWORK] = GECKO_CARDSTATE_NETWORK_LOCKED;
--- a/dom/system/gonk/tests/marionette/test_ril_code_quality.py
+++ b/dom/system/gonk/tests/marionette/test_ril_code_quality.py
@@ -1,13 +1,13 @@
 """
 The test performs the static code analysis check by JSHint.
 
 Target js files:
-- RILContentHelper.js
+- RILContentHelper.js TODO: Bug 815526, deprecate RILContentHelper.
 - RadioInterfaceLayer.js
 - ril_worker.js
 - ril_consts.js
 
 If the js file contains the line of 'importScript()' (Ex: ril_worker.js), the
 test will perform a special merge step before excuting JSHint.
 
 Ex: Script A
@@ -95,17 +95,17 @@ class StringUtility:
 
 
 class ResourceUriFileReader:
 
     """Handle the process of reading the source code from system."""
 
     URI_PREFIX = 'resource://gre/'
     URI_PATH = {
-        'RILContentHelper.js':    'components/RILContentHelper.js',
+        'RILContentHelper.js':    'components/RILContentHelper.js', #TODO: Bug 815526, deprecate RILContentHelper.
         'RadioInterfaceLayer.js': 'components/RadioInterfaceLayer.js',
         'ril_worker.js':          'modules/ril_worker.js',
         'ril_consts.js':          'modules/ril_consts.js',
         'systemlibs.js':          'modules/systemlibs.js',
         'worker_buf.js':          'modules/workers/worker_buf.js',
     }
 
     CODE_OPEN_CHANNEL_BY_URI = '''
@@ -349,16 +349,17 @@ class TestRILCodeQuality(MarionetteTestC
             JSHintEngine(self.marionette,
                          self._read_local_file(self.JSHINT_PATH),
                          self._read_local_file(self.JSHINTRC_PATH)),
             self._get_extended_error_message)
 
     def tearDown(self):
         MarionetteTestCase.tearDown(self)
 
+    # TODO: Bug 815526, deprecate RILContentHelper.
     def test_RILContentHelper(self):
         self._check('RILContentHelper.js')
 
     def test_RadioInterfaceLayer(self):
         self._check('RadioInterfaceLayer.js')
 
     # Bug 936504. Disable the test for 'ril_worker.js'. It sometimes runs very
     # slow and causes the timeout fail on try server.
--- a/dom/system/gonk/tests/test_ril_worker_icc_CardState.js
+++ b/dom/system/gonk/tests/test_ril_worker_icc_CardState.js
@@ -28,75 +28,75 @@ add_test(function test_personalization_s
 
     ril._isCdma = isCdma;
     ril._processICCStatus(iccStatus);
     equal(ril.cardState, geckoCardState);
   }
 
   // Test GSM personalization state.
   testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK,
-                      Ci.nsIIccProvider.CARD_STATE_NETWORK_LOCKED);
+                      Ci.nsIIcc.CARD_STATE_NETWORK_LOCKED);
   testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET,
-                      Ci.nsIIccProvider.CARD_STATE_NETWORK_SUBSET_LOCKED);
+                      Ci.nsIIcc.CARD_STATE_NETWORK_SUBSET_LOCKED);
   testPersonalization(false, CARD_PERSOSUBSTATE_SIM_CORPORATE,
-                      Ci.nsIIccProvider.CARD_STATE_CORPORATE_LOCKED);
+                      Ci.nsIIcc.CARD_STATE_CORPORATE_LOCKED);
   testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER,
-                      Ci.nsIIccProvider.CARD_STATE_SERVICE_PROVIDER_LOCKED);
+                      Ci.nsIIcc.CARD_STATE_SERVICE_PROVIDER_LOCKED);
   testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SIM,
-                      Ci.nsIIccProvider.CARD_STATE_SIM_LOCKED);
+                      Ci.nsIIcc.CARD_STATE_SIM_LOCKED);
   testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK_PUK,
-                      Ci.nsIIccProvider.CARD_STATE_NETWORK_PUK_REQUIRED);
+                      Ci.nsIIcc.CARD_STATE_NETWORK_PUK_REQUIRED);
   testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK,
-                      Ci.nsIIccProvider.CARD_STATE_NETWORK_SUBSET_PUK_REQUIRED);
+                      Ci.nsIIcc.CARD_STATE_NETWORK_SUBSET_PUK_REQUIRED);
   testPersonalization(false, CARD_PERSOSUBSTATE_SIM_CORPORATE_PUK,
-                      Ci.nsIIccProvider.CARD_STATE_CORPORATE_PUK_REQUIRED);
+                      Ci.nsIIcc.CARD_STATE_CORPORATE_PUK_REQUIRED);
   testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK,
-                      Ci.nsIIccProvider.CARD_STATE_SERVICE_PROVIDER_PUK_REQUIRED);
+                      Ci.nsIIcc.CARD_STATE_SERVICE_PROVIDER_PUK_REQUIRED);
   testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SIM_PUK,
-                      Ci.nsIIccProvider.CARD_STATE_SIM_PUK_REQUIRED);
+                      Ci.nsIIcc.CARD_STATE_SIM_PUK_REQUIRED);
 
   testPersonalization(false, CARD_PERSOSUBSTATE_UNKNOWN,
-                      Ci.nsIIccProvider.CARD_STATE_UNKNOWN);
+                      Ci.nsIIcc.CARD_STATE_UNKNOWN);
   testPersonalization(false, CARD_PERSOSUBSTATE_IN_PROGRESS,
-                      Ci.nsIIccProvider.CARD_STATE_PERSONALIZATION_IN_PROGRESS);
+                      Ci.nsIIcc.CARD_STATE_PERSONALIZATION_IN_PROGRESS);
   testPersonalization(false, CARD_PERSOSUBSTATE_READY,
-                      Ci.nsIIccProvider.CARD_STATE_PERSONALIZATION_READY);
+                      Ci.nsIIcc.CARD_STATE_PERSONALIZATION_READY);
 
   // Test CDMA personalization state.
   testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK1,
-                      Ci.nsIIccProvider.CARD_STATE_NETWORK1_LOCKED);
+                      Ci.nsIIcc.CARD_STATE_NETWORK1_LOCKED);
   testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK2,
-                      Ci.nsIIccProvider.CARD_STATE_NETWORK2_LOCKED);
+                      Ci.nsIIcc.CARD_STATE_NETWORK2_LOCKED);
   testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_HRPD,
-                      Ci.nsIIccProvider.CARD_STATE_HRPD_NETWORK_LOCKED);
+                      Ci.nsIIcc.CARD_STATE_HRPD_NETWORK_LOCKED);
   testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_CORPORATE,
-                      Ci.nsIIccProvider.CARD_STATE_RUIM_CORPORATE_LOCKED);
+                      Ci.nsIIcc.CARD_STATE_RUIM_CORPORATE_LOCKED);
   testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER,
-                      Ci.nsIIccProvider.CARD_STATE_RUIM_SERVICE_PROVIDER_LOCKED);
+                      Ci.nsIIcc.CARD_STATE_RUIM_SERVICE_PROVIDER_LOCKED);
   testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_RUIM,
-                      Ci.nsIIccProvider.CARD_STATE_RUIM_LOCKED);
+                      Ci.nsIIcc.CARD_STATE_RUIM_LOCKED);
   testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK1_PUK,
-                      Ci.nsIIccProvider.CARD_STATE_NETWORK1_PUK_REQUIRED);
+                      Ci.nsIIcc.CARD_STATE_NETWORK1_PUK_REQUIRED);
   testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK2_PUK,
-                      Ci.nsIIccProvider.CARD_STATE_NETWORK2_PUK_REQUIRED);
+                      Ci.nsIIcc.CARD_STATE_NETWORK2_PUK_REQUIRED);
   testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_HRPD_PUK,
-                      Ci.nsIIccProvider.CARD_STATE_HRPD_NETWORK_PUK_REQUIRED);
+                      Ci.nsIIcc.CARD_STATE_HRPD_NETWORK_PUK_REQUIRED);
   testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_CORPORATE_PUK,
-                      Ci.nsIIccProvider.CARD_STATE_RUIM_CORPORATE_PUK_REQUIRED);
+                      Ci.nsIIcc.CARD_STATE_RUIM_CORPORATE_PUK_REQUIRED);
   testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK,
-                      Ci.nsIIccProvider.CARD_STATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED);
+                      Ci.nsIIcc.CARD_STATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED);
   testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_RUIM_PUK,
-                      Ci.nsIIccProvider.CARD_STATE_RUIM_PUK_REQUIRED);
+                      Ci.nsIIcc.CARD_STATE_RUIM_PUK_REQUIRED);
 
   testPersonalization(true, CARD_PERSOSUBSTATE_UNKNOWN,
-                      Ci.nsIIccProvider.CARD_STATE_UNKNOWN);
+                      Ci.nsIIcc.CARD_STATE_UNKNOWN);
   testPersonalization(true, CARD_PERSOSUBSTATE_IN_PROGRESS,
-                      Ci.nsIIccProvider.CARD_STATE_PERSONALIZATION_IN_PROGRESS);
+                      Ci.nsIIcc.CARD_STATE_PERSONALIZATION_IN_PROGRESS);
   testPersonalization(true, CARD_PERSOSUBSTATE_READY,
-                      Ci.nsIIccProvider.CARD_STATE_PERSONALIZATION_READY);
+                      Ci.nsIIcc.CARD_STATE_PERSONALIZATION_READY);
 
   run_next_test();
 });
 
 /**
  * Verify SIM app_state in _processICCStatus
  */
 add_test(function test_card_app_state() {
@@ -116,27 +116,27 @@ add_test(function test_card_app_state() 
       }],
     };
 
     ril._processICCStatus(iccStatus);
     equal(ril.cardState, geckoCardState);
   }
 
   testCardAppState(CARD_APPSTATE_ILLEGAL,
-                   Ci.nsIIccProvider.CARD_STATE_ILLEGAL);
+                   Ci.nsIIcc.CARD_STATE_ILLEGAL);
   testCardAppState(CARD_APPSTATE_PIN,
-                   Ci.nsIIccProvider.CARD_STATE_PIN_REQUIRED);
+                   Ci.nsIIcc.CARD_STATE_PIN_REQUIRED);
   testCardAppState(CARD_APPSTATE_PUK,
-                   Ci.nsIIccProvider.CARD_STATE_PUK_REQUIRED);
+                   Ci.nsIIcc.CARD_STATE_PUK_REQUIRED);
   testCardAppState(CARD_APPSTATE_READY,
-                   Ci.nsIIccProvider.CARD_STATE_READY);
+                   Ci.nsIIcc.CARD_STATE_READY);
   testCardAppState(CARD_APPSTATE_UNKNOWN,
-                   Ci.nsIIccProvider.CARD_STATE_UNKNOWN);
+                   Ci.nsIIcc.CARD_STATE_UNKNOWN);
   testCardAppState(CARD_APPSTATE_DETECTED,
-                   Ci.nsIIccProvider.CARD_STATE_UNKNOWN);
+                   Ci.nsIIcc.CARD_STATE_UNKNOWN);
 
   run_next_test();
 });
 
 /**
  * Verify permanent blocked for ICC.
  */
 add_test(function test_icc_permanent_blocked() {
@@ -154,17 +154,17 @@ add_test(function test_icc_permanent_blo
       apps: [
       {
         pin1_replaced: pin1_replaced,
         pin1: pin1
       }]
     };
 
     ril._processICCStatus(iccStatus);
-    equal(ril.cardState, Ci.nsIIccProvider.CARD_STATE_PERMANENT_BLOCKED);
+    equal(ril.cardState, Ci.nsIIcc.CARD_STATE_PERMANENT_BLOCKED);
   }
 
   testPermanentBlocked(1,
                        CARD_PINSTATE_ENABLED_PERM_BLOCKED,
                        CARD_PINSTATE_UNKNOWN);
   testPermanentBlocked(1,
                        CARD_PINSTATE_ENABLED_PERM_BLOCKED,
                        CARD_PINSTATE_ENABLED_PERM_BLOCKED);
--- a/dom/webidl/MozIcc.webidl
+++ b/dom/webidl/MozIcc.webidl
@@ -124,16 +124,26 @@ dictionary IccSetCardLockOptions
 
  DOMString? newPin = null; // Used for changing password operation.
                            // Necessary for lock types: "pin", "pin2"
 
  boolean enabled; // Used for enabling/disabling operation.
                   // Necessary for lock types: "pin", "fdn"
 };
 
+dictionary IccCardLockStatus
+{
+  boolean enabled; // True when CardLock is enabled.
+};
+
+dictionary IccCardLockRetryCount
+{
+  long retryCount; // The number of remaining retries. -1 if unkown.
+};
+
 [Pref="dom.icc.enabled",
  CheckPermissions="mobileconnection",
  AvailableIn="CertifiedApps"]
 interface MozIcc : EventTarget
 {
   // Integrated Circuit Card Information.
 
   /**
@@ -242,16 +252,17 @@ interface MozIcc : EventTarget
    *
    * @param lockType
    *        Identifies the lock type.
    *
    * @return a DOMRequest.
    *         The request's result will be an object containing
    *         information about the specified lock's status.
    *         e.g. {enabled: true}.
+   *         @see IccCardLockStatus.
    */
   [Throws]
   DOMRequest getCardLock(IccLockType lockType);
 
   /**
    * Unlock a card lock.
    *
    * @param info
@@ -284,18 +295,18 @@ interface MozIcc : EventTarget
   /**
    * Retrieve the number of remaining tries for unlocking the card.
    *
    * @param lockType
    *        Identifies the lock type.
    *
    * @return a DOMRequest.
    *         The request's result will be an object containing the number of
-   *         remaining retries.
-   *         e.g. {retryCount: 3}.
+   *         remaining retries. e.g. {retryCount: 3}.
+   *         @see IccCardLockRetryCount.
    */
   [Throws]
   DOMRequest getCardLockRetryCount(IccLockType lockType);
 
   // Integrated Circuit Card Phonebook Interfaces.
 
   /**
    * Read ICC contacts.
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -224,16 +224,17 @@ WEBIDL_FILES = [
     'HTMLTableSectionElement.webidl',
     'HTMLTemplateElement.webidl',
     'HTMLTextAreaElement.webidl',
     'HTMLTimeElement.webidl',
     'HTMLTitleElement.webidl',
     'HTMLTrackElement.webidl',
     'HTMLUListElement.webidl',
     'HTMLVideoElement.webidl',
+    'IccCardLockError.webidl',
     'IDBCursor.webidl',
     'IDBDatabase.webidl',
     'IDBEnvironment.webidl',
     'IDBFactory.webidl',
     'IDBFileHandle.webidl',
     'IDBFileRequest.webidl',
     'IDBIndex.webidl',
     'IDBKeyRange.webidl',
@@ -282,16 +283,19 @@ WEBIDL_FILES = [
     'MimeType.webidl',
     'MimeTypeArray.webidl',
     'MMICall.webidl',
     'MouseEvent.webidl',
     'MouseScrollEvent.webidl',
     'MozActivity.webidl',
     'MozCellBroadcast.webidl',
     'MozCellBroadcastMessage.webidl',
+    'MozIcc.webidl',
+    'MozIccInfo.webidl',
+    'MozIccManager.webidl',
     'MozMmsMessage.webidl',
     'MozMobileCellInfo.webidl',
     'MozMobileConnection.webidl',
     'MozMobileConnectionArray.webidl',
     'MozMobileConnectionInfo.webidl',
     'MozMobileMessageManager.webidl',
     'MozMobileNetworkInfo.webidl',
     'MozPowerManager.webidl',
@@ -646,24 +650,16 @@ if CONFIG['MOZ_B2G_BT']:
         ]
     else:
         WEBIDL_FILES += [
             'BluetoothAdapter.webidl',
             'BluetoothDevice.webidl',
             'BluetoothManager.webidl',
         ]
 
-if CONFIG['MOZ_B2G_RIL']:
-    WEBIDL_FILES += [
-        'IccCardLockError.webidl',
-        'MozIcc.webidl',
-        'MozIccInfo.webidl',
-        'MozIccManager.webidl',
-    ]
-
 if CONFIG['MOZ_NFC']:
     WEBIDL_FILES += [
          'MozIsoDepTech.webidl',
          'MozNDEFRecord.webidl',
          'MozNFC.webidl',
          'MozNFCPeer.webidl',
          'MozNFCTag.webidl',
          'NfcOptions.webidl',
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -845,16 +845,26 @@ var WifiManager = (function() {
       }
       manager.handlePostWifiScan();
       notify("scanresultsavailable");
       return true;
     }
     if (eventData.indexOf("CTRL-EVENT-EAP") === 0) {
       return handleWpaEapEvents(event);
     }
+    if (eventData.indexOf("CTRL-EVENT-ASSOC-REJECT") === 0) {
+      debug("CTRL-EVENT-ASSOC-REJECT: network error");
+      notify("passwordmaybeincorrect");
+      if (manager.authenticationFailuresCount > MAX_RETRIES_ON_AUTHENTICATION_FAILURE) {
+        manager.authenticationFailuresCount = 0;
+        debug("CTRL-EVENT-ASSOC-REJECT: disconnect network");
+        notify("disconnected", {connectionInfo: manager.connectionInfo});
+      }
+      return true;
+    }
     if (eventData.indexOf("WPS-TIMEOUT") === 0) {
       notifyStateChange({ state: "WPS_TIMEOUT", BSSID: null, id: -1 });
       return true;
     }
     if (eventData.indexOf("WPS-FAIL") === 0) {
       notifyStateChange({ state: "WPS_FAIL", BSSID: null, id: -1 });
       return true;
     }
@@ -2157,17 +2167,20 @@ function WifiWorker() {
       case "ASSOCIATING":
         // id has not yet been filled in, so we can only report the ssid and
         // bssid. mode and frequency are simply made up.
         self.currentNetwork =
           { bssid: WifiManager.connectionInfo.bssid,
             ssid: quote(WifiManager.connectionInfo.ssid),
             mode: MODE_ESS,
             frequency: 0};
-        self._fireEvent("onconnecting", { network: netToDOM(self.currentNetwork) });
+        WifiManager.getNetworkConfiguration(self.currentNetwork, function (){
+          // Notify again because we get complete network information.
+          self._fireEvent("onconnecting", { network: netToDOM(self.currentNetwork) });
+        });
         break;
       case "ASSOCIATED":
         // set to full power mode when ready to do 4 way handsharke.
         WifiManager.setPowerSavingMode(false);
         if (!self.currentNetwork) {
           self.currentNetwork =
             { bssid: WifiManager.connectionInfo.bssid,
               ssid: quote(WifiManager.connectionInfo.ssid) };
--- a/js/src/jscntxt.cpp
+++ b/js/src/jscntxt.cpp
@@ -224,16 +224,23 @@ ReportError(JSContext *cx, const char *m
         reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)
     {
         reportp->flags |= JSREPORT_EXCEPTION;
     }
 
     if (cx->options().autoJSAPIOwnsErrorReporting() || JS_IsRunning(cx)) {
         if (ErrorToException(cx, message, reportp, callback, userRef))
             return;
+
+        /*
+         * The AutoJSAPI error reporter only allows warnings to be reported so
+         * just ignore this error rather than try to report it.
+         */
+        if (cx->options().autoJSAPIOwnsErrorReporting())
+            return;
     }
 
     /*
      * Call the error reporter only if an exception wasn't raised.
      */
     if (message)
         CallErrorReporter(cx, message, reportp);
 }
--- a/js/src/jsexn.cpp
+++ b/js/src/jsexn.cpp
@@ -572,16 +572,22 @@ js::ErrorToException(JSContext *cx, cons
     // Flag the error report passed in to indicate an exception was raised.
     reportp->flags |= JSREPORT_EXCEPTION;
     return true;
 }
 
 static bool
 IsDuckTypedErrorObject(JSContext *cx, HandleObject exnObject, const char **filename_strp)
 {
+    /*
+     * This function is called from ErrorReport::init and so should not generate
+     * any new exceptions.
+     */
+    AutoClearPendingException acpe(cx);
+
     bool found;
     if (!JS_HasProperty(cx, exnObject, js_message_str, &found) || !found)
         return false;
 
     const char *filename_str = *filename_strp;
     if (!JS_HasProperty(cx, exnObject, filename_str, &found) || !found) {
         /* Now try "fileName", in case this quacks like an Error */
         filename_str = js_fileName_str;
--- a/js/src/jsexn.h
+++ b/js/src/jsexn.h
@@ -110,11 +110,25 @@ static inline JSExnType
 ExnTypeFromProtoKey(JSProtoKey key)
 {
     JSExnType type = static_cast<JSExnType>(key - JSProto_Error);
     MOZ_ASSERT(type >= JSEXN_ERR);
     MOZ_ASSERT(type < JSEXN_LIMIT);
     return type;
 }
 
+class AutoClearPendingException
+{
+    JSContext *cx;
+
+  public:
+    explicit AutoClearPendingException(JSContext *cxArg)
+      : cx(cxArg)
+    { }
+
+    ~AutoClearPendingException() {
+        cx->clearPendingException();
+    }
+};
+
 } // namespace js
 
 #endif /* jsexn_h */
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -4931,17 +4931,17 @@ FrameLayerBuilder::DrawPaintedLayer(Pain
 
   if (presContext && presContext->GetDocShell() && isActiveLayerManager) {
     nsDocShell* docShell = static_cast<nsDocShell*>(presContext->GetDocShell());
     bool isRecording;
     docShell->GetRecordProfileTimelineMarkers(&isRecording);
     if (isRecording) {
       mozilla::UniquePtr<TimelineMarker> marker =
         MakeUnique<LayerTimelineMarker>(docShell, aRegionToDraw);
-      docShell->AddProfileTimelineMarker(marker);
+      docShell->AddProfileTimelineMarker(Move(marker));
     }
   }
 
   if (!aRegionToInvalidate.IsEmpty()) {
     aLayer->AddInvalidRect(aRegionToInvalidate.GetBounds());
   }
 }
 
--- a/layout/build/nsLayoutModule.cpp
+++ b/layout/build/nsLayoutModule.cpp
@@ -208,16 +208,17 @@ static void Shutdown();
 #include "nsGeolocation.h"
 #include "nsDeviceSensors.h"
 #ifdef MOZ_GAMEPAD
 #include "mozilla/dom/GamepadService.h"
 #endif
 #include "mozilla/dom/nsCSPService.h"
 #include "mozilla/dom/nsCSPContext.h"
 #include "nsICellBroadcastService.h"
+#include "nsIIccService.h"
 #include "nsISmsService.h"
 #include "nsIMmsService.h"
 #include "nsIMobileConnectionService.h"
 #include "nsIMobileMessageService.h"
 #include "nsIMobileMessageDatabaseService.h"
 #include "nsIPowerManagerService.h"
 #include "nsIAlarmHalService.h"
 #include "nsIMediaManager.h"
@@ -333,16 +334,17 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsHapticF
 #endif
 #endif
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ThirdPartyUtil, Init)
 #ifndef DISABLE_MOZ_RIL_GEOLOC
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsICellBroadcastService,
                                          NS_CreateCellBroadcastService)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsISmsService, NS_CreateSmsService)
 #endif
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIIccService, NS_CreateIccService)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIMmsService, NS_CreateMmsService)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIMobileMessageService,
                                          NS_CreateMobileMessageService)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIMobileMessageDatabaseService,
                                          NS_CreateMobileMessageDatabaseService)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIPowerManagerService,
                                          PowerManagerService::GetInstance)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIAlarmHalService,
@@ -793,16 +795,17 @@ NS_DEFINE_NAMED_CID(CELLBROADCAST_SERVIC
 #ifdef MOZ_WIDGET_GONK
 NS_DEFINE_NAMED_CID(GONK_GPS_GEOLOCATION_PROVIDER_CID);
 #endif
 NS_DEFINE_NAMED_CID(TELEPHONY_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_VOICEMAIL_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_MOBILE_CONNECTION_SERVICE_CID);
 NS_DEFINE_NAMED_CID(SMS_SERVICE_CID);
 #endif
+NS_DEFINE_NAMED_CID(ICC_SERVICE_CID);
 NS_DEFINE_NAMED_CID(MMS_SERVICE_CID);
 NS_DEFINE_NAMED_CID(MOBILE_MESSAGE_SERVICE_CID);
 NS_DEFINE_NAMED_CID(MOBILE_MESSAGE_DATABASE_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_POWERMANAGERSERVICE_CID);
 NS_DEFINE_NAMED_CID(OSFILECONSTANTSSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_ALARMHALSERVICE_CID);
 NS_DEFINE_NAMED_CID(TCPSOCKETCHILD_CID);
 NS_DEFINE_NAMED_CID(TCPSOCKETPARENT_CID);
@@ -1087,16 +1090,17 @@ static const mozilla::Module::CIDEntry k
 #endif
 #endif
   { &kTHIRDPARTYUTIL_CID, false, nullptr, ThirdPartyUtilConstructor },
   { &kNS_STRUCTUREDCLONECONTAINER_CID, false, nullptr, nsStructuredCloneContainerConstructor },
 #ifndef DISABLE_MOZ_RIL_GEOLOC
   { &kCELLBROADCAST_SERVICE_CID, false, nullptr, nsICellBroadcastServiceConstructor },
   { &kSMS_SERVICE_CID, false, nullptr, nsISmsServiceConstructor },
 #endif
+  { &kICC_SERVICE_CID, false, nullptr, nsIIccServiceConstructor },
   { &kMMS_SERVICE_CID, false, nullptr, nsIMmsServiceConstructor },
   { &kMOBILE_MESSAGE_SERVICE_CID, false, nullptr, nsIMobileMessageServiceConstructor },
   { &kMOBILE_MESSAGE_DATABASE_SERVICE_CID, false, nullptr, nsIMobileMessageDatabaseServiceConstructor },
   { &kNS_POWERMANAGERSERVICE_CID, false, nullptr, nsIPowerManagerServiceConstructor },
   { &kOSFILECONSTANTSSERVICE_CID, true, nullptr, OSFileConstantsServiceConstructor },
   { &kNS_ALARMHALSERVICE_CID, false, nullptr, nsIAlarmHalServiceConstructor },
   { &kTCPSOCKETCHILD_CID, false, nullptr, TCPSocketChildConstructor },
   { &kTCPSOCKETPARENT_CID, false, nullptr, TCPSocketParentConstructor },
@@ -1250,16 +1254,17 @@ static const mozilla::Module::ContractID
 #endif
 #endif
   { THIRDPARTYUTIL_CONTRACTID, &kTHIRDPARTYUTIL_CID },
   { NS_STRUCTUREDCLONECONTAINER_CONTRACTID, &kNS_STRUCTUREDCLONECONTAINER_CID },
 #ifndef DISABLE_MOZ_RIL_GEOLOC
   { CELLBROADCAST_SERVICE_CONTRACTID, &kCELLBROADCAST_SERVICE_CID },
   { SMS_SERVICE_CONTRACTID, &kSMS_SERVICE_CID },
 #endif
+  { ICC_SERVICE_CONTRACTID, &kICC_SERVICE_CID },
   { MMS_SERVICE_CONTRACTID, &kMMS_SERVICE_CID },
   { MOBILE_MESSAGE_SERVICE_CONTRACTID, &kMOBILE_MESSAGE_SERVICE_CID },
   { MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID, &kMOBILE_MESSAGE_DATABASE_SERVICE_CID },
   { POWERMANAGERSERVICE_CONTRACTID, &kNS_POWERMANAGERSERVICE_CID },
   { OSFILECONSTANTSSERVICE_CONTRACTID, &kOSFILECONSTANTSSERVICE_CID },
   { ALARMHALSERVICE_CONTRACTID, &kNS_ALARMHALSERVICE_CID },
   { "@mozilla.org/tcp-socket-child;1", &kTCPSOCKETCHILD_CID },
   { "@mozilla.org/tcp-socket-parent;1", &kTCPSOCKETPARENT_CID },
--- a/mobile/android/base/reading/LocalReadingListStorage.java
+++ b/mobile/android/base/reading/LocalReadingListStorage.java
@@ -43,64 +43,70 @@ public class LocalReadingListStorage imp
     private final Queue<ClientReadingListRecord> changes;
 
     /**
      * These are deletions that result from uploading new or changed records to the server.
      * They should always correspond to local records.
      * These are not common: they should only occur if a conflict occurs.
      */
     private final Queue<ClientReadingListRecord> deletions;
+    private final Queue<String> deletedGUIDs;
 
     /**
      * These are additions or changes fetched from the server.
      * At the point of collection we don't know if they're records
      * that exist locally.
      *
      * Batching these here, rather than in the client or the synchronizer,
      * puts the storage implementation in control of when batches are flushed,
      * or if batches are used at all.
      */
     private final Queue<ServerReadingListRecord> additionsOrChanges;
 
     LocalReadingListChangeAccumulator() {
       this.changes = new ConcurrentLinkedQueue<>();
       this.deletions = new ConcurrentLinkedQueue<>();
+      this.deletedGUIDs = new ConcurrentLinkedQueue<>();
       this.additionsOrChanges = new ConcurrentLinkedQueue<>();
     }
 
     public boolean flushDeletions() throws RemoteException {
-      if (deletions.isEmpty()) {
+      if (deletions.isEmpty() && deletedGUIDs.isEmpty()) {
         return true;
       }
 
       long[] ids = new long[deletions.size()];
-      String[] guids = new String[deletions.size()];
+      String[] guids = new String[deletions.size() + deletedGUIDs.size()];
       int iID = 0;
       int iGUID = 0;
       for (ClientReadingListRecord record : deletions) {
         if (record.clientMetadata.id > -1L) {
           ids[iID++] = record.clientMetadata.id;
         } else {
           final String guid = record.getGUID();
           if (guid == null) {
             continue;
           }
           guids[iGUID++] = guid;
         }
       }
+      for (String guid : deletedGUIDs) {
+        guids[iGUID++] = guid;
+      }
 
       if (iID > 0) {
         client.delete(URI_WITH_DELETED, RepoUtils.computeSQLLongInClause(ids, ReadingListItems._ID), null);
       }
 
       if (iGUID > 0) {
         client.delete(URI_WITH_DELETED, RepoUtils.computeSQLInClause(iGUID, ReadingListItems.GUID), guids);
       }
 
       deletions.clear();
+      deletedGUIDs.clear();
       return true;
     }
 
     public boolean flushRecordChanges() throws RemoteException {
       if (changes.isEmpty() && additionsOrChanges.isEmpty()) {
         return true;
       }
 
@@ -207,16 +213,21 @@ public class LocalReadingListStorage imp
     }
 
     @Override
     public void addDeletion(ClientReadingListRecord record) {
       deletions.add(record);
     }
 
     @Override
+    public void addDeletion(String guid) {
+      deletedGUIDs.add(guid);
+    }
+
+    @Override
     public void addChangedRecord(ClientReadingListRecord record) {
       changes.add(record);
     }
 
     @Override
     public void addUploadedRecord(ClientReadingListRecord up,
                                   ServerReadingListRecord down) {
       // TODO
@@ -314,16 +325,30 @@ public class LocalReadingListStorage imp
     try {
       return client.query(URI_WITHOUT_DELETED, projection, selection, null, null);
     } catch (RemoteException e) {
       throw new IllegalStateException(e);
     }
   }
 
   @Override
+  public Cursor getDeletedItems() {
+    final String[] projection = new String[] {
+      ReadingListItems.GUID,
+    };
+
+    final String selection = "(" + ReadingListItems.IS_DELETED + " = 1) AND (" + ReadingListItems.GUID + " IS NOT NULL)";
+    try {
+      return client.query(URI_WITH_DELETED, projection, selection, null, null);
+    } catch (RemoteException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
+  @Override
   public Cursor getNew() {
     // N.B., query for items that have no GUID, regardless of status.
     // They should all be marked as NEW, but belt and braces.
     final String selection = WHERE_STATUS_NEW + " OR (" + ReadingListItems.GUID + " IS NULL)";
 
     try {
       return client.query(URI_WITHOUT_DELETED, null, selection, null, null);
     } catch (RemoteException e) {
--- a/mobile/android/base/reading/ReadingListChangeAccumulator.java
+++ b/mobile/android/base/reading/ReadingListChangeAccumulator.java
@@ -6,14 +6,15 @@ package org.mozilla.gecko.reading;
 
 
 /**
  * Grab one of these, then you can add records to it by parsing
  * server responses. Finishing it will flush those changes (e.g.,
  * via UPDATE) to the DB.
  */
 public interface ReadingListChangeAccumulator {
+  void addDeletion(String guid);
   void addDeletion(ClientReadingListRecord record);
   void addChangedRecord(ClientReadingListRecord record);
   void addUploadedRecord(ClientReadingListRecord up, ServerReadingListRecord down);
   void addDownloadedRecord(ServerReadingListRecord down);
   void finish() throws Exception;
 }
--- a/mobile/android/base/reading/ReadingListClient.java
+++ b/mobile/android/base/reading/ReadingListClient.java
@@ -426,16 +426,86 @@ public class ReadingListClient {
     }
 
     @Override
     void again(ClientReadingListRecord record) {
       patch(record, PatchBatchingUploadDelegate.this);
     }
   }
 
+  private class DeleteBatchingDelegate implements ReadingListDeleteDelegate {
+    private final Queue<String> queue;
+    private final ReadingListDeleteDelegate batchDeleteDelegate;
+    private final Executor executor;
+
+    DeleteBatchingDelegate(Queue<String> guids,
+                           ReadingListDeleteDelegate batchDeleteDelegate,
+                           Executor executor) {
+      this.queue = guids;
+      this.batchDeleteDelegate = batchDeleteDelegate;
+      this.executor = executor;
+    }
+
+    void next() {
+      final String guid = queue.poll();
+      executor.execute(new Runnable() {
+        @Override
+        public void run() {
+          if (guid == null) {
+            batchDeleteDelegate.onBatchDone();
+            return;
+          }
+
+          again(guid);
+        }
+      });
+    }
+
+    void again(String guid) {
+      delete(guid, DeleteBatchingDelegate.this, -1L);
+    }
+
+    @Override
+    public void onSuccess(ReadingListRecordResponse response,
+                          ReadingListRecord record) {
+      batchDeleteDelegate.onSuccess(response, record);
+      next();
+    }
+
+    @Override
+    public void onPreconditionFailed(String guid, MozResponse response) {
+      batchDeleteDelegate.onPreconditionFailed(guid, response);
+      next();
+    }
+
+    @Override
+    public void onRecordMissingOrDeleted(String guid, MozResponse response) {
+      batchDeleteDelegate.onRecordMissingOrDeleted(guid, response);
+      next();
+    }
+
+    @Override
+    public void onFailure(Exception e) {
+      batchDeleteDelegate.onFailure(e);
+      next();
+    }
+
+    @Override
+    public void onFailure(MozResponse response) {
+      batchDeleteDelegate.onFailure(response);
+      next();
+    }
+
+    @Override
+    public void onBatchDone() {
+      // This should never occur, but if it does, pass through.
+      batchDeleteDelegate.onBatchDone();
+    }
+  }
+
   // Deliberately declare `delegate` non-final so we can't capture it below. We prefer
   // to use `recordDelegate` explicitly.
   public void getOne(final String guid, ReadingListRecordDelegate delegate, final long ifModifiedSince) {
     final BaseResource r = getRelativeArticleResource(guid);
     r.delegate = new SingleRecordResourceDelegate(r, auth, delegate, ReadingListRecordResponse.FACTORY, ifModifiedSince, guid);
     if (ReadingListConstants.DEBUG) {
       Logger.info(LOG_TAG, "Getting record " + guid);
     }
@@ -506,16 +576,27 @@ public class ReadingListClient {
 
     final ExtendedJSONObject body = up.toJSON();
     if (ReadingListConstants.DEBUG) {
       Logger.info(LOG_TAG, "Uploading new record: " + body.toJSONString());
     }
     r.post(body);
   }
 
+  public void delete(final Queue<String> guids, final Executor executor, final ReadingListDeleteDelegate batchDeleteDelegate) {
+    if (guids.isEmpty()) {
+      batchDeleteDelegate.onBatchDone();
+      return;
+    }
+
+    final ReadingListDeleteDelegate deleteDelegate = new DeleteBatchingDelegate(guids, batchDeleteDelegate, executor);
+
+    delete(guids.poll(), deleteDelegate, -1L);
+  }
+
   public void delete(final String guid, final ReadingListDeleteDelegate delegate, final long ifUnmodifiedSince) {
     final BaseResource r = getRelativeArticleResource(guid);
 
     // If If-Unmodified-Since is provided, and the record has been modified,
     // we'll receive a 412 Precondition Failed.
     // If the record is missing or already deleted, a 404 will be returned.
     // Otherwise, the response will be the deleted record.
     r.delegate = new ReadingListResourceDelegate<ReadingListRecordResponse>(r, auth, ReadingListRecordResponse.FACTORY) {
--- a/mobile/android/base/reading/ReadingListClientRecordFactory.java
+++ b/mobile/android/base/reading/ReadingListClientRecordFactory.java
@@ -5,19 +5,19 @@
 package org.mozilla.gecko.reading;
 
 import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.db.BrowserContract.ReadingListItems;
 import org.mozilla.gecko.reading.ReadingListRecord.ServerMetadata;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 
 import android.annotation.TargetApi;
+import android.database.AbstractWindowedCursor;
 import android.database.Cursor;
 import android.database.CursorWindow;
-import android.database.sqlite.SQLiteCursor;
 import android.os.Build;
 
 /**
  * This class converts database rows into {@link ClientReadingListRecord}s.
  *
  * In doing so it has to:
  *
  *  * Translate column names.
@@ -127,21 +127,21 @@ public class ReadingListClientRecordFact
     default:
       // Do nothing.
       return;
     }
   }
 
   @SuppressWarnings("deprecation")
   private final void fillGingerbread(ExtendedJSONObject o, Cursor c, String f, int i) {
-    if (!(c instanceof SQLiteCursor)) {
+    if (!(c instanceof AbstractWindowedCursor)) {
       throw new IllegalStateException("Unable to handle cursors that don't have a CursorWindow!");
     }
 
-    final SQLiteCursor sqc = (SQLiteCursor) c;
+    final AbstractWindowedCursor sqc = (AbstractWindowedCursor) c;
     final CursorWindow w = sqc.getWindow();
     final int pos = c.getPosition();
     if (w.isNull(pos, i)) {
       putNull(o, f);
     } else if (w.isString(pos, i)) {
       put(o, f, c.getString(i));
     } else if (w.isLong(pos, i)) {
       put(o, f, c.getLong(i));
--- a/mobile/android/base/reading/ReadingListDeleteDelegate.java
+++ b/mobile/android/base/reading/ReadingListDeleteDelegate.java
@@ -3,17 +3,19 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.reading;
 
 import org.mozilla.gecko.sync.net.MozResponse;
 
 /**
  * Response delegate for a server DELETE.
- * Only one of these methods will be called, and it will be called precisely once.
+ * Only one of these methods will be called, and it will be called precisely once,
+ * unless batching is used.
  */
 public interface ReadingListDeleteDelegate {
   void onSuccess(ReadingListRecordResponse response, ReadingListRecord record);
   void onPreconditionFailed(String guid, MozResponse response);
   void onRecordMissingOrDeleted(String guid, MozResponse response);
   void onFailure(Exception e);
   void onFailure(MozResponse response);
+  void onBatchDone();
 }
--- a/mobile/android/base/reading/ReadingListStorage.java
+++ b/mobile/android/base/reading/ReadingListStorage.java
@@ -3,13 +3,14 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.reading;
 
 import android.database.Cursor;
 
 public interface ReadingListStorage {
   Cursor getModified();
+  Cursor getDeletedItems();
   Cursor getStatusChanges();
   Cursor getNew();
   Cursor getAll();
   ReadingListChangeAccumulator getChangeAccumulator();
 }
--- a/mobile/android/base/reading/ReadingListSyncAdapter.java
+++ b/mobile/android/base/reading/ReadingListSyncAdapter.java
@@ -77,16 +77,22 @@ public class ReadingListSyncAdapter exte
     @Override
     public void onUnableToSync(Exception e) {
       Logger.warn(LOG_TAG, "Unable to sync.", e);
       cpc.release();
       syncDelegate.handleError(e);
     }
 
     @Override
+    public void onDeletionsUploadComplete() {
+      Logger.debug(LOG_TAG, "Step: onDeletionsUploadComplete");
+      this.result.stats.numEntries += 1;   // TODO: Bug 1140809.
+    }
+
+    @Override
     public void onStatusUploadComplete(Collection<String> uploaded,
                                        Collection<String> failed) {
       Logger.debug(LOG_TAG, "Step: onStatusUploadComplete");
       this.result.stats.numEntries += 1;   // TODO: Bug 1140809.
     }
 
     @Override
     public void onNewItemUploadComplete(Collection<String> uploaded,
--- a/mobile/android/base/reading/ReadingListSynchronizer.java
+++ b/mobile/android/base/reading/ReadingListSynchronizer.java
@@ -171,16 +171,90 @@ public class ReadingListSynchronizer {
           next.fail(e);
         }
         return;
       }
       next.fail();
     }
   }
 
+  private static class DeletionUploadDelegate implements ReadingListDeleteDelegate {
+    private final ReadingListChangeAccumulator acc;
+    private final StageDelegate next;
+
+    DeletionUploadDelegate(ReadingListChangeAccumulator acc, StageDelegate next) {
+      this.acc = acc;
+      this.next = next;
+    }
+
+    @Override
+    public void onBatchDone() {
+      try {
+        acc.finish();
+      } catch (Exception e) {
+        next.fail(e);
+        return;
+      }
+
+      next.next();
+    }
+
+    @Override
+    public void onSuccess(ReadingListRecordResponse response,
+                          ReadingListRecord record) {
+      Logger.debug(LOG_TAG, "Tracking uploaded deletion " + record.getGUID());
+      acc.addDeletion(record.getGUID());
+    }
+
+    @Override
+    public void onPreconditionFailed(String guid, MozResponse response) {
+      // Should never happen.
+    }
+
+    @Override
+    public void onRecordMissingOrDeleted(String guid, MozResponse response) {
+      // Great!
+      Logger.debug(LOG_TAG, "Tracking redundant deletion " + guid);
+      acc.addDeletion(guid);
+    }
+
+    @Override
+    public void onFailure(Exception e) {
+      // Ignore.
+    }
+
+    @Override
+    public void onFailure(MozResponse response) {
+      // Ignore.
+    }
+  }
+
+
+  private Queue<String> collectDeletedIDsFromCursor(Cursor cursor) {
+    try {
+      final Queue<String> toDelete = new LinkedList<>();
+
+      final int columnGUID = cursor.getColumnIndexOrThrow(ReadingListItems.GUID);
+
+      while (cursor.moveToNext()) {
+        final String guid = cursor.getString(columnGUID);
+        if (guid == null) {
+          // Nothing we can do here.
+          continue;
+        }
+
+        toDelete.add(guid);
+      }
+
+      return toDelete;
+    } finally {
+      cursor.close();
+    }
+  }
+
   private static class StatusUploadDelegate implements ReadingListRecordUploadDelegate {
     private final ReadingListChangeAccumulator acc;
 
     public volatile int failures = 0;
     private final StageDelegate next;
 
     StatusUploadDelegate(ReadingListChangeAccumulator acc, StageDelegate next) {
       this.acc = acc;
@@ -457,16 +531,46 @@ public class ReadingListSynchronizer {
         toUpload.add(record);
       }
       return toUpload;
     } finally {
       cursor.close();
     }
   }
 
+  protected void uploadDeletions(final StageDelegate delegate) {
+    try {
+      final Cursor cursor = local.getDeletedItems();
+
+      if (cursor == null) {
+        delegate.fail(new RuntimeException("Unable to get unread item cursor."));
+        return;
+      }
+
+      final Queue<String> toDelete = collectDeletedIDsFromCursor(cursor);
+
+      // Nothing to do.
+      if (toDelete.isEmpty()) {
+        Logger.debug(LOG_TAG, "No new deletions to upload. Skipping.");
+        delegate.next();
+        return;
+      } else {
+        Logger.debug(LOG_TAG, "Deleting " + toDelete.size() + " records from the server.");
+      }
+
+      final ReadingListChangeAccumulator acc = this.local.getChangeAccumulator();
+      final DeletionUploadDelegate deleteDelegate = new DeletionUploadDelegate(acc, delegate);
+
+      // Don't send I-U-S; we're happy for the client to win, because this is a one-way state change.
+      this.remote.delete(toDelete, executor, deleteDelegate);
+    } catch (Exception e) {
+      delegate.fail(e);
+    }
+  }
+
   // N.B., status changes for items that haven't been uploaded yet are dealt with in
   // uploadNewItems.
   protected void uploadUnreadChanges(final StageDelegate delegate) {
     try {
       final Cursor cursor = local.getStatusChanges();
 
       if (cursor == null) {
         delegate.fail(new RuntimeException("Unable to get unread item cursor."));
@@ -692,53 +796,68 @@ public class ReadingListSynchronizer {
     try {
       remote.getAll(spec, recordDelegate, since);
     } catch (URISyntaxException e) {
       delegate.fail(e);
     }
   }
 
   /**
-   * Upload unread changes, then upload new items, then call `done`.
+   * Upload deletions and unread changes, then upload new items, then call `done`.
    * Substantially modified records are uploaded last.
    *
    * @param syncDelegate only used for status callbacks.
    */
   private void syncUp(final ReadingListSynchronizerDelegate syncDelegate, final StageDelegate done) {
-    // Second.
+    // Third.
     final StageDelegate onNewItemsUploaded = new NextDelegate(executor) {
       @Override
       public void doNext() {
         syncDelegate.onNewItemUploadComplete(null, null);
         done.next();
       }
 
       @Override
       public void doFail(Exception e) {
         done.fail(e);
       }
     };
 
-    // First.
+    // Second.
     final StageDelegate onUnreadChangesUploaded = new NextDelegate(executor) {
       @Override
       public void doNext() {
         syncDelegate.onStatusUploadComplete(null, null);
         uploadNewItems(onNewItemsUploaded);
       }
 
       @Override
       public void doFail(Exception e) {
         Logger.warn(LOG_TAG, "Uploading unread changes failed.", e);
         done.fail(e);
       }
     };
 
+    // First.
+    final StageDelegate onDeletionsUploaded = new NextDelegate(executor) {
+      @Override
+      public void doNext() {
+        syncDelegate.onDeletionsUploadComplete();
+        uploadUnreadChanges(onUnreadChangesUploaded);
+      }
+
+      @Override
+      public void doFail(Exception e) {
+        Logger.warn(LOG_TAG, "Uploading deletions failed.", e);
+        done.fail(e);
+      }
+    };
+
     try {
-      uploadUnreadChanges(onUnreadChangesUploaded);
+      uploadDeletions(onDeletionsUploaded);
     } catch (Exception ee) {
       done.fail(ee);
     }
   }
 
 
   /**
    * Do an upload-only sync.
--- a/mobile/android/base/reading/ReadingListSynchronizerDelegate.java
+++ b/mobile/android/base/reading/ReadingListSynchronizerDelegate.java
@@ -7,16 +7,17 @@ package org.mozilla.gecko.reading;
 import java.util.Collection;
 
 public interface ReadingListSynchronizerDelegate {
   // Called on failure.
   void onUnableToSync(Exception e);
 
   // These are called sequentially, or not at all
   // if a failure occurs.
+  void onDeletionsUploadComplete();
   void onStatusUploadComplete(Collection<String> uploaded, Collection<String> failed);
   void onNewItemUploadComplete(Collection<String> uploaded, Collection<String> failed);
   void onDownloadComplete();
   void onModifiedUploadComplete();
 
   // If no failure occurred, called at the end.
   void onComplete();
 }
--- a/services/mobileid/MobileIdentityManager.jsm
+++ b/services/mobileid/MobileIdentityManager.jsm
@@ -51,19 +51,19 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "@mozilla.org/AppsService;1",
                                    "nsIAppsService");
 
 #ifdef MOZ_B2G_RIL
 XPCOMUtils.defineLazyServiceGetter(this, "Ril",
                                    "@mozilla.org/ril;1",
                                    "nsIRadioInterfaceLayer");
 
-XPCOMUtils.defineLazyServiceGetter(this, "IccProvider",
-                                   "@mozilla.org/ril/content-helper;1",
-                                   "nsIIccProvider");
+XPCOMUtils.defineLazyServiceGetter(this, "IccService",
+                                   "@mozilla.org/icc/iccservice;1",
+                                   "nsIIccService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "MobileConnectionService",
                                    "@mozilla.org/mobileconnection/mobileconnectionservice;1",
                                    "nsIMobileConnectionService");
 #endif
 
 
 this.MobileIdentityManager = {
@@ -111,21 +111,21 @@ this.MobileIdentityManager = {
   // We have these getters to allow mocking RIL stuff from the tests.
   get ril() {
     if (this._ril) {
       return this._ril;
     }
     return Ril;
   },
 
-  get iccProvider() {
-    if (this._iccProvider) {
-      return this._iccProvider;
+  get iccService() {
+    if (this._iccService) {
+      return this._iccService;
     }
-    return IccProvider;
+    return IccService;
   },
 
   get mobileConnectionService() {
     if (this._mobileConnectionService) {
       return this._mobileConnectionService;
     }
     return MobileConnectionService;
   },
@@ -148,18 +148,20 @@ this.MobileIdentityManager = {
         // If we receive a notification about an ICC info change, we clear
         // the ICC related caches so they can be rebuilt with the new changes.
 
         log.debug("ICC info changed observed. Clearing caches");
 
         // We don't need to keep listening for changes until we rebuild the
         // cache again.
         for (let i = 0; i < self._iccInfo.length; i++) {
-          self.iccProvider.unregisterIccMsg(self._iccInfo[i].clientId,
-                                            iccListener);
+          let icc = self.iccService.getIccByServiceId(i);
+          if (icc) {
+            icc.unregisterListener(iccListener);
+          }
         }
 
         self._iccInfo = null;
         self._iccIds = null;
       }
     };
 
     // _iccInfo is a local cache containing the information about the SIM cards
@@ -209,17 +211,20 @@ this.MobileIdentityManager = {
         // GSM SIMs may have MSISDN while CDMA SIMs may have MDN
         msisdn: info.msisdn || info.mdn || null,
         operator: operator,
         roaming: voice && voice.roaming
       });
 
       // We need to subscribe to ICC change notifications so we can refresh
       // the cache if any change is observed.
-      this.iccProvider.registerIccMsg(i, iccListener);
+      let icc = this.iccService.getIccByServiceId(i);
+      if (icc) {
+        icc.registerListener(iccListener);
+      }
     }
 
     return this._iccInfo;
 #endif
     return null;
   },
 
   get iccIds() {
--- a/services/mobileid/tests/xpcshell/test_mobileid_manager.js
+++ b/services/mobileid/tests/xpcshell/test_mobileid_manager.js
@@ -997,23 +997,29 @@ add_test(function() {
 
   MobileIdentityManager._mobileConnectionService = {
     _interfaces: [RADIO_INTERFACE, ANOTHER_RADIO_INTERFACE],
     getItemByServiceId: function(aIndex) {
       return this._interfaces[aIndex];
     }
   };
 
-  MobileIdentityManager._iccProvider = {
+  MobileIdentityManager._iccService = {
+    _iccs: [],
     _listeners: [],
-    registerIccMsg: function(aClientId, aIccListener) {
-      this._listeners.push(aIccListener);
-    },
-    unregisterIccMsg: function() {
-      this._listeners.pop();
+    getIccByServiceId: function(aClientId) {
+      let self = this;
+      this_iccs.push({
+        registerListener: function(aIccListener) {
+          self._listeners.push(aIccListener);
+        },
+        unregisterListener: function() {
+          self._listeners.pop();
+        }
+      });
     }
   };
 
   let ui = new MockUi();
   ui.startFlow = function() {
     // At this point we've already built the ICC cache.
     let interfaces = MobileIdentityManager._ril._interfaces;
     for (let i = 0; i < interfaces.length; i++) {
@@ -1022,27 +1028,27 @@ add_test(function() {
       do_check_eq(interfaceIccInfo.iccid, mIdIccInfo.iccId);
       do_check_eq(interfaceIccInfo.mcc, mIdIccInfo.mcc);
       do_check_eq(interfaceIccInfo.mnc, mIdIccInfo.mnc);
       do_check_eq(interfaceIccInfo.msisdn, mIdIccInfo.msisdn);
       do_check_eq(interfaceIccInfo.operator, mIdIccInfo.operator);
     }
 
     // We should have listeners for each valid icc.
-    do_check_eq(MobileIdentityManager._iccProvider._listeners.length, 2);
+    do_check_eq(MobileIdentityManager._iccService._listeners.length, 2);
 
     // We can mock an ICC change event at this point.
-    MobileIdentityManager._iccProvider._listeners[0].notifyIccInfoChanged();
+    MobileIdentityManager._iccService._listeners[0].notifyIccInfoChanged();
 
     // After the ICC change event the caches should be null.
     do_check_null(MobileIdentityManager._iccInfo);
     do_check_null(MobileIdentityManager._iccIds);
 
     // And we should have unregistered all listeners for ICC change events.
-    do_check_eq(MobileIdentityManager._iccProvider._listeners.length, 0);
+    do_check_eq(MobileIdentityManager._iccService._listeners.length, 0);
 
     do_test_finished();
     run_next_test();
   };
   MobileIdentityManager.ui = ui;
 
   let credStore = new MockCredStore();
   credStore.getByOrigin = function() {
@@ -1099,34 +1105,40 @@ add_test(function() {
 
   MobileIdentityManager._mobileConnectionService = {
     _interfaces: [INVALID_RADIO_INTERFACE],
     getItemByServiceId: function(aIndex) {
       return this._interfaces[aIndex];
     }
   };
 
-  MobileIdentityManager._iccProvider = {
+  MobileIdentityManager._iccService = {
+    _iccs: [],
     _listeners: [],
-    registerIccMsg: function(aClientId, aIccListener) {
-      this._listeners.push(aIccListener);
-    },
-    unregisterIccMsg: function() {
-      this._listeners.pop();
+    getIccByServiceId: function(aClientId) {
+      let self = this;
+      this_iccs.push({
+        registerListener: function(aIccListener) {
+          self._listeners.push(aIccListener);
+        },
+        unregisterListener: function() {
+          self._listeners.pop();
+        }
+      });
     }
   };
 
   let ui = new MockUi();
   ui.startFlow = function() {
     // At this point we've already built the ICC cache.
     do_check_eq(MobileIdentityManager._iccInfo.length, 0);
     do_check_eq(MobileIdentityManager._iccIds.length, 0);
 
     // We should have listeners for each valid icc.
-    do_check_eq(MobileIdentityManager._iccProvider._listeners.length, 0);
+    do_check_eq(MobileIdentityManager._iccService._listeners.length, 0);
 
     do_test_finished();
     run_next_test();
   };
   MobileIdentityManager.ui = ui;
 
   let credStore = new MockCredStore();
   credStore.getByOrigin = function() {
--- a/toolkit/devtools/server/actors/inspector.js
+++ b/toolkit/devtools/server/actors/inspector.js
@@ -2401,17 +2401,39 @@ var WalkerActor = protocol.ActorClass({
       for (let node of this._orphaned) {
         // Release the orphaned node.  Nodes or children that have been
         // retained will be moved to this._retainedOrphans.
         this.releaseNode(node);
       }
       this._orphaned = new Set();
     }
 
-    return pending;
+
+    // Clear out any duplicate attribute mutations before sending them over
+    // the protocol.  Keep only the most recent change for each attribute.
+    let targetMap = {};
+    let filtered = pending.reverse().filter(mutation => {
+      if (mutation.type === "attributes") {
+        if (!targetMap[mutation.target]) {
+          targetMap[mutation.target] = {};
+        }
+        let attributesForTarget = targetMap[mutation.target];
+
+        if (attributesForTarget[mutation.attributeName]) {
+          // Since the array was reversed, if we've seen this attribute already
+          // then this one is a duplicate and can be skipped.
+          return false;
+        }
+
+        attributesForTarget[mutation.attributeName] = true;
+      }
+      return true;
+    }).reverse();
+
+    return filtered;
   }, {
     request: {
       cleanup: Option(0)
     },
     response: {
       mutations: RetVal("array:dommutation")
     }
   }),
--- a/toolkit/devtools/server/actors/profiler.js
+++ b/toolkit/devtools/server/actors/profiler.js
@@ -2,17 +2,17 @@
  * 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/. */
 "use strict";
 
 const {Cc, Ci, Cu, Cr} = require("chrome");
 const Services = require("Services");
 const DevToolsUtils = require("devtools/toolkit/DevToolsUtils.js");
 
-let DEFAULT_PROFILER_ENTRIES = 1000000;
+let DEFAULT_PROFILER_ENTRIES = 10000000;
 let DEFAULT_PROFILER_INTERVAL = 1;
 let DEFAULT_PROFILER_FEATURES = ["js"];
 let DEFAULT_PROFILER_THREADFILTERS = ["GeckoMain"];
 
 /**
  * The nsIProfiler is target agnostic and interacts with the whole platform.
  * Therefore, special care needs to be given to make sure different actor
  * consumers (i.e. "toolboxes") don't interfere with each other.
--- a/toolkit/devtools/server/actors/webconsole.js
+++ b/toolkit/devtools/server/actors/webconsole.js
@@ -66,16 +66,17 @@ function WebConsoleActor(aConnection, aP
 
   this._prefs = {};
 
   this.dbg = this.parentActor.makeDebugger();
 
   this._netEvents = new Map();
   this._gripDepth = 0;
   this._listeners = new Set();
+  this._lastConsoleInputEvaluation = undefined;
 
   this._onWillNavigate = this._onWillNavigate.bind(this);
   this._onChangedToplevelDocument = this._onChangedToplevelDocument.bind(this);
   events.on(this.parentActor, "changed-toplevel-document", this._onChangedToplevelDocument);
   this._onObserverNotification = this._onObserverNotification.bind(this);
   if (this.parentActor.isRootActor) {
     Services.obs.addObserver(this._onObserverNotification,
                              "last-pb-context-exited", false);
@@ -353,16 +354,17 @@ WebConsoleActor.prototype =
     this.conn.removeActorPool(this._actorPool);
     if (this.parentActor.isRootActor) {
       Services.obs.removeObserver(this._onObserverNotification,
                                   "last-pb-context-exited");
     }
     this._actorPool = null;
 
     this._jstermHelpersCache = null;
+    this._lastConsoleInputEvaluation = null;
     this._evalWindow = null;
     this._netEvents.clear();
     this.dbg.enabled = false;
     this.dbg = null;
     this.conn = null;
   },
 
   /**
@@ -498,16 +500,27 @@ WebConsoleActor.prototype =
    * @param object aActor
    *        The actor instance you want to release.
    */
   releaseActor: function WCA_releaseActor(aActor)
   {
     this._actorPool.removeActor(aActor.actorID);
   },
 
+  /**
+   * Returns the latest web console input evaluation.
+   * This is undefined if no evaluations have been completed.
+   *
+   * @return object
+   */
+  getLastConsoleInputEvaluation: function WCU_getLastConsoleInputEvaluation()
+  {
+    return this._lastConsoleInputEvaluation;
+  },
+
   //////////////////
   // Request handlers for known packet types.
   //////////////////
 
   /**
    * Handler for the "startListeners" request.
    *
    * @param object aRequest
@@ -811,16 +824,18 @@ WebConsoleActor.prototype =
     // the console should remain functional.
     let resultGrip;
     try {
       resultGrip = this.createValueGrip(result);
     } catch (e) {
       errorMessage = e;
     }
 
+    this._lastConsoleInputEvaluation = result;
+
     return {
       from: this.actorID,
       input: input,
       result: resultGrip,
       timestamp: timestamp,
       exception: errorGrip,
       exceptionMessage: this._createStringGrip(errorMessage),
       helperResult: helperResult,
--- a/toolkit/devtools/server/tests/mochitest/test_inspector-mutations-attr.html
+++ b/toolkit/devtools/server/tests/mochitest/test_inspector-mutations-attr.html
@@ -40,20 +40,22 @@ addTest(function setup() {
     }).then(runNextTest));
   });
 });
 
 addTest(setupAttrTest);
 addTest(testAddAttribute);
 addTest(testChangeAttribute);
 addTest(testRemoveAttribute);
+addTest(testQueuedMutations);
 addTest(setupFrameAttrTest);
 addTest(testAddAttribute);
 addTest(testChangeAttribute);
 addTest(testRemoveAttribute);
+addTest(testQueuedMutations);
 
 function setupAttrTest() {
   attrNode = gInspectee.querySelector("#a")
   promiseDone(gWalker.querySelector(gWalker.rootNode, "#a").then(node => {
     attrFront = node;
   }).then(runNextTest));
 }
 
@@ -80,35 +82,70 @@ function testAddAttribute() {
     is(attrFront.attributes.length, 3, "Should have id and two new attributes.");
     is(attrFront.getAttribute("data-newattr"), "newvalue", "Node front should have the first new attribute");
     is(attrFront.getAttribute("data-newattr2"), "newvalue", "Node front should have the second new attribute.");
     runNextTest();
   });
 }
 
 function testChangeAttribute() {
-  attrNode.setAttribute("data-newattr", "changedvalue");
-  gWalker.once("mutations", () => {
+  attrNode.setAttribute("data-newattr", "changedvalue1");
+  attrNode.setAttribute("data-newattr", "changedvalue2");
+  attrNode.setAttribute("data-newattr", "changedvalue3");
+  gWalker.once("mutations", mutations => {
+    is(mutations.length, 1, "Only one mutation is sent for multiple queued attribute changes");
     is(attrFront.attributes.length, 3, "Should have id and two new attributes.");
-    is(attrFront.getAttribute("data-newattr"), "changedvalue", "Node front should have the changed first value");
+    is(attrFront.getAttribute("data-newattr"), "changedvalue3", "Node front should have the changed first value");
     is(attrFront.getAttribute("data-newattr2"), "newvalue", "Second value should remain unchanged.");
     runNextTest();
   });
 }
 
 function testRemoveAttribute() {
   attrNode.removeAttribute("data-newattr2");
   gWalker.once("mutations", () => {
     is(attrFront.attributes.length, 2, "Should have id and one remaining attribute.");
-    is(attrFront.getAttribute("data-newattr"), "changedvalue", "Node front should still have the first value");
+    is(attrFront.getAttribute("data-newattr"), "changedvalue3", "Node front should still have the first value");
     ok(!attrFront.hasAttribute("data-newattr2"), "Second value should be removed.");
     runNextTest();
   })
 }
 
+function testQueuedMutations() {
+  // All modifications to each attribute should be queued in one mutation event.
+
+  attrNode.removeAttribute("data-newattr");
+  attrNode.setAttribute("data-newattr", "1");
+  attrNode.removeAttribute("data-newattr");
+  attrNode.setAttribute("data-newattr", "2");
+  attrNode.removeAttribute("data-newattr");
+
+  for (var i = 0; i <= 1000; i++) {
+    attrNode.setAttribute("data-newattr2", i);
+  }
+
+  attrNode.removeAttribute("data-newattr3");
+  attrNode.setAttribute("data-newattr3", "1");
+  attrNode.removeAttribute("data-newattr3");
+  attrNode.setAttribute("data-newattr3", "2");
+  attrNode.removeAttribute("data-newattr3");
+  attrNode.setAttribute("data-newattr3", "3");
+
+  gWalker.once("mutations", mutations => {
+    is(mutations.length, 3, "Only one mutation each is sent for multiple queued attribute changes");
+    is(attrFront.attributes.length, 3, "Should have id, data-newattr2, and data-newattr3.");
+
+    is(attrFront.getAttribute("data-newattr2"), "1000", "Node front should still have the correct value");
+    is(attrFront.getAttribute("data-newattr3"), "3", "Node front should still have the correct value");
+    ok(!attrFront.hasAttribute("data-newattr"), "Attribute value should be removed.");
+
+    runNextTest();
+  })
+}
+
 addTest(function cleanup() {
   delete gInspectee;
   delete gWalker;
   delete gClient;
   runNextTest();
 });
 
 
--- a/toolkit/devtools/webconsole/network-monitor.js
+++ b/toolkit/devtools/webconsole/network-monitor.js
@@ -748,23 +748,18 @@ NetworkMonitor.prototype = {
     let event = {};
     event.startedDateTime = new Date(Math.round(aTimestamp / 1000)).toISOString();
     event.headersSize = aExtraStringData.length;
     event.method = aChannel.requestMethod;
     event.url = aChannel.URI.spec;
     event.private = httpActivity.private;
 
     // Determine if this is an XHR request.
-    try {
-      let callbacks = aChannel.notificationCallbacks;
-      let xhrRequest = callbacks ? callbacks.getInterface(Ci.nsIXMLHttpRequest) : null;
-      httpActivity.isXHR = event.isXHR = !!xhrRequest;
-    } catch (e) {
-      httpActivity.isXHR = event.isXHR = false;
-    }
+    httpActivity.isXHR = event.isXHR =
+        (aChannel.loadInfo.contentPolicyType === Ci.nsIContentPolicy.TYPE_XMLHTTPREQUEST);
 
     // Determine the HTTP version.
     aChannel.QueryInterface(Ci.nsIHttpChannelInternal);
     aChannel.getRequestVersion(httpVersionMaj, httpVersionMin);
 
     event.httpVersion = "HTTP/" + httpVersionMaj.value + "." +
                                   httpVersionMin.value;
 
--- a/toolkit/devtools/webconsole/test/chrome.ini
+++ b/toolkit/devtools/webconsole/test/chrome.ini
@@ -10,20 +10,21 @@ support-files =
 [test_basics.html]
 [test_bug819670_getter_throws.html]
 [test_cached_messages.html]
 [test_consoleapi.html]
 [test_consoleapi_innerID.html]
 [test_file_uri.html]
 [test_reflow.html]
 [test_jsterm.html]
+[test_jsterm_cd_iframe.html]
+[test_jsterm_last_result.html]
 [test_network_get.html]
 [test_network_longstring.html]
 [test_network_post.html]
 [test_network_security-hpkp.html]
 [test_network_security-hsts.html]
 [test_nsiconsolemessage.html]
 [test_object_actor.html]
 [test_object_actor_native_getters.html]
 [test_object_actor_native_getters_lenient_this.html]
 [test_page_errors.html]
 [test_throw.html]
-[test_jsterm_cd_iframe.html]
--- a/toolkit/devtools/webconsole/test/common.js
+++ b/toolkit/devtools/webconsole/test/common.js
@@ -3,16 +3,20 @@
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 
 Cu.import("resource://gre/modules/Services.jsm");
+const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
+
+// This gives logging to stdout for tests
+var {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
 
 let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
 let WebConsoleUtils = devtools.require("devtools/toolkit/webconsole/utils").Utils;
 
 let ConsoleAPIStorage = Cc["@mozilla.org/consoleAPI-storage;1"]
                           .getService(Ci.nsIConsoleAPIStorage);
 
 let {ConsoleServiceListener, ConsoleAPIListener} =
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/webconsole/test/test_jsterm_last_result.html
@@ -0,0 +1,130 @@
+<!DOCTYPE HTML>
+<html lang="en">
+<head>
+  <meta charset="utf8">
+  <title>Test for the $_ getter</title>
+  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript;version=1.8" src="common.js"></script>
+  <!-- Any copyright is dedicated to the Public Domain.
+     - http://creativecommons.org/publicdomain/zero/1.0/ -->
+</head>
+<body>
+<p>Test for the $_ getter</p>
+
+<iframe id="content-iframe" src="http://example.com/chrome/toolkit/devtools/webconsole/test/sandboxed_iframe.html"></iframe>
+
+<script class="testbody" type="text/javascript;version=1.8">
+SimpleTest.waitForExplicitFinish();
+let gState;
+
+function evaluateJS(input, callback) {
+  return new Promise((resolve, reject) => {
+    gState.client.evaluateJSAsync(input, response => {
+      if (callback) {
+        callback(response);
+      }
+      resolve(response);
+    });
+  });
+}
+
+function startTest()
+{
+  removeEventListener("load", startTest);
+  attachConsole([], state => {
+    gState = state;
+    let tests = [checkUndefinedResult,checkAdditionResult,checkObjectResult];
+    runTests(tests, testEnd);
+  }, true);
+}
+
+let checkUndefinedResult = Task.async(function*() {
+  info ("$_ returns undefined if nothing has evaluated yet");
+  let response = yield evaluateJS("$_");
+  basicResultCheck(response, "$_", undefined);
+  nextTest();
+});
+
+let checkAdditionResult = Task.async(function*() {
+  info ("$_ returns last value and performs basic arithmetic");
+  let response = yield evaluateJS("2+2");
+  basicResultCheck(response, "2+2", 4);
+
+  response = yield evaluateJS("$_");
+  basicResultCheck(response, "$_", 4);
+
+  response = yield evaluateJS("$_ + 2");
+  basicResultCheck(response, "$_ + 2", 6);
+
+  response = yield evaluateJS("$_ + 4");
+  basicResultCheck(response, "$_ + 4", 10);
+
+  nextTest();
+});
+
+let checkObjectResult = Task.async(function*() {
+  info ("$_ has correct references to objects");
+
+  let response = yield evaluateJS("var foo = {bar:1}; foo;");
+  basicResultCheck(response, "var foo = {bar:1}; foo;", {
+    type: "object",
+    class: "Object",
+    actor: /[a-z]/,
+  });
+  checkObject(response.result.preview.ownProperties, {
+    bar: {
+      value: 1
+    }
+  });
+
+  response = yield evaluateJS("$_");
+  basicResultCheck(response, "$_", {
+    type: "object",
+    class: "Object",
+    actor: /[a-z]/,
+  });
+  checkObject(response.result.preview.ownProperties, {
+    bar: {
+      value: 1
+    }
+  });
+
+  top.foo.bar = 2;
+
+  response = yield evaluateJS("$_");
+  basicResultCheck(response, "$_", {
+    type: "object",
+    class: "Object",
+    actor: /[a-z]/,
+  });
+  checkObject(response.result.preview.ownProperties, {
+    bar: {
+      value: 2
+    }
+  });
+
+  nextTest();
+});
+
+function basicResultCheck(response, input, output) {
+  checkObject(response, {
+    from: gState.actor,
+    input: input,
+    result: output,
+  });
+  ok(!response.exception, "no eval exception");
+  ok(!response.helperResult, "no helper result");
+}
+
+function testEnd()
+{
+  closeDebugger(gState, function() {
+    gState = null;
+    SimpleTest.finish();
+  });
+}
+
+addEventListener("load", startTest);
+</script>
+</body>
+</html>
--- a/toolkit/devtools/webconsole/utils.js
+++ b/toolkit/devtools/webconsole/utils.js
@@ -1545,16 +1545,30 @@ function JSTermHelpers(aOwner)
    *         Returns the result of document.querySelectorAll(aSelector).
    */
   aOwner.sandbox.$$ = function JSTH_$$(aSelector)
   {
     return aOwner.window.document.querySelectorAll(aSelector);
   };
 
   /**
+   * Returns the result of the last console input evaluation
+   *
+   * @return object|undefined
+   * Returns last console evaluation or undefined
+   */
+  Object.defineProperty(aOwner.sandbox, "$_", {
+    get: function() {
+      return aOwner.consoleActor.getLastConsoleInputEvaluation();
+    },
+    enumerable: true,
+    configurable: true
+  });
+
+  /**
    * Runs an xPath query and returns all matched nodes.
    *
    * @param string aXPath
    *        xPath search query to execute.
    * @param [optional] nsIDOMNode aContext
    *        Context to run the xPath query on. Uses window.document if not set.
    * @return array of nsIDOMNode
    */