merge b2g-inbound to m-c a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 23 Jun 2014 18:55:45 -0700
changeset 190252 e86b84998b186642cb162adb265af423f7f4555a
parent 190185 fa6a7a2f476c7dddd2d3dfc218512cd3ca187acb (current diff)
parent 190251 9130ef564653c2a496df65022bdfed2cfd77fd37 (diff)
child 190378 40dee680339e53ea4a993e1edd939568b77665ad
child 190434 6ff5173e1a859b094a8bdc62b5a31da3c852a364
child 190471 cc4602e0c1d89622c7be5da0555c42f323ae43e4
push id27003
push userkwierso@gmail.com
push dateTue, 24 Jun 2014 01:56:11 +0000
treeherdermozilla-central@e86b84998b18 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone33.0a1
first release with
nightly linux32
e86b84998b18 / 33.0a1 / 20140624030200 / files
nightly linux64
e86b84998b18 / 33.0a1 / 20140624030200 / files
nightly mac
e86b84998b18 / 33.0a1 / 20140624030200 / files
nightly win32
e86b84998b18 / 33.0a1 / 20140624030200 / files
nightly win64
e86b84998b18 / 33.0a1 / 20140624030200 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge b2g-inbound to m-c a=merge
b2g/app/b2g.js
dom/mobilemessage/interfaces/nsIDOMMobileMessageManager.idl
dom/system/gonk/tests/test_ril_worker_icc.js
dom/webidl/MobileMessageManager.webidl
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -906,19 +906,16 @@ pref("gfx.canvas.azure.accelerated", tru
 pref("gfx.canvas.skiagl.dynamic-cache", true);
 
 // Limit skia to canvases the size of the device screen or smaller
 pref("gfx.canvas.max-size-for-skia-gl", -1);
 
 // enable fence with readpixels for SurfaceStream
 pref("gfx.gralloc.fence-with-readpixels", true);
 
-// Cell Broadcast API
-pref("ril.cellbroadcast.disabled", false);
-
 // The url of the page used to display network error details.
 pref("b2g.neterror.url", "app://system.gaiamobile.org/net_error.html");
 
 // Enable Web Speech synthesis API
 pref("media.webspeech.synth.enabled", true);
 
 // Downloads API
 pref("dom.mozDownloads.enabled", true);
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -659,23 +659,23 @@ let settingsToObserve = {
     prefName: 'layers.offmainthreadcomposition.log-animations',
     defaultValue: false
   },
   'debug.paint-flashing.enabled': {
     prefName: 'nglayout.debug.paint_flashing',
     defaultValue: false
   },
   'devtools.eventlooplag.threshold': 100,
+  'dom.mozApps.use_reviewer_certs': false,
   'layers.draw-borders': false,
   'layers.draw-tile-borders': false,
   'layers.dump': false,
   'layers.enable-tiles': true,
   'layers.simple-tiles': false,
   'privacy.donottrackheader.enabled': false,
-  'ril.cellbroadcast.disabled': false,
   'ril.radio.disabled': false,
   'ril.mms.requestReadReport.enabled': {
     prefName: 'dom.mms.requestReadReport',
     defaultValue: true
   },
   'ril.mms.requestStatusReport.enabled': {
     prefName: 'dom.mms.requestStatusReport',
     defaultValue: false
--- a/b2g/components/B2GComponents.manifest
+++ b/b2g/components/B2GComponents.manifest
@@ -35,16 +35,17 @@ contract @mozilla.org/dom/messages/syste
 # ProcessGlobal.js
 component {1a94c87a-5ece-4d11-91e1-d29c29f21b28} ProcessGlobal.js
 contract @mozilla.org/b2g-process-global;1 {1a94c87a-5ece-4d11-91e1-d29c29f21b28}
 category app-startup ProcessGlobal service,@mozilla.org/b2g-process-global;1
 
 # OMAContentHandler.js
 component {a6b2ab13-9037-423a-9897-dde1081be323} OMAContentHandler.js
 contract @mozilla.org/uriloader/content-handler;1?type=application/vnd.oma.drm.message {a6b2ab13-9037-423a-9897-dde1081be323}
+contract @mozilla.org/uriloader/content-handler;1?type=application/vnd.oma.dd+xml {a6b2ab13-9037-423a-9897-dde1081be323}
 
 # PaymentGlue.js
 component {8b83eabc-7929-47f4-8b48-4dea8d887e4b} PaymentGlue.js
 contract @mozilla.org/payment/ui-glue;1 {8b83eabc-7929-47f4-8b48-4dea8d887e4b}
 
 # TelProtocolHandler.js
 component {782775dd-7351-45ea-aff1-0ffa872cfdd2} TelProtocolHandler.js
 contract @mozilla.org/network/protocol;1?name=tel {782775dd-7351-45ea-aff1-0ffa872cfdd2}
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,23 +14,23 @@
   <!--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="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="41cc1de26e4edbe12add0009cdc0bd292f2e94fe"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="45479c07cb6ba8c733093d6ee32c767c090c9a28"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="3326b51017252e09ccdd715dec6c5e12a7d1ecfe"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="23db533981ee2cd04fc5d946420402aed2792381"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c2544b1797eb5c59f484c442a24c4dc14c37e68c"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,20 +12,20 @@
   <!--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="cc67f31dc638c0b7edba3cf7e3d87cadf0ed52bf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="41cc1de26e4edbe12add0009cdc0bd292f2e94fe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="45479c07cb6ba8c733093d6ee32c767c090c9a28"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="23db533981ee2cd04fc5d946420402aed2792381"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c2544b1797eb5c59f484c442a24c4dc14c37e68c"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--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="276ce45e78b09c4a4ee643646f691d22804754c1">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="41cc1de26e4edbe12add0009cdc0bd292f2e94fe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="45479c07cb6ba8c733093d6ee32c767c090c9a28"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <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="23db533981ee2cd04fc5d946420402aed2792381"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c2544b1797eb5c59f484c442a24c4dc14c37e68c"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
   <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,23 +14,23 @@
   <!--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="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="41cc1de26e4edbe12add0009cdc0bd292f2e94fe"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="45479c07cb6ba8c733093d6ee32c767c090c9a28"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="3326b51017252e09ccdd715dec6c5e12a7d1ecfe"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="23db533981ee2cd04fc5d946420402aed2792381"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c2544b1797eb5c59f484c442a24c4dc14c37e68c"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,20 +12,20 @@
   <!--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="cc67f31dc638c0b7edba3cf7e3d87cadf0ed52bf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="41cc1de26e4edbe12add0009cdc0bd292f2e94fe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="45479c07cb6ba8c733093d6ee32c767c090c9a28"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="23db533981ee2cd04fc5d946420402aed2792381"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c2544b1797eb5c59f484c442a24c4dc14c37e68c"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
@@ -109,29 +109,31 @@
   <project name="platform/prebuilts/qemu-kernel" path="prebuilts/qemu-kernel" revision="ec4a882d411d0d4ceadc5912ab4ce6fd4df23ab7"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="b86c0ecb186ffdbfb85d9c65b8a4b084b3ee9514"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="31ec211efafde89ab39472d7bd040f00d1b71945"/>
   <project name="platform/system/extras" path="system/extras" revision="4d4bc6e7777887d93340f577d9b46de4a7c75f26"/>
   <project name="platform/system/media" path="system/media" revision="df2cdd433738a891102873710bdd3c3db7adb0cc"/>
   <project name="platform/system/netd" path="system/netd" revision="ea8103eae5642621ca8202e00620f4ca954ed413"/>
   <project name="platform/system/security" path="system/security" revision="360f51f7af191316cd739f229db1c5f7233be063"/>
   <project name="platform/system/vold" path="system/vold" revision="153df4d067a4149c7d78f1c92fed2ce2bd6a272e"/>
+  <!--original fetch url was git://github.com/t2m-foxfone/-->
+  <remote fetch="https://git.mozilla.org/external/t2m-foxfone" name="t2m"/>
   <default remote="caf" revision="jb_3.2" sync-j="4"/>
   <!-- Flame specific things -->
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="e8a318f7690092e639ba88891606f4183e846d3f"/>
   <project name="device/qcom/common" path="device/qcom/common" revision="34ed8345250bb97262d70a052217a92e83444ede"/>
-  <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="243b6f3d219592a84c7318e9446cde397233ae39"/>
+  <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="33faca8033c6f8cda0c383ab40d69c7a45e6db38"/>
   <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="30a441fb7275fc5bc347f84ccb29e977a7eca34e"/>
   <project name="kernel_lk" path="bootable/bootloader/lk" remote="b2g" revision="2b1d8b5b7a760230f4c94c02e733e3929f44253a"/>
   <project name="platform_bootable_recovery" path="bootable/recovery" remote="b2g" revision="e81502511cda303c803e63f049574634bc96f9f2"/>
   <project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="81c4a859d75d413ad688067829d21b7ba9205f81"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="f0689ac1914cdbc59e53bdc9edd9013dc157c299"/>
   <project name="platform/external/bluetooth/glib" path="external/bluetooth/glib" revision="dd925f76e4f149c3d5571b80e12f7e24bbe89c59"/>
   <project name="platform/external/dbus" path="external/dbus" revision="ea87119c843116340f5df1d94eaf8275e1055ae8"/>
-  <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="494c177966fdc31183a5f7af82dc9130f523da4b"/>
+  <project name="platform_external_libnfc-nci" path="external/libnfc-nci" remote="t2m" revision="4186bdecb4dae911b39a8202252cc2310d91b0be"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="320b05a5761eb2a4816f7529c91ea49422979b55"/>
   <project name="platform/frameworks/av" path="frameworks/av" revision="5b934dc57dae25f286b0e7210dc6ff47f3244927"/>
   <project name="platform/frameworks/base" path="frameworks/base" revision="af3e4fbdc9369643a92015ea2657361f3b1b46fe"/>
   <project name="platform/frameworks/native" path="frameworks/native" revision="33a2b51f78416536e1bfba0c0b7776db307f3a4f"/>
   <project name="platform/hardware/libhardware" path="hardware/libhardware" revision="484802559ed106bac4811bd01c024ca64f741e60"/>
   <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="83f363a26069e9c188d2aaef5b9ef63e84ad1511"/>
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="5e110615212302c5d798a3c223dcee458817651c"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="280d29203b2aa30d713c5a6cc63d626e5a7df822"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "aba00cfd579caaf205e05c269f0a8100f242f39c", 
+    "revision": "8ac363347c96715adf6bec5fc30a975a2cfbaafd", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,22 +12,22 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="41cc1de26e4edbe12add0009cdc0bd292f2e94fe"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="45479c07cb6ba8c733093d6ee32c767c090c9a28"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="23db533981ee2cd04fc5d946420402aed2792381"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c2544b1797eb5c59f484c442a24c4dc14c37e68c"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
   <project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
   <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
   <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="41cc1de26e4edbe12add0009cdc0bd292f2e94fe"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="45479c07cb6ba8c733093d6ee32c767c090c9a28"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,20 +12,20 @@
   <!--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="cc67f31dc638c0b7edba3cf7e3d87cadf0ed52bf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="41cc1de26e4edbe12add0009cdc0bd292f2e94fe"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="45479c07cb6ba8c733093d6ee32c767c090c9a28"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="23db533981ee2cd04fc5d946420402aed2792381"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c2544b1797eb5c59f484c442a24c4dc14c37e68c"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,22 +12,22 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
     <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="41cc1de26e4edbe12add0009cdc0bd292f2e94fe"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="45479c07cb6ba8c733093d6ee32c767c090c9a28"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="bbb7659d8ea2afb396f99b3dc971ab3c42da3778"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="c510babaf88dfa2cfe2c202afb2649ee124569af"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="23db533981ee2cd04fc5d946420402aed2792381"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="c2544b1797eb5c59f484c442a24c4dc14c37e68c"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
   <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
   <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
   <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/dom/alarm/AlarmDB.jsm
+++ b/dom/alarm/AlarmDB.jsm
@@ -31,55 +31,52 @@ AlarmDB.prototype = {
   __proto__: IndexedDBHelper.prototype,
 
   init: function init() {
     debug("init()");
 
     this.initDBHelper(ALARMDB_NAME, ALARMDB_VERSION, [ALARMSTORE_NAME]);
   },
 
-  upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
+  upgradeSchema: function upgradeSchema(aTransaction, aDb,
+                                        aOldVersion, aNewVersion) {
     debug("upgradeSchema()");
 
-    let objectStore = aDb.createObjectStore(ALARMSTORE_NAME, { keyPath: "id", autoIncrement: true });
+    let objStore =
+      aDb.createObjectStore(ALARMSTORE_NAME,
+                            { keyPath: "id", autoIncrement: true });
 
-    objectStore.createIndex("date",           "date",           { unique: false });
-    objectStore.createIndex("ignoreTimezone", "ignoreTimezone", { unique: false });
-    objectStore.createIndex("timezoneOffset", "timezoneOffset", { unique: false });
-    objectStore.createIndex("data",           "data",           { unique: false });
-    objectStore.createIndex("pageURL",        "pageURL",        { unique: false });
-    objectStore.createIndex("manifestURL",    "manifestURL",    { unique: false });
+    objStore.createIndex("date",           "date",           { unique: false });
+    objStore.createIndex("ignoreTimezone", "ignoreTimezone", { unique: false });
+    objStore.createIndex("timezoneOffset", "timezoneOffset", { unique: false });
+    objStore.createIndex("data",           "data",           { unique: false });
+    objStore.createIndex("pageURL",        "pageURL",        { unique: false });
+    objStore.createIndex("manifestURL",    "manifestURL",    { unique: false });
 
     debug("Created object stores and indexes");
   },
 
   /**
    * @param aAlarm
    *        The record to be added.
    * @param aSuccessCb
    *        Callback function to invoke with result ID.
    * @param aErrorCb [optional]
    *        Callback function to invoke when there was an error.
    */
   add: function add(aAlarm, aSuccessCb, aErrorCb) {
     debug("add()");
 
-    this.newTxn(
-      "readwrite",
-      ALARMSTORE_NAME,
-      function txnCb(aTxn, aStore) {
-        debug("Going to add " + JSON.stringify(aAlarm));
-        aStore.put(aAlarm).onsuccess = function setTxnResult(aEvent) {
-          aTxn.result = aEvent.target.result;
-          debug("Request successful. New record ID: " + aTxn.result);
-        };
-      },
-      aSuccessCb,
-      aErrorCb
-    );
+    this.newTxn("readwrite", ALARMSTORE_NAME, function txnCb(aTxn, aStore) {
+      debug("Going to add " + JSON.stringify(aAlarm));
+      aStore.put(aAlarm).onsuccess = function setTxnResult(aEvent) {
+        aTxn.result = aEvent.target.result;
+        debug("Request successful. New record ID: " + aTxn.result);
+      };
+    }, aSuccessCb, aErrorCb);
   },
 
   /**
    * @param aId
    *        The ID of record to be removed.
    * @param aManifestURL
    *        The manifest URL of the app that alarm belongs to.
    *        If null, directly remove the ID record; otherwise,
@@ -87,69 +84,57 @@ AlarmDB.prototype = {
    * @param aSuccessCb
    *        Callback function to invoke with result.
    * @param aErrorCb [optional]
    *        Callback function to invoke when there was an error.
    */
   remove: function remove(aId, aManifestURL, aSuccessCb, aErrorCb) {
     debug("remove()");
 
-    this.newTxn(
-      "readwrite",
-      ALARMSTORE_NAME,
-      function txnCb(aTxn, aStore) {
-        debug("Going to remove " + aId);
+    this.newTxn("readwrite", ALARMSTORE_NAME, function txnCb(aTxn, aStore) {
+      debug("Going to remove " + aId);
 
-        // Look up the existing record and compare the manifestURL
-        // to see if the alarm to be removed belongs to this app.
-        aStore.get(aId).onsuccess = function doRemove(aEvent) {
-          let alarm = aEvent.target.result;
+      // Look up the existing record and compare the manifestURL
+      // to see if the alarm to be removed belongs to this app.
+      aStore.get(aId).onsuccess = function doRemove(aEvent) {
+        let alarm = aEvent.target.result;
 
-          if (!alarm) {
-            debug("Alarm doesn't exist. No need to remove it.");
-            return;
-          }
+        if (!alarm) {
+          debug("Alarm doesn't exist. No need to remove it.");
+          return;
+        }
 
-          if (aManifestURL && aManifestURL != alarm.manifestURL) {
-            debug("Cannot remove the alarm added by other apps.");
-            return;
-          }
+        if (aManifestURL && aManifestURL != alarm.manifestURL) {
+          debug("Cannot remove the alarm added by other apps.");
+          return;
+        }
 
-          aStore.delete(aId);
-        };
-      },
-      aSuccessCb,
-      aErrorCb
-    );
+        aStore.delete(aId);
+      };
+    }, aSuccessCb, aErrorCb);
   },
 
   /**
    * @param aManifestURL
    *        The manifest URL of the app that alarms belong to.
    *        If null, directly return all alarms; otherwise,
    *        only return the alarms that belong to this app.
    * @param aSuccessCb
    *        Callback function to invoke with result array.
    * @param aErrorCb [optional]
    *        Callback function to invoke when there was an error.
    */
   getAll: function getAll(aManifestURL, aSuccessCb, aErrorCb) {
     debug("getAll()");
 
-    this.newTxn(
-      "readonly",
-      ALARMSTORE_NAME,
-      function txnCb(aTxn, aStore) {
-        if (!aTxn.result) {
-          aTxn.result = [];
-        }
+    this.newTxn("readonly", ALARMSTORE_NAME, function txnCb(aTxn, aStore) {
+      if (!aTxn.result) {
+        aTxn.result = [];
+      }
 
-        let index = aStore.index("manifestURL");
-        index.mozGetAll(aManifestURL).onsuccess = function setTxnResult(aEvent) {
-          aTxn.result = aEvent.target.result;
-          debug("Request successful. Record count: " + aTxn.result.length);
-        };
-      },
-      aSuccessCb,
-      aErrorCb
-    );
+      let index = aStore.index("manifestURL");
+      index.mozGetAll(aManifestURL).onsuccess = function setTxnResult(aEvent) {
+        aTxn.result = aEvent.target.result;
+        debug("Request successful. Record count: " + aTxn.result.length);
+      };
+    }, aSuccessCb, aErrorCb);
   }
 };
--- a/dom/alarm/AlarmService.jsm
+++ b/dom/alarm/AlarmService.jsm
@@ -24,45 +24,47 @@ XPCOMUtils.defineLazyGetter(this, "appsS
   return Cc["@mozilla.org/AppsService;1"].getService(Ci.nsIAppsService);
 });
 
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIMessageListenerManager");
 
 XPCOMUtils.defineLazyGetter(this, "messenger", function() {
-  return Cc["@mozilla.org/system-message-internal;1"].getService(Ci.nsISystemMessagesInternal);
+  return Cc["@mozilla.org/system-message-internal;1"]
+           .getService(Ci.nsISystemMessagesInternal);
 });
 
 XPCOMUtils.defineLazyGetter(this, "powerManagerService", function() {
-  return Cc["@mozilla.org/power/powermanagerservice;1"].getService(Ci.nsIPowerManagerService);
+  return Cc["@mozilla.org/power/powermanagerservice;1"]
+           .getService(Ci.nsIPowerManagerService);
 });
 
 /**
  * AlarmService provides an API to schedule alarms using the device's RTC.
  *
  * AlarmService is primarily used by the mozAlarms API (navigator.mozAlarms)
  * which uses IPC to communicate with the service.
  *
  * AlarmService can also be used by Gecko code by importing the module and then
  * using AlarmService.add() and AlarmService.remove(). Only Gecko code running
  * in the parent process should do this.
  */
 
 this.AlarmService = {
   init: function init() {
     debug("init()");
+
     Services.obs.addObserver(this, "profile-change-teardown", false);
     Services.obs.addObserver(this, "webapps-clear-data",false);
 
     this._currentTimezoneOffset = (new Date()).getTimezoneOffset();
 
-    let alarmHalService =
-      this._alarmHalService = Cc["@mozilla.org/alarmHalService;1"]
-                              .getService(Ci.nsIAlarmHalService);
+    let alarmHalService = this._alarmHalService =
+      Cc["@mozilla.org/alarmHalService;1"].getService(Ci.nsIAlarmHalService);
 
     alarmHalService.setAlarmFiredCb(this._onAlarmFired.bind(this));
     alarmHalService.setTimezoneChangedCb(this._onTimezoneChanged.bind(this));
 
     // Add the messages to be listened to.
     this._messages = ["AlarmsManager:GetAll",
                       "AlarmsManager:Add",
                       "AlarmsManager:Remove"];
@@ -104,54 +106,52 @@ this.AlarmService = {
 
     // To prevent the hacked child process from sending commands to parent
     // to schedule alarms, we need to check its permission and manifest URL.
     if (this._messages.indexOf(aMessage.name) != -1) {
       if (!aMessage.target.assertPermission("alarms")) {
         debug("Got message from a child process with no 'alarms' permission.");
         return null;
       }
+
       if (!aMessage.target.assertContainApp(json.manifestURL)) {
         debug("Got message from a child process containing illegal manifest URL.");
         return null;
       }
     }
 
     let mm = aMessage.target.QueryInterface(Ci.nsIMessageSender);
+
     switch (aMessage.name) {
       case "AlarmsManager:GetAll":
-        this._db.getAll(
-          json.manifestURL,
+        this._db.getAll(json.manifestURL,
           function getAllSuccessCb(aAlarms) {
             debug("Callback after getting alarms from database: " +
                   JSON.stringify(aAlarms));
+
             this._sendAsyncMessage(mm, "GetAll", true, json.requestId, aAlarms);
           }.bind(this),
           function getAllErrorCb(aErrorMsg) {
             this._sendAsyncMessage(mm, "GetAll", false, json.requestId, aErrorMsg);
-          }.bind(this)
-        );
+          }.bind(this));
         break;
 
       case "AlarmsManager:Add":
         // Prepare a record for the new alarm to be added.
-        let newAlarm = {
-          date: json.date,
-          ignoreTimezone: json.ignoreTimezone,
-          data: json.data,
-          pageURL: json.pageURL,
-          manifestURL: json.manifestURL
-        };
+        let newAlarm = { date: json.date,
+                         ignoreTimezone: json.ignoreTimezone,
+                         data: json.data,
+                         pageURL: json.pageURL,
+                         manifestURL: json.manifestURL };
 
         this.add(newAlarm, null,
           // Receives the alarm ID as the last argument.
           this._sendAsyncMessage.bind(this, mm, "Add", true, json.requestId),
           // Receives the error message as the last argument.
-          this._sendAsyncMessage.bind(this, mm, "Add", false, json.requestId)
-        );
+          this._sendAsyncMessage.bind(this, mm, "Add", false, json.requestId));
         break;
 
       case "AlarmsManager:Remove":
         this.remove(json.id, json.manifestURL);
         break;
 
       default:
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
@@ -164,18 +164,17 @@ this.AlarmService = {
     debug("_sendAsyncMessage()");
 
     if (!aMessageManager) {
       debug("Invalid message manager: null");
       throw Components.results.NS_ERROR_FAILURE;
     }
 
     let json = null;
-    switch (aMessageName)
-    {
+    switch (aMessageName) {
       case "Add":
         json = aSuccess ?
           { requestId: aRequestId, id: aData } :
           { requestId: aRequestId, errorMsg: aData };
         break;
 
       case "GetAll":
         json = aSuccess ?
@@ -184,66 +183,63 @@ this.AlarmService = {
         break;
 
       default:
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
         break;
     }
 
     aMessageManager.sendAsyncMessage("AlarmsManager:" + aMessageName +
-                                     ":Return:" + (aSuccess ? "OK" : "KO"), json);
+                                       ":Return:" + (aSuccess ? "OK" : "KO"),
+                                     json);
   },
 
   _removeAlarmFromDb: function _removeAlarmFromDb(aId, aManifestURL,
                                                   aRemoveSuccessCb) {
     debug("_removeAlarmFromDb()");
 
     // If the aRemoveSuccessCb is undefined or null, set a dummy callback for
     // it which is needed for _db.remove().
     if (!aRemoveSuccessCb) {
       aRemoveSuccessCb = function removeSuccessCb() {
         debug("Remove alarm from DB successfully.");
       };
     }
 
-    this._db.remove(
-      aId,
-      aManifestURL,
-      aRemoveSuccessCb,
-      function removeErrorCb(aErrorMsg) {
-        throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-      }
-    );
+    this._db.remove(aId, aManifestURL, aRemoveSuccessCb,
+                    function removeErrorCb(aErrorMsg) {
+                      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+                    });
   },
 
   /**
    * Create a copy of the alarm that does not expose internal fields to
    * receivers and sticks to the public |respectTimezone| API rather than the
    * boolean |ignoreTimezone| field.
    */
   _publicAlarm: function _publicAlarm(aAlarm) {
-    let alarm = {
-      "id":              aAlarm.id,
-      "date":            aAlarm.date,
-      "respectTimezone": aAlarm.ignoreTimezone ?
-                           "ignoreTimezone" : "honorTimezone",
-      "data":            aAlarm.data
-    };
+    let alarm = { "id": aAlarm.id,
+                  "date": aAlarm.date,
+                  "respectTimezone": aAlarm.ignoreTimezone ?
+                                       "ignoreTimezone" : "honorTimezone",
+                  "data": aAlarm.data };
 
     return alarm;
   },
 
   _fireSystemMessage: function _fireSystemMessage(aAlarm) {
     debug("Fire system message: " + JSON.stringify(aAlarm));
 
     let manifestURI = Services.io.newURI(aAlarm.manifestURL, null, null);
     let pageURI = Services.io.newURI(aAlarm.pageURL, null, null);
 
-    messenger.sendMessage("alarm", this._publicAlarm(aAlarm),
-                          pageURI, manifestURI);
+    messenger.sendMessage("alarm",
+                          this._publicAlarm(aAlarm),
+                          pageURI,
+                          manifestURI);
   },
 
   _notifyAlarmObserver: function _notifyAlarmObserver(aAlarm) {
     debug("_notifyAlarmObserver()");
 
     if (aAlarm.manifestURL) {
       this._fireSystemMessage(aAlarm);
     } else if (typeof aAlarm.alarmFiredCb === "function") {
@@ -271,31 +267,31 @@ this.AlarmService = {
       if (nextAlarmTime <= Date.now()) {
         this._removeAlarmFromDb(nextAlarm.id, null);
         this._notifyAlarmObserver(nextAlarm);
       } else {
         this._currentAlarm = nextAlarm;
         break;
       }
     }
+
     this._debugCurrentAlarm();
   },
 
   _onTimezoneChanged: function _onTimezoneChanged(aTimezoneOffset) {
     debug("_onTimezoneChanged()");
 
     this._currentTimezoneOffset = aTimezoneOffset;
     this._restoreAlarmsFromDb();
   },
 
   _restoreAlarmsFromDb: function _restoreAlarmsFromDb() {
     debug("_restoreAlarmsFromDb()");
 
-    this._db.getAll(
-      null,
+    this._db.getAll(null,
       function getAllSuccessCb(aAlarms) {
         debug("Callback after getting alarms from database: " +
               JSON.stringify(aAlarms));
 
         // Clear any alarms set or queued in the cache.
         let alarmQueue = this._alarmQueue;
         alarmQueue.length = 0;
         this._currentAlarm = null;
@@ -306,28 +302,27 @@ this.AlarmService = {
           if (this._getAlarmTime(aAlarm) > Date.now()) {
             alarmQueue.push(aAlarm);
           } else {
             this._removeAlarmFromDb(aAlarm.id, null);
             this._notifyAlarmObserver(aAlarm);
           }
         }.bind(this));
 
-        // Set the next alarm from queue.
+        // Set the next alarm from the queue.
         if (alarmQueue.length) {
           alarmQueue.sort(this._sortAlarmByTimeStamps.bind(this));
           this._currentAlarm = alarmQueue.shift();
         }
 
         this._debugCurrentAlarm();
       }.bind(this),
       function getAllErrorCb(aErrorMsg) {
         throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-      }
-    );
+      });
   },
 
   _getAlarmTime: function _getAlarmTime(aAlarm) {
     // Avoid casting a Date object to a Date again to
     // preserve milliseconds. See bug 810973.
     let alarmTime;
     if (aAlarm.date instanceof Date) {
       alarmTime = aAlarm.date.getTime();
@@ -336,17 +331,18 @@ this.AlarmService = {
     }
 
     // For an alarm specified with "ignoreTimezone", it must be fired respect
     // to the user's timezone.  Supposing an alarm was set at 7:00pm at Tokyo,
     // it must be gone off at 7:00pm respect to Paris' local time when the user
     // is located at Paris.  We can adjust the alarm UTC time by calculating
     // the difference of the orginal timezone and the current timezone.
     if (aAlarm.ignoreTimezone) {
-       alarmTime += (this._currentTimezoneOffset - aAlarm.timezoneOffset) * 60000;
+      alarmTime +=
+        (this._currentTimezoneOffset - aAlarm.timezoneOffset) * 60000;
     }
     return alarmTime;
   },
 
   _sortAlarmByTimeStamps: function _sortAlarmByTimeStamps(aAlarm1, aAlarm2) {
     return this._getAlarmTime(aAlarm1) - this._getAlarmTime(aAlarm2);
   },
 
@@ -397,18 +393,17 @@ this.AlarmService = {
 
     if (!aNewAlarm.date) {
       aErrorCb("alarm.date is null");
       return;
     }
 
     aNewAlarm['timezoneOffset'] = this._currentTimezoneOffset;
 
-    this._db.add(
-      aNewAlarm,
+    this._db.add(aNewAlarm,
       function addSuccessCb(aNewId) {
         debug("Callback after adding alarm in database.");
 
         aNewAlarm['id'] = aNewId;
 
         // Now that the alarm has been added to the database, we can tack on
         // the non-serializable callback to the in-memory object.
         aNewAlarm['alarmFiredCb'] = aAlarmFiredCb;
@@ -417,17 +412,17 @@ this.AlarmService = {
         if (this._currentAlarm == null) {
           this._currentAlarm = aNewAlarm;
           this._debugCurrentAlarm();
           aSuccessCb(aNewId);
           return;
         }
 
         // If the new alarm is earlier than the current alarm, swap them and
-        // push the previous alarm back to queue.
+        // push the previous alarm back to the queue.
         let alarmQueue = this._alarmQueue;
         let aNewAlarmTime = this._getAlarmTime(aNewAlarm);
         let currentAlarmTime = this._getAlarmTime(this._currentAlarm);
         if (aNewAlarmTime < currentAlarmTime) {
           alarmQueue.unshift(this._currentAlarm);
           this._currentAlarm = aNewAlarm;
           this._debugCurrentAlarm();
           aSuccessCb(aNewId);
@@ -437,34 +432,32 @@ this.AlarmService = {
         // Push the new alarm in the queue.
         alarmQueue.push(aNewAlarm);
         alarmQueue.sort(this._sortAlarmByTimeStamps.bind(this));
         this._debugCurrentAlarm();
         aSuccessCb(aNewId);
       }.bind(this),
       function addErrorCb(aErrorMsg) {
         aErrorCb(aErrorMsg);
-      }.bind(this)
-    );
+      }.bind(this));
   },
 
   /*
    * Remove the alarm associated with an ID.
    *
    * @param number aAlarmId
    *        The ID of the alarm to be removed.
    * @param string aManifestURL
    *        Manifest URL for application which added the alarm. (Optional)
    * @returns void
    */
   remove: function(aAlarmId, aManifestURL) {
     debug("remove(" + aAlarmId + ", " + aManifestURL + ")");
-    this._removeAlarmFromDb(
-      aAlarmId,
-      aManifestURL,
+
+    this._removeAlarmFromDb(aAlarmId, aManifestURL,
       function removeSuccessCb() {
         debug("Callback after removing alarm from database.");
 
         // If there are no alarms set, nothing to do.
         if (!this._currentAlarm) {
           debug("No alarms set.");
           return;
         }
@@ -483,35 +476,37 @@ this.AlarmService = {
               break;
             }
           }
           this._debugCurrentAlarm();
           return;
         }
 
         // The alarm to be removed is the current alarm reset the next alarm
-        // from queue if any.
+        // from the queue if any.
         if (alarmQueue.length) {
           this._currentAlarm = alarmQueue.shift();
           this._debugCurrentAlarm();
           return;
         }
 
         // No alarm waiting to be set in the queue.
         this._currentAlarm = null;
         this._debugCurrentAlarm();
-      }.bind(this)
-    );
+      }.bind(this));
   },
 
   observe: function(aSubject, aTopic, aData) {
+    debug("observe(): " + aTopic);
+
     switch (aTopic) {
       case "profile-change-teardown":
         this.uninit();
         break;
+
       case "webapps-clear-data":
         let params =
           aSubject.QueryInterface(Ci.mozIApplicationClearPrivateDataParams);
         if (!params) {
           debug("Error! Fail to remove alarms for an uninstalled app.");
           return;
         }
 
@@ -521,33 +516,32 @@ this.AlarmService = {
         }
 
         let manifestURL = appsService.getManifestURLByLocalId(params.appId);
         if (!manifestURL) {
           debug("Error! Fail to remove alarms for an uninstalled app.");
           return;
         }
 
-        this._db.getAll(
-          manifestURL,
+        this._db.getAll(manifestURL,
           function getAllSuccessCb(aAlarms) {
             aAlarms.forEach(function removeAlarm(aAlarm) {
               this.remove(aAlarm.id, manifestURL);
             }, this);
           }.bind(this),
           function getAllErrorCb(aErrorMsg) {
             throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
-          }
-        );
+          });
         break;
     }
   },
 
   uninit: function uninit() {
     debug("uninit()");
+
     Services.obs.removeObserver(this, "profile-change-teardown");
     Services.obs.removeObserver(this, "webapps-clear-data");
 
     this._messages.forEach(function(aMsgName) {
       ppmm.removeMessageListener(aMsgName, this);
     }.bind(this));
     ppmm = null;
 
--- a/dom/alarm/AlarmsManager.js
+++ b/dom/alarm/AlarmsManager.js
@@ -13,23 +13,21 @@ function debug(aStr) {
 }
 
 const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
 
-function AlarmsManager()
-{
+function AlarmsManager() {
   debug("Constructor");
 }
 
 AlarmsManager.prototype = {
-
   __proto__: DOMRequestIpcHelper.prototype,
 
   contractID : "@mozilla.org/alarmsManager;1",
 
   classID : Components.ID("{fea1e884-9b05-11e1-9b64-87a7016c3860}"),
 
   QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
                                           Ci.nsISupportsWeakReference,
@@ -43,60 +41,56 @@ AlarmsManager.prototype = {
       throw Components.results.NS_ERROR_FAILURE;
     }
 
     if (!aDate) {
       throw Components.results.NS_ERROR_INVALID_ARG;
     }
 
     let isIgnoreTimezone = true;
+
     switch (aRespectTimezone) {
       case "honorTimezone":
         isIgnoreTimezone = false;
         break;
 
       case "ignoreTimezone":
         isIgnoreTimezone = true;
         break;
 
       default:
         throw Components.results.NS_ERROR_INVALID_ARG;
         break;
     }
 
     let request = this.createRequest();
-    this._cpmm.sendAsyncMessage(
-      "AlarmsManager:Add",
-      { requestId: this.getRequestId(request),
-        date: aDate,
-        ignoreTimezone: isIgnoreTimezone,
-        data: aData,
-        pageURL: this._pageURL,
-        manifestURL: this._manifestURL }
-    );
+    this._cpmm.sendAsyncMessage("AlarmsManager:Add",
+                                { requestId: this.getRequestId(request),
+                                  date: aDate,
+                                  ignoreTimezone: isIgnoreTimezone,
+                                  data: aData,
+                                  pageURL: this._pageURL,
+                                  manifestURL: this._manifestURL });
     return request;
   },
 
   remove: function remove(aId) {
     debug("remove()");
 
-    this._cpmm.sendAsyncMessage(
-      "AlarmsManager:Remove",
-      { id: aId, manifestURL: this._manifestURL }
-    );
+    this._cpmm.sendAsyncMessage("AlarmsManager:Remove",
+                                { id: aId, manifestURL: this._manifestURL });
   },
 
   getAll: function getAll() {
     debug("getAll()");
 
     let request = this.createRequest();
-    this._cpmm.sendAsyncMessage(
-      "AlarmsManager:GetAll",
-      { requestId: this.getRequestId(request), manifestURL: this._manifestURL }
-    );
+    this._cpmm.sendAsyncMessage("AlarmsManager:GetAll",
+                                { requestId: this.getRequestId(request),
+                                  manifestURL: this._manifestURL });
     return request;
   },
 
   receiveMessage: function receiveMessage(aMessage) {
     debug("receiveMessage(): " + aMessage.name);
 
     let json = aMessage.json;
     let request = this.getRequest(json.requestId);
@@ -110,39 +104,41 @@ AlarmsManager.prototype = {
       case "AlarmsManager:Add:Return:OK":
         Services.DOMRequest.fireSuccess(request, json.id);
         break;
 
       case "AlarmsManager:GetAll:Return:OK":
         // We don't need to expose everything to the web content.
         let alarms = [];
         json.alarms.forEach(function trimAlarmInfo(aAlarm) {
-          let alarm = { "id":              aAlarm.id,
-                        "date":            aAlarm.date,
+          let alarm = { "id": aAlarm.id,
+                        "date": aAlarm.date,
                         "respectTimezone": aAlarm.ignoreTimezone ?
                                              "ignoreTimezone" : "honorTimezone",
-                        "data":            aAlarm.data };
+                        "data": aAlarm.data };
           alarms.push(alarm);
         });
+
         Services.DOMRequest.fireSuccess(request,
                                         Cu.cloneInto(alarms, this._window));
         break;
 
       case "AlarmsManager:Add:Return:KO":
         Services.DOMRequest.fireError(request, json.errorMsg);
         break;
 
       case "AlarmsManager:GetAll:Return:KO":
         Services.DOMRequest.fireError(request, json.errorMsg);
         break;
 
       default:
         debug("Wrong message: " + aMessage.name);
         break;
     }
+
     this.removeRequest(json.requestId);
    },
 
   // nsIDOMGlobalPropertyInitializer implementation
   init: function init(aWindow) {
     debug("init()");
 
     this._cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
--- a/dom/cellbroadcast/interfaces/nsIDOMMozCellBroadcastMessage.idl
+++ b/dom/cellbroadcast/interfaces/nsIDOMMozCellBroadcastMessage.idl
@@ -6,20 +6,25 @@
 #include "nsISupports.idl"
 
 interface nsIDOMMozCellBroadcastEtwsInfo;
 
 /**
  * MozCellBroadcastMessage encapsulates Cell Broadcast short message service
  * (CBS) messages.
  */
-[scriptable, uuid(701e74a9-5fc4-4e2d-a324-9b7693395159)]
+[scriptable, uuid(dc729df4-f1d8-11e3-b00d-d3332542c557)]
 interface nsIDOMMozCellBroadcastMessage : nsISupports
 {
   /**
+   * The Service Id in the device where the message is received from.
+   */
+  readonly attribute unsigned long serviceId;
+
+  /**
    * Indication of the geographical area over which the Message Code is unique,
    * and the display mode.
    *
    * Possible values are: "cell-immediate", "plmn", "location-area" and "cell".
    */
   readonly attribute DOMString gsmGeographicalScope;
 
   /**
new file mode 100644
--- /dev/null
+++ b/dom/cellbroadcast/tests/marionette/head.js
@@ -0,0 +1,229 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const {Cc: Cc, Ci: Ci, Cr: Cr, Cu: Cu} = SpecialPowers;
+
+let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise;
+
+/**
+ * Push required permissions and test if |navigator.mozCellBroadcast| exists.
+ * Resolve if it does, reject otherwise.
+ *
+ * Fulfill params:
+ *   cbManager -- an reference to navigator.mozCellBroadcast.
+ *
+ * Reject params: (none)
+ *
+ * @return A deferred promise.
+ */
+let cbManager;
+function ensureCellBroadcast() {
+  let deferred = Promise.defer();
+
+  let permissions = [{
+    "type": "cellbroadcast",
+    "allow": 1,
+    "context": document,
+  }];
+  SpecialPowers.pushPermissions(permissions, function() {
+    ok(true, "permissions pushed: " + JSON.stringify(permissions));
+
+    cbManager = window.navigator.mozCellBroadcast;
+    if (cbManager) {
+      log("navigator.mozCellBroadcast is instance of " + cbManager.constructor);
+    } else {
+      log("navigator.mozCellBroadcast is undefined.");
+    }
+
+    if (cbManager instanceof window.MozCellBroadcast) {
+      deferred.resolve(cbManager);
+    } else {
+      deferred.reject();
+    }
+  });
+
+  return deferred.promise;
+}
+
+/**
+ * Send emulator command with safe guard.
+ *
+ * We should only call |finish()| after all emulator command transactions
+ * end, so here comes with the pending counter.  Resolve when the emulator
+ * gives positive response, and reject otherwise.
+ *
+ * Fulfill params:
+ *   result -- an array of emulator response lines.
+ *
+ * Reject params:
+ *   result -- an array of emulator response lines.
+ *
+ * @return A deferred promise.
+ */
+let pendingEmulatorCmdCount = 0;
+function runEmulatorCmdSafe(aCommand) {
+  let deferred = Promise.defer();
+
+  ++pendingEmulatorCmdCount;
+  runEmulatorCmd(aCommand, function(aResult) {
+    --pendingEmulatorCmdCount;
+
+    ok(true, "Emulator response: " + JSON.stringify(aResult));
+    if (Array.isArray(aResult) && aResult[aResult.length - 1] === "OK") {
+      deferred.resolve(aResult);
+    } else {
+      deferred.reject(aResult);
+    }
+  });
+
+  return deferred.promise;
+}
+
+/**
+ * Send raw CBS PDU to emulator.
+ *
+ * @param: aPdu
+ *         A hex string representing the whole CBS PDU.
+ *
+ * Fulfill params:
+ *   result -- an array of emulator response lines.
+ *
+ * Reject params:
+ *   result -- an array of emulator response lines.
+ *
+ * @return A deferred promise.
+ */
+function sendRawCbsToEmulator(aPdu) {
+  let command = "cbs pdu " + aPdu;
+  return runEmulatorCmdSafe(command);
+}
+
+/**
+ * Wait for one named Cellbroadcast event.
+ *
+ * Resolve if that named event occurs.  Never reject.
+ *
+ * Fulfill params: the DOMEvent passed.
+ *
+ * @param aEventName
+ *        A string event name.
+ *
+ * @return A deferred promise.
+ */
+function waitForManagerEvent(aEventName) {
+  let deferred = Promise.defer();
+
+  cbManager.addEventListener(aEventName, function onevent(aEvent) {
+    cbManager.removeEventListener(aEventName, onevent);
+
+    ok(true, "Cellbroadcast event '" + aEventName + "' got.");
+    deferred.resolve(aEvent);
+  });
+
+  return deferred.promise;
+}
+
+/**
+ * Send multiple raw CB PDU to emulator and wait
+ *
+ * @param: aPdus
+ *         A array of hex strings. Each represents a CB PDU.
+ *         These PDUs are expected to be concatenated into single CB Message.
+ *
+ * Fulfill params:
+ *   result -- array of resolved Promise, where
+ *             result[0].message representing the received message.
+ *             result[1-n] represents the response of sent emulator command.
+ *
+ * Reject params:
+ *   result -- an array of emulator response lines.
+ *
+ * @return A deferred promise.
+ */
+function sendMultipleRawCbsToEmulatorAndWait(aPdus) {
+  let promises = [];
+
+  promises.push(waitForManagerEvent("received"));
+  for (let pdu of aPdus) {
+    promises.push(sendRawCbsToEmulator(pdu));
+  }
+
+  return Promise.all(promises);
+}
+
+/**
+ * Flush permission settings and call |finish()|.
+ */
+function cleanUp() {
+  waitFor(function() {
+    SpecialPowers.flushPermissions(function() {
+      // Use ok here so that we have at least one test run.
+      ok(true, "permissions flushed");
+
+      finish();
+    });
+  }, function() {
+    return pendingEmulatorCmdCount === 0;
+  });
+}
+
+/**
+ * Switch modem for receving upcoming emulator commands.
+ *
+ * @param: aServiceId
+ *         The id of the modem to be switched to.
+ *
+ * Fulfill params:
+ *   result -- an array of emulator response lines.
+ *
+ * Reject params:
+ *   result -- an array of emulator response lines.
+ *
+ * @return A deferred promise.
+ */
+function selectModem(aServiceId) {
+  let command = "mux modem " + aServiceId;
+  return runEmulatorCmdSafe(command);
+}
+
+/**
+ * Helper to run the test case only needed in Multi-SIM environment.
+ *
+ * @param  aTest
+ *         A function which will be invoked w/o parameter.
+ * @return a Promise object.
+ */
+function runIfMultiSIM(aTest) {
+  let numRIL;
+  try {
+    numRIL = SpecialPowers.getIntPref("ril.numRadioInterfaces");
+  } catch (ex) {
+    numRIL = 1;  // Pref not set.
+  }
+
+  if (numRIL > 1) {
+    return aTest();
+  } else {
+    log("Not a Multi-SIM environment. Test is skipped.");
+    return Promise.resolve();
+  }
+}
+
+/**
+ * Common test routine helper for cell broadcast tests.
+ *
+ * This function ensures global |cbManager| variable is available during the
+ * process and performs clean-ups as well.
+ *
+ * @param aTestCaseMain
+ *        A function that takes no parameter.
+ */
+function startTestCommon(aTestCaseMain) {
+  Promise.resolve()
+         .then(ensureCellBroadcast)
+         .then(aTestCaseMain)
+         .then(cleanUp, function() {
+           ok(false, 'promise rejects during test.');
+           cleanUp();
+         });
+}
--- a/dom/cellbroadcast/tests/marionette/manifest.ini
+++ b/dom/cellbroadcast/tests/marionette/manifest.ini
@@ -1,7 +1,8 @@
 [DEFAULT]
 b2g = true
 browser = false
 qemu = true
 
 [test_cellbroadcast_etws.js]
 [test_cellbroadcast_gsm.js]
+[test_cellbroadcast_multi_sim.js]
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/cellbroadcast/tests/marionette/test_cellbroadcast_multi_sim.js
@@ -0,0 +1,34 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = 'head.js';
+
+const BODY_7BITS = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+                 + "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
+                 + "@@@@@@@@@@@@@"; // 93 ascii chars.
+const CB_PDU_SIZE = 88;
+
+function testReceivingMultiSIM() {
+  let CB_PDU = "";
+  while (CB_PDU.length < CB_PDU_SIZE * 2) {
+    CB_PDU += "00";
+  }
+
+  let verifyCBMessage = (aMessage, aServiceId) => {
+    log("Verify CB message received from serviceId: " + aServiceId);
+    is(aMessage.body, BODY_7BITS, "Checking message body.");
+    is(aMessage.serviceId, aServiceId, "Checking serviceId.");
+  };
+
+  return selectModem(1)
+    .then(() => sendMultipleRawCbsToEmulatorAndWait([CB_PDU]))
+    .then((results) => verifyCBMessage(results[0].message, 1))
+    .then(() => selectModem(0))
+    .then(() => sendMultipleRawCbsToEmulatorAndWait([CB_PDU]))
+    .then((results) => verifyCBMessage(results[0].message, 0));
+}
+
+startTestCommon(function testCaseMain() {
+  return runIfMultiSIM(testReceivingMultiSIM);
+});
--- a/dom/inputmethod/MozKeyboard.js
+++ b/dom/inputmethod/MozKeyboard.js
@@ -569,17 +569,17 @@ MozInputContext.prototype = {
 
   setComposition: function ic_setComposition(text, cursor, clauses) {
     let self = this;
     return this._sendPromise(function(resolverId) {
       cpmm.sendAsyncMessage('Keyboard:SetComposition', {
         contextId: self._contextId,
         requestId: resolverId,
         text: text,
-        cursor: cursor || text.length,
+        cursor: (typeof cursor !== 'undefined') ? cursor : text.length,
         clauses: clauses || null
       });
     });
   },
 
   endComposition: function ic_endComposition(text) {
     let self = this;
     return this._sendPromise(function(resolverId) {
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -300,17 +300,18 @@ MobileCallForwardingInfo.prototype = {
   __exposedProps__ : {active: 'r',
                       action: 'r',
                       reason: 'r',
                       number: 'r',
                       timeSeconds: 'r',
                       serviceClass: 'r'}
 };
 
-function CellBroadcastMessage(pdu) {
+function CellBroadcastMessage(clientId, pdu) {
+  this.serviceId = clientId;
   this.gsmGeographicalScope = RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[pdu.geographicalScope];
   this.messageCode = pdu.messageCode;
   this.messageId = pdu.messageId;
   this.language = pdu.language;
   this.body = pdu.fullBody;
   this.messageClass = pdu.messageClass;
   this.timestamp = pdu.timestamp;
 
@@ -326,16 +327,17 @@ CellBroadcastMessage.prototype = {
   classInfo:      XPCOMUtils.generateCI({
     classID:          CELLBROADCASTMESSAGE_CID,
     classDescription: "CellBroadcastMessage",
     flags:            Ci.nsIClassInfo.DOM_OBJECT,
     interfaces:       [Ci.nsIDOMMozCellBroadcastMessage]
   }),
 
   // nsIDOMMozCellBroadcastMessage
+  serviceId: -1,
 
   gsmGeographicalScope: null,
   messageCode: null,
   messageId: null,
   language: null,
   body: null,
   messageClass: null,
   timestamp: null,
@@ -1539,23 +1541,27 @@ RILContentHelper.prototype = {
     // To follow the listener unregistration scheme, we add a dummy clientId 0.
     // All voicemail events are routed to listener for client id 0.
     // See |handleVoicemailNotification|.
     this.unregisterListener("_voicemailListeners", 0, listener);
   },
 
   registerCellBroadcastMsg: function(listener) {
     if (DEBUG) debug("Registering for Cell Broadcast related messages");
-    //TODO: Bug 921326 - Cellbroadcast API: support multiple sim cards
+    // Instead of registering multiple listeners for Multi-SIM, we reuse
+    // clientId 0 to route all CBS messages to single listener and provide the
+    // |clientId| info by |CellBroadcastMessage.serviceId|.
     this.registerListener("_cellBroadcastListeners", 0, listener);
     cpmm.sendAsyncMessage("RIL:RegisterCellBroadcastMsg");
   },
 
   unregisterCellBroadcastMsg: function(listener) {
-    //TODO: Bug 921326 - Cellbroadcast API: support multiple sim cards
+    // Instead of unregistering multiple listeners for Multi-SIM, we reuse
+    // clientId 0 to route all CBS messages to single listener and provide the
+    // |clientId| info by |CellBroadcastMessage.serviceId|.
     this.unregisterListener("_cellBroadcastListeners", 0, listener);
   },
 
   registerIccMsg: function(clientId, listener) {
     if (DEBUG) debug("Registering for ICC related messages");
     this.registerListener("_iccListeners", clientId, listener);
     cpmm.sendAsyncMessage("RIL:RegisterIccMsg");
   },
@@ -1819,18 +1825,20 @@ RILContentHelper.prototype = {
         break;
       case "RIL:GetCallingLineIdRestriction":
         this.handleGetCallingLineIdRestriction(data);
         break;
       case "RIL:SetCallingLineIdRestriction":
         this.handleSimpleRequest(data.requestId, data.errorMsg, null);
         break;
       case "RIL:CellBroadcastReceived": {
-        let message = new CellBroadcastMessage(data);
-        this._deliverEvent(clientId,
+        // All CBS messages are to routed the listener for clientId 0 and
+        // provide the |clientId| info by |CellBroadcastMessage.serviceId|.
+        let message = new CellBroadcastMessage(clientId, data);
+        this._deliverEvent(0, // route to clientId 0.
                            "_cellBroadcastListeners",
                            "notifyMessageReceived",
                            [message]);
         break;
       }
       case "RIL:SetRoamingPreference":
         this.handleSimpleRequest(data.requestId, data.errorMsg, null);
         break;
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -66,25 +66,25 @@ const kSmsSentObserverTopic             
 const kSmsFailedObserverTopic            = "sms-failed";
 const kSmsDeliverySuccessObserverTopic   = "sms-delivery-success";
 const kSmsDeliveryErrorObserverTopic     = "sms-delivery-error";
 const kMozSettingsChangedObserverTopic   = "mozsettings-changed";
 const kSysMsgListenerReadyObserverTopic  = "system-message-listener-ready";
 const kSysClockChangeObserverTopic       = "system-clock-change";
 const kScreenStateChangedTopic           = "screen-state-changed";
 
+const kSettingsCellBroadcastDisabled = "ril.cellbroadcast.disabled";
 const kSettingsCellBroadcastSearchList = "ril.cellbroadcast.searchlist";
 const kSettingsClockAutoUpdateEnabled = "time.clock.automatic-update.enabled";
 const kSettingsClockAutoUpdateAvailable = "time.clock.automatic-update.available";
 const kSettingsTimezoneAutoUpdateEnabled = "time.timezone.automatic-update.enabled";
 const kSettingsTimezoneAutoUpdateAvailable = "time.timezone.automatic-update.available";
 
 const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
 
-const kPrefCellBroadcastDisabled = "ril.cellbroadcast.disabled";
 const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces";
 const kPrefRilDebuggingEnabled = "ril.debugging.enabled";
 
 const DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED = "received";
 const DOM_MOBILE_MESSAGE_DELIVERY_SENDING  = "sending";
 const DOM_MOBILE_MESSAGE_DELIVERY_SENT     = "sent";
 const DOM_MOBILE_MESSAGE_DELIVERY_ERROR    = "error";
 
@@ -1586,17 +1586,16 @@ WorkerMessenger.prototype = {
   token: 1,
 
   // Maps tokens we send out with messages to the message callback.
   tokenCallbackMap: null,
 
   init: function() {
     let options = {
       debug: DEBUG,
-      cellBroadcastDisabled: false,
       quirks: {
         callstateExtraUint32:
           libcutils.property_get("ro.moz.ril.callstate_extra_int", "false") === "true",
         v5Legacy:
           libcutils.property_get("ro.moz.ril.v5_legacy", "true") === "true",
         requestUseDialEmergencyCall:
           libcutils.property_get("ro.moz.ril.dial_emergency_call", "false") === "true",
         simAppStateExtraFields:
@@ -1609,21 +1608,16 @@ WorkerMessenger.prototype = {
           libcutils.property_get("ro.moz.ril.send_stk_profile_dl", "false") == "true",
         dataRegistrationOnDemand: RILQUIRKS_DATA_REGISTRATION_ON_DEMAND,
         subscriptionControl: RILQUIRKS_SUBSCRIPTION_CONTROL
       },
       rilEmergencyNumbers: libcutils.property_get("ril.ecclist") ||
                            libcutils.property_get("ro.ril.ecclist")
     };
 
-    try {
-      options.cellBroadcastDisabled =
-        Services.prefs.getBoolPref(kPrefCellBroadcastDisabled);
-    } catch(e) {}
-
     this.send(null, "setInitialOptions", options);
   },
 
   setDebugFlag: function(aDebug) {
     let options = { debug: aDebug };
     this.send(null, "setDebugFlag", options);
   },
 
@@ -1810,27 +1804,48 @@ function RadioInterface(aClientId, aWork
   lock.get(kSettingsTimezoneAutoUpdateEnabled, this);
 
   // Set "time.clock.automatic-update.available" to false when starting up.
   this.setClockAutoUpdateAvailable(false);
 
   // Set "time.timezone.automatic-update.available" to false when starting up.
   this.setTimezoneAutoUpdateAvailable(false);
 
-  // Read the Cell Broadcast Search List setting, string of integers or integer
-  // ranges separated by comma, to set listening channels.
+  /**
+  * Read the settings of the toggle of Cellbroadcast Service:
+  *
+  * Simple Format: Boolean
+  *   true if CBS is disabled. The value is applied to all RadioInterfaces.
+  * Enhanced Format: Array of Boolean
+  *   Each element represents the toggle of CBS per RadioInterface.
+  */
+  lock.get(kSettingsCellBroadcastDisabled, this);
+
+  /**
+   * Read the Cell Broadcast Search List setting to set listening channels:
+   *
+   * Simple Format:
+   *   String of integers or integer ranges separated by comma.
+   *   For example, "1, 2, 4-6"
+   * Enhanced Format:
+   *   Array of Objects with search lists specified in gsm/cdma network.
+   *   For example, [{'gsm' : "1, 2, 4-6", 'cdma' : "1, 50, 99"},
+   *                 {'cdma' : "3, 6, 8-9"}]
+   *   This provides the possibility to
+   *   1. set gsm/cdma search list individually for CDMA+LTE device.
+   *   2. set search list per RadioInterface.
+   */
   lock.get(kSettingsCellBroadcastSearchList, this);
 
   Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false);
   Services.obs.addObserver(this, kSysClockChangeObserverTopic, false);
   Services.obs.addObserver(this, kScreenStateChangedTopic, false);
 
   Services.obs.addObserver(this, kNetworkConnStateChangedTopic, false);
   Services.obs.addObserver(this, kNetworkActiveChangedTopic, false);
-  Services.prefs.addObserver(kPrefCellBroadcastDisabled, this, false);
 
   this.portAddressedSmsApps = {};
   this.portAddressedSmsApps[WAP.WDP_PORT_PUSH] = this.handleSmsWdpPortPush.bind(this);
 
   this._receivedSmsSegmentsMap = {};
 
   this._sntp = new Sntp(this.setClockBySntp.bind(this),
                         Services.prefs.getIntPref("network.sntp.maxRetryCount"),
@@ -2488,33 +2503,40 @@ RadioInterface.prototype = {
       this._selectingNetwork = null;
       target.sendAsyncMessage("RIL:SelectNetworkAuto", {
         clientId: this.clientId,
         data: response
       });
     }).bind(this));
   },
 
-  setCellBroadcastSearchList: function(newSearchList) {
-    if ((newSearchList == this._cellBroadcastSearchList) ||
-          (newSearchList && this._cellBroadcastSearchList &&
-            newSearchList.gsm == this._cellBroadcastSearchList.gsm &&
-            newSearchList.cdma == this._cellBroadcastSearchList.cdma)) {
+  setCellBroadcastSearchList: function(settings) {
+    let newSearchList =
+      Array.isArray(settings) ? settings[this.clientId] : settings;
+    let oldSearchList =
+      Array.isArray(this._cellBroadcastSearchList) ?
+        this._cellBroadcastSearchList[this.clientId] :
+        this._cellBroadcastSearchList;
+
+    if ((newSearchList == oldSearchList) ||
+          (newSearchList && oldSearchList &&
+            newSearchList.gsm == oldSearchList.gsm &&
+            newSearchList.cdma == oldSearchList.cdma)) {
       return;
     }
 
     this.workerMessenger.send("setCellBroadcastSearchList",
                               { searchList: newSearchList },
                               (function callback(response) {
       if (!response.success) {
         let lock = gSettingsService.createLock();
         lock.set(kSettingsCellBroadcastSearchList,
                  this._cellBroadcastSearchList, null);
       } else {
-        this._cellBroadcastSearchList = response.searchList;
+        this._cellBroadcastSearchList = settings;
       }
 
       return false;
     }).bind(this));
   },
 
   /**
    * Handle signal strength changes.
@@ -3299,26 +3321,16 @@ RadioInterface.prototype = {
   // nsIObserver
 
   observe: function(subject, topic, data) {
     switch (topic) {
       case kMozSettingsChangedObserverTopic:
         let setting = JSON.parse(data);
         this.handleSettingsChange(setting.key, setting.value, setting.message);
         break;
-      case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
-        if (data === kPrefCellBroadcastDisabled) {
-          let value = false;
-          try {
-            value = Services.prefs.getBoolPref(kPrefCellBroadcastDisabled);
-          } catch(e) {}
-          this.workerMessenger.send("setCellBroadcastDisabled",
-                                    { disabled: value });
-        }
-        break;
       case kSysClockChangeObserverTopic:
         let offset = parseInt(data, 10);
         if (this._lastNitzMessage) {
           this._lastNitzMessage.receiveTimeInMS += offset;
         }
         this._sntp.updateOffset(offset);
         break;
       case kNetworkConnStateChangedTopic:
@@ -3470,19 +3482,29 @@ RadioInterface.prototype = {
           }
         }
         break;
       case kSettingsCellBroadcastSearchList:
         if (DEBUG) {
           this.debug("'" + kSettingsCellBroadcastSearchList +
             "' is now " + JSON.stringify(aResult));
         }
-        // TODO: Set searchlist for Multi-SIM. See Bug 921326.
-        let result = Array.isArray(aResult) ? aResult[0] : aResult;
-        this.setCellBroadcastSearchList(result);
+
+        this.setCellBroadcastSearchList(aResult);
+        break;
+      case kSettingsCellBroadcastDisabled:
+        if (DEBUG) {
+          this.debug("'" + kSettingsCellBroadcastDisabled +
+            "' is now " + JSON.stringify(aResult));
+        }
+
+        let setCbsDisabled =
+          Array.isArray(aResult) ? aResult[this.clientId] : aResult;
+        this.workerMessenger.send("setCellBroadcastDisabled",
+                                  { disabled: setCbsDisabled });
         break;
     }
   },
 
   handleError: function(aErrorMessage) {
     if (DEBUG) {
       this.debug("There was an error while reading RIL settings.");
     }
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -47,17 +47,16 @@ let GLOBAL = this;
 
 if (!this.debug) {
   // Debugging stub that goes nowhere.
   this.debug = function debug(message) {
     dump("RIL Worker: " + message + "\n");
   };
 }
 
-let RIL_CELLBROADCAST_DISABLED;
 let RIL_EMERGENCY_NUMBERS;
 const DEFAULT_EMERGENCY_NUMBERS = ["112", "911"];
 
 // Timeout value for emergency callback mode.
 const EMERGENCY_CB_MODE_TIMEOUT_MS = 300000;  // 5 mins = 300000 ms.
 
 const ICC_MAX_LINEAR_FIXED_RECORDS = 0xfe;
 
@@ -348,17 +347,16 @@ function RilObject(aContext) {
   this.currentDataCalls = {};
   this._pendingSentSmsMap = {};
   this.pendingNetworkType = {};
   this._receivedSmsCbPagesMap = {};
   this._getCurrentCallsRetryCount = 0;
 
   // Init properties that are only initialized once.
   this.v5Legacy = RILQUIRKS_V5_LEGACY;
-  this.cellBroadcastDisabled = RIL_CELLBROADCAST_DISABLED;
 
   this.pendingMO = null;
 }
 RilObject.prototype = {
   context: null,
 
   v5Legacy: null,
 
@@ -6445,17 +6443,21 @@ RilObject.prototype[REQUEST_CDMA_SMS_ACK
 RilObject.prototype[REQUEST_GSM_GET_BROADCAST_SMS_CONFIG] = null;
 RilObject.prototype[REQUEST_GSM_SET_BROADCAST_SMS_CONFIG] = function REQUEST_GSM_SET_BROADCAST_SMS_CONFIG(length, options) {
   if (options.rilRequestError == ERROR_SUCCESS) {
     this.setSmsBroadcastActivation(true);
   }
 };
 RilObject.prototype[REQUEST_GSM_SMS_BROADCAST_ACTIVATION] = null;
 RilObject.prototype[REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG] = null;
-RilObject.prototype[REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG] = null;
+RilObject.prototype[REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG] = function REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG(length, options) {
+  if (options.rilRequestError == ERROR_SUCCESS) {
+    this.setSmsBroadcastActivation(true);
+  }
+};
 RilObject.prototype[REQUEST_CDMA_SMS_BROADCAST_ACTIVATION] = null;
 RilObject.prototype[REQUEST_CDMA_SUBSCRIPTION] = function REQUEST_CDMA_SUBSCRIPTION(length, options) {
   if (options.rilRequestError) {
     return;
   }
 
   let result = this.context.Buf.readStringList();
 
@@ -13929,18 +13931,18 @@ ICCUtilsHelperObject.prototype = {
               break;
             }
           }
           iccInfo.isDisplaySpnRequired = inHomeArea;
         }
       }
     } else {
       // GSM family display rule.
-      let operatorMnc = RIL.operator.mnc;
-      let operatorMcc = RIL.operator.mcc;
+      let operatorMnc = RIL.operator ? RIL.operator.mnc : -1;
+      let operatorMcc = RIL.operator ? RIL.operator.mcc : -1;
 
       // First detect if we are on HPLMN or one of the PLMN
       // specified by the SIM card.
       let isOnMatchingPlmn = false;
 
       // If the current network is the one defined as mcc/mnc
       // in SIM card, it's okay.
       if (iccInfo.mcc == operatorMcc && iccInfo.mnc == operatorMnc) {
@@ -14895,17 +14897,16 @@ let ContextPool = {
       return;
     }
     method.call(this, aMessage);
   },
 
   setInitialOptions: function(aOptions) {
     DEBUG = DEBUG_WORKER || aOptions.debug;
     RIL_EMERGENCY_NUMBERS = aOptions.rilEmergencyNumbers;
-    RIL_CELLBROADCAST_DISABLED = aOptions.cellBroadcastDisabled;
 
     let quirks = aOptions.quirks;
     RILQUIRKS_CALLSTATE_EXTRA_UINT32 = quirks.callstateExtraUint32;
     RILQUIRKS_V5_LEGACY = quirks.v5Legacy;
     RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = quirks.requestUseDialEmergencyCall;
     RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS = quirks.simAppStateExtraFields;
     RILQUIRKS_EXTRA_UINT32_2ND_CALL = quirks.extraUint2ndCall;
     RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT = quirks.haveQueryIccLockRetryCount;
--- a/dom/system/gonk/tests/header_helpers.js
+++ b/dom/system/gonk/tests/header_helpers.js
@@ -74,16 +74,70 @@ function newWorker(custom_ns) {
 
   // Register at least one client.
   worker_ns.ContextPool.registerClient({ clientId: 0 });
 
   return worker_ns;
 }
 
 /**
+ * Create a buffered RIL worker.
+ *
+ * @return A worker object that stores sending octets in a internal buffer.
+ */
+function newUint8Worker() {
+  let worker = newWorker();
+  let index = 0; // index for read
+  let buf = [];
+
+  let context = worker.ContextPool._contexts[0];
+  context.Buf.writeUint8 = function(value) {
+    buf.push(value);
+  };
+
+  context.Buf.readUint8 = function() {
+    return buf[index++];
+  };
+
+  context.Buf.seekIncoming = function(offset) {
+    index += offset;
+  };
+
+  context.Buf.getReadAvailable = function() {
+    return buf.length - index;
+  };
+
+  worker.debug = do_print;
+
+  return worker;
+}
+
+/**
+ * Create a worker that keeps posted chrome message.
+ */
+function newInterceptWorker() {
+  let postedMessage;
+  let worker = newWorker({
+    postRILMessage: function(data) {
+    },
+    postMessage: function(message) {
+      postedMessage = message;
+    }
+  });
+  return {
+    get postedMessage() {
+      return postedMessage;
+    },
+    get worker() {
+      return worker;
+    }
+  };
+}
+
+/**
  * Create a parcel suitable for postRILMessage().
  *
  * @param fakeParcelSize
  *        Value to be written to parcel size field for testing
  *        incorrect/incomplete parcel reading. Replaced with correct
  *        one determined length of data if negative.
  * @param response
  *        Response code of the incoming parcel.
--- a/dom/system/gonk/tests/test_ril_worker_barring_password.js
+++ b/dom/system/gonk/tests/test_ril_worker_barring_password.js
@@ -5,42 +5,16 @@ subscriptLoader.loadSubScript("resource:
 
 function run_test() {
   run_next_test();
 }
 
 const PIN = "0000";
 const NEW_PIN = "1234";
 
-/**
- * Helper function.
- */
-function newUint8Worker() {
-  let worker = newWorker();
-  let context = worker.ContextPool._contexts[0];
-  let index = 0; // index for read
-  let buf = [];
-
-  context.Buf.writeUint8 = function(value) {
-    buf.push(value);
-  };
-
-  context.Buf.readUint8 = function() {
-    return buf[index++];
-  };
-
-  context.Buf.seekIncoming = function(offset) {
-    index += offset;
-  };
-
-  worker.debug = do_print;
-
-  return worker;
-}
-
 add_test(function test_change_call_barring_password() {
   let worker = newUint8Worker();
   let context = worker.ContextPool._contexts[0];
   let buf = context.Buf;
 
   function do_test(facility, pin, newPin) {
     buf.sendParcel = function fakeSendParcel () {
       // Request Type.
--- a/dom/system/gonk/tests/test_ril_worker_cf.js
+++ b/dom/system/gonk/tests/test_ril_worker_cf.js
@@ -47,37 +47,18 @@ add_test(function test_toaFromString_unk
 add_test(function test_toaFromString_international() {
   let retval = toaFromString("+34666222333");
 
   do_check_eq(retval, TOA_INTERNATIONAL);
 
   run_next_test();
 });
 
-function _getWorker() {
-  let _postedMessage;
-  let _worker = newWorker({
-    postRILMessage: function(data) {
-    },
-    postMessage: function(message) {
-      _postedMessage = message;
-    }
-  });
-  return {
-    get postedMessage() {
-      return _postedMessage;
-    },
-    get worker() {
-      return _worker;
-    }
-  };
-}
-
 add_test(function test_setCallForward_unconditional() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.RIL.setCallForward = function fakeSetCallForward(options) {
     context.RIL[REQUEST_SET_CALL_FORWARD](0, {
       rilRequestError: ERROR_SUCCESS
     });
   };
@@ -94,17 +75,17 @@ add_test(function test_setCallForward_un
 
   do_check_eq(postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
   do_check_true(postedMessage.success);
 
   run_next_test();
 });
 
 add_test(function test_queryCallForwardStatus_unconditional() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.RIL.setCallForward = function fakeSetCallForward(options) {
     context.RIL[REQUEST_SET_CALL_FORWARD](0, {
       rilRequestError: ERROR_SUCCESS
     });
   };
--- a/dom/system/gonk/tests/test_ril_worker_clip.js
+++ b/dom/system/gonk/tests/test_ril_worker_clip.js
@@ -2,37 +2,18 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
 
 function run_test() {
   run_next_test();
 }
 
-function _getWorker() {
-  let _postedMessage;
-  let _worker = newWorker({
-    postRILMessage: function(data) {
-    },
-    postMessage: function(message) {
-      _postedMessage = message;
-    }
-  });
-  return {
-    get postedMessage() {
-      return _postedMessage;
-    },
-    get worker() {
-      return _worker;
-    }
-  };
-}
-
 add_test(function test_queryCLIP_provisioned() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.Buf.readInt32 = function fakeReadUint32() {
     return context.Buf.int32Array.pop();
   };
 
   context.RIL.queryCLIP = function fakeQueryCLIP(options) {
@@ -51,17 +32,17 @@ add_test(function test_queryCLIP_provisi
 
   do_check_eq(postedMessage.errorMsg, undefined);
   do_check_true(postedMessage.success);
   do_check_eq(postedMessage.provisioned, 1);
   run_next_test();
 });
 
 add_test(function test_getCLIP_error_generic_failure_invalid_length() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.Buf.readInt32 = function fakeReadUint32() {
     return context.Buf.int32Array.pop();
   };
 
   context.RIL.queryCLIP = function fakeQueryCLIP(options) {
--- a/dom/system/gonk/tests/test_ril_worker_clir.js
+++ b/dom/system/gonk/tests/test_ril_worker_clir.js
@@ -11,37 +11,18 @@ const CLIR_DEFAULT     = 0;
 const CLIR_INVOCATION  = 1;
 // Allows CLI presentation.
 const CLIR_SUPPRESSION = 2;
 
 function run_test() {
   run_next_test();
 }
 
-function _getWorker() {
-  let _postedMessage;
-  let _worker = newWorker({
-    postRILMessage: function(data) {
-    },
-    postMessage: function(message) {
-      _postedMessage = message;
-    }
-  });
-  return {
-    get postedMessage() {
-      return _postedMessage;
-    },
-    get worker() {
-      return _worker;
-    }
-  };
-}
-
 add_test(function test_setCLIR_success() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.RIL.setCLIR = function fakeSetCLIR(options) {
     context.RIL[REQUEST_SET_CLIR](0, {
       rilMessageType: "setCLIR",
       rilRequestError: ERROR_SUCCESS
     });
@@ -55,17 +36,17 @@ add_test(function test_setCLIR_success()
 
   do_check_eq(postedMessage.errorMsg, undefined);
   do_check_true(postedMessage.success);
 
   run_next_test();
 });
 
 add_test(function test_setCLIR_generic_failure() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.RIL.setCLIR = function fakeSetCLIR(options) {
     context.RIL[REQUEST_SET_CLIR](0, {
       rilMessageType: "setCLIR",
       rilRequestError: ERROR_GENERIC_FAILURE
     });
@@ -79,17 +60,17 @@ add_test(function test_setCLIR_generic_f
 
   do_check_eq(postedMessage.errorMsg, "GenericFailure");
   do_check_false(postedMessage.success);
 
   run_next_test();
 });
 
 add_test(function test_getCLIR_n0_m1() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.Buf.readInt32 = function fakeReadUint32() {
     return context.Buf.int32Array.pop();
   };
 
   context.RIL.getCLIR = function fakeGetCLIR(options) {
@@ -112,17 +93,17 @@ add_test(function test_getCLIR_n0_m1() {
   do_check_eq(postedMessage.errorMsg, undefined);
   do_check_true(postedMessage.success);
   do_check_eq(postedMessage.n, 0);
   do_check_eq(postedMessage.m, 1);
   run_next_test();
 });
 
 add_test(function test_getCLIR_error_generic_failure_invalid_length() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.Buf.readInt32 = function fakeReadUint32() {
     return context.Buf.int32Array.pop();
   };
 
   context.RIL.getCLIR = function fakeGetCLIR(options) {
--- a/dom/system/gonk/tests/test_ril_worker_cw.js
+++ b/dom/system/gonk/tests/test_ril_worker_cw.js
@@ -2,37 +2,18 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
 
 function run_test() {
   run_next_test();
 }
 
-function _getWorker() {
-  let _postedMessage;
-  let _worker = newWorker({
-    postRILMessage: function(data) {
-    },
-    postMessage: function(message) {
-      _postedMessage = message;
-    }
-  });
-  return {
-    get postedMessage() {
-      return _postedMessage;
-    },
-    get worker() {
-      return _worker;
-    }
-  };
-}
-
 add_test(function test_setCallWaiting_success() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.RIL.setCallWaiting = function fakeSetCallWaiting(options) {
     context.RIL[REQUEST_SET_CALL_WAITING](0, {
       rilRequestError: ERROR_SUCCESS
     });
   };
@@ -45,17 +26,17 @@ add_test(function test_setCallWaiting_su
 
   do_check_eq(postedMessage.errorMsg, undefined);
   do_check_true(postedMessage.success);
 
   run_next_test();
 });
 
 add_test(function test_setCallWaiting_generic_failure() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.RIL.setCallWaiting = function fakeSetCallWaiting(options) {
     context.RIL[REQUEST_SET_CALL_WAITING](0, {
       rilRequestError: ERROR_GENERIC_FAILURE
     });
   };
@@ -68,17 +49,17 @@ add_test(function test_setCallWaiting_ge
 
   do_check_eq(postedMessage.errorMsg, "GenericFailure");
   do_check_false(postedMessage.success);
 
   run_next_test();
 });
 
 add_test(function test_queryCallWaiting_success_enabled_true() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.Buf.readInt32 = function fakeReadUint32() {
     return context.Buf.int32Array.pop();
   };
 
   context.RIL.queryCallWaiting = function fakeQueryCallWaiting(options) {
@@ -99,17 +80,17 @@ add_test(function test_queryCallWaiting_
   do_check_eq(postedMessage.errorMsg, undefined);
   do_check_true(postedMessage.success);
   do_check_eq(postedMessage.length, 1);
   do_check_true(postedMessage.enabled);
   run_next_test();
 });
 
 add_test(function test_queryCallWaiting_success_enabled_false() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.Buf.readInt32 = function fakeReadUint32() {
     return context.Buf.int32Array.pop();
   };
 
   context.RIL.queryCallWaiting = function fakeQueryCallWaiting(options) {
--- a/dom/system/gonk/tests/test_ril_worker_ecm.js
+++ b/dom/system/gonk/tests/test_ril_worker_ecm.js
@@ -2,35 +2,16 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
 
 function run_test() {
   run_next_test();
 }
 
-function _getWorker() {
-  let _postedMessage;
-  let _worker = newWorker({
-    postRILMessage: function(data) {
-    },
-    postMessage: function(message) {
-      _postedMessage = message;
-    }
-  });
-  return {
-    get postedMessage() {
-      return _postedMessage;
-    },
-    get worker() {
-      return _worker;
-    }
-  };
-}
-
 var timeoutCallback = null;
 var timeoutDelayMs = 0;
 const TIMER_ID = 1234;
 const TIMEOUT_VALUE = 300000;  // 5 mins.
 
 // No window in xpcshell-test. Create our own timer mechanism.
 
 function setTimeout(callback, timeoutMs) {
@@ -49,17 +30,17 @@ function fireTimeout() {
   do_check_neq(timeoutCallback, null);
   if (timeoutCallback) {
     timeoutCallback();
     timeoutCallback = null;
   }
 }
 
 add_test(function test_enter_emergencyCbMode() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   // Do it twice. Should always send the event.
   for (let i = 0; i < 2; ++i) {
     context.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE]();
     let postedMessage = workerHelper.postedMessage;
 
@@ -74,17 +55,17 @@ add_test(function test_enter_emergencyCb
     // Should start timer.
     do_check_eq(context.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID);
   }
 
   run_next_test();
 });
 
 add_test(function test_exit_emergencyCbMode() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE]();
   context.RIL[UNSOLICITED_EXIT_EMERGENCY_CALLBACK_MODE]();
   let postedMessage = workerHelper.postedMessage;
 
   // Should store the mode.
@@ -96,17 +77,17 @@ add_test(function test_exit_emergencyCbM
 
   // Should clear timer.
   do_check_eq(context.RIL._exitEmergencyCbModeTimeoutID, null);
 
   run_next_test();
 });
 
 add_test(function test_request_exit_emergencyCbMode_when_timeout() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE]();
   do_check_eq(context.RIL._isInEmergencyCbMode, true);
   do_check_eq(context.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID);
 
   let parcelTypes = [];
@@ -122,17 +103,17 @@ add_test(function test_request_exit_emer
 
   // Check indeed sent out REQUEST_EXIT_EMERGENCY_CALLBACK_MODE.
   do_check_neq(parcelTypes.indexOf(REQUEST_EXIT_EMERGENCY_CALLBACK_MODE), -1);
 
   run_next_test();
 });
 
 add_test(function test_request_exit_emergencyCbMode_when_dial() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE]();
   do_check_eq(context.RIL._isInEmergencyCbMode, true);
   do_check_eq(context.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID);
 
   let parcelTypes = [];
@@ -149,17 +130,17 @@ add_test(function test_request_exit_emer
 
   // Check indeed sent out REQUEST_EXIT_EMERGENCY_CALLBACK_MODE.
   do_check_neq(parcelTypes.indexOf(REQUEST_EXIT_EMERGENCY_CALLBACK_MODE), -1);
 
   run_next_test();
 });
 
 add_test(function test_request_exit_emergencyCbMode_explicitly() {
-  let workerHelper = _getWorker();
+  let workerHelper = newInterceptWorker();
   let worker = workerHelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE]();
   do_check_eq(context.RIL._isInEmergencyCbMode, true);
   do_check_eq(context.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID);
 
   let parcelTypes = [];
deleted file mode 100644
--- a/dom/system/gonk/tests/test_ril_worker_icc.js
+++ /dev/null
@@ -1,3198 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
-
-subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
-
-function run_test() {
-  run_next_test();
-}
-
-/**
- * Helper function.
- */
-function newUint8Worker() {
-  let worker = newWorker();
-  let index = 0; // index for read
-  let buf = [];
-
-  let context = worker.ContextPool._contexts[0];
-  context.Buf.writeUint8 = function(value) {
-    buf.push(value);
-  };
-
-  context.Buf.readUint8 = function() {
-    return buf[index++];
-  };
-
-  context.Buf.seekIncoming = function(offset) {
-    index += offset;
-  };
-
-  context.Buf.getReadAvailable = function() {
-    return buf.length - index;
-  };
-
-  worker.debug = do_print;
-
-  return worker;
-}
-
-/**
- * Verify ICCPDUHelper#readICCUCS2String()
- */
-add_test(function test_read_icc_ucs2_string() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-  let iccHelper = context.ICCPDUHelper;
-
-  // 0x80
-  let text = "TEST";
-  helper.writeUCS2String(text);
-  // Also write two unused octets.
-  let ffLen = 2;
-  for (let i = 0; i < ffLen; i++) {
-    helper.writeHexOctet(0xff);
-  }
-  do_check_eq(iccHelper.readICCUCS2String(0x80, (2 * text.length) + ffLen), text);
-
-  // 0x81
-  let array = [0x08, 0xd2, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca,
-               0xff, 0xff];
-  let len = array.length;
-  for (let i = 0; i < len; i++) {
-    helper.writeHexOctet(array[i]);
-  }
-  do_check_eq(iccHelper.readICCUCS2String(0x81, len), "Mozilla\u694a");
-
-  // 0x82
-  let array2 = [0x08, 0x69, 0x00, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61,
-                0xca, 0xff, 0xff];
-  let len2 = array2.length;
-  for (let i = 0; i < len2; i++) {
-    helper.writeHexOctet(array2[i]);
-  }
-  do_check_eq(iccHelper.readICCUCS2String(0x82, len2), "Mozilla\u694a");
-
-  run_next_test();
-});
-
-/**
- * Verify ICCPDUHelper#readDiallingNumber
- */
-add_test(function test_read_dialling_number() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-  let iccHelper = context.ICCPDUHelper;
-  let str = "123456789";
-
-  helper.readHexOctet = function() {
-    return 0x81;
-  };
-
-  helper.readSwappedNibbleBcdString = function(len) {
-    return str.substring(0, len);
-  };
-
-  for (let i = 0; i < str.length; i++) {
-    do_check_eq(str.substring(0, i - 1), // -1 for the TON
-                iccHelper.readDiallingNumber(i));
-  }
-
-  run_next_test();
-});
-
-/**
- * Verify ICCPDUHelper#read8BitUnpackedToString
- */
-add_test(function test_read_8bit_unpacked_to_string() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-  let iccHelper = context.ICCPDUHelper;
-  const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
-  const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
-
-  // Test 1: Read GSM alphabets.
-  // Write alphabets before ESCAPE.
-  for (let i = 0; i < PDU_NL_EXTENDED_ESCAPE; i++) {
-    helper.writeHexOctet(i);
-  }
-
-  // Write two ESCAPEs to make it become ' '.
-  helper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE);
-  helper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE);
-
-  for (let i = PDU_NL_EXTENDED_ESCAPE + 1; i < langTable.length; i++) {
-    helper.writeHexOctet(i);
-  }
-
-  // Also write two unused fields.
-  let ffLen = 2;
-  for (let i = 0; i < ffLen; i++) {
-    helper.writeHexOctet(0xff);
-  }
-
-  do_check_eq(iccHelper.read8BitUnpackedToString(PDU_NL_EXTENDED_ESCAPE),
-              langTable.substring(0, PDU_NL_EXTENDED_ESCAPE));
-  do_check_eq(iccHelper.read8BitUnpackedToString(2), " ");
-  do_check_eq(iccHelper.read8BitUnpackedToString(langTable.length -
-                                              PDU_NL_EXTENDED_ESCAPE - 1 + ffLen),
-              langTable.substring(PDU_NL_EXTENDED_ESCAPE + 1));
-
-  // Test 2: Read GSM extended alphabets.
-  for (let i = 0; i < langShiftTable.length; i++) {
-    helper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE);
-    helper.writeHexOctet(i);
-  }
-
-  // Read string before RESERVED_CONTROL.
-  do_check_eq(iccHelper.read8BitUnpackedToString(PDU_NL_RESERVED_CONTROL  * 2),
-              langShiftTable.substring(0, PDU_NL_RESERVED_CONTROL));
-  // ESCAPE + RESERVED_CONTROL will become ' '.
-  do_check_eq(iccHelper.read8BitUnpackedToString(2), " ");
-  // Read string between RESERVED_CONTROL and EXTENDED_ESCAPE.
-  do_check_eq(iccHelper.read8BitUnpackedToString(
-                (PDU_NL_EXTENDED_ESCAPE - PDU_NL_RESERVED_CONTROL - 1)  * 2),
-              langShiftTable.substring(PDU_NL_RESERVED_CONTROL + 1,
-                                       PDU_NL_EXTENDED_ESCAPE));
-  // ESCAPE + ESCAPE will become ' '.
-  do_check_eq(iccHelper.read8BitUnpackedToString(2), " ");
-  // Read remaining string.
-  do_check_eq(iccHelper.read8BitUnpackedToString(
-                (langShiftTable.length - PDU_NL_EXTENDED_ESCAPE - 1)  * 2),
-              langShiftTable.substring(PDU_NL_EXTENDED_ESCAPE + 1));
-
-  run_next_test();
-});
-
-/**
- * Verify ICCPDUHelper#writeStringTo8BitUnpacked.
- *
- * Test writing GSM 8 bit alphabets.
- */
-add_test(function test_write_string_to_8bit_unpacked() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-  let iccHelper = context.ICCPDUHelper;
-  const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
-  const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
-  // Length of trailing 0xff.
-  let ffLen = 2;
-  let str;
-
-  // Test 1, write GSM alphabets.
-  iccHelper.writeStringTo8BitUnpacked(langTable.length + ffLen, langTable);
-
-  for (let i = 0; i < langTable.length; i++) {
-    do_check_eq(helper.readHexOctet(), i);
-  }
-
-  for (let i = 0; i < ffLen; i++) {
-    do_check_eq(helper.readHexOctet(), 0xff);
-  }
-
-  // Test 2, write GSM extended alphabets.
-  str = "\u000c\u20ac";
-  iccHelper.writeStringTo8BitUnpacked(4, str);
-
-  do_check_eq(iccHelper.read8BitUnpackedToString(4), str);
-
-  // Test 3, write GSM and GSM extended alphabets.
-  // \u000c, \u20ac are from gsm extended alphabets.
-  // \u00a3 is from gsm alphabet.
-  str = "\u000c\u20ac\u00a3";
-
-  // 2 octets * 2 = 4 octets for 2 gsm extended alphabets,
-  // 1 octet for 1 gsm alphabet,
-  // 2 octes for trailing 0xff.
-  // "Totally 7 octets are to be written."
-  iccHelper.writeStringTo8BitUnpacked(7, str);
-
-  do_check_eq(iccHelper.read8BitUnpackedToString(7), str);
-
-  run_next_test();
-});
-
-/**
- * Verify ICCPDUHelper#writeStringTo8BitUnpacked with maximum octets written.
- */
-add_test(function test_write_string_to_8bit_unpacked_with_max_octets_written() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-  let iccHelper = context.ICCPDUHelper;
-  const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
-  const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
-
-  // The maximum of the number of octets that can be written is 3.
-  // Only 3 characters shall be written even the length of the string is 4.
-  iccHelper.writeStringTo8BitUnpacked(3, langTable.substring(0, 4));
-  helper.writeHexOctet(0xff); // dummy octet.
-  for (let i = 0; i < 3; i++) {
-    do_check_eq(helper.readHexOctet(), i);
-  }
-  do_check_false(helper.readHexOctet() == 4);
-
-  // \u000c is GSM extended alphabet, 2 octets.
-  // \u00a3 is GSM alphabet, 1 octet.
-  let str = "\u000c\u00a3";
-  iccHelper.writeStringTo8BitUnpacked(3, str);
-  do_check_eq(iccHelper.read8BitUnpackedToString(3), str);
-
-  str = "\u00a3\u000c";
-  iccHelper.writeStringTo8BitUnpacked(3, str);
-  do_check_eq(iccHelper.read8BitUnpackedToString(3), str);
-
-  // 2 GSM extended alphabets cost 4 octets, but maximum is 3, so only the 1st
-  // alphabet can be written.
-  str = "\u000c\u000c";
-  iccHelper.writeStringTo8BitUnpacked(3, str);
-  helper.writeHexOctet(0xff); // dummy octet.
-  do_check_eq(iccHelper.read8BitUnpackedToString(4), str.substring(0, 1));
-
-  run_next_test();
-});
-
-/**
- * Verify ICCPDUHelper.readAlphaIdentifier
- */
-add_test(function test_read_alpha_identifier() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-  let iccHelper = context.ICCPDUHelper;
-
-  // UCS2: 0x80
-  let text = "TEST";
-  helper.writeHexOctet(0x80);
-  helper.writeUCS2String(text);
-  // Also write two unused octets.
-  let ffLen = 2;
-  for (let i = 0; i < ffLen; i++) {
-    helper.writeHexOctet(0xff);
-  }
-  do_check_eq(iccHelper.readAlphaIdentifier(1 + (2 * text.length) + ffLen), text);
-
-  // UCS2: 0x81
-  let array = [0x81, 0x08, 0xd2, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff];
-  for (let i = 0; i < array.length; i++) {
-    helper.writeHexOctet(array[i]);
-  }
-  do_check_eq(iccHelper.readAlphaIdentifier(array.length), "Mozilla\u694a");
-
-  // UCS2: 0x82
-  let array2 = [0x82, 0x08, 0x69, 0x00, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff];
-  for (let i = 0; i < array2.length; i++) {
-    helper.writeHexOctet(array2[i]);
-  }
-  do_check_eq(iccHelper.readAlphaIdentifier(array2.length), "Mozilla\u694a");
-
-  // GSM 8 Bit Unpacked
-  const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
-  for (let i = 0; i < PDU_NL_EXTENDED_ESCAPE; i++) {
-    helper.writeHexOctet(i);
-  }
-  do_check_eq(iccHelper.readAlphaIdentifier(PDU_NL_EXTENDED_ESCAPE),
-              langTable.substring(0, PDU_NL_EXTENDED_ESCAPE));
-
-  run_next_test();
-});
-
-/**
- * Verify ICCPDUHelper.writeAlphaIdentifier
- */
-add_test(function test_write_alpha_identifier() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-  let iccHelper = context.ICCPDUHelper;
-  // Length of trailing 0xff.
-  let ffLen = 2;
-
-  // Removal
-  iccHelper.writeAlphaIdentifier(10, null);
-  do_check_eq(iccHelper.readAlphaIdentifier(10), "");
-
-  // GSM 8 bit
-  let str = "Mozilla";
-  iccHelper.writeAlphaIdentifier(str.length + ffLen, str);
-  do_check_eq(iccHelper.readAlphaIdentifier(str.length + ffLen), str);
-
-  // UCS2
-  str = "Mozilla\u694a";
-  iccHelper.writeAlphaIdentifier(str.length * 2 + ffLen, str);
-  // * 2 for each character will be encoded to UCS2 alphabets.
-  do_check_eq(iccHelper.readAlphaIdentifier(str.length * 2 + ffLen), str);
-
-  // Test with maximum octets written.
-  // 1 coding scheme (0x80) and 1 UCS2 character, total 3 octets.
-  str = "\u694a";
-  iccHelper.writeAlphaIdentifier(3, str);
-  do_check_eq(iccHelper.readAlphaIdentifier(3), str);
-
-  // 1 coding scheme (0x80) and 2 UCS2 characters, total 5 octets.
-  // numOctets is limited to 4, so only 1 UCS2 character can be written.
-  str = "\u694a\u694a";
-  iccHelper.writeAlphaIdentifier(4, str);
-  helper.writeHexOctet(0xff); // dummy octet.
-  do_check_eq(iccHelper.readAlphaIdentifier(5), str.substring(0, 1));
-
-  // Write 0 octet.
-  iccHelper.writeAlphaIdentifier(0, "1");
-  helper.writeHexOctet(0xff); // dummy octet.
-  do_check_eq(iccHelper.readAlphaIdentifier(1), "");
-
-  run_next_test();
-});
-
-/**
- * Verify ICCPDUHelper.readAlphaIdDiallingNumber
- */
-add_test(function test_read_alpha_id_dialling_number() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-  let iccHelper = context.ICCPDUHelper;
-  let buf = context.Buf;
-  const recordSize = 32;
-
-  function testReadAlphaIdDiallingNumber(contact) {
-    iccHelper.readAlphaIdentifier = function() {
-      return contact.alphaId;
-    };
-
-    iccHelper.readNumberWithLength = function() {
-      return contact.number;
-    };
-
-    let strLen = recordSize * 2;
-    buf.writeInt32(strLen);     // fake length
-    helper.writeHexOctet(0xff); // fake CCP
-    helper.writeHexOctet(0xff); // fake EXT1
-    buf.writeStringDelimiter(strLen);
-
-    let contactR = iccHelper.readAlphaIdDiallingNumber(recordSize);
-    if (contact.alphaId == "" && contact.number == "") {
-      do_check_eq(contactR, null);
-    } else {
-      do_check_eq(contactR.alphaId, contact.alphaId);
-      do_check_eq(contactR.number, contact.number);
-    }
-  }
-
-  testReadAlphaIdDiallingNumber({alphaId: "AlphaId", number: "0987654321"});
-  testReadAlphaIdDiallingNumber({alphaId: "", number: ""});
-
-  run_next_test();
-});
-
-/**
- * Verify ICCPDUHelper.writeAlphaIdDiallingNumber
- */
-add_test(function test_write_alpha_id_dialling_number() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.ICCPDUHelper;
-  const recordSize = 32;
-
-  // Write a normal contact.
-  let contactW = {
-    alphaId: "Mozilla",
-    number: "1234567890"
-  };
-  helper.writeAlphaIdDiallingNumber(recordSize, contactW.alphaId,
-                                    contactW.number);
-
-  let contactR = helper.readAlphaIdDiallingNumber(recordSize);
-  do_check_eq(contactW.alphaId, contactR.alphaId);
-  do_check_eq(contactW.number, contactR.number);
-
-  // Write a contact with alphaId encoded in UCS2 and number has '+'.
-  let contactUCS2 = {
-    alphaId: "火狐",
-    number: "+1234567890"
-  };
-  helper.writeAlphaIdDiallingNumber(recordSize, contactUCS2.alphaId,
-                                    contactUCS2.number);
-  contactR = helper.readAlphaIdDiallingNumber(recordSize);
-  do_check_eq(contactUCS2.alphaId, contactR.alphaId);
-  do_check_eq(contactUCS2.number, contactR.number);
-
-  // Write a null contact (Removal).
-  helper.writeAlphaIdDiallingNumber(recordSize);
-  contactR = helper.readAlphaIdDiallingNumber(recordSize);
-  do_check_eq(contactR, null);
-
-  // Write a longer alphaId/dialling number
-  // Dialling Number : Maximum 20 digits(10 octets).
-  // Alpha Identifier: 32(recordSize) - 14 (10 octets for Dialling Number, 1
-  //                   octet for TON/NPI, 1 for number length octet, and 2 for
-  //                   Ext) = Maximum 18 octets.
-  let longContact = {
-    alphaId: "AAAAAAAAABBBBBBBBBCCCCCCCCC",
-    number: "123456789012345678901234567890",
-  };
-  helper.writeAlphaIdDiallingNumber(recordSize, longContact.alphaId,
-                                    longContact.number);
-  contactR = helper.readAlphaIdDiallingNumber(recordSize);
-  do_check_eq(contactR.alphaId, "AAAAAAAAABBBBBBBBB");
-  do_check_eq(contactR.number, "12345678901234567890");
-
-  // Add '+' to number and test again.
-  longContact.number = "+123456789012345678901234567890";
-  helper.writeAlphaIdDiallingNumber(recordSize, longContact.alphaId,
-                                    longContact.number);
-  contactR = helper.readAlphaIdDiallingNumber(recordSize);
-  do_check_eq(contactR.alphaId, "AAAAAAAAABBBBBBBBB");
-  do_check_eq(contactR.number, "+12345678901234567890");
-
-  run_next_test();
-});
-
-/**
- * Verify ICCPDUHelper.writeDiallingNumber
- */
-add_test(function test_write_dialling_number() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.ICCPDUHelper;
-
-  // with +
-  let number = "+123456";
-  let len = 4;
-  helper.writeDiallingNumber(number);
-  do_check_eq(helper.readDiallingNumber(len), number);
-
-  // without +
-  number = "987654";
-  len = 4;
-  helper.writeDiallingNumber(number);
-  do_check_eq(helper.readDiallingNumber(len), number);
-
-  number = "9876543";
-  len = 5;
-  helper.writeDiallingNumber(number);
-  do_check_eq(helper.readDiallingNumber(len), number);
-
-  run_next_test();
-});
-
-/**
- * Verify ICCPDUHelper.readNumberWithLength
- */
-add_test(function test_read_number_with_length() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-  let iccHelper = context.ICCPDUHelper;
-  let number = "123456789";
-
-  iccHelper.readDiallingNumber = function(numLen) {
-    return number.substring(0, numLen);
-  };
-
-  helper.writeHexOctet(number.length + 1);
-  helper.writeHexOctet(PDU_TOA_ISDN);
-  do_check_eq(iccHelper.readNumberWithLength(), number);
-
-  helper.writeHexOctet(0xff);
-  do_check_eq(iccHelper.readNumberWithLength(), null);
-
-  run_next_test();
-});
-
-/**
- * Verify ICCPDUHelper.writeNumberWithLength
- */
-add_test(function test_write_number_with_length() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-  let iccHelper = context.ICCPDUHelper;
-
-  function test(number, expectedNumber) {
-    expectedNumber = expectedNumber || number;
-    iccHelper.writeNumberWithLength(number);
-    let numLen = helper.readHexOctet();
-    do_check_eq(expectedNumber, iccHelper.readDiallingNumber(numLen));
-    for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES - numLen); i++) {
-      do_check_eq(0xff, helper.readHexOctet());
-    }
-  }
-
-  // without +
-  test("123456789");
-
-  // with +
-  test("+987654321");
-
-  // extended BCD coding
-  test("1*2#3,4*5#6,");
-
-  // with + and extended BCD coding
-  test("+1*2#3,4*5#6,");
-
-  // non-supported characters should not be written.
-  test("(1)23-456+789", "123456789");
-
-  test("++(01)2*3-4#5,6+7(8)9*0#1,", "+012*34#5,6789*0#1,");
-
-  // null
-  iccHelper.writeNumberWithLength(null);
-  for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES + 1); i++) {
-    do_check_eq(0xff, helper.readHexOctet());
-  }
-
-  run_next_test();
-});
-
-/**
- * Verify GsmPDUHelper.writeTimestamp
- */
-add_test(function test_write_timestamp() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-
-  // current date
-  let dateInput = new Date();
-  let dateOutput = new Date();
-  helper.writeTimestamp(dateInput);
-  dateOutput.setTime(helper.readTimestamp());
-
-  do_check_eq(dateInput.getFullYear(), dateOutput.getFullYear());
-  do_check_eq(dateInput.getMonth(), dateOutput.getMonth());
-  do_check_eq(dateInput.getDate(), dateOutput.getDate());
-  do_check_eq(dateInput.getHours(), dateOutput.getHours());
-  do_check_eq(dateInput.getMinutes(), dateOutput.getMinutes());
-  do_check_eq(dateInput.getSeconds(), dateOutput.getSeconds());
-  do_check_eq(dateInput.getTimezoneOffset(), dateOutput.getTimezoneOffset());
-
-  // 2034-01-23 12:34:56 -0800 GMT
-  let time = Date.UTC(2034, 1, 23, 12, 34, 56);
-  time = time - (8 * 60 * 60 * 1000);
-  dateInput.setTime(time);
-  helper.writeTimestamp(dateInput);
-  dateOutput.setTime(helper.readTimestamp());
-
-  do_check_eq(dateInput.getFullYear(), dateOutput.getFullYear());
-  do_check_eq(dateInput.getMonth(), dateOutput.getMonth());
-  do_check_eq(dateInput.getDate(), dateOutput.getDate());
-  do_check_eq(dateInput.getHours(), dateOutput.getHours());
-  do_check_eq(dateInput.getMinutes(), dateOutput.getMinutes());
-  do_check_eq(dateInput.getSeconds(), dateOutput.getSeconds());
-  do_check_eq(dateInput.getTimezoneOffset(), dateOutput.getTimezoneOffset());
-
-  run_next_test();
-});
-
-/**
- * Verify GsmPDUHelper.octectToBCD and GsmPDUHelper.BCDToOctet
- */
-add_test(function test_octect_BCD() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-
-  // 23
-  let number = 23;
-  let octet = helper.BCDToOctet(number);
-  do_check_eq(helper.octetToBCD(octet), number);
-
-  // 56
-  number = 56;
-  octet = helper.BCDToOctet(number);
-  do_check_eq(helper.octetToBCD(octet), number);
-
-  // 0x23
-  octet = 0x23;
-  number = helper.octetToBCD(octet);
-  do_check_eq(helper.BCDToOctet(number), octet);
-
-  // 0x56
-  octet = 0x56;
-  number = helper.octetToBCD(octet);
-  do_check_eq(helper.BCDToOctet(number), octet);
-
-  run_next_test();
-});
-
-/**
- * Verify ICCUtilsHelper.isICCServiceAvailable.
- */
-add_test(function test_is_icc_service_available() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let ICCUtilsHelper = context.ICCUtilsHelper;
-  let RIL = context.RIL;
-
-  function test_table(sst, geckoService, simEnabled, usimEnabled) {
-    RIL.iccInfoPrivate.sst = sst;
-    RIL.appType = CARD_APPTYPE_SIM;
-    do_check_eq(ICCUtilsHelper.isICCServiceAvailable(geckoService), simEnabled);
-    RIL.appType = CARD_APPTYPE_USIM;
-    do_check_eq(ICCUtilsHelper.isICCServiceAvailable(geckoService), usimEnabled);
-  }
-
-  test_table([0x08], "ADN", true, false);
-  test_table([0x08], "FDN", false, false);
-  test_table([0x08], "SDN", false, true);
-
-  run_next_test();
-});
-
-/**
- * Verify ICCUtilsHelper.isGsm8BitAlphabet
- */
-add_test(function test_is_gsm_8bit_alphabet() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let ICCUtilsHelper = context.ICCUtilsHelper;
-  const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
-  const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
-
-  do_check_eq(ICCUtilsHelper.isGsm8BitAlphabet(langTable), true);
-  do_check_eq(ICCUtilsHelper.isGsm8BitAlphabet(langShiftTable), true);
-  do_check_eq(ICCUtilsHelper.isGsm8BitAlphabet("\uaaaa"), false);
-
-  run_next_test();
-});
-
-/**
- * Verify RIL.iccGetCardLockState("fdn")
- */
-add_test(function test_icc_get_card_lock_state_fdn() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let ril = context.RIL;
-  let buf = context.Buf;
-
-  buf.sendParcel = function() {
-    // Request Type.
-    do_check_eq(this.readInt32(), REQUEST_QUERY_FACILITY_LOCK)
-
-    // Token : we don't care.
-    this.readInt32();
-
-    // String Array Length.
-    do_check_eq(this.readInt32(), ril.v5Legacy ? 3 : 4);
-
-    // Facility.
-    do_check_eq(this.readString(), ICC_CB_FACILITY_FDN);
-
-    // Password.
-    do_check_eq(this.readString(), "");
-
-    // Service class.
-    do_check_eq(this.readString(), (ICC_SERVICE_CLASS_VOICE |
-                                    ICC_SERVICE_CLASS_DATA  |
-                                    ICC_SERVICE_CLASS_FAX).toString());
-
-    if (!ril.v5Legacy) {
-      // AID. Ignore because it's from modem.
-      this.readInt32();
-    }
-
-    run_next_test();
-  };
-
-  ril.iccGetCardLockState({lockType: "fdn"});
-});
-
-add_test(function test_get_network_name_from_icc() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let RIL = context.RIL;
-  let ICCUtilsHelper = context.ICCUtilsHelper;
-
-  function testGetNetworkNameFromICC(operatorData, expectedResult) {
-    let result = ICCUtilsHelper.getNetworkNameFromICC(operatorData.mcc,
-                                                      operatorData.mnc,
-                                                      operatorData.lac);
-
-    if (expectedResult == null) {
-      do_check_eq(result, expectedResult);
-    } else {
-      do_check_eq(result.fullName, expectedResult.longName);
-      do_check_eq(result.shortName, expectedResult.shortName);
-    }
-  }
-
-  // Before EF_OPL and EF_PNN have been loaded.
-  testGetNetworkNameFromICC({mcc: 123, mnc: 456, lac: 0x1000}, null);
-  testGetNetworkNameFromICC({mcc: 321, mnc: 654, lac: 0x2000}, null);
-
-  // Set HPLMN
-  RIL.iccInfo.mcc = 123;
-  RIL.iccInfo.mnc = 456;
-
-  RIL.voiceRegistrationState = {
-    cell: {
-      gsmLocationAreaCode: 0x1000
-    }
-  };
-  RIL.operator = {};
-
-  // Set EF_PNN
-  RIL.iccInfoPrivate = {
-    PNN: [
-      {"fullName": "PNN1Long", "shortName": "PNN1Short"},
-      {"fullName": "PNN2Long", "shortName": "PNN2Short"},
-      {"fullName": "PNN3Long", "shortName": "PNN3Short"},
-      {"fullName": "PNN4Long", "shortName": "PNN4Short"}
-    ]
-  };
-
-  // EF_OPL isn't available and current isn't in HPLMN,
-  testGetNetworkNameFromICC({mcc: 321, mnc: 654, lac: 0x1000}, null);
-
-  // EF_OPL isn't available and current is in HPLMN,
-  // the first record of PNN should be returned.
-  testGetNetworkNameFromICC({mcc: 123, mnc: 456, lac: 0x1000},
-                            {longName: "PNN1Long", shortName: "PNN1Short"});
-
-  // Set EF_OPL
-  RIL.iccInfoPrivate.OPL = [
-    {
-      "mcc": 123,
-      "mnc": 456,
-      "lacTacStart": 0,
-      "lacTacEnd": 0xFFFE,
-      "pnnRecordId": 4
-    },
-    {
-      "mcc": 321,
-      "mnc": 654,
-      "lacTacStart": 0,
-      "lacTacEnd": 0x0010,
-      "pnnRecordId": 3
-    },
-    {
-      "mcc": 321,
-      "mnc": 654,
-      "lacTacStart": 0x0100,
-      "lacTacEnd": 0x1010,
-      "pnnRecordId": 2
-    }
-  ];
-
-  // Both EF_PNN and EF_OPL are presented, and current PLMN is HPLMN,
-  testGetNetworkNameFromICC({mcc: 123, mnc: 456, lac: 0x1000},
-                            {longName: "PNN4Long", shortName: "PNN4Short"});
-
-  // Current PLMN is not HPLMN, and according to LAC, we should get
-  // the second PNN record.
-  testGetNetworkNameFromICC({mcc: 321, mnc: 654, lac: 0x1000},
-                            {longName: "PNN2Long", shortName: "PNN2Short"});
-
-  // Current PLMN is not HPLMN, and according to LAC, we should get
-  // the thrid PNN record.
-  testGetNetworkNameFromICC({mcc: 321, mnc: 654, lac: 0x0001},
-                            {longName: "PNN3Long", shortName: "PNN3Short"});
-
-  run_next_test();
-});
-
-add_test(function test_path_id_for_spid_and_spn() {
-  let worker = newWorker({
-    postRILMessage: function(data) {
-      // Do nothing
-    },
-    postMessage: function(message) {
-      // Do nothing
-    }});
-  let context = worker.ContextPool._contexts[0];
-  let RIL = context.RIL;
-  let ICCFileHelper = context.ICCFileHelper;
-
-  // Test SIM
-  RIL.appType = CARD_APPTYPE_SIM;
-  do_check_eq(ICCFileHelper.getEFPath(ICC_EF_SPDI),
-              EF_PATH_MF_SIM + EF_PATH_DF_GSM);
-  do_check_eq(ICCFileHelper.getEFPath(ICC_EF_SPN),
-              EF_PATH_MF_SIM + EF_PATH_DF_GSM);
-
-  // Test USIM
-  RIL.appType = CARD_APPTYPE_USIM;
-  do_check_eq(ICCFileHelper.getEFPath(ICC_EF_SPDI),
-              EF_PATH_MF_SIM + EF_PATH_ADF_USIM);
-  do_check_eq(ICCFileHelper.getEFPath(ICC_EF_SPDI),
-              EF_PATH_MF_SIM + EF_PATH_ADF_USIM);
-  run_next_test();
-});
-
-/**
- * Verify ICCUtilsHelper.parsePbrTlvs
- */
-add_test(function test_parse_pbr_tlvs() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let buf = context.Buf;
-
-  let pbrTlvs = [
-    {tag: ICC_USIM_TYPE1_TAG,
-     length: 0x0F,
-     value: [{tag: ICC_USIM_EFADN_TAG,
-              length: 0x03,
-              value: [0x4F, 0x3A, 0x02]},
-             {tag: ICC_USIM_EFIAP_TAG,
-              length: 0x03,
-              value: [0x4F, 0x25, 0x01]},
-             {tag: ICC_USIM_EFPBC_TAG,
-              length: 0x03,
-              value: [0x4F, 0x09, 0x04]}]
-    },
-    {tag: ICC_USIM_TYPE2_TAG,
-     length: 0x05,
-     value: [{tag: ICC_USIM_EFEMAIL_TAG,
-              length: 0x03,
-              value: [0x4F, 0x50, 0x0B]},
-             {tag: ICC_USIM_EFANR_TAG,
-              length: 0x03,
-              value: [0x4F, 0x11, 0x02]},
-             {tag: ICC_USIM_EFANR_TAG,
-              length: 0x03,
-              value: [0x4F, 0x12, 0x03]}]
-    },
-    {tag: ICC_USIM_TYPE3_TAG,
-     length: 0x0A,
-     value: [{tag: ICC_USIM_EFCCP1_TAG,
-              length: 0x03,
-              value: [0x4F, 0x3D, 0x0A]},
-             {tag: ICC_USIM_EFEXT1_TAG,
-              length: 0x03,
-              value: [0x4F, 0x4A, 0x03]}]
-    },
-  ];
-
-  let pbr = context.ICCUtilsHelper.parsePbrTlvs(pbrTlvs);
-  do_check_eq(pbr.adn.fileId, 0x4F3a);
-  do_check_eq(pbr.iap.fileId, 0x4F25);
-  do_check_eq(pbr.pbc.fileId, 0x4F09);
-  do_check_eq(pbr.email.fileId, 0x4F50);
-  do_check_eq(pbr.anr0.fileId, 0x4f11);
-  do_check_eq(pbr.anr1.fileId, 0x4f12);
-  do_check_eq(pbr.ccp1.fileId, 0x4F3D);
-  do_check_eq(pbr.ext1.fileId, 0x4F4A);
-
-  run_next_test();
-});
-
-/**
- * Verify ICCIOHelper.loadLinearFixedEF with recordSize.
- */
-add_test(function test_load_linear_fixed_ef() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let ril = context.RIL;
-  let io = context.ICCIOHelper;
-
-  io.getResponse = function fakeGetResponse(options) {
-    // When recordSize is provided, loadLinearFixedEF should call iccIO directly.
-    do_check_true(false);
-    run_next_test();
-  };
-
-  ril.iccIO = function fakeIccIO(options) {
-    do_check_true(true);
-    run_next_test();
-  };
-
-  io.loadLinearFixedEF({recordSize: 0x20});
-});
-
-/**
- * Verify ICCIOHelper.loadLinearFixedEF without recordSize.
- */
-add_test(function test_load_linear_fixed_ef() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let ril = context.RIL;
-  let io = context.ICCIOHelper;
-
-  io.getResponse = function fakeGetResponse(options) {
-    do_check_true(true);
-    run_next_test();
-  };
-
-  ril.iccIO = function fakeIccIO(options) {
-    // When recordSize is not provided, loadLinearFixedEF should call getResponse.
-    do_check_true(false);
-    run_next_test();
-  };
-
-  io.loadLinearFixedEF({});
-});
-
-/**
- * Verify ICCRecordHelper.readPBR
- */
-add_test(function test_read_pbr() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-  let record = context.ICCRecordHelper;
-  let buf    = context.Buf;
-  let io     = context.ICCIOHelper;
-
-  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) {
-    let pbr_1 = [
-      0xa8, 0x05, 0xc0, 0x03, 0x4f, 0x3a, 0x01
-    ];
-
-    // Write data size
-    buf.writeInt32(pbr_1.length * 2);
-
-    // Write pbr
-    for (let i = 0; i < pbr_1.length; i++) {
-      helper.writeHexOctet(pbr_1[i]);
-    }
-
-    // Write string delimiter
-    buf.writeStringDelimiter(pbr_1.length * 2);
-
-    options.totalRecords = 2;
-    if (options.callback) {
-      options.callback(options);
-    }
-  };
-
-  io.loadNextRecord = function fakeLoadNextRecord(options) {
-    let pbr_2 = [
-      0xff, 0xff, 0xff, 0xff, 0xff, 0xff
-    ];
-
-    options.p1++;
-    if (options.callback) {
-      options.callback(options);
-    }
-  };
-
-  let successCb = function successCb(pbrs) {
-    do_check_eq(pbrs[0].adn.fileId, 0x4f3a);
-    do_check_eq(pbrs.length, 1);
-  };
-
-  let errorCb = function errorCb(errorMsg) {
-    do_print("Reading EF_PBR failed, msg = " + errorMsg);
-    do_check_true(false);
-  };
-
-  record.readPBR(successCb, errorCb);
-
-  // Check cache pbrs when 2nd call
-  let ifLoadEF = false;
-  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options)  {
-    ifLoadEF = true;
-  }
-  record.readPBR(successCb, errorCb);
-  do_check_false(ifLoadEF);
-
-  run_next_test();
-});
-
-/**
- * Verify ICCRecordHelper.readEmail
- */
-add_test(function test_read_email() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-  let record = context.ICCRecordHelper;
-  let buf    = context.Buf;
-  let io     = context.ICCIOHelper;
-  let recordSize;
-
-  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options)  {
-    let email_1 = [
-      0x65, 0x6D, 0x61, 0x69, 0x6C,
-      0x00, 0x6D, 0x6F, 0x7A, 0x69,
-      0x6C, 0x6C, 0x61, 0x2E, 0x63,
-      0x6F, 0x6D, 0x02, 0x23];
-
-    // Write data size
-    buf.writeInt32(email_1.length * 2);
-
-    // Write email
-    for (let i = 0; i < email_1.length; i++) {
-      helper.writeHexOctet(email_1[i]);
-    }
-
-    // Write string delimiter
-    buf.writeStringDelimiter(email_1.length * 2);
-
-    recordSize = email_1.length;
-    options.recordSize = recordSize;
-    if (options.callback) {
-      options.callback(options);
-    }
-  };
-
-  function doTestReadEmail(type, expectedResult) {
-    let fileId = 0x6a75;
-    let recordNumber = 1;
-
-    // fileId and recordNumber are dummy arguments.
-    record.readEmail(fileId, type, recordNumber, function(email) {
-      do_check_eq(email, expectedResult);
-    });
-  };
-
-  doTestReadEmail(ICC_USIM_TYPE1_TAG, "email@mozilla.com$#");
-  doTestReadEmail(ICC_USIM_TYPE2_TAG, "email@mozilla.com");
-  do_check_eq(record._emailRecordSize, recordSize);
-
-  run_next_test();
-});
-
-/**
- * Verify ICCRecordHelper.updateEmail
- */
-add_test(function test_update_email() {
-  const recordSize = 0x20;
-  const recordNumber = 1;
-  const fileId = 0x4f50;
-  const NUM_TESTS = 2;
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let pduHelper = context.GsmPDUHelper;
-  let iccHelper = context.ICCPDUHelper;
-  let ril = context.RIL;
-  ril.appType = CARD_APPTYPE_USIM;
-  let recordHelper = context.ICCRecordHelper;
-  let buf = context.Buf;
-  let ioHelper = context.ICCIOHelper;
-  let pbr = {email: {fileId: fileId, fileType: ICC_USIM_TYPE1_TAG},
-             adn: {sfi: 1}};
-  let count = 0;
-
-  // Override.
-  ioHelper.updateLinearFixedEF = function(options) {
-    options.pathId = context.ICCFileHelper.getEFPath(options.fileId);
-    options.command = ICC_COMMAND_UPDATE_RECORD;
-    options.p1 = options.recordNumber;
-    options.p2 = READ_RECORD_ABSOLUTE_MODE;
-    options.p3 = recordSize;
-    ril.iccIO(options);
-  };
-
-  function do_test(pbr, expectedEmail, expectedAdnRecordId) {
-    buf.sendParcel = function() {
-      count++;
-
-      // Request Type.
-      do_check_eq(this.readInt32(), REQUEST_SIM_IO);
-
-      // Token : we don't care
-      this.readInt32();
-
-      // command.
-      do_check_eq(this.readInt32(), ICC_COMMAND_UPDATE_RECORD);
-
-      // fileId.
-      do_check_eq(this.readInt32(), fileId);
-
-      // pathId.
-      do_check_eq(this.readString(),
-                  EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK);
-
-      // p1.
-      do_check_eq(this.readInt32(), recordNumber);
-
-      // p2.
-      do_check_eq(this.readInt32(), READ_RECORD_ABSOLUTE_MODE);
-
-      // p3.
-      do_check_eq(this.readInt32(), recordSize);
-
-      // data.
-      let strLen = this.readInt32();
-      let email;
-      if (pbr.email.fileType === ICC_USIM_TYPE1_TAG) {
-        email = iccHelper.read8BitUnpackedToString(recordSize);
-      } else {
-        email = iccHelper.read8BitUnpackedToString(recordSize - 2);
-        do_check_eq(pduHelper.readHexOctet(), pbr.adn.sfi);
-        do_check_eq(pduHelper.readHexOctet(), expectedAdnRecordId);
-      }
-      this.readStringDelimiter(strLen);
-      do_check_eq(email, expectedEmail);
-
-      // pin2.
-      do_check_eq(this.readString(), null);
-
-      if (!ril.v5Legacy) {
-        // AID. Ignore because it's from modem.
-        this.readInt32();
-      }
-
-      if (count == NUM_TESTS) {
-        run_next_test();
-      }
-    };
-    recordHelper.updateEmail(pbr, recordNumber, expectedEmail, expectedAdnRecordId);
-  }
-
-  do_test(pbr, "test@mail.com");
-  pbr.email.fileType = ICC_USIM_TYPE2_TAG;
-  do_test(pbr, "test@mail.com", 1);
-});
-
-/**
- * Verify ICCRecordHelper.readANR
- */
-add_test(function test_read_anr() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-  let record = context.ICCRecordHelper;
-  let buf    = context.Buf;
-  let io     = context.ICCIOHelper;
-  let recordSize;
-
-  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options)  {
-    let anr_1 = [
-      0x01, 0x05, 0x81, 0x10, 0x32,
-      0x54, 0xF6, 0xFF, 0xFF];
-
-    // Write data size
-    buf.writeInt32(anr_1.length * 2);
-
-    // Write anr
-    for (let i = 0; i < anr_1.length; i++) {
-      helper.writeHexOctet(anr_1[i]);
-    }
-
-    // Write string delimiter
-    buf.writeStringDelimiter(anr_1.length * 2);
-
-    recordSize = anr_1.length;
-    options.recordSize = recordSize;
-    if (options.callback) {
-      options.callback(options);
-    }
-  };
-
-  function doTestReadAnr(fileType, expectedResult) {
-    let fileId = 0x4f11;
-    let recordNumber = 1;
-
-    // fileId and recordNumber are dummy arguments.
-    record.readANR(fileId, fileType, recordNumber, function(anr) {
-      do_check_eq(anr, expectedResult);
-    });
-  };
-
-  doTestReadAnr(ICC_USIM_TYPE1_TAG, "0123456");
-  do_check_eq(record._anrRecordSize, recordSize);
-
-  run_next_test();
-});
-
-/**
- * Verify ICCRecordHelper.updateANR
- */
-add_test(function test_update_anr() {
-  const recordSize = 0x20;
-  const recordNumber = 1;
-  const fileId = 0x4f11;
-  const NUM_TESTS = 2;
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let pduHelper = context.GsmPDUHelper;
-  let iccHelper = context.ICCPDUHelper;
-  let ril = context.RIL;
-  ril.appType = CARD_APPTYPE_USIM;
-  let recordHelper = context.ICCRecordHelper;
-  let buf = context.Buf;
-  let ioHelper = context.ICCIOHelper;
-  let pbr = {anr0: {fileId: fileId, fileType: ICC_USIM_TYPE1_TAG},
-             adn: {sfi: 1}};
-  let count = 0;
-
-  // Override.
-  ioHelper.updateLinearFixedEF = function(options) {
-    options.pathId = context.ICCFileHelper.getEFPath(options.fileId);
-    options.command = ICC_COMMAND_UPDATE_RECORD;
-    options.p1 = options.recordNumber;
-    options.p2 = READ_RECORD_ABSOLUTE_MODE;
-    options.p3 = recordSize;
-    ril.iccIO(options);
-  };
-
-  function do_test(pbr, expectedANR, expectedAdnRecordId) {
-    buf.sendParcel = function() {
-      count++;
-
-      // Request Type.
-      do_check_eq(this.readInt32(), REQUEST_SIM_IO);
-
-      // Token : we don't care
-      this.readInt32();
-
-      // command.
-      do_check_eq(this.readInt32(), ICC_COMMAND_UPDATE_RECORD);
-
-      // fileId.
-      do_check_eq(this.readInt32(), fileId);
-
-      // pathId.
-      do_check_eq(this.readString(),
-                  EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK);
-
-      // p1.
-      do_check_eq(this.readInt32(), recordNumber);
-
-      // p2.
-      do_check_eq(this.readInt32(), READ_RECORD_ABSOLUTE_MODE);
-
-      // p3.
-      do_check_eq(this.readInt32(), recordSize);
-
-      // data.
-      let strLen = this.readInt32();
-      // EF_AAS, ignore.
-      pduHelper.readHexOctet();
-      do_check_eq(iccHelper.readNumberWithLength(), expectedANR);
-      // EF_CCP, ignore.
-      pduHelper.readHexOctet();
-      // EF_EXT1, ignore.
-      pduHelper.readHexOctet();
-      if (pbr.anr0.fileType === ICC_USIM_TYPE2_TAG) {
-        do_check_eq(pduHelper.readHexOctet(), pbr.adn.sfi);
-        do_check_eq(pduHelper.readHexOctet(), expectedAdnRecordId);
-      }
-      this.readStringDelimiter(strLen);
-
-      // pin2.
-      do_check_eq(this.readString(), null);
-
-      if (!ril.v5Legacy) {
-        // AID. Ignore because it's from modem.
-        this.readInt32();
-      }
-
-      if (count == NUM_TESTS) {
-        run_next_test();
-      }
-    };
-    recordHelper.updateANR(pbr, recordNumber, expectedANR, expectedAdnRecordId);
-  }
-
-  do_test(pbr, "+123456789");
-  pbr.anr0.fileType = ICC_USIM_TYPE2_TAG;
-  do_test(pbr, "123456789", 1);
-});
-
-/**
- * Verify ICCRecordHelper.readIAP
- */
-add_test(function test_read_iap() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-  let record = context.ICCRecordHelper;
-  let buf    = context.Buf;
-  let io     = context.ICCIOHelper;
-  let recordSize;
-
-  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options)  {
-    let iap_1 = [0x01, 0x02];
-
-    // Write data size/
-    buf.writeInt32(iap_1.length * 2);
-
-    // Write iap.
-    for (let i = 0; i < iap_1.length; i++) {
-      helper.writeHexOctet(iap_1[i]);
-    }
-
-    // Write string delimiter.
-    buf.writeStringDelimiter(iap_1.length * 2);
-
-    recordSize = iap_1.length;
-    options.recordSize = recordSize;
-    if (options.callback) {
-      options.callback(options);
-    }
-  };
-
-  function doTestReadIAP(expectedIAP) {
-    const fileId = 0x4f17;
-    const recordNumber = 1;
-
-    let successCb = function successCb(iap) {
-      for (let i = 0; i < iap.length; i++) {
-        do_check_eq(expectedIAP[i], iap[i]);
-      }
-      run_next_test();
-    }.bind(this);
-
-    let errorCb = function errorCb(errorMsg) {
-      do_print(errorMsg);
-      do_check_true(false);
-      run_next_test();
-    }.bind(this);
-
-    record.readIAP(fileId, recordNumber, successCb, errorCb);
-  };
-
-  doTestReadIAP([1, 2]);
-});
-
-/**
- * Verify ICCRecordHelper.updateIAP
- */
-add_test(function test_update_iap() {
-  const recordSize = 2;
-  const recordNumber = 1;
-  const fileId = 0x4f17;
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let pduHelper = context.GsmPDUHelper;
-  let ril = context.RIL;
-  ril.appType = CARD_APPTYPE_USIM;
-  let recordHelper = context.ICCRecordHelper;
-  let buf = context.Buf;
-  let ioHelper = context.ICCIOHelper;
-  let count = 0;
-
-  // Override.
-  ioHelper.updateLinearFixedEF = function(options) {
-    options.pathId = context.ICCFileHelper.getEFPath(options.fileId);
-    options.command = ICC_COMMAND_UPDATE_RECORD;
-    options.p1 = options.recordNumber;
-    options.p2 = READ_RECORD_ABSOLUTE_MODE;
-    options.p3 = recordSize;
-    ril.iccIO(options);
-  };
-
-  function do_test(expectedIAP) {
-    buf.sendParcel = function() {
-      // Request Type.
-      do_check_eq(this.readInt32(), REQUEST_SIM_IO);
-
-      // Token : we don't care
-      this.readInt32();
-
-      // command.
-      do_check_eq(this.readInt32(), ICC_COMMAND_UPDATE_RECORD);
-
-      // fileId.
-      do_check_eq(this.readInt32(), fileId);
-
-      // pathId.
-      do_check_eq(this.readString(),
-                  EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK);
-
-      // p1.
-      do_check_eq(this.readInt32(), recordNumber);
-
-      // p2.
-      do_check_eq(this.readInt32(), READ_RECORD_ABSOLUTE_MODE);
-
-      // p3.
-      do_check_eq(this.readInt32(), recordSize);
-
-      // data.
-      let strLen = this.readInt32();
-      for (let i = 0; i < recordSize; i++) {
-        do_check_eq(expectedIAP[i], pduHelper.readHexOctet());
-      }
-      this.readStringDelimiter(strLen);
-
-      // pin2.
-      do_check_eq(this.readString(), null);
-
-      if (!ril.v5Legacy) {
-        // AID. Ignore because it's from modem.
-        this.readInt32();
-      }
-
-      run_next_test();
-    };
-    recordHelper.updateIAP(fileId, recordNumber, expectedIAP);
-  }
-
-  do_test([1, 2]);
-});
-
-/**
- * Verify ICCRecordHelper.updateADNLike.
- */
-add_test(function test_update_adn_like() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let ril = context.RIL;
-  let record = context.ICCRecordHelper;
-  let io = context.ICCIOHelper;
-  let pdu = context.ICCPDUHelper;
-  let buf = context.Buf;
-
-  ril.appType = CARD_APPTYPE_SIM;
-  const recordSize = 0x20;
-  let fileId;
-
-  // Override.
-  io.updateLinearFixedEF = function(options) {
-    options.pathId = context.ICCFileHelper.getEFPath(options.fileId);
-    options.command = ICC_COMMAND_UPDATE_RECORD;
-    options.p1 = options.recordNumber;
-    options.p2 = READ_RECORD_ABSOLUTE_MODE;
-    options.p3 = recordSize;
-    ril.iccIO(options);
-  };
-
-  buf.sendParcel = function() {
-    // Request Type.
-    do_check_eq(this.readInt32(), REQUEST_SIM_IO);
-
-    // Token : we don't care
-    this.readInt32();
-
-    // command.
-    do_check_eq(this.readInt32(), ICC_COMMAND_UPDATE_RECORD);
-
-    // fileId.
-    do_check_eq(this.readInt32(), fileId);
-
-    // pathId.
-    do_check_eq(this.readString(), EF_PATH_MF_SIM + EF_PATH_DF_TELECOM);
-
-    // p1.
-    do_check_eq(this.readInt32(), 1);
-
-    // p2.
-    do_check_eq(this.readInt32(), READ_RECORD_ABSOLUTE_MODE);
-
-    // p3.
-    do_check_eq(this.readInt32(), 0x20);
-
-    // data.
-    let contact = pdu.readAlphaIdDiallingNumber(0x20);
-    do_check_eq(contact.alphaId, "test");
-    do_check_eq(contact.number, "123456");
-
-    // pin2.
-    if (fileId == ICC_EF_ADN) {
-      do_check_eq(this.readString(), null);
-    } else {
-      do_check_eq(this.readString(), "1111");
-    }
-
-    if (!ril.v5Legacy) {
-      // AID. Ignore because it's from modem.
-      this.readInt32();
-    }
-
-    if (fileId == ICC_EF_FDN) {
-      run_next_test();
-    }
-  };
-
-  fileId = ICC_EF_ADN;
-  record.updateADNLike(fileId,
-                       {recordId: 1, alphaId: "test", number: "123456"});
-
-  fileId = ICC_EF_FDN;
-  record.updateADNLike(fileId,
-                       {recordId: 1, alphaId: "test", number: "123456"},
-                       "1111");
-});
-
-/**
- * Verify ICCRecordHelper.findFreeRecordId.
- */
-add_test(function test_find_free_record_id() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let pduHelper = context.GsmPDUHelper;
-  let recordHelper = context.ICCRecordHelper;
-  let buf = context.Buf;
-  let io  = context.ICCIOHelper;
-
-  function writeRecord (record) {
-    // Write data size
-    buf.writeInt32(record.length * 2);
-
-    for (let i = 0; i < record.length; i++) {
-      pduHelper.writeHexOctet(record[i]);
-    }
-
-    // Write string delimiter
-    buf.writeStringDelimiter(record.length * 2);
-  }
-
-  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options)  {
-    // Some random data.
-    let record = [0x12, 0x34, 0x56, 0x78, 0x90];
-    options.p1 = 1;
-    options.totalRecords = 2;
-    writeRecord(record);
-    if (options.callback) {
-      options.callback(options);
-    }
-  };
-
-  io.loadNextRecord = function fakeLoadNextRecord(options) {
-    // Unused bytes.
-    let record = [0xff, 0xff, 0xff, 0xff, 0xff];
-    options.p1++;
-    writeRecord(record);
-    if (options.callback) {
-      options.callback(options);
-    }
-  };
-
-  let fileId = 0x0000; // Dummy.
-  recordHelper.findFreeRecordId(
-    fileId,
-    function(recordId) {
-      do_check_eq(recordId, 2);
-      run_next_test();
-    }.bind(this),
-    function(errorMsg) {
-      do_print(errorMsg);
-      do_check_true(false);
-      run_next_test();
-    }.bind(this));
-});
-
-/**
- * Verify ICCContactHelper.readICCContacts
- */
-add_test(function test_read_icc_contacts() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let record = context.ICCRecordHelper;
-  let contactHelper = context.ICCContactHelper;
-  let ril = context.RIL;
-
-  function do_test(aSimType, aContactType, aExpectedContact, aEnhancedPhoneBook) {
-    ril.appType = aSimType;
-    ril._isCdma = (aSimType === CARD_APPTYPE_RUIM);
-    ril.iccInfoPrivate.cst = (aEnhancedPhoneBook) ?
-                                    [0x0, 0x0C, 0x0, 0x0, 0x0]:
-                                    [0x0, 0x00, 0x0, 0x0, 0x0];
-
-    // Override some functions to test.
-    contactHelper.getContactFieldRecordId = function(pbr, contact, field, onsuccess, onerror) {
-      onsuccess(1);
-    };
-
-    record.readPBR = function readPBR(onsuccess, onerror) {
-      onsuccess([{adn:{fileId: 0x6f3a}, email: {}, anr0: {}}]);
-    };
-
-    record.readADNLike = function readADNLike(fileId, onsuccess, onerror) {
-      onsuccess([{recordId: 1, alphaId: "name", number: "111111"}])
-    };
-
-    record.readEmail = function readEmail(fileId, fileType, recordNumber, onsuccess, onerror) {
-      onsuccess("hello@mail.com");
-    };
-
-    record.readANR = function readANR(fileId, fileType, recordNumber, onsuccess, onerror) {
-      onsuccess("123456");
-    };
-
-    let onsuccess = function onsuccess(contacts) {
-      let contact = contacts[0];
-      for (let key in contact) {
-        do_print("check " + key);
-        if (Array.isArray(contact[key])) {
-          do_check_eq(contact[key][0], aExpectedContact[key]);
-        } else {
-          do_check_eq(contact[key], aExpectedContact[key]);
-        }
-      }
-    };
-
-    let onerror = function onerror(errorMsg) {
-      do_print("readICCContacts failed: " + errorMsg);
-      do_check_true(false);
-    };
-
-    contactHelper.readICCContacts(aSimType, aContactType, onsuccess, onerror);
-  }
-
-  let expectedContact1 = {
-    pbrIndex: 0,
-    recordId: 1,
-    alphaId:  "name",
-    number:   "111111"
-  };
-
-  let expectedContact2 = {
-    pbrIndex: 0,
-    recordId: 1,
-    alphaId:  "name",
-    number:   "111111",
-    email:    "hello@mail.com",
-    anr:      "123456"
-  };
-
-  // SIM
-  do_print("Test read SIM adn contacts");
-  do_test(CARD_APPTYPE_SIM, "adn", expectedContact1);
-
-  do_print("Test read SIM fdn contacts");
-  do_test(CARD_APPTYPE_SIM, "fdn", expectedContact1);
-
-  // USIM
-  do_print("Test read USIM adn contacts");
-  do_test(CARD_APPTYPE_USIM, "adn", expectedContact2);
-
-  do_print("Test read USIM fdn contacts");
-  do_test(CARD_APPTYPE_USIM, "fdn", expectedContact1);
-
-  // RUIM
-  do_print("Test read RUIM adn contacts");
-  do_test(CARD_APPTYPE_RUIM, "adn", expectedContact1);
-
-  do_print("Test read RUIM fdn contacts");
-  do_test(CARD_APPTYPE_RUIM, "fdn", expectedContact1);
-
-  // RUIM with enhanced phone book
-  do_print("Test read RUIM adn contacts with enhanced phone book");
-  do_test(CARD_APPTYPE_RUIM, "adn", expectedContact2, true);
-
-  do_print("Test read RUIM fdn contacts with enhanced phone book");
-  do_test(CARD_APPTYPE_RUIM, "fdn", expectedContact1, true);
-
-  run_next_test();
-});
-
-/**
- * Verify ICCContactHelper.updateICCContact with appType is CARD_APPTYPE_USIM.
- */
-add_test(function test_update_icc_contact() {
-  const ADN_RECORD_ID   = 100;
-  const ADN_SFI         = 1;
-  const IAP_FILE_ID     = 0x4f17;
-  const EMAIL_FILE_ID   = 0x4f50;
-  const EMAIL_RECORD_ID = 20;
-  const ANR0_FILE_ID    = 0x4f11;
-  const ANR0_RECORD_ID  = 30;
-
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let recordHelper = context.ICCRecordHelper;
-  let contactHelper = context.ICCContactHelper;
-  let ril = context.RIL;
-
-  function do_test(aSimType, aContactType, aContact, aPin2, aFileType, aHaveIapIndex, aEnhancedPhoneBook) {
-    ril.appType = aSimType;
-    ril._isCdma = (aSimType === CARD_APPTYPE_RUIM);
-    ril.iccInfoPrivate.cst = (aEnhancedPhoneBook) ? [0x0, 0x0C, 0x0, 0x0, 0x0]
-                                                  : [0x0, 0x00, 0x0, 0x0, 0x0];
-
-    recordHelper.readPBR = function(onsuccess, onerror) {
-      if (aFileType === ICC_USIM_TYPE1_TAG) {
-        onsuccess([{
-          adn:   {fileId: ICC_EF_ADN},
-          email: {fileId: EMAIL_FILE_ID,
-                  fileType: ICC_USIM_TYPE1_TAG},
-          anr0:  {fileId: ANR0_FILE_ID,
-                  fileType: ICC_USIM_TYPE1_TAG}
-        }]);
-      } else if (aFileType === ICC_USIM_TYPE2_TAG) {
-        onsuccess([{
-          adn:   {fileId: ICC_EF_ADN,
-                  sfi: ADN_SFI},
-          iap:   {fileId: IAP_FILE_ID},
-          email: {fileId: EMAIL_FILE_ID,
-                  fileType: ICC_USIM_TYPE2_TAG,
-                  indexInIAP: 0},
-          anr0:  {fileId: ANR0_FILE_ID,
-                  fileType: ICC_USIM_TYPE2_TAG,
-                  indexInIAP: 1}
-        }]);
-      }
-    };
-
-    recordHelper.updateADNLike = function(fileId, contact, pin2, onsuccess, onerror) {
-      if (aContactType === "fdn") {
-        do_check_eq(fileId, ICC_EF_FDN);
-      } else if (aContactType === "adn") {
-        do_check_eq(fileId, ICC_EF_ADN);
-      }
-      do_check_eq(pin2, aPin2);
-      do_check_eq(contact.alphaId, aContact.alphaId);
-      do_check_eq(contact.number, aContact.number);
-      onsuccess();
-    };
-
-    recordHelper.readIAP = function(fileId, recordNumber, onsuccess, onerror) {
-      do_check_eq(fileId, IAP_FILE_ID);
-      do_check_eq(recordNumber, ADN_RECORD_ID);
-      onsuccess((aHaveIapIndex) ? [EMAIL_RECORD_ID, ANR0_RECORD_ID]
-                                : [0xff, 0xff]);
-    };
-
-    recordHelper.updateIAP = function(fileId, recordNumber, iap, onsuccess, onerror) {
-      do_check_eq(fileId, IAP_FILE_ID);
-      do_check_eq(recordNumber, ADN_RECORD_ID);
-      onsuccess();
-    };
-
-    recordHelper.updateEmail = function(pbr, recordNumber, email, adnRecordId, onsuccess, onerror) {
-      do_check_eq(pbr.email.fileId, EMAIL_FILE_ID);
-      if (pbr.email.fileType === ICC_USIM_TYPE1_TAG) {
-        do_check_eq(recordNumber, ADN_RECORD_ID);
-      } else if (pbr.email.fileType === ICC_USIM_TYPE2_TAG) {
-        do_check_eq(recordNumber, EMAIL_RECORD_ID);
-      }
-      do_check_eq(email, aContact.email);
-      onsuccess();
-    };
-
-    recordHelper.updateANR = function(pbr, recordNumber, number, adnRecordId, onsuccess, onerror) {
-      do_check_eq(pbr.anr0.fileId, ANR0_FILE_ID);
-      if (pbr.anr0.fileType === ICC_USIM_TYPE1_TAG) {
-        do_check_eq(recordNumber, ADN_RECORD_ID);
-      } else if (pbr.anr0.fileType === ICC_USIM_TYPE2_TAG) {
-        do_check_eq(recordNumber, ANR0_RECORD_ID);
-      }
-      if (Array.isArray(aContact.anr)) {
-        do_check_eq(number, aContact.anr[0]);
-      }
-      onsuccess();
-    };
-
-    recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) {
-      let recordId = 0;
-      if (fileId === EMAIL_FILE_ID) {
-        recordId = EMAIL_RECORD_ID;
-      } else if (fileId === ANR0_FILE_ID) {
-        recordId = ANR0_RECORD_ID;
-      }
-      onsuccess(recordId);
-    };
-
-    let isSuccess = false;
-    let onsuccess = function onsuccess() {
-      do_print("updateICCContact success");
-      isSuccess = true;
-    };
-
-    let onerror = function onerror(errorMsg) {
-      do_print("updateICCContact failed: " + errorMsg);
-    };
-
-    contactHelper.updateICCContact(aSimType, aContactType, aContact, aPin2, onsuccess, onerror);
-    do_check_true(isSuccess);
-  }
-
-  let contacts = [
-    {
-      pbrIndex: 0,
-      recordId: ADN_RECORD_ID,
-      alphaId:  "test",
-      number:   "123456",
-      email:    "test@mail.com",
-      anr:      ["+654321"]
-    },
-    // a contact without email and anr.
-    {
-      pbrIndex: 0,
-      recordId: ADN_RECORD_ID,
-      alphaId:  "test2",
-      number:   "123456",
-    },
-    // a contact with email but no anr.
-    {
-      pbrIndex: 0,
-      recordId: ADN_RECORD_ID,
-      alphaId:  "test3",
-      number:   "123456",
-      email:    "test@mail.com"
-    },
-    // a contact with anr but no email.
-    {
-      pbrIndex: 0,
-      recordId: ADN_RECORD_ID,
-      alphaId:  "test4",
-      number:   "123456",
-      anr:      ["+654321"]
-    }];
-
-  for (let i = 0; i < contacts.length; i++) {
-    let contact = contacts[i];
-    // SIM
-    do_print("Test update SIM adn contacts");
-    do_test(CARD_APPTYPE_SIM, "adn", contact);
-
-    do_print("Test update SIM fdn contacts");
-    do_test(CARD_APPTYPE_SIM, "fdn", contact, "1234");
-
-    // USIM
-    do_print("Test update USIM adn contacts");
-    do_test(CARD_APPTYPE_USIM, "adn", contact, null, ICC_USIM_TYPE1_TAG);
-    do_test(CARD_APPTYPE_USIM, "adn", contact, null, ICC_USIM_TYPE2_TAG, true);
-    do_test(CARD_APPTYPE_USIM, "adn", contact, null, ICC_USIM_TYPE2_TAG, false);
-
-    do_print("Test update USIM fdn contacts");
-    do_test(CARD_APPTYPE_USIM, "fdn", contact, "1234");
-
-    // RUIM
-    do_print("Test update RUIM adn contacts");
-    do_test(CARD_APPTYPE_RUIM, "adn", contact);
-
-    do_print("Test update RUIM fdn contacts");
-    do_test(CARD_APPTYPE_RUIM, "fdn", contact, "1234");
-
-    // RUIM with enhanced phone book
-    do_print("Test update RUIM adn contacts with enhanced phone book");
-    do_test(CARD_APPTYPE_RUIM, "adn", contact, null, ICC_USIM_TYPE1_TAG, null, true);
-    do_test(CARD_APPTYPE_RUIM, "adn", contact, null, ICC_USIM_TYPE2_TAG, true, true);
-    do_test(CARD_APPTYPE_RUIM, "adn", contact, null, ICC_USIM_TYPE2_TAG, false, true);
-
-    do_print("Test update RUIM fdn contacts with enhanced phone book");
-    do_test(CARD_APPTYPE_RUIM, "fdn", contact, "1234", null, true);
-  }
-
-  run_next_test();
-});
-
-/**
- * Verify updateICCContact with removal of anr and email with File Type 1.
- */
-add_test(function test_update_icc_contact_with_remove_type1_attr() {
-  const ADN_RECORD_ID   = 100;
-  const IAP_FILE_ID     = 0x4f17;
-  const EMAIL_FILE_ID   = 0x4f50;
-  const EMAIL_RECORD_ID = 20;
-  const ANR0_FILE_ID    = 0x4f11;
-  const ANR0_RECORD_ID  = 30;
-
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let recordHelper = context.ICCRecordHelper;
-  let contactHelper = context.ICCContactHelper;
-
-  recordHelper.updateADNLike = function(fileId, contact, pin2, onsuccess, onerror) {
-    onsuccess();
-  };
-
-  let contact = {
-    pbrIndex: 0,
-    recordId: ADN_RECORD_ID,
-    alphaId:  "test2",
-    number:   "123456",
-  };
-
-  recordHelper.readIAP = function(fileId, recordNumber, onsuccess, onerror) {
-    onsuccess([EMAIL_RECORD_ID, ANR0_RECORD_ID]);
-  };
-
-  recordHelper.updateEmail = function(pbr, recordNumber, email, adnRecordId, onsuccess, onerror) {
-    do_check_true(email == null);
-    onsuccess();
-  };
-
-  recordHelper.updateANR = function(pbr, recordNumber, number, adnRecordId, onsuccess, onerror) {
-    do_check_true(number == null);
-    onsuccess();
-  };
-
-  function do_test(type) {
-    recordHelper.readPBR = function(onsuccess, onerror) {
-      if (type == ICC_USIM_TYPE1_TAG) {
-        onsuccess([{
-          adn:   {fileId: ICC_EF_ADN},
-          email: {fileId: EMAIL_FILE_ID,
-                  fileType: ICC_USIM_TYPE1_TAG},
-          anr0:  {fileId: ANR0_FILE_ID,
-                  fileType: ICC_USIM_TYPE1_TAG}}]);
-      } else {
-        onsuccess([{
-          adn:   {fileId: ICC_EF_ADN},
-          iap:   {fileId: IAP_FILE_ID},
-          email: {fileId: EMAIL_FILE_ID,
-                  fileType: ICC_USIM_TYPE2_TAG,
-                  indexInIAP: 0},
-          anr0:  {fileId: ANR0_FILE_ID,
-                  fileType: ICC_USIM_TYPE2_TAG,
-                  indexInIAP: 1}}]);
-      }
-    };
-
-    let successCb = function() {
-      do_check_true(true);
-    };
-
-    let errorCb = function(errorMsg) {
-      do_print(errorMsg);
-      do_check_true(false);
-    };
-
-    contactHelper.updateICCContact(CARD_APPTYPE_USIM, "adn", contact, null, successCb, errorCb);
-  }
-
-  do_test(ICC_USIM_TYPE1_TAG);
-  do_test(ICC_USIM_TYPE2_TAG);
-
-  run_next_test();
-});
-
-/**
- * Verify ICCContactHelper.findFreeICCContact in SIM
- */
-add_test(function test_find_free_icc_contact_sim() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let recordHelper = context.ICCRecordHelper;
-  let contactHelper = context.ICCContactHelper;
-  // Correct record Id starts with 1, so put a null element at index 0.
-  let records = [null];
-  const MAX_RECORDS = 3;
-  const PBR_INDEX = 0;
-
-  recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) {
-    if (records.length > MAX_RECORDS) {
-      onerror("No free record found.");
-      return;
-    }
-
-    onsuccess(records.length);
-  };
-
-  let successCb = function(pbrIndex, recordId) {
-    do_check_eq(pbrIndex, PBR_INDEX);
-    records[recordId] = {};
-  };
-
-  let errorCb = function(errorMsg) {
-    do_print(errorMsg);
-    do_check_true(false);
-  };
-
-  for (let i = 0; i < MAX_RECORDS; i++) {
-    contactHelper.findFreeICCContact(CARD_APPTYPE_SIM, "adn", successCb, errorCb);
-  }
-  // The 1st element, records[0], is null.
-  do_check_eq(records.length - 1, MAX_RECORDS);
-
-  // Now the EF is full, so finding a free one should result failure.
-  successCb = function(pbrIndex, recordId) {
-    do_check_true(false);
-  };
-
-  errorCb = function(errorMsg) {
-    do_check_true(errorMsg === "No free record found.");
-  };
-  contactHelper.findFreeICCContact(CARD_APPTYPE_SIM, "adn", successCb, errorCb);
-
-  run_next_test();
-});
-
-/**
- * Verify ICCContactHelper.findFreeICCContact in USIM
- */
-add_test(function test_find_free_icc_contact_usim() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let recordHelper = context.ICCRecordHelper;
-  let contactHelper = context.ICCContactHelper;
-  const ADN1_FILE_ID = 0x6f3a;
-  const ADN2_FILE_ID = 0x6f3b;
-  const MAX_RECORDS = 3;
-
-  // The adn in the first phonebook set has already two records, which means
-  // only 1 free record remained.
-  let pbrs = [{adn: {fileId: ADN1_FILE_ID, records: [null, {}, {}]}},
-              {adn: {fileId: ADN2_FILE_ID, records: [null]}}];
-
-  recordHelper.readPBR = function readPBR(onsuccess, onerror) {
-    onsuccess(pbrs);
-  };
-
-  recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) {
-    let pbr = (fileId == ADN1_FILE_ID ? pbrs[0]: pbrs[1]);
-    if (pbr.adn.records.length > MAX_RECORDS) {
-      onerror("No free record found.");
-      return;
-    }
-
-    onsuccess(pbr.adn.records.length);
-  };
-
-  let successCb = function(pbrIndex, recordId) {
-    do_check_eq(pbrIndex, 0);
-    pbrs[pbrIndex].adn.records[recordId] = {};
-  };
-
-  let errorCb = function(errorMsg) {
-    do_check_true(false);
-  };
-
-  contactHelper.findFreeICCContact(CARD_APPTYPE_USIM, "adn", successCb, errorCb);
-
-  // Now the EF_ADN in the 1st phonebook set is full, so the next free contact
-  // will come from the 2nd phonebook set.
-  successCb = function(pbrIndex, recordId) {
-    do_check_eq(pbrIndex, 1);
-    do_check_eq(recordId, 1);
-  }
-  contactHelper.findFreeICCContact(CARD_APPTYPE_USIM, "adn", successCb, errorCb);
-
-  run_next_test();
-});
-
-/**
- * Test error message returned in onerror for readICCContacts.
- */
-add_test(function test_error_message_read_icc_contact () {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let ril = context.RIL;
-
-  function do_test(options, expectedErrorMsg) {
-    ril.sendChromeMessage = function(message) {
-      do_check_eq(message.errorMsg, expectedErrorMsg);
-    }
-    ril.readICCContacts(options);
-  }
-
-  // Error 1, didn't specify correct contactType.
-  do_test({}, CONTACT_ERR_REQUEST_NOT_SUPPORTED);
-
-  // Error 2, specifying a non-supported contactType.
-  ril.appType = CARD_APPTYPE_USIM;
-  do_test({contactType: "sdn"}, CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED);
-
-  // Error 3, suppose we update the supported PBR fields in USIM_PBR_FIELDS,
-  // but forget to add implemenetations for it.
-  USIM_PBR_FIELDS.push("pbc");
-  do_test({contactType: "adn"}, CONTACT_ERR_FIELD_NOT_SUPPORTED);
-
-  run_next_test();
-});
-
-/**
- * Test error message returned in onerror for updateICCContact.
- */
-add_test(function test_error_message_update_icc_contact() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let ril = context.RIL;
-
-  const ICCID = "123456789";
-  ril.iccInfo.iccid = ICCID;
-
-  function do_test(options, expectedErrorMsg) {
-    ril.sendChromeMessage = function(message) {
-      do_check_eq(message.errorMsg, expectedErrorMsg);
-    }
-    ril.updateICCContact(options);
-  }
-
-  // Error 1, didn't specify correct contactType.
-  do_test({}, CONTACT_ERR_REQUEST_NOT_SUPPORTED);
-
-  // Error 2, specifying a correct contactType, but without providing 'contact'.
-  do_test({contactType: "adn"}, CONTACT_ERR_REQUEST_NOT_SUPPORTED);
-
-  // Error 3, specifying a non-supported contactType.
-  ril.appType = CARD_APPTYPE_USIM;
-  do_test({contactType: "sdn", contact: {}}, CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED);
-
-  // Error 4, without supplying pin2.
-  do_test({contactType: "fdn", contact: {contactId: ICCID + "1"}}, GECKO_ERROR_SIM_PIN2);
-
-  // Error 5, No free record found in EF_ADN.
-  let record = context.ICCRecordHelper;
-  record.readPBR = function(onsuccess, onerror) {
-    onsuccess([{adn: {fileId: 0x4f3a}}]);
-  };
-
-  let io = context.ICCIOHelper;
-  io.loadLinearFixedEF = function(options) {
-    options.totalRecords = 1;
-    options.p1 = 1;
-    options.callback(options);
-  };
-
-  do_test({contactType: "adn", contact: {}}, CONTACT_ERR_NO_FREE_RECORD_FOUND);
-
-  // Error 6, ICC IO Error.
-  io.loadLinearFixedEF = function(options) {
-    ril[REQUEST_SIM_IO](0, {rilRequestError: ERROR_GENERIC_FAILURE});
-  };
-  do_test({contactType: "adn", contact: {contactId: ICCID + "1"}},
-          GECKO_ERROR_GENERIC_FAILURE);
-
-  // Error 7, suppose we update the supported PBR fields in USIM_PBR_FIELDS,
-  // but forget to add implemenetations for it.
-  USIM_PBR_FIELDS.push("pbc");
-  do_test({contactType: "adn", contact: {contactId: ICCID + "1"}},
-          CONTACT_ERR_FIELD_NOT_SUPPORTED);
-
-  // Error 8, EF_PBR doesn't exist.
-  record.readPBR = function(onsuccess, onerror) {
-    onsuccess([]);
-  };
-
-  do_test({contactType: "adn", contact: {contactId: ICCID + "1"}},
-          CONTACT_ERR_CANNOT_ACCESS_PHONEBOOK);
-
-  run_next_test();
-});
-
-add_test(function test_process_icc_io_error() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let ioHelper = context.ICCIOHelper;
-
-  function do_test(errorCode, expectedErrorMsg) {
-    let called = false;
-    function errorCb(errorMsg) {
-      called = true;
-      do_check_eq(errorMsg, expectedErrorMsg);
-    }
-
-    ioHelper.processICCIOError({rilRequestError: errorCode,
-                                fileId: 0xffff,
-                                command: 0xff,
-                                sw1: 0xff,
-                                sw2: 0xff,
-                                onerror: errorCb});
-    do_check_true(called);
-  }
-
-  for (let i = 0; i < ERROR_REJECTED_BY_REMOTE + 1; i++) {
-    do_test(i, RIL_ERROR_TO_GECKO_ERROR[i]);
-  }
-
-  run_next_test();
-});
-
-add_test(function test_personalization_state() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let ril = context.RIL;
-
-  context.ICCRecordHelper.readICCID = function fakeReadICCID() {};
-
-  function testPersonalization(isCdma, cardPersoState, geckoCardState) {
-    let iccStatus = {
-      cardState: CARD_STATE_PRESENT,
-      gsmUmtsSubscriptionAppIndex: (!isCdma) ? 0 : -1,
-      cdmaSubscriptionAppIndex: (isCdma) ? 0 : -1,
-      apps: [
-        {
-          app_state: CARD_APPSTATE_SUBSCRIPTION_PERSO,
-          perso_substate: cardPersoState
-        }],
-    };
-
-    ril._isCdma = isCdma;
-    ril._processICCStatus(iccStatus);
-    do_check_eq(ril.cardState, geckoCardState);
-  }
-
-  // Test GSM personalization state.
-  testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK,
-                      GECKO_CARDSTATE_NETWORK_LOCKED);
-  testPersonalization(false, CARD_PERSOSUBSTATE_SIM_CORPORATE,
-                      GECKO_CARDSTATE_CORPORATE_LOCKED);
-  testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER,
-                      GECKO_CARDSTATE_SERVICE_PROVIDER_LOCKED);
-  testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK_PUK,
-                      GECKO_CARDSTATE_NETWORK_PUK_REQUIRED);
-  testPersonalization(false, CARD_PERSOSUBSTATE_SIM_CORPORATE_PUK,
-                      GECKO_CARDSTATE_CORPORATE_PUK_REQUIRED);
-  testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK,
-                      GECKO_CARDSTATE_SERVICE_PROVIDER_PUK_REQUIRED);
-  testPersonalization(false, CARD_PERSOSUBSTATE_READY,
-                      GECKO_CARDSTATE_PERSONALIZATION_READY);
-
-  // Test CDMA personalization state.
-  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK1,
-                      GECKO_CARDSTATE_NETWORK1_LOCKED);
-  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK2,
-                      GECKO_CARDSTATE_NETWORK2_LOCKED);
-  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_HRPD,
-                      GECKO_CARDSTATE_HRPD_NETWORK_LOCKED);
-  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_CORPORATE,
-                      GECKO_CARDSTATE_RUIM_CORPORATE_LOCKED);
-  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER,
-                      GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_LOCKED);
-  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_RUIM,
-                      GECKO_CARDSTATE_RUIM_LOCKED);
-  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK1_PUK,
-                      GECKO_CARDSTATE_NETWORK1_PUK_REQUIRED);
-  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK2_PUK,
-                      GECKO_CARDSTATE_NETWORK2_PUK_REQUIRED);
-  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_HRPD_PUK,
-                      GECKO_CARDSTATE_HRPD_NETWORK_PUK_REQUIRED);
-  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_CORPORATE_PUK,
-                      GECKO_CARDSTATE_RUIM_CORPORATE_PUK_REQUIRED);
-  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK,
-                      GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED);
-  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_RUIM_PUK,
-                      GECKO_CARDSTATE_RUIM_PUK_REQUIRED);
-
-  run_next_test();
-});
-
-/**
- * Verify SIM app_state in _processICCStatus
- */
-add_test(function test_card_app_state() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let ril = context.RIL;
-
-  context.ICCRecordHelper.readICCID = function fakeReadICCID() {};
-
-  function testCardAppState(cardAppState, geckoCardState) {
-    let iccStatus = {
-      cardState: CARD_STATE_PRESENT,
-      gsmUmtsSubscriptionAppIndex: 0,
-      apps: [
-      {
-        app_state: cardAppState
-      }],
-    };
-
-    ril._processICCStatus(iccStatus);
-    do_check_eq(ril.cardState, geckoCardState);
-  }
-
-  testCardAppState(CARD_APPSTATE_ILLEGAL,
-                   GECKO_CARDSTATE_ILLEGAL);
-  testCardAppState(CARD_APPSTATE_PIN,
-                   GECKO_CARDSTATE_PIN_REQUIRED);
-  testCardAppState(CARD_APPSTATE_PUK,
-                   GECKO_CARDSTATE_PUK_REQUIRED);
-  testCardAppState(CARD_APPSTATE_READY,
-                   GECKO_CARDSTATE_READY);
-  testCardAppState(CARD_APPSTATE_UNKNOWN,
-                   GECKO_CARDSTATE_UNKNOWN);
-  testCardAppState(CARD_APPSTATE_DETECTED,
-                   GECKO_CARDSTATE_UNKNOWN);
-
-  run_next_test();
-});
-
-/**
- * Verify permanent blocked for ICC.
- */
-add_test(function test_icc_permanent_blocked() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let ril = context.RIL;
-
-  context.ICCRecordHelper.readICCID = function fakeReadICCID() {};
-
-  function testPermanentBlocked(pin1_replaced, universalPINState, pin1) {
-    let iccStatus = {
-      cardState: CARD_STATE_PRESENT,
-      gsmUmtsSubscriptionAppIndex: 0,
-      universalPINState: universalPINState,
-      apps: [
-      {
-        pin1_replaced: pin1_replaced,
-        pin1: pin1
-      }]
-    };
-
-    ril._processICCStatus(iccStatus);
-    do_check_eq(ril.cardState, GECKO_CARDSTATE_PERMANENT_BLOCKED);
-  }
-
-  testPermanentBlocked(1,
-                       CARD_PINSTATE_ENABLED_PERM_BLOCKED,
-                       CARD_PINSTATE_UNKNOWN);
-  testPermanentBlocked(1,
-                       CARD_PINSTATE_ENABLED_PERM_BLOCKED,
-                       CARD_PINSTATE_ENABLED_PERM_BLOCKED);
-  testPermanentBlocked(0,
-                       CARD_PINSTATE_UNKNOWN,
-                       CARD_PINSTATE_ENABLED_PERM_BLOCKED);
-
-  run_next_test();
-});
-
-/**
- * Verify iccSetCardLock - Facility Lock.
- */
-add_test(function test_set_icc_card_lock_facility_lock() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let aid = "123456789";
-  let ril = context.RIL;
-  ril.aid = aid;
-  ril.v5Legacy = false;
-  let buf = context.Buf;
-
-  let GECKO_CARDLOCK_TO_FACILITIY_LOCK = {};
-  GECKO_CARDLOCK_TO_FACILITIY_LOCK[GECKO_CARDLOCK_PIN] = ICC_CB_FACILITY_SIM;
-  GECKO_CARDLOCK_TO_FACILITIY_LOCK[GECKO_CARDLOCK_FDN] = ICC_CB_FACILITY_FDN;
-
-  let GECKO_CARDLOCK_TO_PASSWORD_TYPE = {};
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_PIN] = "pin";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_FDN] = "pin2";
-
-  const pin = "1234";
-  const pin2 = "4321";
-  let GECKO_CARDLOCK_TO_PASSWORD = {};
-  GECKO_CARDLOCK_TO_PASSWORD[GECKO_CARDLOCK_PIN] = pin;
-  GECKO_CARDLOCK_TO_PASSWORD[GECKO_CARDLOCK_FDN] = pin2;
-
-  const serviceClass = ICC_SERVICE_CLASS_VOICE |
-                       ICC_SERVICE_CLASS_DATA  |
-                       ICC_SERVICE_CLASS_FAX;
-
-  function do_test(aLock, aPassword, aEnabled) {
-    buf.sendParcel = function fakeSendParcel () {
-      // Request Type.
-      do_check_eq(this.readInt32(), REQUEST_SET_FACILITY_LOCK);
-
-      // Token : we don't care
-      this.readInt32();
-
-      let parcel = this.readStringList();
-      do_check_eq(parcel.length, 5);
-      do_check_eq(parcel[0], GECKO_CARDLOCK_TO_FACILITIY_LOCK[aLock]);
-      do_check_eq(parcel[1], aEnabled ? "1" : "0");
-      do_check_eq(parcel[2], GECKO_CARDLOCK_TO_PASSWORD[aLock]);
-      do_check_eq(parcel[3], serviceClass.toString());
-      do_check_eq(parcel[4], aid);
-    };
-
-    let lock = {lockType: aLock,
-                enabled: aEnabled};
-    lock[GECKO_CARDLOCK_TO_PASSWORD_TYPE[aLock]] = aPassword;
-
-    ril.iccSetCardLock(lock);
-  }
-
-  do_test(GECKO_CARDLOCK_PIN, pin, true);
-  do_test(GECKO_CARDLOCK_PIN, pin, false);
-  do_test(GECKO_CARDLOCK_FDN, pin2, true);
-  do_test(GECKO_CARDLOCK_FDN, pin2, false);
-
-  run_next_test();
-});
-
-/**
- * Verify iccUnlockCardLock.
- */
-add_test(function test_unlock_card_lock_corporateLocked() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let ril = context.RIL;
-  let buf = context.Buf;
-  const pin = "12345678";
-  const puk = "12345678";
-
-  let GECKO_CARDLOCK_TO_PASSWORD_TYPE = {};
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK] = "pin";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK1] = "pin";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK2] = "pin";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_HNCK] = "pin";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_CCK] = "pin";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_SPCK] = "pin";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_RCCK] = "pin";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_RSPCK] = "pin";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK_PUK] = "puk";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK1_PUK] = "puk";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK2_PUK] = "puk";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_HNCK_PUK] = "puk";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_CCK_PUK] = "puk";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_SPCK_PUK] = "puk";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_RCCK_PUK] = "puk";
-  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_RSPCK_PUK] = "puk";
-
-  function do_test(aLock, aPassword) {
-    buf.sendParcel = function fakeSendParcel () {
-      // Request Type.
-      do_check_eq(this.readInt32(), REQUEST_ENTER_NETWORK_DEPERSONALIZATION_CODE);
-
-      // Token : we don't care
-      this.readInt32();
-
-      let lockType = GECKO_PERSO_LOCK_TO_CARD_PERSO_LOCK[aLock];
-      // Lock Type
-      do_check_eq(this.readInt32(), lockType);
-
-      // Pin/Puk.
-      do_check_eq(this.readString(), aPassword);
-    };
-
-    let lock = {lockType: aLock};
-    lock[GECKO_CARDLOCK_TO_PASSWORD_TYPE[aLock]] = aPassword;
-    ril.iccUnlockCardLock(lock);
-  }
-
-  do_test(GECKO_CARDLOCK_NCK, pin);
-  do_test(GECKO_CARDLOCK_NCK1, pin);
-  do_test(GECKO_CARDLOCK_NCK2, pin);
-  do_test(GECKO_CARDLOCK_HNCK, pin);
-  do_test(GECKO_CARDLOCK_CCK, pin);
-  do_test(GECKO_CARDLOCK_SPCK, pin);
-  do_test(GECKO_CARDLOCK_RCCK, pin);
-  do_test(GECKO_CARDLOCK_RSPCK, pin);
-  do_test(GECKO_CARDLOCK_NCK_PUK, puk);
-  do_test(GECKO_CARDLOCK_NCK1_PUK, puk);
-  do_test(GECKO_CARDLOCK_NCK2_PUK, puk);
-  do_test(GECKO_CARDLOCK_HNCK_PUK, puk);
-  do_test(GECKO_CARDLOCK_CCK_PUK, puk);
-  do_test(GECKO_CARDLOCK_SPCK_PUK, puk);
-  do_test(GECKO_CARDLOCK_RCCK_PUK, puk);
-  do_test(GECKO_CARDLOCK_RSPCK_PUK, puk);
-
-  run_next_test();
-});
-
-/**
- * Verify MCC and MNC parsing
- */
-add_test(function test_mcc_mnc_parsing() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.ICCUtilsHelper;
-
-  function do_test(imsi, mncLength, expectedMcc, expectedMnc) {
-    let result = helper.parseMccMncFromImsi(imsi, mncLength);
-
-    if (!imsi) {
-      do_check_eq(result, null);
-      return;
-    }
-
-    do_check_eq(result.mcc, expectedMcc);
-    do_check_eq(result.mnc, expectedMnc);
-  }
-
-  // Test the imsi is null.
-  do_test(null, null, null, null);
-
-  // Test MCC is Taiwan
-  do_test("466923202422409", 0x02, "466", "92");
-  do_test("466923202422409", 0x03, "466", "923");
-  do_test("466923202422409", null, "466", "92");
-
-  // Test MCC is US
-  do_test("310260542718417", 0x02, "310", "26");
-  do_test("310260542718417", 0x03, "310", "260");
-  do_test("310260542718417", null, "310", "260");
-
-  run_next_test();
- });
-
- /**
-  * Verify reading EF_AD and parsing MCC/MNC
-  */
-add_test(function test_reading_ad_and_parsing_mcc_mnc() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let record = context.SimRecordHelper;
-  let helper = context.GsmPDUHelper;
-  let ril    = context.RIL;
-  let buf    = context.Buf;
-  let io     = context.ICCIOHelper;
-
-  function do_test(mncLengthInEf, imsi, expectedMcc, expectedMnc) {
-    ril.iccInfoPrivate.imsi = imsi;
-
-    io.loadTransparentEF = function fakeLoadTransparentEF(options) {
-      let ad = [0x00, 0x00, 0x00];
-      if (typeof mncLengthInEf === 'number') {
-        ad.push(mncLengthInEf);
-      }
-
-      // Write data size
-      buf.writeInt32(ad.length * 2);
-
-      // Write data
-      for (let i = 0; i < ad.length; i++) {
-        helper.writeHexOctet(ad[i]);
-      }
-
-      // Write string delimiter
-      buf.writeStringDelimiter(ad.length * 2);
-
-      if (options.callback) {
-        options.callback(options);
-      }
-    };
-
-    record.readAD();
-
-    do_check_eq(ril.iccInfo.mcc, expectedMcc);
-    do_check_eq(ril.iccInfo.mnc, expectedMnc);
-  }
-
-  do_test(undefined, "466923202422409", "466", "92" );
-  do_test(0x00,      "466923202422409", "466", "92" );
-  do_test(0x01,      "466923202422409", "466", "92" );
-  do_test(0x02,      "466923202422409", "466", "92" );
-  do_test(0x03,      "466923202422409", "466", "923");
-  do_test(0x04,      "466923202422409", "466", "92" );
-  do_test(0xff,      "466923202422409", "466", "92" );
-
-  do_test(undefined, "310260542718417", "310", "260");
-  do_test(0x00,      "310260542718417", "310", "260");
-  do_test(0x01,      "310260542718417", "310", "260");
-  do_test(0x02,      "310260542718417", "310", "26" );
-  do_test(0x03,      "310260542718417", "310", "260");
-  do_test(0x04,      "310260542718417", "310", "260");
-  do_test(0xff,      "310260542718417", "310", "260");
-
-  run_next_test();
-});
-
-add_test(function test_reading_optional_efs() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let record = context.SimRecordHelper;
-  let gsmPdu = context.GsmPDUHelper;
-  let ril    = context.RIL;
-  let buf    = context.Buf;
-  let io     = context.ICCIOHelper;
-
-  function buildSST(supportedEf) {
-    let sst = [];
-    let len = supportedEf.length;
-    for (let i = 0; i < len; i++) {
-      let index, bitmask, iccService;
-      if (ril.appType === CARD_APPTYPE_SIM) {
-        iccService = GECKO_ICC_SERVICES.sim[supportedEf[i]];
-        iccService -= 1;
-        index = Math.floor(iccService / 4);
-        bitmask = 2 << ((iccService % 4) << 1);
-      } else if (ril.appType === CARD_APPTYPE_USIM){
-        iccService = GECKO_ICC_SERVICES.usim[supportedEf[i]];
-        iccService -= 1;
-        index = Math.floor(iccService / 8);
-        bitmask = 1 << ((iccService % 8) << 0);
-      }
-
-      if (sst) {
-        sst[index] |= bitmask;
-      }
-    }
-    return sst;
-  }
-
-  ril.updateCellBroadcastConfig = function fakeUpdateCellBroadcastConfig() {
-    // Ignore updateCellBroadcastConfig after reading SST
-  };
-
-  function do_test(sst, supportedEf) {
-    // Clone supportedEf to local array for testing
-    let testEf = supportedEf.slice(0);
-
-    record.readMSISDN = function fakeReadMSISDN() {
-      testEf.splice(testEf.indexOf("MSISDN"), 1);
-    };
-
-    record.readMBDN = function fakeReadMBDN() {
-      testEf.splice(testEf.indexOf("MDN"), 1);
-    };
-
-    record.readMWIS = function fakeReadMWIS() {
-      testEf.splice(testEf.indexOf("MWIS"), 1);
-    };
-
-    io.loadTransparentEF = function fakeLoadTransparentEF(options) {
-      // Write data size
-      buf.writeInt32(sst.length * 2);
-
-      // Write data
-      for (let i = 0; i < sst.length; i++) {
-         gsmPdu.writeHexOctet(sst[i] || 0);
-      }
-
-      // Write string delimiter
-      buf.writeStringDelimiter(sst.length * 2);
-
-      if (options.callback) {
-        options.callback(options);
-      }
-
-      if (testEf.length !== 0) {
-        do_print("Un-handled EF: " + JSON.stringify(testEf));
-        do_check_true(false);
-      }
-    };
-
-    record.readSST();
-  }
-
-  // TODO: Add all necessary optional EFs eventually
-  let supportedEf = ["MSISDN", "MDN", "MWIS"];
-  ril.appType = CARD_APPTYPE_SIM;
-  do_test(buildSST(supportedEf), supportedEf);
-  ril.appType = CARD_APPTYPE_USIM;
-  do_test(buildSST(supportedEf), supportedEf);
-
-  run_next_test();
-});
-
-/**
- * Verify fetchSimRecords.
- */
-add_test(function test_fetch_sim_recodes() {
-  let worker = newWorker();
-  let context = worker.ContextPool._contexts[0];
-  let RIL = context.RIL;
-  let iccRecord = context.ICCRecordHelper;
-  let simRecord = context.SimRecordHelper;
-
-  function testFetchSimRecordes(expectCalled) {
-    let ifCalled = [];
-
-    RIL.getIMSI = function() {
-      ifCalled.push("getIMSI");
-    };
-
-    simRecord.readAD = function() {
-      ifCalled.push("readAD");
-    };
-
-    simRecord.readSST = function() {
-      ifCalled.push("readSST");
-    };
-
-    simRecord.fetchSimRecords();
-
-    for (let i = 0; i < expectCalled.length; i++ ) {
-      if (ifCalled[i] != expectCalled[i]) {
-        do_print(expectCalled[i] + " is not called.");
-        do_check_true(false);
-      }
-    }
-  }
-
-  let expectCalled = ["getIMSI", "readAD", "readSST"];
-  testFetchSimRecordes(expectCalled);
-
-  run_next_test();
-});
-
-add_test(function test_fetch_icc_recodes() {
-  let worker = newWorker();
-  let context = worker.ContextPool._contexts[0];
-  let RIL = context.RIL;
-  let iccRecord = context.ICCRecordHelper;
-  let simRecord = context.SimRecordHelper;
-  let ruimRecord = context.RuimRecordHelper;
-  let fetchTag = 0x00;
-
-  simRecord.fetchSimRecords = function() {
-    fetchTag = 0x01;
-  };
-
-  ruimRecord.fetchRuimRecords = function() {
-    fetchTag = 0x02;
-  };
-
-  RIL.appType = CARD_APPTYPE_SIM;
-  iccRecord.fetchICCRecords();
-  do_check_eq(fetchTag, 0x01);
-
-  RIL.appType = CARD_APPTYPE_RUIM;
-  iccRecord.fetchICCRecords();
-  do_check_eq(fetchTag, 0x02);
-
-  RIL.appType = CARD_APPTYPE_USIM;
-  iccRecord.fetchICCRecords();
-  do_check_eq(fetchTag, 0x01);
-
-  run_next_test();
-});
-
-/**
- * Verify SimRecordHelper.readMWIS
- */
-add_test(function test_read_mwis() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let helper = context.GsmPDUHelper;
-  let recordHelper = context.SimRecordHelper;
-  let buf    = context.Buf;
-  let io     = context.ICCIOHelper;
-  let mwisData;
-  let postedMessage;
-
-  worker.postMessage = function fakePostMessage(message) {
-    postedMessage = message;
-  };
-
-  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) {
-    if (mwisData) {
-      // Write data size
-      buf.writeInt32(mwisData.length * 2);
-
-      // Write MWIS
-      for (let i = 0; i < mwisData.length; i++) {
-        helper.writeHexOctet(mwisData[i]);
-      }
-
-      // Write string delimiter
-      buf.writeStringDelimiter(mwisData.length * 2);
-
-      options.recordSize = mwisData.length;
-      if (options.callback) {
-        options.callback(options);
-      }
-    } else {
-      do_print("mwisData[] is not set.");
-    }
-  };
-
-  function buildMwisData(isActive, msgCount) {
-    if (msgCount < 0 || msgCount === GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN) {
-      msgCount = 0;
-    } else if (msgCount > 255) {
-      msgCount = 255;
-    }
-
-    mwisData =  [ (isActive) ? 0x01 : 0x00,
-                  msgCount,
-                  0xFF, 0xFF, 0xFF ];
-  }
-
-  function do_test(isActive, msgCount) {
-    buildMwisData(isActive, msgCount);
-    recordHelper.readMWIS();
-
-    do_check_eq("iccmwis", postedMessage.rilMessageType);
-    do_check_eq(isActive, postedMessage.mwi.active);
-    do_check_eq((isActive) ? msgCount : 0, postedMessage.mwi.msgCount);
-  }
-
-  do_test(true, GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN);
-  do_test(true, 1);
-  do_test(true, 255);
-
-  do_test(false, 0);
-  do_test(false, 255); // Test the corner case when mwi is disable with incorrect msgCount.
-
-  run_next_test();
-});
-
-/**
- * Verify SimRecordHelper.updateMWIS
- */
-add_test(function test_update_mwis() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let pduHelper = context.GsmPDUHelper;
-  let ril = context.RIL;
-  ril.appType = CARD_APPTYPE_USIM;
-  ril.iccInfoPrivate.mwis = [0x00, 0x00, 0x00, 0x00, 0x00];
-  let recordHelper = context.SimRecordHelper;
-  let buf = context.Buf;
-  let ioHelper = context.ICCIOHelper;
-  let recordSize = ril.iccInfoPrivate.mwis.length;
-  let recordNum = 1;
-
-  ioHelper.updateLinearFixedEF = function(options) {
-    options.pathId = context.ICCFileHelper.getEFPath(options.fileId);
-    options.command = ICC_COMMAND_UPDATE_RECORD;
-    options.p1 = options.recordNumber;
-    options.p2 = READ_RECORD_ABSOLUTE_MODE;
-    options.p3 = recordSize;
-    ril.iccIO(options);
-  };
-
-  function do_test(isActive, count) {
-    let mwis = ril.iccInfoPrivate.mwis;
-    let isUpdated = false;
-
-    function buildMwisData() {
-      let result = mwis.slice(0);
-      result[0] = isActive? (mwis[0] | 0x01) : (mwis[0] & 0xFE);
-      result[1] = (count === GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN) ? 0 : count;
-
-      return result;
-    }
-
-    buf.sendParcel = function() {
-      isUpdated = true;
-
-      // Request Type.
-      do_check_eq(this.readInt32(), REQUEST_SIM_IO);
-
-      // Token : we don't care
-      this.readInt32();
-
-      // command.
-      do_check_eq(this.readInt32(), ICC_COMMAND_UPDATE_RECORD);
-
-      // fileId.
-      do_check_eq(this.readInt32(), ICC_EF_MWIS);
-
-      // pathId.
-      do_check_eq(this.readString(),
-                  EF_PATH_MF_SIM + ((ril.appType === CARD_APPTYPE_USIM) ? EF_PATH_ADF_USIM : EF_PATH_DF_GSM));
-
-      // p1.
-      do_check_eq(this.readInt32(), recordNum);
-
-      // p2.
-      do_check_eq(this.readInt32(), READ_RECORD_ABSOLUTE_MODE);
-
-      // p3.
-      do_check_eq(this.readInt32(), recordSize);
-
-      // data.
-      let strLen = this.readInt32();
-      do_check_eq(recordSize * 2, strLen);
-      let expectedMwis = buildMwisData();
-      for (let i = 0; i < recordSize; i++) {
-        do_check_eq(expectedMwis[i], pduHelper.readHexOctet());
-      }
-      this.readStringDelimiter(strLen);
-
-      // pin2.
-      do_check_eq(this.readString(), null);
-
-      if (!ril.v5Legacy) {
-        // AID. Ignore because it's from modem.
-        this.readInt32();
-      }
-    };
-
-    do_check_false(isUpdated);
-
-    recordHelper.updateMWIS({ active: isActive,
-                              msgCount: count });
-
-    do_check_true((ril.iccInfoPrivate.mwis) ? isUpdated : !isUpdated);
-  }
-
-  do_test(true, GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN);
-  do_test(true, 1);
-  do_test(true, 255);
-
-  do_test(false, 0);
-
-  // Test if Path ID is correct for SIM.
-  ril.appType = CARD_APPTYPE_SIM;
-  do_test(false, 0);
-
-  // Test if loadLinearFixedEF() is not invoked in updateMWIS() when
-  // EF_MWIS is not loaded/available.
-  delete ril.iccInfoPrivate.mwis;
-  do_test(false, 0);
-
-  run_next_test();
-});
-
-/**
- * Verify the call flow of receiving Class 2 SMS stored in SIM:
- * 1. UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM.
- * 2. SimRecordHelper.readSMS().
- * 3. sendChromeMessage() with rilMessageType == "sms-received".
- */
-add_test(function test_read_new_sms_on_sim() {
-  // Instead of reusing newUint8Worker defined in this file,
-  // we define our own worker to fake the methods in WorkerBuffer dynamically.
-  function newSmsOnSimWorkerHelper() {
-    let _postedMessage;
-    let _worker = newWorker({
-      postRILMessage: function(data) {
-      },
-      postMessage: function(message) {
-        _postedMessage = message;
-      }
-    });
-
-    _worker.debug = do_print;
-
-    return {
-      get postedMessage() {
-        return _postedMessage;
-      },
-      get worker() {
-        return _worker;
-      },
-      fakeWokerBuffer: function() {
-        let context = _worker.ContextPool._contexts[0];
-        let index = 0; // index for read
-        let buf = [];
-        context.Buf.writeUint8 = function(value) {
-          buf.push(value);
-        };
-        context.Buf.readUint8 = function() {
-          return buf[index++];
-        };
-        context.Buf.seekIncoming = function(offset) {
-          index += offset;
-        };
-        context.Buf.getReadAvailable = function() {
-          return buf.length - index;
-        };
-      }
-    };
-  }
-
-  let workerHelper = newSmsOnSimWorkerHelper();
-  let worker = workerHelper.worker;
-  let context = worker.ContextPool._contexts[0];
-
-  context.ICCIOHelper.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) {
-      // SimStatus: Unread, SMSC:+0123456789, Sender: +9876543210, Text: How are you?
-      let SimSmsPduHex = "0306911032547698040A9189674523010000208062917314080CC8F71D14969741F977FD07"
-                       // In 4.2.25 EF_SMS Short Messages of 3GPP TS 31.102:
-                       // 1. Record length == 176 bytes.
-                       // 2. Any bytes in the record following the TPDU shall be filled with 'FF'.
-                       + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
-                       + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
-                       + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
-                       + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF";
-
-      workerHelper.fakeWokerBuffer();
-
-      context.Buf.writeString(SimSmsPduHex);
-
-      options.recordSize = 176; // Record length is fixed to 176 bytes.
-      if (options.callback) {
-        options.callback(options);
-      }
-  };
-
-  function newSmsOnSimParcel() {
-    let data = new Uint8Array(4 + 4); // Int32List with 1 element.
-    let offset = 0;
-
-    function writeInt(value) {
-      data[offset++] = value & 0xFF;
-      data[offset++] = (value >>  8) & 0xFF;
-      data[offset++] = (value >> 16) & 0xFF;
-      data[offset++] = (value >> 24) & 0xFF;
-    }
-
-    writeInt(1); // Length of Int32List
-    writeInt(1); // RecordNum = 1.
-
-    return newIncomingParcel(-1,
-                             RESPONSE_TYPE_UNSOLICITED,
-                             UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM,
-                             data);
-  }
-
-  function do_test() {
-    worker.onRILMessage(0, newSmsOnSimParcel());
-
-    let postedMessage = workerHelper.postedMessage;
-
-    do_check_eq("sms-received", postedMessage.rilMessageType);
-    do_check_eq("+0123456789", postedMessage.SMSC);
-    do_check_eq("+9876543210", postedMessage.sender);
-    do_check_eq("How are you?", postedMessage.body);
-  }
-
-  do_test();
-
-  run_next_test();
-});
-
-// Test ICC_COMMAND_GET_RESPONSE with FCP template format.
-/**
- * Verify transparent structure with FCP template format.
- */
-add_test(function test_fcp_template_for_transparent_structure() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let pduHelper = context.GsmPDUHelper;
-  let berHelper = context.BerTlvHelper;
-
-  let tag_test = [
-    0x62,
-    0x22,
-    0x82, 0x02, 0x41, 0x21,
-    0x83, 0x02, 0x2F, 0xE2,
-    0xA5, 0x09, 0xC1, 0x04, 0x40, 0x0F, 0xF5, 0x55, 0x92, 0x01, 0x00,
-    0x8A, 0x01, 0x05,
-    0x8B, 0x03, 0x2F, 0x06, 0x0B,
-    0x80, 0x02, 0x00, 0x0A,
-    0x88, 0x01, 0x10];
-
-  for (let i = 0; i < tag_test.length; i++) {
-    pduHelper.writeHexOctet(tag_test[i]);
-  }
-
-  let berTlv = berHelper.decode(tag_test.length);
-  let iter = Iterator(berTlv.value);
-  let tlv = berHelper.searchForNextTag(BER_FCP_FILE_DESCRIPTOR_TAG, iter);
-  do_check_eq(tlv.value.fileStructure, UICC_EF_STRUCTURE[EF_TYPE_TRANSPARENT]);
-
-  tlv = berHelper.searchForNextTag(BER_FCP_FILE_IDENTIFIER_TAG, iter);
-  do_check_eq(tlv.value.fileId, 0x2FE2);
-
-  tlv = berHelper.searchForNextTag(BER_FCP_FILE_SIZE_DATA_TAG, iter);
-  do_check_eq(tlv.value.fileSizeData, 0x0A);
-
-  run_next_test();
-});
-
-/**
- * Verify linear fixed structure with FCP template format.
- */
-add_test(function test_fcp_template_for_linear_fixed_structure() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let pduHelper = context.GsmPDUHelper;
-  let berHelper = context.BerTlvHelper;
-
-  let tag_test = [
-    0x62,
-    0x1E,
-    0x82, 0x05, 0x42, 0x21, 0x00, 0x1A, 0x01,
-    0x83, 0x02, 0x6F, 0x40,
-    0xA5, 0x03, 0x92, 0x01, 0x00,
-    0x8A, 0x01, 0x07,
-    0x8B, 0x03, 0x6F, 0x06, 0x02,
-    0x80, 0x02, 0x00, 0x1A,
-    0x88, 0x00];
-
-  for (let i = 0; i < tag_test.length; i++) {
-    pduHelper.writeHexOctet(tag_test[i]);
-  }
-
-  let berTlv = berHelper.decode(tag_test.length);
-  let iter = Iterator(berTlv.value);
-  let tlv = berHelper.searchForNextTag(BER_FCP_FILE_DESCRIPTOR_TAG, iter);
-  do_check_eq(tlv.value.fileStructure, UICC_EF_STRUCTURE[EF_TYPE_LINEAR_FIXED]);
-  do_check_eq(tlv.value.recordLength, 0x1A);
-  do_check_eq(tlv.value.numOfRecords, 0x01);
-
-  tlv = berHelper.searchForNextTag(BER_FCP_FILE_IDENTIFIER_TAG, iter);
-  do_check_eq(tlv.value.fileId, 0x6F40);
-
-  tlv = berHelper.searchForNextTag(BER_FCP_FILE_SIZE_DATA_TAG, iter);
-  do_check_eq(tlv.value.fileSizeData, 0x1A);
-
-  run_next_test();
-});
-
-add_test(function test_icc_io_get_response_for_transparent_structure() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let buf = context.Buf;
-  let iccioHelper = context.ICCIOHelper;
-  let pduHelper = context.GsmPDUHelper;
-
-  let responseArray = [
-    // SIM response.
-    [0x00, 0x00, 0x00, 0x0A, 0x2F, 0xE2, 0x04, 0x00, 0x0A, 0xA0, 0xAA, 0x00,
-     0x02, 0x00, 0x00],
-    // USIM response.
-    [0x62, 0x22, 0x82, 0x02, 0x41, 0x21, 0x83, 0x02, 0x2F, 0xE2, 0xA5, 0x09,
-     0xC1, 0x04, 0x40, 0x0F, 0xF5, 0x55, 0x92, 0x01, 0x00, 0x8A, 0x01, 0x05,
-     0x8B, 0x03, 0x2F, 0x06, 0x0B, 0x80, 0x02, 0x00, 0x0A, 0x88, 0x01, 0x10]
-  ];
-
-  for (let i = 0; i < responseArray.length; i++) {
-    let strLen = responseArray[i].length * 2;
-    buf.writeInt32(strLen);
-    for (let j = 0; j < responseArray[i].length; j++) {
-      pduHelper.writeHexOctet(responseArray[i][j]);
-    }
-    buf.writeStringDelimiter(strLen);
-
-    let options = {fileId: ICC_EF_ICCID,
-                   type: EF_TYPE_TRANSPARENT};
-    iccioHelper.processICCIOGetResponse(options);
-
-    do_check_eq(options.fileSize, 0x0A);
-  }
-
-  run_next_test();
-});
-
-add_test(function test_icc_io_get_response_for_linear_fixed_structure() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let buf = context.Buf;
-  let iccioHelper = context.ICCIOHelper;
-  let pduHelper = context.GsmPDUHelper;
-
-  let responseArray = [
-    // SIM response.
-    [0x00, 0x00, 0x00, 0x1A, 0x6F, 0x40, 0x04, 0x00, 0x11, 0xA0, 0xAA, 0x00,
-     0x02, 0x01, 0x1A],
-    // USIM response.
-    [0x62, 0x1E, 0x82, 0x05, 0x42, 0x21, 0x00, 0x1A, 0x01, 0x83, 0x02, 0x6F,
-     0x40, 0xA5, 0x03, 0x92, 0x01, 0x00, 0x8A, 0x01, 0x07, 0x8B, 0x03, 0x6F,
-     0x06, 0x02, 0x80, 0x02, 0x00, 0x1A, 0x88, 0x00]
-  ];
-
-  for (let i = 0; i < responseArray.length; i++) {
-    let strLen = responseArray[i].length * 2;
-    buf.writeInt32(strLen);
-    for (let j = 0; j < responseArray[i].length; j++) {
-      pduHelper.writeHexOctet(responseArray[i][j]);
-    }
-    buf.writeStringDelimiter(strLen);
-
-    let options = {fileId: ICC_EF_MSISDN,
-                   type: EF_TYPE_LINEAR_FIXED};
-    iccioHelper.processICCIOGetResponse(options);
-
-    do_check_eq(options.fileSize, 0x1A);
-    do_check_eq(options.recordSize, 0x1A);
-    do_check_eq(options.totalRecords, 0x01);
-  }
-
-  run_next_test();
-});
-
-/**
- * Verify reading EF_ICCID.
- */
-add_test(function test_handling_iccid() {
-  let worker = newUint8Worker();
-  let context = worker.ContextPool._contexts[0];
-  let record = context.ICCRecordHelper;
-  let helper = context.GsmPDUHelper;
-  let ril = context.RIL;
-  let buf = context.Buf;
-  let io = context.ICCIOHelper;
-
-  ril.reportStkServiceIsRunning = function fakeReportStkServiceIsRunning() {
-  };
-
-  function do_test(rawICCID, expectedICCID) {
-    io.loadTransparentEF = function fakeLoadTransparentEF(options) {
-      // Write data size
-      buf.writeInt32(rawICCID.length);
-
-      // Write data
-      for (let i = 0; i < rawICCID.length; i += 2) {
-        helper.writeHexOctet(parseInt(rawICCID.substr(i, 2), 16));
-      }
-
-      // Write string delimiter
-      buf.writeStringDelimiter(rawICCID.length);
-
-      if (options.callback) {
-        options.callback(options);
-      }
-    };
-
-    record.readICCID();
-
-    do_check_eq(ril.iccInfo.iccid, expectedICCID);
-  }
-
-  // Invalid char at high nibbile + low nibbile contains 0xF.
-  do_test("9868002E90909F001519", "89860020909");
-  // Invalid char at low nibbile.
-  do_test("986800E2909090001519", "8986002090909005191");
-  // Valid ICCID.
-  do_test("98101430121181157002", "89014103211118510720");
-
-  run_next_test();
-});
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_icc_BerTlvHelper.js
@@ -0,0 +1,87 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+function run_test() {
+  run_next_test();
+}
+
+// Test ICC_COMMAND_GET_RESPONSE with FCP template format.
+/**
+ * Verify transparent structure with FCP template format.
+ */
+add_test(function test_fcp_template_for_transparent_structure() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let pduHelper = context.GsmPDUHelper;
+  let berHelper = context.BerTlvHelper;
+
+  let tag_test = [
+    0x62,
+    0x22,
+    0x82, 0x02, 0x41, 0x21,
+    0x83, 0x02, 0x2F, 0xE2,
+    0xA5, 0x09, 0xC1, 0x04, 0x40, 0x0F, 0xF5, 0x55, 0x92, 0x01, 0x00,
+    0x8A, 0x01, 0x05,
+    0x8B, 0x03, 0x2F, 0x06, 0x0B,
+    0x80, 0x02, 0x00, 0x0A,
+    0x88, 0x01, 0x10];
+
+  for (let i = 0; i < tag_test.length; i++) {
+    pduHelper.writeHexOctet(tag_test[i]);
+  }
+
+  let berTlv = berHelper.decode(tag_test.length);
+  let iter = Iterator(berTlv.value);
+  let tlv = berHelper.searchForNextTag(BER_FCP_FILE_DESCRIPTOR_TAG, iter);
+  do_check_eq(tlv.value.fileStructure, UICC_EF_STRUCTURE[EF_TYPE_TRANSPARENT]);
+
+  tlv = berHelper.searchForNextTag(BER_FCP_FILE_IDENTIFIER_TAG, iter);
+  do_check_eq(tlv.value.fileId, 0x2FE2);
+
+  tlv = berHelper.searchForNextTag(BER_FCP_FILE_SIZE_DATA_TAG, iter);
+  do_check_eq(tlv.value.fileSizeData, 0x0A);
+
+  run_next_test();
+});
+
+/**
+ * Verify linear fixed structure with FCP template format.
+ */
+add_test(function test_fcp_template_for_linear_fixed_structure() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let pduHelper = context.GsmPDUHelper;
+  let berHelper = context.BerTlvHelper;
+
+  let tag_test = [
+    0x62,
+    0x1E,
+    0x82, 0x05, 0x42, 0x21, 0x00, 0x1A, 0x01,
+    0x83, 0x02, 0x6F, 0x40,
+    0xA5, 0x03, 0x92, 0x01, 0x00,
+    0x8A, 0x01, 0x07,
+    0x8B, 0x03, 0x6F, 0x06, 0x02,
+    0x80, 0x02, 0x00, 0x1A,
+    0x88, 0x00];
+
+  for (let i = 0; i < tag_test.length; i++) {
+    pduHelper.writeHexOctet(tag_test[i]);
+  }
+
+  let berTlv = berHelper.decode(tag_test.length);
+  let iter = Iterator(berTlv.value);
+  let tlv = berHelper.searchForNextTag(BER_FCP_FILE_DESCRIPTOR_TAG, iter);
+  do_check_eq(tlv.value.fileStructure, UICC_EF_STRUCTURE[EF_TYPE_LINEAR_FIXED]);
+  do_check_eq(tlv.value.recordLength, 0x1A);
+  do_check_eq(tlv.value.numOfRecords, 0x01);
+
+  tlv = berHelper.searchForNextTag(BER_FCP_FILE_IDENTIFIER_TAG, iter);
+  do_check_eq(tlv.value.fileId, 0x6F40);
+
+  tlv = berHelper.searchForNextTag(BER_FCP_FILE_SIZE_DATA_TAG, iter);
+  do_check_eq(tlv.value.fileSizeData, 0x1A);
+
+  run_next_test();
+});
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_icc_CardLock.js
@@ -0,0 +1,357 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+function run_test() {
+  run_next_test();
+}
+
+/**
+ * Verify RIL.iccGetCardLockState("fdn")
+ */
+add_test(function test_icc_get_card_lock_state_fdn() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ril = context.RIL;
+  let buf = context.Buf;
+
+  buf.sendParcel = function() {
+    // Request Type.
+    do_check_eq(this.readInt32(), REQUEST_QUERY_FACILITY_LOCK)
+
+    // Token : we don't care.
+    this.readInt32();
+
+    // String Array Length.
+    do_check_eq(this.readInt32(), ril.v5Legacy ? 3 : 4);
+
+    // Facility.
+    do_check_eq(this.readString(), ICC_CB_FACILITY_FDN);
+
+    // Password.
+    do_check_eq(this.readString(), "");
+
+    // Service class.
+    do_check_eq(this.readString(), (ICC_SERVICE_CLASS_VOICE |
+                                    ICC_SERVICE_CLASS_DATA  |
+                                    ICC_SERVICE_CLASS_FAX).toString());
+
+    if (!ril.v5Legacy) {
+      // AID. Ignore because it's from modem.
+      this.readInt32();
+    }
+
+    run_next_test();
+  };
+
+  ril.iccGetCardLockState({lockType: "fdn"});
+});
+
+add_test(function test_path_id_for_spid_and_spn() {
+  let worker = newWorker({
+    postRILMessage: function(data) {
+      // Do nothing
+    },
+    postMessage: function(message) {
+      // Do nothing
+    }});
+  let context = worker.ContextPool._contexts[0];
+  let RIL = context.RIL;
+  let ICCFileHelper = context.ICCFileHelper;
+
+  // Test SIM
+  RIL.appType = CARD_APPTYPE_SIM;
+  do_check_eq(ICCFileHelper.getEFPath(ICC_EF_SPDI),
+              EF_PATH_MF_SIM + EF_PATH_DF_GSM);
+  do_check_eq(ICCFileHelper.getEFPath(ICC_EF_SPN),
+              EF_PATH_MF_SIM + EF_PATH_DF_GSM);
+
+  // Test USIM
+  RIL.appType = CARD_APPTYPE_USIM;
+  do_check_eq(ICCFileHelper.getEFPath(ICC_EF_SPDI),
+              EF_PATH_MF_SIM + EF_PATH_ADF_USIM);
+  do_check_eq(ICCFileHelper.getEFPath(ICC_EF_SPDI),
+              EF_PATH_MF_SIM + EF_PATH_ADF_USIM);
+  run_next_test();
+});
+
+add_test(function test_personalization_state() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ril = context.RIL;
+
+  context.ICCRecordHelper.readICCID = function fakeReadICCID() {};
+
+  function testPersonalization(isCdma, cardPersoState, geckoCardState) {
+    let iccStatus = {
+      cardState: CARD_STATE_PRESENT,
+      gsmUmtsSubscriptionAppIndex: (!isCdma) ? 0 : -1,
+      cdmaSubscriptionAppIndex: (isCdma) ? 0 : -1,
+      apps: [
+        {
+          app_state: CARD_APPSTATE_SUBSCRIPTION_PERSO,
+          perso_substate: cardPersoState
+        }],
+    };
+
+    ril._isCdma = isCdma;
+    ril._processICCStatus(iccStatus);
+    do_check_eq(ril.cardState, geckoCardState);
+  }
+
+  // Test GSM personalization state.
+  testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK,
+                      GECKO_CARDSTATE_NETWORK_LOCKED);
+  testPersonalization(false, CARD_PERSOSUBSTATE_SIM_CORPORATE,
+                      GECKO_CARDSTATE_CORPORATE_LOCKED);
+  testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER,
+                      GECKO_CARDSTATE_SERVICE_PROVIDER_LOCKED);
+  testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK_PUK,
+                      GECKO_CARDSTATE_NETWORK_PUK_REQUIRED);
+  testPersonalization(false, CARD_PERSOSUBSTATE_SIM_CORPORATE_PUK,
+                      GECKO_CARDSTATE_CORPORATE_PUK_REQUIRED);
+  testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK,
+                      GECKO_CARDSTATE_SERVICE_PROVIDER_PUK_REQUIRED);
+  testPersonalization(false, CARD_PERSOSUBSTATE_READY,
+                      GECKO_CARDSTATE_PERSONALIZATION_READY);
+
+  // Test CDMA personalization state.
+  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK1,
+                      GECKO_CARDSTATE_NETWORK1_LOCKED);
+  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK2,
+                      GECKO_CARDSTATE_NETWORK2_LOCKED);
+  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_HRPD,
+                      GECKO_CARDSTATE_HRPD_NETWORK_LOCKED);
+  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_CORPORATE,
+                      GECKO_CARDSTATE_RUIM_CORPORATE_LOCKED);
+  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER,
+                      GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_LOCKED);
+  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_RUIM,
+                      GECKO_CARDSTATE_RUIM_LOCKED);
+  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK1_PUK,
+                      GECKO_CARDSTATE_NETWORK1_PUK_REQUIRED);
+  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK2_PUK,
+                      GECKO_CARDSTATE_NETWORK2_PUK_REQUIRED);
+  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_HRPD_PUK,
+                      GECKO_CARDSTATE_HRPD_NETWORK_PUK_REQUIRED);
+  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_CORPORATE_PUK,
+                      GECKO_CARDSTATE_RUIM_CORPORATE_PUK_REQUIRED);
+  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK,
+                      GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED);
+  testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_RUIM_PUK,
+                      GECKO_CARDSTATE_RUIM_PUK_REQUIRED);
+
+  run_next_test();
+});
+
+/**
+ * Verify SIM app_state in _processICCStatus
+ */
+add_test(function test_card_app_state() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ril = context.RIL;
+
+  context.ICCRecordHelper.readICCID = function fakeReadICCID() {};
+
+  function testCardAppState(cardAppState, geckoCardState) {
+    let iccStatus = {
+      cardState: CARD_STATE_PRESENT,
+      gsmUmtsSubscriptionAppIndex: 0,
+      apps: [
+      {
+        app_state: cardAppState
+      }],
+    };
+
+    ril._processICCStatus(iccStatus);
+    do_check_eq(ril.cardState, geckoCardState);
+  }
+
+  testCardAppState(CARD_APPSTATE_ILLEGAL,
+                   GECKO_CARDSTATE_ILLEGAL);
+  testCardAppState(CARD_APPSTATE_PIN,
+                   GECKO_CARDSTATE_PIN_REQUIRED);
+  testCardAppState(CARD_APPSTATE_PUK,
+                   GECKO_CARDSTATE_PUK_REQUIRED);
+  testCardAppState(CARD_APPSTATE_READY,
+                   GECKO_CARDSTATE_READY);
+  testCardAppState(CARD_APPSTATE_UNKNOWN,
+                   GECKO_CARDSTATE_UNKNOWN);
+  testCardAppState(CARD_APPSTATE_DETECTED,
+                   GECKO_CARDSTATE_UNKNOWN);
+
+  run_next_test();
+});
+
+/**
+ * Verify permanent blocked for ICC.
+ */
+add_test(function test_icc_permanent_blocked() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ril = context.RIL;
+
+  context.ICCRecordHelper.readICCID = function fakeReadICCID() {};
+
+  function testPermanentBlocked(pin1_replaced, universalPINState, pin1) {
+    let iccStatus = {
+      cardState: CARD_STATE_PRESENT,
+      gsmUmtsSubscriptionAppIndex: 0,
+      universalPINState: universalPINState,
+      apps: [
+      {
+        pin1_replaced: pin1_replaced,
+        pin1: pin1
+      }]
+    };
+
+    ril._processICCStatus(iccStatus);
+    do_check_eq(ril.cardState, GECKO_CARDSTATE_PERMANENT_BLOCKED);
+  }
+
+  testPermanentBlocked(1,
+                       CARD_PINSTATE_ENABLED_PERM_BLOCKED,
+                       CARD_PINSTATE_UNKNOWN);
+  testPermanentBlocked(1,
+                       CARD_PINSTATE_ENABLED_PERM_BLOCKED,
+                       CARD_PINSTATE_ENABLED_PERM_BLOCKED);
+  testPermanentBlocked(0,
+                       CARD_PINSTATE_UNKNOWN,
+                       CARD_PINSTATE_ENABLED_PERM_BLOCKED);
+
+  run_next_test();
+});
+
+/**
+ * Verify iccSetCardLock - Facility Lock.
+ */
+add_test(function test_set_icc_card_lock_facility_lock() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let aid = "123456789";
+  let ril = context.RIL;
+  ril.aid = aid;
+  ril.v5Legacy = false;
+  let buf = context.Buf;
+
+  let GECKO_CARDLOCK_TO_FACILITIY_LOCK = {};
+  GECKO_CARDLOCK_TO_FACILITIY_LOCK[GECKO_CARDLOCK_PIN] = ICC_CB_FACILITY_SIM;
+  GECKO_CARDLOCK_TO_FACILITIY_LOCK[GECKO_CARDLOCK_FDN] = ICC_CB_FACILITY_FDN;
+
+  let GECKO_CARDLOCK_TO_PASSWORD_TYPE = {};
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_PIN] = "pin";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_FDN] = "pin2";
+
+  const pin = "1234";
+  const pin2 = "4321";
+  let GECKO_CARDLOCK_TO_PASSWORD = {};
+  GECKO_CARDLOCK_TO_PASSWORD[GECKO_CARDLOCK_PIN] = pin;
+  GECKO_CARDLOCK_TO_PASSWORD[GECKO_CARDLOCK_FDN] = pin2;
+
+  const serviceClass = ICC_SERVICE_CLASS_VOICE |
+                       ICC_SERVICE_CLASS_DATA  |
+                       ICC_SERVICE_CLASS_FAX;
+
+  function do_test(aLock, aPassword, aEnabled) {
+    buf.sendParcel = function fakeSendParcel () {
+      // Request Type.
+      do_check_eq(this.readInt32(), REQUEST_SET_FACILITY_LOCK);
+
+      // Token : we don't care
+      this.readInt32();
+
+      let parcel = this.readStringList();
+      do_check_eq(parcel.length, 5);
+      do_check_eq(parcel[0], GECKO_CARDLOCK_TO_FACILITIY_LOCK[aLock]);
+      do_check_eq(parcel[1], aEnabled ? "1" : "0");
+      do_check_eq(parcel[2], GECKO_CARDLOCK_TO_PASSWORD[aLock]);
+      do_check_eq(parcel[3], serviceClass.toString());
+      do_check_eq(parcel[4], aid);
+    };
+
+    let lock = {lockType: aLock,
+                enabled: aEnabled};
+    lock[GECKO_CARDLOCK_TO_PASSWORD_TYPE[aLock]] = aPassword;
+
+    ril.iccSetCardLock(lock);
+  }
+
+  do_test(GECKO_CARDLOCK_PIN, pin, true);
+  do_test(GECKO_CARDLOCK_PIN, pin, false);
+  do_test(GECKO_CARDLOCK_FDN, pin2, true);
+  do_test(GECKO_CARDLOCK_FDN, pin2, false);
+
+  run_next_test();
+});
+
+/**
+ * Verify iccUnlockCardLock.
+ */
+add_test(function test_unlock_card_lock_corporateLocked() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ril = context.RIL;
+  let buf = context.Buf;
+  const pin = "12345678";
+  const puk = "12345678";
+
+  let GECKO_CARDLOCK_TO_PASSWORD_TYPE = {};
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK] = "pin";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK1] = "pin";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK2] = "pin";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_HNCK] = "pin";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_CCK] = "pin";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_SPCK] = "pin";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_RCCK] = "pin";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_RSPCK] = "pin";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK_PUK] = "puk";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK1_PUK] = "puk";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK2_PUK] = "puk";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_HNCK_PUK] = "puk";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_CCK_PUK] = "puk";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_SPCK_PUK] = "puk";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_RCCK_PUK] = "puk";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_RSPCK_PUK] = "puk";
+
+  function do_test(aLock, aPassword) {
+    buf.sendParcel = function fakeSendParcel () {
+      // Request Type.
+      do_check_eq(this.readInt32(), REQUEST_ENTER_NETWORK_DEPERSONALIZATION_CODE);
+
+      // Token : we don't care
+      this.readInt32();
+
+      let lockType = GECKO_PERSO_LOCK_TO_CARD_PERSO_LOCK[aLock];
+      // Lock Type
+      do_check_eq(this.readInt32(), lockType);
+
+      // Pin/Puk.
+      do_check_eq(this.readString(), aPassword);
+    };
+
+    let lock = {lockType: aLock};
+    lock[GECKO_CARDLOCK_TO_PASSWORD_TYPE[aLock]] = aPassword;
+    ril.iccUnlockCardLock(lock);
+  }
+
+  do_test(GECKO_CARDLOCK_NCK, pin);
+  do_test(GECKO_CARDLOCK_NCK1, pin);
+  do_test(GECKO_CARDLOCK_NCK2, pin);
+  do_test(GECKO_CARDLOCK_HNCK, pin);
+  do_test(GECKO_CARDLOCK_CCK, pin);
+  do_test(GECKO_CARDLOCK_SPCK, pin);
+  do_test(GECKO_CARDLOCK_RCCK, pin);
+  do_test(GECKO_CARDLOCK_RSPCK, pin);
+  do_test(GECKO_CARDLOCK_NCK_PUK, puk);
+  do_test(GECKO_CARDLOCK_NCK1_PUK, puk);
+  do_test(GECKO_CARDLOCK_NCK2_PUK, puk);
+  do_test(GECKO_CARDLOCK_HNCK_PUK, puk);
+  do_test(GECKO_CARDLOCK_CCK_PUK, puk);
+  do_test(GECKO_CARDLOCK_SPCK_PUK, puk);
+  do_test(GECKO_CARDLOCK_RCCK_PUK, puk);
+  do_test(GECKO_CARDLOCK_RSPCK_PUK, puk);
+
+  run_next_test();
+});
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_icc_GsmPDUHelper.js
@@ -0,0 +1,79 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+function run_test() {
+  run_next_test();
+}
+
+/**
+ * Verify GsmPDUHelper.writeTimestamp
+ */
+add_test(function test_write_timestamp() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+
+  // current date
+  let dateInput = new Date();
+  let dateOutput = new Date();
+  helper.writeTimestamp(dateInput);
+  dateOutput.setTime(helper.readTimestamp());
+
+  do_check_eq(dateInput.getFullYear(), dateOutput.getFullYear());
+  do_check_eq(dateInput.getMonth(), dateOutput.getMonth());
+  do_check_eq(dateInput.getDate(), dateOutput.getDate());
+  do_check_eq(dateInput.getHours(), dateOutput.getHours());
+  do_check_eq(dateInput.getMinutes(), dateOutput.getMinutes());
+  do_check_eq(dateInput.getSeconds(), dateOutput.getSeconds());
+  do_check_eq(dateInput.getTimezoneOffset(), dateOutput.getTimezoneOffset());
+
+  // 2034-01-23 12:34:56 -0800 GMT
+  let time = Date.UTC(2034, 1, 23, 12, 34, 56);
+  time = time - (8 * 60 * 60 * 1000);
+  dateInput.setTime(time);
+  helper.writeTimestamp(dateInput);
+  dateOutput.setTime(helper.readTimestamp());
+
+  do_check_eq(dateInput.getFullYear(), dateOutput.getFullYear());
+  do_check_eq(dateInput.getMonth(), dateOutput.getMonth());
+  do_check_eq(dateInput.getDate(), dateOutput.getDate());
+  do_check_eq(dateInput.getHours(), dateOutput.getHours());
+  do_check_eq(dateInput.getMinutes(), dateOutput.getMinutes());
+  do_check_eq(dateInput.getSeconds(), dateOutput.getSeconds());
+  do_check_eq(dateInput.getTimezoneOffset(), dateOutput.getTimezoneOffset());
+
+  run_next_test();
+});
+
+/**
+ * Verify GsmPDUHelper.octectToBCD and GsmPDUHelper.BCDToOctet
+ */
+add_test(function test_octect_BCD() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+
+  // 23
+  let number = 23;
+  let octet = helper.BCDToOctet(number);
+  do_check_eq(helper.octetToBCD(octet), number);
+
+  // 56
+  number = 56;
+  octet = helper.BCDToOctet(number);
+  do_check_eq(helper.octetToBCD(octet), number);
+
+  // 0x23
+  octet = 0x23;
+  number = helper.octetToBCD(octet);
+  do_check_eq(helper.BCDToOctet(number), octet);
+
+  // 0x56
+  octet = 0x56;
+  number = helper.octetToBCD(octet);
+  do_check_eq(helper.BCDToOctet(number), octet);
+
+  run_next_test();
+});
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_icc_ICCContactHelper.js
@@ -0,0 +1,590 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+function run_test() {
+  run_next_test();
+}
+
+/**
+ * Test error message returned in onerror for readICCContacts.
+ */
+add_test(function test_error_message_read_icc_contact () {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ril = context.RIL;
+
+  function do_test(options, expectedErrorMsg) {
+    ril.sendChromeMessage = function(message) {
+      do_check_eq(message.errorMsg, expectedErrorMsg);
+    }
+    ril.readICCContacts(options);
+  }
+
+  // Error 1, didn't specify correct contactType.
+  do_test({}, CONTACT_ERR_REQUEST_NOT_SUPPORTED);
+
+  // Error 2, specifying a non-supported contactType.
+  ril.appType = CARD_APPTYPE_USIM;
+  do_test({contactType: "sdn"}, CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED);
+
+  // Error 3, suppose we update the supported PBR fields in USIM_PBR_FIELDS,
+  // but forget to add implemenetations for it.
+  USIM_PBR_FIELDS.push("pbc");
+  do_test({contactType: "adn"}, CONTACT_ERR_FIELD_NOT_SUPPORTED);
+
+  run_next_test();
+});
+
+/**
+ * Test error message returned in onerror for updateICCContact.
+ */
+add_test(function test_error_message_update_icc_contact() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ril = context.RIL;
+
+  const ICCID = "123456789";
+  ril.iccInfo.iccid = ICCID;
+
+  function do_test(options, expectedErrorMsg) {
+    ril.sendChromeMessage = function(message) {
+      do_check_eq(message.errorMsg, expectedErrorMsg);
+    }
+    ril.updateICCContact(options);
+  }
+
+  // Error 1, didn't specify correct contactType.
+  do_test({}, CONTACT_ERR_REQUEST_NOT_SUPPORTED);
+
+  // Error 2, specifying a correct contactType, but without providing 'contact'.
+  do_test({contactType: "adn"}, CONTACT_ERR_REQUEST_NOT_SUPPORTED);
+
+  // Error 3, specifying a non-supported contactType.
+  ril.appType = CARD_APPTYPE_USIM;
+  do_test({contactType: "sdn", contact: {}}, CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED);
+
+  // Error 4, without supplying pin2.
+  do_test({contactType: "fdn", contact: {contactId: ICCID + "1"}}, GECKO_ERROR_SIM_PIN2);
+
+  // Error 5, No free record found in EF_ADN.
+  let record = context.ICCRecordHelper;
+  record.readPBR = function(onsuccess, onerror) {
+    onsuccess([{adn: {fileId: 0x4f3a}}]);
+  };
+
+  let io = context.ICCIOHelper;
+  io.loadLinearFixedEF = function(options) {
+    options.totalRecords = 1;
+    options.p1 = 1;
+    options.callback(options);
+  };
+
+  do_test({contactType: "adn", contact: {}}, CONTACT_ERR_NO_FREE_RECORD_FOUND);
+
+  // Error 6, ICC IO Error.
+  io.loadLinearFixedEF = function(options) {
+    ril[REQUEST_SIM_IO](0, {rilRequestError: ERROR_GENERIC_FAILURE});
+  };
+  do_test({contactType: "adn", contact: {contactId: ICCID + "1"}},
+          GECKO_ERROR_GENERIC_FAILURE);
+
+  // Error 7, suppose we update the supported PBR fields in USIM_PBR_FIELDS,
+  // but forget to add implemenetations for it.
+  USIM_PBR_FIELDS.push("pbc");
+  do_test({contactType: "adn", contact: {contactId: ICCID + "1"}},
+          CONTACT_ERR_FIELD_NOT_SUPPORTED);
+
+  // Error 8, EF_PBR doesn't exist.
+  record.readPBR = function(onsuccess, onerror) {
+    onsuccess([]);
+  };
+
+  do_test({contactType: "adn", contact: {contactId: ICCID + "1"}},
+          CONTACT_ERR_CANNOT_ACCESS_PHONEBOOK);
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCContactHelper.readICCContacts
+ */
+add_test(function test_read_icc_contacts() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let record = context.ICCRecordHelper;
+  let contactHelper = context.ICCContactHelper;
+  let ril = context.RIL;
+
+  function do_test(aSimType, aContactType, aExpectedContact, aEnhancedPhoneBook) {
+    ril.appType = aSimType;
+    ril._isCdma = (aSimType === CARD_APPTYPE_RUIM);
+    ril.iccInfoPrivate.cst = (aEnhancedPhoneBook) ?
+                                    [0x0, 0x0C, 0x0, 0x0, 0x0]:
+                                    [0x0, 0x00, 0x0, 0x0, 0x0];
+
+    // Override some functions to test.
+    contactHelper.getContactFieldRecordId = function(pbr, contact, field, onsuccess, onerror) {
+      onsuccess(1);
+    };
+
+    record.readPBR = function readPBR(onsuccess, onerror) {
+      onsuccess([{adn:{fileId: 0x6f3a}, email: {}, anr0: {}}]);
+    };
+
+    record.readADNLike = function readADNLike(fileId, onsuccess, onerror) {
+      onsuccess([{recordId: 1, alphaId: "name", number: "111111"}])
+    };
+
+    record.readEmail = function readEmail(fileId, fileType, recordNumber, onsuccess, onerror) {
+      onsuccess("hello@mail.com");
+    };
+
+    record.readANR = function readANR(fileId, fileType, recordNumber, onsuccess, onerror) {
+      onsuccess("123456");
+    };
+
+    let onsuccess = function onsuccess(contacts) {
+      let contact = contacts[0];
+      for (let key in contact) {
+        do_print("check " + key);
+        if (Array.isArray(contact[key])) {
+          do_check_eq(contact[key][0], aExpectedContact[key]);
+        } else {
+          do_check_eq(contact[key], aExpectedContact[key]);
+        }
+      }
+    };
+
+    let onerror = function onerror(errorMsg) {
+      do_print("readICCContacts failed: " + errorMsg);
+      do_check_true(false);
+    };
+
+    contactHelper.readICCContacts(aSimType, aContactType, onsuccess, onerror);
+  }
+
+  let expectedContact1 = {
+    pbrIndex: 0,
+    recordId: 1,
+    alphaId:  "name",
+    number:   "111111"
+  };
+
+  let expectedContact2 = {
+    pbrIndex: 0,
+    recordId: 1,
+    alphaId:  "name",
+    number:   "111111",
+    email:    "hello@mail.com",
+    anr:      "123456"
+  };
+
+  // SIM
+  do_print("Test read SIM adn contacts");
+  do_test(CARD_APPTYPE_SIM, "adn", expectedContact1);
+
+  do_print("Test read SIM fdn contacts");
+  do_test(CARD_APPTYPE_SIM, "fdn", expectedContact1);
+
+  // USIM
+  do_print("Test read USIM adn contacts");
+  do_test(CARD_APPTYPE_USIM, "adn", expectedContact2);
+
+  do_print("Test read USIM fdn contacts");
+  do_test(CARD_APPTYPE_USIM, "fdn", expectedContact1);
+
+  // RUIM
+  do_print("Test read RUIM adn contacts");
+  do_test(CARD_APPTYPE_RUIM, "adn", expectedContact1);
+
+  do_print("Test read RUIM fdn contacts");
+  do_test(CARD_APPTYPE_RUIM, "fdn", expectedContact1);
+
+  // RUIM with enhanced phone book
+  do_print("Test read RUIM adn contacts with enhanced phone book");
+  do_test(CARD_APPTYPE_RUIM, "adn", expectedContact2, true);
+
+  do_print("Test read RUIM fdn contacts with enhanced phone book");
+  do_test(CARD_APPTYPE_RUIM, "fdn", expectedContact1, true);
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCContactHelper.updateICCContact with appType is CARD_APPTYPE_USIM.
+ */
+add_test(function test_update_icc_contact() {
+  const ADN_RECORD_ID   = 100;
+  const ADN_SFI         = 1;
+  const IAP_FILE_ID     = 0x4f17;
+  const EMAIL_FILE_ID   = 0x4f50;
+  const EMAIL_RECORD_ID = 20;
+  const ANR0_FILE_ID    = 0x4f11;
+  const ANR0_RECORD_ID  = 30;
+
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let recordHelper = context.ICCRecordHelper;
+  let contactHelper = context.ICCContactHelper;
+  let ril = context.RIL;
+
+  function do_test(aSimType, aContactType, aContact, aPin2, aFileType, aHaveIapIndex, aEnhancedPhoneBook) {
+    ril.appType = aSimType;
+    ril._isCdma = (aSimType === CARD_APPTYPE_RUIM);
+    ril.iccInfoPrivate.cst = (aEnhancedPhoneBook) ? [0x0, 0x0C, 0x0, 0x0, 0x0]
+                                                  : [0x0, 0x00, 0x0, 0x0, 0x0];
+
+    recordHelper.readPBR = function(onsuccess, onerror) {
+      if (aFileType === ICC_USIM_TYPE1_TAG) {
+        onsuccess([{
+          adn:   {fileId: ICC_EF_ADN},
+          email: {fileId: EMAIL_FILE_ID,
+                  fileType: ICC_USIM_TYPE1_TAG},
+          anr0:  {fileId: ANR0_FILE_ID,
+                  fileType: ICC_USIM_TYPE1_TAG}
+        }]);
+      } else if (aFileType === ICC_USIM_TYPE2_TAG) {
+        onsuccess([{
+          adn:   {fileId: ICC_EF_ADN,
+                  sfi: ADN_SFI},
+          iap:   {fileId: IAP_FILE_ID},
+          email: {fileId: EMAIL_FILE_ID,
+                  fileType: ICC_USIM_TYPE2_TAG,
+                  indexInIAP: 0},
+          anr0:  {fileId: ANR0_FILE_ID,
+                  fileType: ICC_USIM_TYPE2_TAG,
+                  indexInIAP: 1}
+        }]);
+      }
+    };
+
+    recordHelper.updateADNLike = function(fileId, contact, pin2, onsuccess, onerror) {
+      if (aContactType === "fdn") {
+        do_check_eq(fileId, ICC_EF_FDN);
+      } else if (aContactType === "adn") {
+        do_check_eq(fileId, ICC_EF_ADN);
+      }
+      do_check_eq(pin2, aPin2);
+      do_check_eq(contact.alphaId, aContact.alphaId);
+      do_check_eq(contact.number, aContact.number);
+      onsuccess();
+    };
+
+    recordHelper.readIAP = function(fileId, recordNumber, onsuccess, onerror) {
+      do_check_eq(fileId, IAP_FILE_ID);
+      do_check_eq(recordNumber, ADN_RECORD_ID);
+      onsuccess((aHaveIapIndex) ? [EMAIL_RECORD_ID, ANR0_RECORD_ID]
+                                : [0xff, 0xff]);
+    };
+
+    recordHelper.updateIAP = function(fileId, recordNumber, iap, onsuccess, onerror) {
+      do_check_eq(fileId, IAP_FILE_ID);
+      do_check_eq(recordNumber, ADN_RECORD_ID);
+      onsuccess();
+    };
+
+    recordHelper.updateEmail = function(pbr, recordNumber, email, adnRecordId, onsuccess, onerror) {
+      do_check_eq(pbr.email.fileId, EMAIL_FILE_ID);
+      if (pbr.email.fileType === ICC_USIM_TYPE1_TAG) {
+        do_check_eq(recordNumber, ADN_RECORD_ID);
+      } else if (pbr.email.fileType === ICC_USIM_TYPE2_TAG) {
+        do_check_eq(recordNumber, EMAIL_RECORD_ID);
+      }
+      do_check_eq(email, aContact.email);
+      onsuccess();
+    };
+
+    recordHelper.updateANR = function(pbr, recordNumber, number, adnRecordId, onsuccess, onerror) {
+      do_check_eq(pbr.anr0.fileId, ANR0_FILE_ID);
+      if (pbr.anr0.fileType === ICC_USIM_TYPE1_TAG) {
+        do_check_eq(recordNumber, ADN_RECORD_ID);
+      } else if (pbr.anr0.fileType === ICC_USIM_TYPE2_TAG) {
+        do_check_eq(recordNumber, ANR0_RECORD_ID);
+      }
+      if (Array.isArray(aContact.anr)) {
+        do_check_eq(number, aContact.anr[0]);
+      }
+      onsuccess();
+    };
+
+    recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) {
+      let recordId = 0;
+      if (fileId === EMAIL_FILE_ID) {
+        recordId = EMAIL_RECORD_ID;
+      } else if (fileId === ANR0_FILE_ID) {
+        recordId = ANR0_RECORD_ID;
+      }
+      onsuccess(recordId);
+    };
+
+    let isSuccess = false;
+    let onsuccess = function onsuccess() {
+      do_print("updateICCContact success");
+      isSuccess = true;
+    };
+
+    let onerror = function onerror(errorMsg) {
+      do_print("updateICCContact failed: " + errorMsg);
+    };
+
+    contactHelper.updateICCContact(aSimType, aContactType, aContact, aPin2, onsuccess, onerror);
+    do_check_true(isSuccess);
+  }
+
+  let contacts = [
+    {
+      pbrIndex: 0,
+      recordId: ADN_RECORD_ID,
+      alphaId:  "test",
+      number:   "123456",
+      email:    "test@mail.com",
+      anr:      ["+654321"]
+    },
+    // a contact without email and anr.
+    {
+      pbrIndex: 0,
+      recordId: ADN_RECORD_ID,
+      alphaId:  "test2",
+      number:   "123456",
+    },
+    // a contact with email but no anr.
+    {
+      pbrIndex: 0,
+      recordId: ADN_RECORD_ID,
+      alphaId:  "test3",
+      number:   "123456",
+      email:    "test@mail.com"
+    },
+    // a contact with anr but no email.
+    {
+      pbrIndex: 0,
+      recordId: ADN_RECORD_ID,
+      alphaId:  "test4",
+      number:   "123456",
+      anr:      ["+654321"]
+    }];
+
+  for (let i = 0; i < contacts.length; i++) {
+    let contact = contacts[i];
+    // SIM
+    do_print("Test update SIM adn contacts");
+    do_test(CARD_APPTYPE_SIM, "adn", contact);
+
+    do_print("Test update SIM fdn contacts");
+    do_test(CARD_APPTYPE_SIM, "fdn", contact, "1234");
+
+    // USIM
+    do_print("Test update USIM adn contacts");
+    do_test(CARD_APPTYPE_USIM, "adn", contact, null, ICC_USIM_TYPE1_TAG);
+    do_test(CARD_APPTYPE_USIM, "adn", contact, null, ICC_USIM_TYPE2_TAG, true);
+    do_test(CARD_APPTYPE_USIM, "adn", contact, null, ICC_USIM_TYPE2_TAG, false);
+
+    do_print("Test update USIM fdn contacts");
+    do_test(CARD_APPTYPE_USIM, "fdn", contact, "1234");
+
+    // RUIM
+    do_print("Test update RUIM adn contacts");
+    do_test(CARD_APPTYPE_RUIM, "adn", contact);
+
+    do_print("Test update RUIM fdn contacts");
+    do_test(CARD_APPTYPE_RUIM, "fdn", contact, "1234");
+
+    // RUIM with enhanced phone book
+    do_print("Test update RUIM adn contacts with enhanced phone book");
+    do_test(CARD_APPTYPE_RUIM, "adn", contact, null, ICC_USIM_TYPE1_TAG, null, true);
+    do_test(CARD_APPTYPE_RUIM, "adn", contact, null, ICC_USIM_TYPE2_TAG, true, true);
+    do_test(CARD_APPTYPE_RUIM, "adn", contact, null, ICC_USIM_TYPE2_TAG, false, true);
+
+    do_print("Test update RUIM fdn contacts with enhanced phone book");
+    do_test(CARD_APPTYPE_RUIM, "fdn", contact, "1234", null, true);
+  }
+
+  run_next_test();
+});
+
+/**
+ * Verify updateICCContact with removal of anr and email with File Type 1.
+ */
+add_test(function test_update_icc_contact_with_remove_type1_attr() {
+  const ADN_RECORD_ID   = 100;
+  const IAP_FILE_ID     = 0x4f17;
+  const EMAIL_FILE_ID   = 0x4f50;
+  const EMAIL_RECORD_ID = 20;
+  const ANR0_FILE_ID    = 0x4f11;
+  const ANR0_RECORD_ID  = 30;
+
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let recordHelper = context.ICCRecordHelper;
+  let contactHelper = context.ICCContactHelper;
+
+  recordHelper.updateADNLike = function(fileId, contact, pin2, onsuccess, onerror) {
+    onsuccess();
+  };
+
+  let contact = {
+    pbrIndex: 0,
+    recordId: ADN_RECORD_ID,
+    alphaId:  "test2",
+    number:   "123456",
+  };
+
+  recordHelper.readIAP = function(fileId, recordNumber, onsuccess, onerror) {
+    onsuccess([EMAIL_RECORD_ID, ANR0_RECORD_ID]);
+  };
+
+  recordHelper.updateEmail = function(pbr, recordNumber, email, adnRecordId, onsuccess, onerror) {
+    do_check_true(email == null);
+    onsuccess();
+  };
+
+  recordHelper.updateANR = function(pbr, recordNumber, number, adnRecordId, onsuccess, onerror) {
+    do_check_true(number == null);
+    onsuccess();
+  };
+
+  function do_test(type) {
+    recordHelper.readPBR = function(onsuccess, onerror) {
+      if (type == ICC_USIM_TYPE1_TAG) {
+        onsuccess([{
+          adn:   {fileId: ICC_EF_ADN},
+          email: {fileId: EMAIL_FILE_ID,
+                  fileType: ICC_USIM_TYPE1_TAG},
+          anr0:  {fileId: ANR0_FILE_ID,
+                  fileType: ICC_USIM_TYPE1_TAG}}]);
+      } else {
+        onsuccess([{
+          adn:   {fileId: ICC_EF_ADN},
+          iap:   {fileId: IAP_FILE_ID},
+          email: {fileId: EMAIL_FILE_ID,
+                  fileType: ICC_USIM_TYPE2_TAG,
+                  indexInIAP: 0},
+          anr0:  {fileId: ANR0_FILE_ID,
+                  fileType: ICC_USIM_TYPE2_TAG,
+                  indexInIAP: 1}}]);
+      }
+    };
+
+    let successCb = function() {
+      do_check_true(true);
+    };
+
+    let errorCb = function(errorMsg) {
+      do_print(errorMsg);
+      do_check_true(false);
+    };
+
+    contactHelper.updateICCContact(CARD_APPTYPE_USIM, "adn", contact, null, successCb, errorCb);
+  }
+
+  do_test(ICC_USIM_TYPE1_TAG);
+  do_test(ICC_USIM_TYPE2_TAG);
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCContactHelper.findFreeICCContact in SIM
+ */
+add_test(function test_find_free_icc_contact_sim() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let recordHelper = context.ICCRecordHelper;
+  let contactHelper = context.ICCContactHelper;
+  // Correct record Id starts with 1, so put a null element at index 0.
+  let records = [null];
+  const MAX_RECORDS = 3;
+  const PBR_INDEX = 0;
+
+  recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) {
+    if (records.length > MAX_RECORDS) {
+      onerror("No free record found.");
+      return;
+    }
+
+    onsuccess(records.length);
+  };
+
+  let successCb = function(pbrIndex, recordId) {
+    do_check_eq(pbrIndex, PBR_INDEX);
+    records[recordId] = {};
+  };
+
+  let errorCb = function(errorMsg) {
+    do_print(errorMsg);
+    do_check_true(false);
+  };
+
+  for (let i = 0; i < MAX_RECORDS; i++) {
+    contactHelper.findFreeICCContact(CARD_APPTYPE_SIM, "adn", successCb, errorCb);
+  }
+  // The 1st element, records[0], is null.
+  do_check_eq(records.length - 1, MAX_RECORDS);
+
+  // Now the EF is full, so finding a free one should result failure.
+  successCb = function(pbrIndex, recordId) {
+    do_check_true(false);
+  };
+
+  errorCb = function(errorMsg) {
+    do_check_true(errorMsg === "No free record found.");
+  };
+  contactHelper.findFreeICCContact(CARD_APPTYPE_SIM, "adn", successCb, errorCb);
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCContactHelper.findFreeICCContact in USIM
+ */
+add_test(function test_find_free_icc_contact_usim() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let recordHelper = context.ICCRecordHelper;
+  let contactHelper = context.ICCContactHelper;
+  const ADN1_FILE_ID = 0x6f3a;
+  const ADN2_FILE_ID = 0x6f3b;
+  const MAX_RECORDS = 3;
+
+  // The adn in the first phonebook set has already two records, which means
+  // only 1 free record remained.
+  let pbrs = [{adn: {fileId: ADN1_FILE_ID, records: [null, {}, {}]}},
+              {adn: {fileId: ADN2_FILE_ID, records: [null]}}];
+
+  recordHelper.readPBR = function readPBR(onsuccess, onerror) {
+    onsuccess(pbrs);
+  };
+
+  recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) {
+    let pbr = (fileId == ADN1_FILE_ID ? pbrs[0]: pbrs[1]);
+    if (pbr.adn.records.length > MAX_RECORDS) {
+      onerror("No free record found.");
+      return;
+    }
+
+    onsuccess(pbr.adn.records.length);
+  };
+
+  let successCb = function(pbrIndex, recordId) {
+    do_check_eq(pbrIndex, 0);
+    pbrs[pbrIndex].adn.records[recordId] = {};
+  };
+
+  let errorCb = function(errorMsg) {
+    do_check_true(false);
+  };
+
+  contactHelper.findFreeICCContact(CARD_APPTYPE_USIM, "adn", successCb, errorCb);
+
+  // Now the EF_ADN in the 1st phonebook set is full, so the next free contact
+  // will come from the 2nd phonebook set.
+  successCb = function(pbrIndex, recordId) {
+    do_check_eq(pbrIndex, 1);
+    do_check_eq(recordId, 1);
+  }
+  contactHelper.findFreeICCContact(CARD_APPTYPE_USIM, "adn", successCb, errorCb);
+
+  run_next_test();
+});
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_icc_ICCIOHelper.js
@@ -0,0 +1,164 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+function run_test() {
+  run_next_test();
+}
+
+/**
+ * Verify ICCIOHelper.loadLinearFixedEF with recordSize.
+ */
+add_test(function test_load_linear_fixed_ef() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ril = context.RIL;
+  let io = context.ICCIOHelper;
+
+  io.getResponse = function fakeGetResponse(options) {
+    // When recordSize is provided, loadLinearFixedEF should call iccIO directly.
+    do_check_true(false);
+    run_next_test();
+  };
+
+  ril.iccIO = function fakeIccIO(options) {
+    do_check_true(true);
+    run_next_test();
+  };
+
+  io.loadLinearFixedEF({recordSize: 0x20});
+});
+
+/**
+ * Verify ICCIOHelper.loadLinearFixedEF without recordSize.
+ */
+add_test(function test_load_linear_fixed_ef() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ril = context.RIL;
+  let io = context.ICCIOHelper;
+
+  io.getResponse = function fakeGetResponse(options) {
+    do_check_true(true);
+    run_next_test();
+  };
+
+  ril.iccIO = function fakeIccIO(options) {
+    // When recordSize is not provided, loadLinearFixedEF should call getResponse.
+    do_check_true(false);
+    run_next_test();
+  };
+
+  io.loadLinearFixedEF({});
+});
+
+/**
+ * Verify ICCIOHelper.processICCIOError.
+ */
+add_test(function test_process_icc_io_error() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ioHelper = context.ICCIOHelper;
+
+  function do_test(errorCode, expectedErrorMsg) {
+    let called = false;
+    function errorCb(errorMsg) {
+      called = true;
+      do_check_eq(errorMsg, expectedErrorMsg);
+    }
+
+    ioHelper.processICCIOError({rilRequestError: errorCode,
+                                fileId: 0xffff,
+                                command: 0xff,
+                                sw1: 0xff,
+                                sw2: 0xff,
+                                onerror: errorCb});
+    do_check_true(called);
+  }
+
+  for (let i = 0; i < ERROR_REJECTED_BY_REMOTE + 1; i++) {
+    do_test(i, RIL_ERROR_TO_GECKO_ERROR[i]);
+  }
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCIOHelper.processICCIOGetResponse for EF_TYPE_TRANSPARENT.
+ */
+add_test(function test_icc_io_get_response_for_transparent_structure() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let buf = context.Buf;
+  let iccioHelper = context.ICCIOHelper;
+  let pduHelper = context.GsmPDUHelper;
+
+  let responseArray = [
+    // SIM response.
+    [0x00, 0x00, 0x00, 0x0A, 0x2F, 0xE2, 0x04, 0x00, 0x0A, 0xA0, 0xAA, 0x00,
+     0x02, 0x00, 0x00],
+    // USIM response.
+    [0x62, 0x22, 0x82, 0x02, 0x41, 0x21, 0x83, 0x02, 0x2F, 0xE2, 0xA5, 0x09,
+     0xC1, 0x04, 0x40, 0x0F, 0xF5, 0x55, 0x92, 0x01, 0x00, 0x8A, 0x01, 0x05,
+     0x8B, 0x03, 0x2F, 0x06, 0x0B, 0x80, 0x02, 0x00, 0x0A, 0x88, 0x01, 0x10]
+  ];
+
+  for (let i = 0; i < responseArray.length; i++) {
+    let strLen = responseArray[i].length * 2;
+    buf.writeInt32(strLen);
+    for (let j = 0; j < responseArray[i].length; j++) {
+      pduHelper.writeHexOctet(responseArray[i][j]);
+    }
+    buf.writeStringDelimiter(strLen);
+
+    let options = {fileId: ICC_EF_ICCID,
+                   type: EF_TYPE_TRANSPARENT};
+    iccioHelper.processICCIOGetResponse(options);
+
+    do_check_eq(options.fileSize, 0x0A);
+  }
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCIOHelper.processICCIOGetResponse for EF_TYPE_LINEAR_FIXED.
+ */
+add_test(function test_icc_io_get_response_for_linear_fixed_structure() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let buf = context.Buf;
+  let iccioHelper = context.ICCIOHelper;
+  let pduHelper = context.GsmPDUHelper;
+
+  let responseArray = [
+    // SIM response.
+    [0x00, 0x00, 0x00, 0x1A, 0x6F, 0x40, 0x04, 0x00, 0x11, 0xA0, 0xAA, 0x00,
+     0x02, 0x01, 0x1A],
+    // USIM response.
+    [0x62, 0x1E, 0x82, 0x05, 0x42, 0x21, 0x00, 0x1A, 0x01, 0x83, 0x02, 0x6F,
+     0x40, 0xA5, 0x03, 0x92, 0x01, 0x00, 0x8A, 0x01, 0x07, 0x8B, 0x03, 0x6F,
+     0x06, 0x02, 0x80, 0x02, 0x00, 0x1A, 0x88, 0x00]
+  ];
+
+  for (let i = 0; i < responseArray.length; i++) {
+    let strLen = responseArray[i].length * 2;
+    buf.writeInt32(strLen);
+    for (let j = 0; j < responseArray[i].length; j++) {
+      pduHelper.writeHexOctet(responseArray[i][j]);
+    }
+    buf.writeStringDelimiter(strLen);
+
+    let options = {fileId: ICC_EF_MSISDN,
+                   type: EF_TYPE_LINEAR_FIXED};
+    iccioHelper.processICCIOGetResponse(options);
+
+    do_check_eq(options.fileSize, 0x1A);
+    do_check_eq(options.recordSize, 0x1A);
+    do_check_eq(options.totalRecords, 0x01);
+  }
+
+  run_next_test();
+});
+
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_icc_ICCPDUHelper.js
@@ -0,0 +1,520 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+function run_test() {
+  run_next_test();
+}
+
+/**
+ * Verify ICCPDUHelper#readICCUCS2String()
+ */
+add_test(function test_read_icc_ucs2_string() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+  let iccHelper = context.ICCPDUHelper;
+
+  // 0x80
+  let text = "TEST";
+  helper.writeUCS2String(text);
+  // Also write two unused octets.
+  let ffLen = 2;
+  for (let i = 0; i < ffLen; i++) {
+    helper.writeHexOctet(0xff);
+  }
+  do_check_eq(iccHelper.readICCUCS2String(0x80, (2 * text.length) + ffLen), text);
+
+  // 0x81
+  let array = [0x08, 0xd2, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca,
+               0xff, 0xff];
+  let len = array.length;
+  for (let i = 0; i < len; i++) {
+    helper.writeHexOctet(array[i]);
+  }
+  do_check_eq(iccHelper.readICCUCS2String(0x81, len), "Mozilla\u694a");
+
+  // 0x82
+  let array2 = [0x08, 0x69, 0x00, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61,
+                0xca, 0xff, 0xff];
+  let len2 = array2.length;
+  for (let i = 0; i < len2; i++) {
+    helper.writeHexOctet(array2[i]);
+  }
+  do_check_eq(iccHelper.readICCUCS2String(0x82, len2), "Mozilla\u694a");
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCPDUHelper#readDiallingNumber
+ */
+add_test(function test_read_dialling_number() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+  let iccHelper = context.ICCPDUHelper;
+  let str = "123456789";
+
+  helper.readHexOctet = function() {
+    return 0x81;
+  };
+
+  helper.readSwappedNibbleBcdString = function(len) {
+    return str.substring(0, len);
+  };
+
+  for (let i = 0; i < str.length; i++) {
+    do_check_eq(str.substring(0, i - 1), // -1 for the TON
+                iccHelper.readDiallingNumber(i));
+  }
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCPDUHelper#read8BitUnpackedToString
+ */
+add_test(function test_read_8bit_unpacked_to_string() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+  let iccHelper = context.ICCPDUHelper;
+  const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
+  const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
+
+  // Test 1: Read GSM alphabets.
+  // Write alphabets before ESCAPE.
+  for (let i = 0; i < PDU_NL_EXTENDED_ESCAPE; i++) {
+    helper.writeHexOctet(i);
+  }
+
+  // Write two ESCAPEs to make it become ' '.
+  helper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE);
+  helper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE);
+
+  for (let i = PDU_NL_EXTENDED_ESCAPE + 1; i < langTable.length; i++) {
+    helper.writeHexOctet(i);
+  }
+
+  // Also write two unused fields.
+  let ffLen = 2;
+  for (let i = 0; i < ffLen; i++) {
+    helper.writeHexOctet(0xff);
+  }
+
+  do_check_eq(iccHelper.read8BitUnpackedToString(PDU_NL_EXTENDED_ESCAPE),
+              langTable.substring(0, PDU_NL_EXTENDED_ESCAPE));
+  do_check_eq(iccHelper.read8BitUnpackedToString(2), " ");
+  do_check_eq(iccHelper.read8BitUnpackedToString(langTable.length -
+                                              PDU_NL_EXTENDED_ESCAPE - 1 + ffLen),
+              langTable.substring(PDU_NL_EXTENDED_ESCAPE + 1));
+
+  // Test 2: Read GSM extended alphabets.
+  for (let i = 0; i < langShiftTable.length; i++) {
+    helper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE);
+    helper.writeHexOctet(i);
+  }
+
+  // Read string before RESERVED_CONTROL.
+  do_check_eq(iccHelper.read8BitUnpackedToString(PDU_NL_RESERVED_CONTROL  * 2),
+              langShiftTable.substring(0, PDU_NL_RESERVED_CONTROL));
+  // ESCAPE + RESERVED_CONTROL will become ' '.
+  do_check_eq(iccHelper.read8BitUnpackedToString(2), " ");
+  // Read string between RESERVED_CONTROL and EXTENDED_ESCAPE.
+  do_check_eq(iccHelper.read8BitUnpackedToString(
+                (PDU_NL_EXTENDED_ESCAPE - PDU_NL_RESERVED_CONTROL - 1)  * 2),
+              langShiftTable.substring(PDU_NL_RESERVED_CONTROL + 1,
+                                       PDU_NL_EXTENDED_ESCAPE));
+  // ESCAPE + ESCAPE will become ' '.
+  do_check_eq(iccHelper.read8BitUnpackedToString(2), " ");
+  // Read remaining string.
+  do_check_eq(iccHelper.read8BitUnpackedToString(
+                (langShiftTable.length - PDU_NL_EXTENDED_ESCAPE - 1)  * 2),
+              langShiftTable.substring(PDU_NL_EXTENDED_ESCAPE + 1));
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCPDUHelper#writeStringTo8BitUnpacked.
+ *
+ * Test writing GSM 8 bit alphabets.
+ */
+add_test(function test_write_string_to_8bit_unpacked() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+  let iccHelper = context.ICCPDUHelper;
+  const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
+  const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
+  // Length of trailing 0xff.
+  let ffLen = 2;
+  let str;
+
+  // Test 1, write GSM alphabets.
+  iccHelper.writeStringTo8BitUnpacked(langTable.length + ffLen, langTable);
+
+  for (let i = 0; i < langTable.length; i++) {
+    do_check_eq(helper.readHexOctet(), i);
+  }
+
+  for (let i = 0; i < ffLen; i++) {
+    do_check_eq(helper.readHexOctet(), 0xff);
+  }
+
+  // Test 2, write GSM extended alphabets.
+  str = "\u000c\u20ac";
+  iccHelper.writeStringTo8BitUnpacked(4, str);
+
+  do_check_eq(iccHelper.read8BitUnpackedToString(4), str);
+
+  // Test 3, write GSM and GSM extended alphabets.
+  // \u000c, \u20ac are from gsm extended alphabets.
+  // \u00a3 is from gsm alphabet.
+  str = "\u000c\u20ac\u00a3";
+
+  // 2 octets * 2 = 4 octets for 2 gsm extended alphabets,
+  // 1 octet for 1 gsm alphabet,
+  // 2 octes for trailing 0xff.
+  // "Totally 7 octets are to be written."
+  iccHelper.writeStringTo8BitUnpacked(7, str);
+
+  do_check_eq(iccHelper.read8BitUnpackedToString(7), str);
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCPDUHelper#writeStringTo8BitUnpacked with maximum octets written.
+ */
+add_test(function test_write_string_to_8bit_unpacked_with_max_octets_written() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+  let iccHelper = context.ICCPDUHelper;
+  const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
+  const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
+
+  // The maximum of the number of octets that can be written is 3.
+  // Only 3 characters shall be written even the length of the string is 4.
+  iccHelper.writeStringTo8BitUnpacked(3, langTable.substring(0, 4));
+  helper.writeHexOctet(0xff); // dummy octet.
+  for (let i = 0; i < 3; i++) {
+    do_check_eq(helper.readHexOctet(), i);
+  }
+  do_check_false(helper.readHexOctet() == 4);
+
+  // \u000c is GSM extended alphabet, 2 octets.
+  // \u00a3 is GSM alphabet, 1 octet.
+  let str = "\u000c\u00a3";
+  iccHelper.writeStringTo8BitUnpacked(3, str);
+  do_check_eq(iccHelper.read8BitUnpackedToString(3), str);
+
+  str = "\u00a3\u000c";
+  iccHelper.writeStringTo8BitUnpacked(3, str);
+  do_check_eq(iccHelper.read8BitUnpackedToString(3), str);
+
+  // 2 GSM extended alphabets cost 4 octets, but maximum is 3, so only the 1st
+  // alphabet can be written.
+  str = "\u000c\u000c";
+  iccHelper.writeStringTo8BitUnpacked(3, str);
+  helper.writeHexOctet(0xff); // dummy octet.
+  do_check_eq(iccHelper.read8BitUnpackedToString(4), str.substring(0, 1));
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCPDUHelper.readAlphaIdentifier
+ */
+add_test(function test_read_alpha_identifier() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+  let iccHelper = context.ICCPDUHelper;
+
+  // UCS2: 0x80
+  let text = "TEST";
+  helper.writeHexOctet(0x80);
+  helper.writeUCS2String(text);
+  // Also write two unused octets.
+  let ffLen = 2;
+  for (let i = 0; i < ffLen; i++) {
+    helper.writeHexOctet(0xff);
+  }
+  do_check_eq(iccHelper.readAlphaIdentifier(1 + (2 * text.length) + ffLen), text);
+
+  // UCS2: 0x81
+  let array = [0x81, 0x08, 0xd2, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff];
+  for (let i = 0; i < array.length; i++) {
+    helper.writeHexOctet(array[i]);
+  }
+  do_check_eq(iccHelper.readAlphaIdentifier(array.length), "Mozilla\u694a");
+
+  // UCS2: 0x82
+  let array2 = [0x82, 0x08, 0x69, 0x00, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff];
+  for (let i = 0; i < array2.length; i++) {
+    helper.writeHexOctet(array2[i]);
+  }
+  do_check_eq(iccHelper.readAlphaIdentifier(array2.length), "Mozilla\u694a");
+
+  // GSM 8 Bit Unpacked
+  const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
+  for (let i = 0; i < PDU_NL_EXTENDED_ESCAPE; i++) {
+    helper.writeHexOctet(i);
+  }
+  do_check_eq(iccHelper.readAlphaIdentifier(PDU_NL_EXTENDED_ESCAPE),
+              langTable.substring(0, PDU_NL_EXTENDED_ESCAPE));
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCPDUHelper.writeAlphaIdentifier
+ */
+add_test(function test_write_alpha_identifier() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+  let iccHelper = context.ICCPDUHelper;
+  // Length of trailing 0xff.
+  let ffLen = 2;
+
+  // Removal
+  iccHelper.writeAlphaIdentifier(10, null);
+  do_check_eq(iccHelper.readAlphaIdentifier(10), "");
+
+  // GSM 8 bit
+  let str = "Mozilla";
+  iccHelper.writeAlphaIdentifier(str.length + ffLen, str);
+  do_check_eq(iccHelper.readAlphaIdentifier(str.length + ffLen), str);
+
+  // UCS2
+  str = "Mozilla\u694a";
+  iccHelper.writeAlphaIdentifier(str.length * 2 + ffLen, str);
+  // * 2 for each character will be encoded to UCS2 alphabets.
+  do_check_eq(iccHelper.readAlphaIdentifier(str.length * 2 + ffLen), str);
+
+  // Test with maximum octets written.
+  // 1 coding scheme (0x80) and 1 UCS2 character, total 3 octets.
+  str = "\u694a";
+  iccHelper.writeAlphaIdentifier(3, str);
+  do_check_eq(iccHelper.readAlphaIdentifier(3), str);
+
+  // 1 coding scheme (0x80) and 2 UCS2 characters, total 5 octets.
+  // numOctets is limited to 4, so only 1 UCS2 character can be written.
+  str = "\u694a\u694a";
+  iccHelper.writeAlphaIdentifier(4, str);
+  helper.writeHexOctet(0xff); // dummy octet.
+  do_check_eq(iccHelper.readAlphaIdentifier(5), str.substring(0, 1));
+
+  // Write 0 octet.
+  iccHelper.writeAlphaIdentifier(0, "1");
+  helper.writeHexOctet(0xff); // dummy octet.
+  do_check_eq(iccHelper.readAlphaIdentifier(1), "");
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCPDUHelper.readAlphaIdDiallingNumber
+ */
+add_test(function test_read_alpha_id_dialling_number() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+  let iccHelper = context.ICCPDUHelper;
+  let buf = context.Buf;
+  const recordSize = 32;
+
+  function testReadAlphaIdDiallingNumber(contact) {
+    iccHelper.readAlphaIdentifier = function() {
+      return contact.alphaId;
+    };
+
+    iccHelper.readNumberWithLength = function() {
+      return contact.number;
+    };
+
+    let strLen = recordSize * 2;
+    buf.writeInt32(strLen);     // fake length
+    helper.writeHexOctet(0xff); // fake CCP
+    helper.writeHexOctet(0xff); // fake EXT1
+    buf.writeStringDelimiter(strLen);
+
+    let contactR = iccHelper.readAlphaIdDiallingNumber(recordSize);
+    if (contact.alphaId == "" && contact.number == "") {
+      do_check_eq(contactR, null);
+    } else {
+      do_check_eq(contactR.alphaId, contact.alphaId);
+      do_check_eq(contactR.number, contact.number);
+    }
+  }
+
+  testReadAlphaIdDiallingNumber({alphaId: "AlphaId", number: "0987654321"});
+  testReadAlphaIdDiallingNumber({alphaId: "", number: ""});
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCPDUHelper.writeAlphaIdDiallingNumber
+ */
+add_test(function test_write_alpha_id_dialling_number() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.ICCPDUHelper;
+  const recordSize = 32;
+
+  // Write a normal contact.
+  let contactW = {
+    alphaId: "Mozilla",
+    number: "1234567890"
+  };
+  helper.writeAlphaIdDiallingNumber(recordSize, contactW.alphaId,
+                                    contactW.number);
+
+  let contactR = helper.readAlphaIdDiallingNumber(recordSize);
+  do_check_eq(contactW.alphaId, contactR.alphaId);
+  do_check_eq(contactW.number, contactR.number);
+
+  // Write a contact with alphaId encoded in UCS2 and number has '+'.
+  let contactUCS2 = {
+    alphaId: "火狐",
+    number: "+1234567890"
+  };
+  helper.writeAlphaIdDiallingNumber(recordSize, contactUCS2.alphaId,
+                                    contactUCS2.number);
+  contactR = helper.readAlphaIdDiallingNumber(recordSize);
+  do_check_eq(contactUCS2.alphaId, contactR.alphaId);
+  do_check_eq(contactUCS2.number, contactR.number);
+
+  // Write a null contact (Removal).
+  helper.writeAlphaIdDiallingNumber(recordSize);
+  contactR = helper.readAlphaIdDiallingNumber(recordSize);
+  do_check_eq(contactR, null);
+
+  // Write a longer alphaId/dialling number
+  // Dialling Number : Maximum 20 digits(10 octets).
+  // Alpha Identifier: 32(recordSize) - 14 (10 octets for Dialling Number, 1
+  //                   octet for TON/NPI, 1 for number length octet, and 2 for
+  //                   Ext) = Maximum 18 octets.
+  let longContact = {
+    alphaId: "AAAAAAAAABBBBBBBBBCCCCCCCCC",
+    number: "123456789012345678901234567890",
+  };
+  helper.writeAlphaIdDiallingNumber(recordSize, longContact.alphaId,
+                                    longContact.number);
+  contactR = helper.readAlphaIdDiallingNumber(recordSize);
+  do_check_eq(contactR.alphaId, "AAAAAAAAABBBBBBBBB");
+  do_check_eq(contactR.number, "12345678901234567890");
+
+  // Add '+' to number and test again.
+  longContact.number = "+123456789012345678901234567890";
+  helper.writeAlphaIdDiallingNumber(recordSize, longContact.alphaId,
+                                    longContact.number);
+  contactR = helper.readAlphaIdDiallingNumber(recordSize);
+  do_check_eq(contactR.alphaId, "AAAAAAAAABBBBBBBBB");
+  do_check_eq(contactR.number, "+12345678901234567890");
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCPDUHelper.writeDiallingNumber
+ */
+add_test(function test_write_dialling_number() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.ICCPDUHelper;
+
+  // with +
+  let number = "+123456";
+  let len = 4;
+  helper.writeDiallingNumber(number);
+  do_check_eq(helper.readDiallingNumber(len), number);
+
+  // without +
+  number = "987654";
+  len = 4;
+  helper.writeDiallingNumber(number);
+  do_check_eq(helper.readDiallingNumber(len), number);
+
+  number = "9876543";
+  len = 5;
+  helper.writeDiallingNumber(number);
+  do_check_eq(helper.readDiallingNumber(len), number);
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCPDUHelper.readNumberWithLength
+ */
+add_test(function test_read_number_with_length() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+  let iccHelper = context.ICCPDUHelper;
+  let number = "123456789";
+
+  iccHelper.readDiallingNumber = function(numLen) {
+    return number.substring(0, numLen);
+  };
+
+  helper.writeHexOctet(number.length + 1);
+  helper.writeHexOctet(PDU_TOA_ISDN);
+  do_check_eq(iccHelper.readNumberWithLength(), number);
+
+  helper.writeHexOctet(0xff);
+  do_check_eq(iccHelper.readNumberWithLength(), null);
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCPDUHelper.writeNumberWithLength
+ */
+add_test(function test_write_number_with_length() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+  let iccHelper = context.ICCPDUHelper;
+
+  function test(number, expectedNumber) {
+    expectedNumber = expectedNumber || number;
+    iccHelper.writeNumberWithLength(number);
+    let numLen = helper.readHexOctet();
+    do_check_eq(expectedNumber, iccHelper.readDiallingNumber(numLen));
+    for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES - numLen); i++) {
+      do_check_eq(0xff, helper.readHexOctet());
+    }
+  }
+
+  // without +
+  test("123456789");
+
+  // with +
+  test("+987654321");
+
+  // extended BCD coding
+  test("1*2#3,4*5#6,");
+
+  // with + and extended BCD coding
+  test("+1*2#3,4*5#6,");
+
+  // non-supported characters should not be written.
+  test("(1)23-456+789", "123456789");
+
+  test("++(01)2*3-4#5,6+7(8)9*0#1,", "+012*34#5,6789*0#1,");
+
+  // null
+  iccHelper.writeNumberWithLength(null);
+  for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES + 1); i++) {
+    do_check_eq(0xff, helper.readHexOctet());
+  }
+
+  run_next_test();
+});
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_icc_ICCRecordHelper.js
@@ -0,0 +1,725 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+function run_test() {
+  run_next_test();
+}
+
+/**
+ * Verify ICCRecordHelper.readPBR
+ */
+add_test(function test_read_pbr() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+  let record = context.ICCRecordHelper;
+  let buf    = context.Buf;
+  let io     = context.ICCIOHelper;
+
+  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) {
+    let pbr_1 = [
+      0xa8, 0x05, 0xc0, 0x03, 0x4f, 0x3a, 0x01
+    ];
+
+    // Write data size
+    buf.writeInt32(pbr_1.length * 2);
+
+    // Write pbr
+    for (let i = 0; i < pbr_1.length; i++) {
+      helper.writeHexOctet(pbr_1[i]);
+    }
+
+    // Write string delimiter
+    buf.writeStringDelimiter(pbr_1.length * 2);
+
+    options.totalRecords = 2;
+    if (options.callback) {
+      options.callback(options);
+    }
+  };
+
+  io.loadNextRecord = function fakeLoadNextRecord(options) {
+    let pbr_2 = [
+      0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+    ];
+
+    options.p1++;
+    if (options.callback) {
+      options.callback(options);
+    }
+  };
+
+  let successCb = function successCb(pbrs) {
+    do_check_eq(pbrs[0].adn.fileId, 0x4f3a);
+    do_check_eq(pbrs.length, 1);
+  };
+
+  let errorCb = function errorCb(errorMsg) {
+    do_print("Reading EF_PBR failed, msg = " + errorMsg);
+    do_check_true(false);
+  };
+
+  record.readPBR(successCb, errorCb);
+
+  // Check cache pbrs when 2nd call
+  let ifLoadEF = false;
+  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options)  {
+    ifLoadEF = true;
+  }
+  record.readPBR(successCb, errorCb);
+  do_check_false(ifLoadEF);
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCRecordHelper.readEmail
+ */
+add_test(function test_read_email() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+  let record = context.ICCRecordHelper;
+  let buf    = context.Buf;
+  let io     = context.ICCIOHelper;
+  let recordSize;
+
+  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options)  {
+    let email_1 = [
+      0x65, 0x6D, 0x61, 0x69, 0x6C,
+      0x00, 0x6D, 0x6F, 0x7A, 0x69,
+      0x6C, 0x6C, 0x61, 0x2E, 0x63,
+      0x6F, 0x6D, 0x02, 0x23];
+
+    // Write data size
+    buf.writeInt32(email_1.length * 2);
+
+    // Write email
+    for (let i = 0; i < email_1.length; i++) {
+      helper.writeHexOctet(email_1[i]);
+    }
+
+    // Write string delimiter
+    buf.writeStringDelimiter(email_1.length * 2);
+
+    recordSize = email_1.length;
+    options.recordSize = recordSize;
+    if (options.callback) {
+      options.callback(options);
+    }
+  };
+
+  function doTestReadEmail(type, expectedResult) {
+    let fileId = 0x6a75;
+    let recordNumber = 1;
+
+    // fileId and recordNumber are dummy arguments.
+    record.readEmail(fileId, type, recordNumber, function(email) {
+      do_check_eq(email, expectedResult);
+    });
+  };
+
+  doTestReadEmail(ICC_USIM_TYPE1_TAG, "email@mozilla.com$#");
+  doTestReadEmail(ICC_USIM_TYPE2_TAG, "email@mozilla.com");
+  do_check_eq(record._emailRecordSize, recordSize);
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCRecordHelper.updateEmail
+ */
+add_test(function test_update_email() {
+  const recordSize = 0x20;
+  const recordNumber = 1;
+  const fileId = 0x4f50;
+  const NUM_TESTS = 2;
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let pduHelper = context.GsmPDUHelper;
+  let iccHelper = context.ICCPDUHelper;
+  let ril = context.RIL;
+  ril.appType = CARD_APPTYPE_USIM;
+  let recordHelper = context.ICCRecordHelper;
+  let buf = context.Buf;
+  let ioHelper = context.ICCIOHelper;
+  let pbr = {email: {fileId: fileId, fileType: ICC_USIM_TYPE1_TAG},
+             adn: {sfi: 1}};
+  let count = 0;
+
+  // Override.
+  ioHelper.updateLinearFixedEF = function(options) {
+    options.pathId = context.ICCFileHelper.getEFPath(options.fileId);
+    options.command = ICC_COMMAND_UPDATE_RECORD;
+    options.p1 = options.recordNumber;
+    options.p2 = READ_RECORD_ABSOLUTE_MODE;
+    options.p3 = recordSize;
+    ril.iccIO(options);
+  };
+
+  function do_test(pbr, expectedEmail, expectedAdnRecordId) {
+    buf.sendParcel = function() {
+      count++;
+
+      // Request Type.
+      do_check_eq(this.readInt32(), REQUEST_SIM_IO);
+
+      // Token : we don't care
+      this.readInt32();
+
+      // command.
+      do_check_eq(this.readInt32(), ICC_COMMAND_UPDATE_RECORD);
+
+      // fileId.
+      do_check_eq(this.readInt32(), fileId);
+
+      // pathId.
+      do_check_eq(this.readString(),
+                  EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK);
+
+      // p1.
+      do_check_eq(this.readInt32(), recordNumber);
+
+      // p2.
+      do_check_eq(this.readInt32(), READ_RECORD_ABSOLUTE_MODE);
+
+      // p3.
+      do_check_eq(this.readInt32(), recordSize);
+
+      // data.
+      let strLen = this.readInt32();
+      let email;
+      if (pbr.email.fileType === ICC_USIM_TYPE1_TAG) {
+        email = iccHelper.read8BitUnpackedToString(recordSize);
+      } else {
+        email = iccHelper.read8BitUnpackedToString(recordSize - 2);
+        do_check_eq(pduHelper.readHexOctet(), pbr.adn.sfi);
+        do_check_eq(pduHelper.readHexOctet(), expectedAdnRecordId);
+      }
+      this.readStringDelimiter(strLen);
+      do_check_eq(email, expectedEmail);
+
+      // pin2.
+      do_check_eq(this.readString(), null);
+
+      if (!ril.v5Legacy) {
+        // AID. Ignore because it's from modem.
+        this.readInt32();
+      }
+
+      if (count == NUM_TESTS) {
+        run_next_test();
+      }
+    };
+    recordHelper.updateEmail(pbr, recordNumber, expectedEmail, expectedAdnRecordId);
+  }
+
+  do_test(pbr, "test@mail.com");
+  pbr.email.fileType = ICC_USIM_TYPE2_TAG;
+  do_test(pbr, "test@mail.com", 1);
+});
+
+/**
+ * Verify ICCRecordHelper.readANR
+ */
+add_test(function test_read_anr() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+  let record = context.ICCRecordHelper;
+  let buf    = context.Buf;
+  let io     = context.ICCIOHelper;
+  let recordSize;
+
+  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options)  {
+    let anr_1 = [
+      0x01, 0x05, 0x81, 0x10, 0x32,
+      0x54, 0xF6, 0xFF, 0xFF];
+
+    // Write data size
+    buf.writeInt32(anr_1.length * 2);
+
+    // Write anr
+    for (let i = 0; i < anr_1.length; i++) {
+      helper.writeHexOctet(anr_1[i]);
+    }
+
+    // Write string delimiter
+    buf.writeStringDelimiter(anr_1.length * 2);
+
+    recordSize = anr_1.length;
+    options.recordSize = recordSize;
+    if (options.callback) {
+      options.callback(options);
+    }
+  };
+
+  function doTestReadAnr(fileType, expectedResult) {
+    let fileId = 0x4f11;
+    let recordNumber = 1;
+
+    // fileId and recordNumber are dummy arguments.
+    record.readANR(fileId, fileType, recordNumber, function(anr) {
+      do_check_eq(anr, expectedResult);
+    });
+  };
+
+  doTestReadAnr(ICC_USIM_TYPE1_TAG, "0123456");
+  do_check_eq(record._anrRecordSize, recordSize);
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCRecordHelper.updateANR
+ */
+add_test(function test_update_anr() {
+  const recordSize = 0x20;
+  const recordNumber = 1;
+  const fileId = 0x4f11;
+  const NUM_TESTS = 2;
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let pduHelper = context.GsmPDUHelper;
+  let iccHelper = context.ICCPDUHelper;
+  let ril = context.RIL;
+  ril.appType = CARD_APPTYPE_USIM;
+  let recordHelper = context.ICCRecordHelper;
+  let buf = context.Buf;
+  let ioHelper = context.ICCIOHelper;
+  let pbr = {anr0: {fileId: fileId, fileType: ICC_USIM_TYPE1_TAG},
+             adn: {sfi: 1}};
+  let count = 0;
+
+  // Override.
+  ioHelper.updateLinearFixedEF = function(options) {
+    options.pathId = context.ICCFileHelper.getEFPath(options.fileId);
+    options.command = ICC_COMMAND_UPDATE_RECORD;
+    options.p1 = options.recordNumber;
+    options.p2 = READ_RECORD_ABSOLUTE_MODE;
+    options.p3 = recordSize;
+    ril.iccIO(options);
+  };
+
+  function do_test(pbr, expectedANR, expectedAdnRecordId) {
+    buf.sendParcel = function() {
+      count++;
+
+      // Request Type.
+      do_check_eq(this.readInt32(), REQUEST_SIM_IO);
+
+      // Token : we don't care
+      this.readInt32();
+
+      // command.
+      do_check_eq(this.readInt32(), ICC_COMMAND_UPDATE_RECORD);
+
+      // fileId.
+      do_check_eq(this.readInt32(), fileId);
+
+      // pathId.
+      do_check_eq(this.readString(),
+                  EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK);
+
+      // p1.
+      do_check_eq(this.readInt32(), recordNumber);
+
+      // p2.
+      do_check_eq(this.readInt32(), READ_RECORD_ABSOLUTE_MODE);
+
+      // p3.
+      do_check_eq(this.readInt32(), recordSize);
+
+      // data.
+      let strLen = this.readInt32();
+      // EF_AAS, ignore.
+      pduHelper.readHexOctet();
+      do_check_eq(iccHelper.readNumberWithLength(), expectedANR);
+      // EF_CCP, ignore.
+      pduHelper.readHexOctet();
+      // EF_EXT1, ignore.
+      pduHelper.readHexOctet();
+      if (pbr.anr0.fileType === ICC_USIM_TYPE2_TAG) {
+        do_check_eq(pduHelper.readHexOctet(), pbr.adn.sfi);
+        do_check_eq(pduHelper.readHexOctet(), expectedAdnRecordId);
+      }
+      this.readStringDelimiter(strLen);
+
+      // pin2.
+      do_check_eq(this.readString(), null);
+
+      if (!ril.v5Legacy) {
+        // AID. Ignore because it's from modem.
+        this.readInt32();
+      }
+
+      if (count == NUM_TESTS) {
+        run_next_test();
+      }
+    };
+    recordHelper.updateANR(pbr, recordNumber, expectedANR, expectedAdnRecordId);
+  }
+
+  do_test(pbr, "+123456789");
+  pbr.anr0.fileType = ICC_USIM_TYPE2_TAG;
+  do_test(pbr, "123456789", 1);
+});
+
+/**
+ * Verify ICCRecordHelper.readIAP
+ */
+add_test(function test_read_iap() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+  let record = context.ICCRecordHelper;
+  let buf    = context.Buf;
+  let io     = context.ICCIOHelper;
+  let recordSize;
+
+  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options)  {
+    let iap_1 = [0x01, 0x02];
+
+    // Write data size/
+    buf.writeInt32(iap_1.length * 2);
+
+    // Write iap.
+    for (let i = 0; i < iap_1.length; i++) {
+      helper.writeHexOctet(iap_1[i]);
+    }
+
+    // Write string delimiter.
+    buf.writeStringDelimiter(iap_1.length * 2);
+
+    recordSize = iap_1.length;
+    options.recordSize = recordSize;
+    if (options.callback) {
+      options.callback(options);
+    }
+  };
+
+  function doTestReadIAP(expectedIAP) {
+    const fileId = 0x4f17;
+    const recordNumber = 1;
+
+    let successCb = function successCb(iap) {
+      for (let i = 0; i < iap.length; i++) {
+        do_check_eq(expectedIAP[i], iap[i]);
+      }
+      run_next_test();
+    }.bind(this);
+
+    let errorCb = function errorCb(errorMsg) {
+      do_print(errorMsg);
+      do_check_true(false);
+      run_next_test();
+    }.bind(this);
+
+    record.readIAP(fileId, recordNumber, successCb, errorCb);
+  };
+
+  doTestReadIAP([1, 2]);
+});
+
+/**
+ * Verify ICCRecordHelper.updateIAP
+ */
+add_test(function test_update_iap() {
+  const recordSize = 2;
+  const recordNumber = 1;
+  const fileId = 0x4f17;
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let pduHelper = context.GsmPDUHelper;
+  let ril = context.RIL;
+  ril.appType = CARD_APPTYPE_USIM;
+  let recordHelper = context.ICCRecordHelper;
+  let buf = context.Buf;
+  let ioHelper = context.ICCIOHelper;
+  let count = 0;
+
+  // Override.
+  ioHelper.updateLinearFixedEF = function(options) {
+    options.pathId = context.ICCFileHelper.getEFPath(options.fileId);
+    options.command = ICC_COMMAND_UPDATE_RECORD;
+    options.p1 = options.recordNumber;
+    options.p2 = READ_RECORD_ABSOLUTE_MODE;
+    options.p3 = recordSize;
+    ril.iccIO(options);
+  };
+
+  function do_test(expectedIAP) {
+    buf.sendParcel = function() {
+      // Request Type.
+      do_check_eq(this.readInt32(), REQUEST_SIM_IO);
+
+      // Token : we don't care
+      this.readInt32();
+
+      // command.
+      do_check_eq(this.readInt32(), ICC_COMMAND_UPDATE_RECORD);
+
+      // fileId.
+      do_check_eq(this.readInt32(), fileId);
+
+      // pathId.
+      do_check_eq(this.readString(),
+                  EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK);
+
+      // p1.
+      do_check_eq(this.readInt32(), recordNumber);
+
+      // p2.
+      do_check_eq(this.readInt32(), READ_RECORD_ABSOLUTE_MODE);
+
+      // p3.
+      do_check_eq(this.readInt32(), recordSize);
+
+      // data.
+      let strLen = this.readInt32();
+      for (let i = 0; i < recordSize; i++) {
+        do_check_eq(expectedIAP[i], pduHelper.readHexOctet());
+      }
+      this.readStringDelimiter(strLen);
+
+      // pin2.
+      do_check_eq(this.readString(), null);
+
+      if (!ril.v5Legacy) {
+        // AID. Ignore because it's from modem.
+        this.readInt32();
+      }
+
+      run_next_test();
+    };
+    recordHelper.updateIAP(fileId, recordNumber, expectedIAP);
+  }
+
+  do_test([1, 2]);
+});
+
+/**
+ * Verify ICCRecordHelper.updateADNLike.
+ */
+add_test(function test_update_adn_like() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ril = context.RIL;
+  let record = context.ICCRecordHelper;
+  let io = context.ICCIOHelper;
+  let pdu = context.ICCPDUHelper;
+  let buf = context.Buf;
+
+  ril.appType = CARD_APPTYPE_SIM;
+  const recordSize = 0x20;
+  let fileId;
+
+  // Override.
+  io.updateLinearFixedEF = function(options) {
+    options.pathId = context.ICCFileHelper.getEFPath(options.fileId);
+    options.command = ICC_COMMAND_UPDATE_RECORD;
+    options.p1 = options.recordNumber;
+    options.p2 = READ_RECORD_ABSOLUTE_MODE;
+    options.p3 = recordSize;
+    ril.iccIO(options);
+  };
+
+  buf.sendParcel = function() {
+    // Request Type.
+    do_check_eq(this.readInt32(), REQUEST_SIM_IO);
+
+    // Token : we don't care
+    this.readInt32();
+
+    // command.
+    do_check_eq(this.readInt32(), ICC_COMMAND_UPDATE_RECORD);
+
+    // fileId.
+    do_check_eq(this.readInt32(), fileId);
+
+    // pathId.
+    do_check_eq(this.readString(), EF_PATH_MF_SIM + EF_PATH_DF_TELECOM);
+
+    // p1.
+    do_check_eq(this.readInt32(), 1);
+
+    // p2.
+    do_check_eq(this.readInt32(), READ_RECORD_ABSOLUTE_MODE);
+
+    // p3.
+    do_check_eq(this.readInt32(), 0x20);
+
+    // data.
+    let contact = pdu.readAlphaIdDiallingNumber(0x20);
+    do_check_eq(contact.alphaId, "test");
+    do_check_eq(contact.number, "123456");
+
+    // pin2.
+    if (fileId == ICC_EF_ADN) {
+      do_check_eq(this.readString(), null);
+    } else {
+      do_check_eq(this.readString(), "1111");
+    }
+
+    if (!ril.v5Legacy) {
+      // AID. Ignore because it's from modem.
+      this.readInt32();
+    }
+
+    if (fileId == ICC_EF_FDN) {
+      run_next_test();
+    }
+  };
+
+  fileId = ICC_EF_ADN;
+  record.updateADNLike(fileId,
+                       {recordId: 1, alphaId: "test", number: "123456"});
+
+  fileId = ICC_EF_FDN;
+  record.updateADNLike(fileId,
+                       {recordId: 1, alphaId: "test", number: "123456"},
+                       "1111");
+});
+
+/**
+ * Verify ICCRecordHelper.findFreeRecordId.
+ */
+add_test(function test_find_free_record_id() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let pduHelper = context.GsmPDUHelper;
+  let recordHelper = context.ICCRecordHelper;
+  let buf = context.Buf;
+  let io  = context.ICCIOHelper;
+
+  function writeRecord (record) {
+    // Write data size
+    buf.writeInt32(record.length * 2);
+
+    for (let i = 0; i < record.length; i++) {
+      pduHelper.writeHexOctet(record[i]);
+    }
+
+    // Write string delimiter
+    buf.writeStringDelimiter(record.length * 2);
+  }
+
+  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options)  {
+    // Some random data.
+    let record = [0x12, 0x34, 0x56, 0x78, 0x90];
+    options.p1 = 1;
+    options.totalRecords = 2;
+    writeRecord(record);
+    if (options.callback) {
+      options.callback(options);
+    }
+  };
+
+  io.loadNextRecord = function fakeLoadNextRecord(options) {
+    // Unused bytes.
+    let record = [0xff, 0xff, 0xff, 0xff, 0xff];
+    options.p1++;
+    writeRecord(record);
+    if (options.callback) {
+      options.callback(options);
+    }
+  };
+
+  let fileId = 0x0000; // Dummy.
+  recordHelper.findFreeRecordId(
+    fileId,
+    function(recordId) {
+      do_check_eq(recordId, 2);
+      run_next_test();
+    }.bind(this),
+    function(errorMsg) {
+      do_print(errorMsg);
+      do_check_true(false);
+      run_next_test();
+    }.bind(this));
+});
+
+/**
+ * Verify ICCRecordHelper.fetchICCRecords.
+ */
+add_test(function test_fetch_icc_recodes() {
+  let worker = newWorker();
+  let context = worker.ContextPool._contexts[0];
+  let RIL = context.RIL;
+  let iccRecord = context.ICCRecordHelper;
+  let simRecord = context.SimRecordHelper;
+  let ruimRecord = context.RuimRecordHelper;
+  let fetchTag = 0x00;
+
+  simRecord.fetchSimRecords = function() {
+    fetchTag = 0x01;
+  };
+
+  ruimRecord.fetchRuimRecords = function() {
+    fetchTag = 0x02;
+  };
+
+  RIL.appType = CARD_APPTYPE_SIM;
+  iccRecord.fetchICCRecords();
+  do_check_eq(fetchTag, 0x01);
+
+  RIL.appType = CARD_APPTYPE_RUIM;
+  iccRecord.fetchICCRecords();
+  do_check_eq(fetchTag, 0x02);
+
+  RIL.appType = CARD_APPTYPE_USIM;
+  iccRecord.fetchICCRecords();
+  do_check_eq(fetchTag, 0x01);
+
+  run_next_test();
+});
+
+/**
+ * Verify reading EF_ICCID.
+ */
+add_test(function test_handling_iccid() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let record = context.ICCRecordHelper;
+  let helper = context.GsmPDUHelper;
+  let ril = context.RIL;
+  let buf = context.Buf;
+  let io = context.ICCIOHelper;
+
+  ril.reportStkServiceIsRunning = function fakeReportStkServiceIsRunning() {
+  };
+
+  function do_test(rawICCID, expectedICCID) {
+    io.loadTransparentEF = function fakeLoadTransparentEF(options) {
+      // Write data size
+      buf.writeInt32(rawICCID.length);
+
+      // Write data
+      for (let i = 0; i < rawICCID.length; i += 2) {
+        helper.writeHexOctet(parseInt(rawICCID.substr(i, 2), 16));
+      }
+
+      // Write string delimiter
+      buf.writeStringDelimiter(rawICCID.length);
+
+      if (options.callback) {
+        options.callback(options);
+      }
+    };
+
+    record.readICCID();
+
+    do_check_eq(ril.iccInfo.iccid, expectedICCID);
+  }
+
+  // Invalid char at high nibbile + low nibbile contains 0xF.
+  do_test("9868002E90909F001519", "89860020909");
+  // Invalid char at low nibbile.
+  do_test("986800E2909090001519", "8986002090909005191");
+  // Valid ICCID.
+  do_test("98101430121181157002", "89014103211118510720");
+
+  run_next_test();
+});
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_icc_ICCUtilsHelper.js
@@ -0,0 +1,236 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+function run_test() {
+  run_next_test();
+}
+
+/**
+ * Verify ICCUtilsHelper.isICCServiceAvailable.
+ */
+add_test(function test_is_icc_service_available() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ICCUtilsHelper = context.ICCUtilsHelper;
+  let RIL = context.RIL;
+
+  function test_table(sst, geckoService, simEnabled, usimEnabled) {
+    RIL.iccInfoPrivate.sst = sst;
+    RIL.appType = CARD_APPTYPE_SIM;
+    do_check_eq(ICCUtilsHelper.isICCServiceAvailable(geckoService), simEnabled);
+    RIL.appType = CARD_APPTYPE_USIM;
+    do_check_eq(ICCUtilsHelper.isICCServiceAvailable(geckoService), usimEnabled);
+  }
+
+  test_table([0x08], "ADN", true, false);
+  test_table([0x08], "FDN", false, false);
+  test_table([0x08], "SDN", false, true);
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCUtilsHelper.isGsm8BitAlphabet
+ */
+add_test(function test_is_gsm_8bit_alphabet() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let ICCUtilsHelper = context.ICCUtilsHelper;
+  const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
+  const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT];
+
+  do_check_eq(ICCUtilsHelper.isGsm8BitAlphabet(langTable), true);
+  do_check_eq(ICCUtilsHelper.isGsm8BitAlphabet(langShiftTable), true);
+  do_check_eq(ICCUtilsHelper.isGsm8BitAlphabet("\uaaaa"), false);
+
+  run_next_test();
+});
+
+/**
+ * Verify ICCUtilsHelper.parsePbrTlvs
+ */
+add_test(function test_parse_pbr_tlvs() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let buf = context.Buf;
+
+  let pbrTlvs = [
+    {tag: ICC_USIM_TYPE1_TAG,
+     length: 0x0F,
+     value: [{tag: ICC_USIM_EFADN_TAG,
+              length: 0x03,
+              value: [0x4F, 0x3A, 0x02]},
+             {tag: ICC_USIM_EFIAP_TAG,
+              length: 0x03,
+              value: [0x4F, 0x25, 0x01]},
+             {tag: ICC_USIM_EFPBC_TAG,
+              length: 0x03,
+              value: [0x4F, 0x09, 0x04]}]
+    },
+    {tag: ICC_USIM_TYPE2_TAG,
+     length: 0x05,
+     value: [{tag: ICC_USIM_EFEMAIL_TAG,
+              length: 0x03,
+              value: [0x4F, 0x50, 0x0B]},
+             {tag: ICC_USIM_EFANR_TAG,
+              length: 0x03,
+              value: [0x4F, 0x11, 0x02]},
+             {tag: ICC_USIM_EFANR_TAG,
+              length: 0x03,
+              value: [0x4F, 0x12, 0x03]}]
+    },
+    {tag: ICC_USIM_TYPE3_TAG,
+     length: 0x0A,
+     value: [{tag: ICC_USIM_EFCCP1_TAG,
+              length: 0x03,
+              value: [0x4F, 0x3D, 0x0A]},
+             {tag: ICC_USIM_EFEXT1_TAG,
+              length: 0x03,
+              value: [0x4F, 0x4A, 0x03]}]
+    },
+  ];
+
+  let pbr = context.ICCUtilsHelper.parsePbrTlvs(pbrTlvs);
+  do_check_eq(pbr.adn.fileId, 0x4F3a);
+  do_check_eq(pbr.iap.fileId, 0x4F25);
+  do_check_eq(pbr.pbc.fileId, 0x4F09);
+  do_check_eq(pbr.email.fileId, 0x4F50);
+  do_check_eq(pbr.anr0.fileId, 0x4f11);
+  do_check_eq(pbr.anr1.fileId, 0x4f12);
+  do_check_eq(pbr.ccp1.fileId, 0x4F3D);
+  do_check_eq(pbr.ext1.fileId, 0x4F4A);
+
+  run_next_test();
+});
+
+/**
+ * Verify MCC and MNC parsing
+ */
+add_test(function test_mcc_mnc_parsing() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.ICCUtilsHelper;
+
+  function do_test(imsi, mncLength, expectedMcc, expectedMnc) {
+    let result = helper.parseMccMncFromImsi(imsi, mncLength);
+
+    if (!imsi) {
+      do_check_eq(result, null);
+      return;
+    }
+
+    do_check_eq(result.mcc, expectedMcc);
+    do_check_eq(result.mnc, expectedMnc);
+  }
+
+  // Test the imsi is null.
+  do_test(null, null, null, null);
+
+  // Test MCC is Taiwan
+  do_test("466923202422409", 0x02, "466", "92");
+  do_test("466923202422409", 0x03, "466", "923");
+  do_test("466923202422409", null, "466", "92");
+
+  // Test MCC is US
+  do_test("310260542718417", 0x02, "310", "26");
+  do_test("310260542718417", 0x03, "310", "260");
+  do_test("310260542718417", null, "310", "260");
+
+  run_next_test();
+});
+
+add_test(function test_get_network_name_from_icc() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let RIL = context.RIL;
+  let ICCUtilsHelper = context.ICCUtilsHelper;
+
+  function testGetNetworkNameFromICC(operatorData, expectedResult) {
+    let result = ICCUtilsHelper.getNetworkNameFromICC(operatorData.mcc,
+                                                      operatorData.mnc,
+                                                      operatorData.lac);
+
+    if (expectedResult == null) {
+      do_check_eq(result, expectedResult);
+    } else {
+      do_check_eq(result.fullName, expectedResult.longName);
+      do_check_eq(result.shortName, expectedResult.shortName);
+    }
+  }
+
+  // Before EF_OPL and EF_PNN have been loaded.
+  testGetNetworkNameFromICC({mcc: 123, mnc: 456, lac: 0x1000}, null);
+  testGetNetworkNameFromICC({mcc: 321, mnc: 654, lac: 0x2000}, null);
+
+  // Set HPLMN
+  RIL.iccInfo.mcc = 123;
+  RIL.iccInfo.mnc = 456;
+
+  RIL.voiceRegistrationState = {
+    cell: {
+      gsmLocationAreaCode: 0x1000
+    }
+  };
+  RIL.operator = {};
+
+  // Set EF_PNN
+  RIL.iccInfoPrivate = {
+    PNN: [
+      {"fullName": "PNN1Long", "shortName": "PNN1Short"},
+      {"fullName": "PNN2Long", "shortName": "PNN2Short"},
+      {"fullName": "PNN3Long", "shortName": "PNN3Short"},
+      {"fullName": "PNN4Long", "shortName": "PNN4Short"}
+    ]
+  };
+
+  // EF_OPL isn't available and current isn't in HPLMN,
+  testGetNetworkNameFromICC({mcc: 321, mnc: 654, lac: 0x1000}, null);
+
+  // EF_OPL isn't available and current is in HPLMN,
+  // the first record of PNN should be returned.
+  testGetNetworkNameFromICC({mcc: 123, mnc: 456, lac: 0x1000},
+                            {longName: "PNN1Long", shortName: "PNN1Short"});
+
+  // Set EF_OPL
+  RIL.iccInfoPrivate.OPL = [
+    {
+      "mcc": 123,
+      "mnc": 456,
+      "lacTacStart": 0,
+      "lacTacEnd": 0xFFFE,
+      "pnnRecordId": 4
+    },
+    {
+      "mcc": 321,
+      "mnc": 654,
+      "lacTacStart": 0,
+      "lacTacEnd": 0x0010,
+      "pnnRecordId": 3
+    },
+    {
+      "mcc": 321,
+      "mnc": 654,
+      "lacTacStart": 0x0100,
+      "lacTacEnd": 0x1010,
+      "pnnRecordId": 2
+    }
+  ];
+
+  // Both EF_PNN and EF_OPL are presented, and current PLMN is HPLMN,
+  testGetNetworkNameFromICC({mcc: 123, mnc: 456, lac: 0x1000},
+                            {longName: "PNN4Long", shortName: "PNN4Short"});
+
+  // Current PLMN is not HPLMN, and according to LAC, we should get
+  // the second PNN record.
+  testGetNetworkNameFromICC({mcc: 321, mnc: 654, lac: 0x1000},
+                            {longName: "PNN2Long", shortName: "PNN2Short"});
+
+  // Current PLMN is not HPLMN, and according to LAC, we should get
+  // the thrid PNN record.
+  testGetNetworkNameFromICC({mcc: 321, mnc: 654, lac: 0x0001},
+                            {longName: "PNN3Long", shortName: "PNN3Short"});
+
+  run_next_test();
+});
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_icc_SimRecordHelper.js
@@ -0,0 +1,489 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+function run_test() {
+  run_next_test();
+}
+
+/**
+ * Verify reading EF_AD and parsing MCC/MNC
+ */
+add_test(function test_reading_ad_and_parsing_mcc_mnc() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let record = context.SimRecordHelper;
+  let helper = context.GsmPDUHelper;
+  let ril    = context.RIL;
+  let buf    = context.Buf;
+  let io     = context.ICCIOHelper;
+
+  function do_test(mncLengthInEf, imsi, expectedMcc, expectedMnc) {
+    ril.iccInfoPrivate.imsi = imsi;
+
+    io.loadTransparentEF = function fakeLoadTransparentEF(options) {
+      let ad = [0x00, 0x00, 0x00];
+      if (typeof mncLengthInEf === 'number') {
+        ad.push(mncLengthInEf);
+      }
+
+      // Write data size
+      buf.writeInt32(ad.length * 2);
+
+      // Write data
+      for (let i = 0; i < ad.length; i++) {
+        helper.writeHexOctet(ad[i]);
+      }
+
+      // Write string delimiter
+      buf.writeStringDelimiter(ad.length * 2);
+
+      if (options.callback) {
+        options.callback(options);
+      }
+    };
+
+    record.readAD();
+
+    do_check_eq(ril.iccInfo.mcc, expectedMcc);
+    do_check_eq(ril.iccInfo.mnc, expectedMnc);
+  }
+
+  do_test(undefined, "466923202422409", "466", "92" );
+  do_test(0x00,      "466923202422409", "466", "92" );
+  do_test(0x01,      "466923202422409", "466", "92" );
+  do_test(0x02,      "466923202422409", "466", "92" );
+  do_test(0x03,      "466923202422409", "466", "923");
+  do_test(0x04,      "466923202422409", "466", "92" );
+  do_test(0xff,      "466923202422409", "466", "92" );
+
+  do_test(undefined, "310260542718417", "310", "260");
+  do_test(0x00,      "310260542718417", "310", "260");
+  do_test(0x01,      "310260542718417", "310", "260");
+  do_test(0x02,      "310260542718417", "310", "26" );
+  do_test(0x03,      "310260542718417", "310", "260");
+  do_test(0x04,      "310260542718417", "310", "260");
+  do_test(0xff,      "310260542718417", "310", "260");
+
+  run_next_test();
+});
+
+add_test(function test_reading_optional_efs() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let record = context.SimRecordHelper;
+  let gsmPdu = context.GsmPDUHelper;
+  let ril    = context.RIL;
+  let buf    = context.Buf;
+  let io     = context.ICCIOHelper;
+
+  function buildSST(supportedEf) {
+    let sst = [];
+    let len = supportedEf.length;
+    for (let i = 0; i < len; i++) {
+      let index, bitmask, iccService;
+      if (ril.appType === CARD_APPTYPE_SIM) {
+        iccService = GECKO_ICC_SERVICES.sim[supportedEf[i]];
+        iccService -= 1;
+        index = Math.floor(iccService / 4);
+        bitmask = 2 << ((iccService % 4) << 1);
+      } else if (ril.appType === CARD_APPTYPE_USIM){
+        iccService = GECKO_ICC_SERVICES.usim[supportedEf[i]];
+        iccService -= 1;
+        index = Math.floor(iccService / 8);
+        bitmask = 1 << ((iccService % 8) << 0);
+      }
+
+      if (sst) {
+        sst[index] |= bitmask;
+      }
+    }
+    return sst;
+  }
+
+  ril.updateCellBroadcastConfig = function fakeUpdateCellBroadcastConfig() {
+    // Ignore updateCellBroadcastConfig after reading SST
+  };
+
+  function do_test(sst, supportedEf) {
+    // Clone supportedEf to local array for testing
+    let testEf = supportedEf.slice(0);
+
+    record.readMSISDN = function fakeReadMSISDN() {
+      testEf.splice(testEf.indexOf("MSISDN"), 1);
+    };
+
+    record.readMBDN = function fakeReadMBDN() {
+      testEf.splice(testEf.indexOf("MDN"), 1);
+    };
+
+    record.readMWIS = function fakeReadMWIS() {
+      testEf.splice(testEf.indexOf("MWIS"), 1);
+    };
+
+    io.loadTransparentEF = function fakeLoadTransparentEF(options) {
+      // Write data size
+      buf.writeInt32(sst.length * 2);
+
+      // Write data
+      for (let i = 0; i < sst.length; i++) {
+         gsmPdu.writeHexOctet(sst[i] || 0);
+      }
+
+      // Write string delimiter
+      buf.writeStringDelimiter(sst.length * 2);
+
+      if (options.callback) {
+        options.callback(options);
+      }
+
+      if (testEf.length !== 0) {
+        do_print("Un-handled EF: " + JSON.stringify(testEf));
+        do_check_true(false);
+      }
+    };
+
+    record.readSST();
+  }
+
+  // TODO: Add all necessary optional EFs eventually
+  let supportedEf = ["MSISDN", "MDN", "MWIS"];
+  ril.appType = CARD_APPTYPE_SIM;
+  do_test(buildSST(supportedEf), supportedEf);
+  ril.appType = CARD_APPTYPE_USIM;
+  do_test(buildSST(supportedEf), supportedEf);
+
+  run_next_test();
+});
+
+/**
+ * Verify fetchSimRecords.
+ */
+add_test(function test_fetch_sim_recodes() {
+  let worker = newWorker();
+  let context = worker.ContextPool._contexts[0];
+  let RIL = context.RIL;
+  let iccRecord = context.ICCRecordHelper;
+  let simRecord = context.SimRecordHelper;
+
+  function testFetchSimRecordes(expectCalled) {
+    let ifCalled = [];
+
+    RIL.getIMSI = function() {
+      ifCalled.push("getIMSI");
+    };
+
+    simRecord.readAD = function() {
+      ifCalled.push("readAD");
+    };
+
+    simRecord.readSST = function() {
+      ifCalled.push("readSST");
+    };
+
+    simRecord.fetchSimRecords();
+
+    for (let i = 0; i < expectCalled.length; i++ ) {
+      if (ifCalled[i] != expectCalled[i]) {
+        do_print(expectCalled[i] + " is not called.");
+        do_check_true(false);
+      }
+    }
+  }
+
+  let expectCalled = ["getIMSI", "readAD", "readSST"];
+  testFetchSimRecordes(expectCalled);
+
+  run_next_test();
+});
+
+/**
+ * Verify SimRecordHelper.readMWIS
+ */
+add_test(function test_read_mwis() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let helper = context.GsmPDUHelper;
+  let recordHelper = context.SimRecordHelper;
+  let buf    = context.Buf;
+  let io     = context.ICCIOHelper;
+  let mwisData;
+  let postedMessage;
+
+  worker.postMessage = function fakePostMessage(message) {
+    postedMessage = message;
+  };
+
+  io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) {
+    if (mwisData) {
+      // Write data size
+      buf.writeInt32(mwisData.length * 2);
+
+      // Write MWIS
+      for (let i = 0; i < mwisData.length; i++) {
+        helper.writeHexOctet(mwisData[i]);
+      }
+
+      // Write string delimiter
+      buf.writeStringDelimiter(mwisData.length * 2);
+
+      options.recordSize = mwisData.length;
+      if (options.callback) {
+        options.callback(options);
+      }
+    } else {
+      do_print("mwisData[] is not set.");
+    }
+  };
+
+  function buildMwisData(isActive, msgCount) {
+    if (msgCount < 0 || msgCount === GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN) {
+      msgCount = 0;
+    } else if (msgCount > 255) {
+      msgCount = 255;
+    }
+
+    mwisData =  [ (isActive) ? 0x01 : 0x00,
+                  msgCount,
+                  0xFF, 0xFF, 0xFF ];
+  }
+
+  function do_test(isActive, msgCount) {
+    buildMwisData(isActive, msgCount);
+    recordHelper.readMWIS();
+
+    do_check_eq("iccmwis", postedMessage.rilMessageType);
+    do_check_eq(isActive, postedMessage.mwi.active);
+    do_check_eq((isActive) ? msgCount : 0, postedMessage.mwi.msgCount);
+  }
+
+  do_test(true, GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN);
+  do_test(true, 1);
+  do_test(true, 255);
+
+  do_test(false, 0);
+  do_test(false, 255); // Test the corner case when mwi is disable with incorrect msgCount.
+
+  run_next_test();
+});
+
+/**
+ * Verify SimRecordHelper.updateMWIS
+ */
+add_test(function test_update_mwis() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let pduHelper = context.GsmPDUHelper;
+  let ril = context.RIL;
+  ril.appType = CARD_APPTYPE_USIM;
+  ril.iccInfoPrivate.mwis = [0x00, 0x00, 0x00, 0x00, 0x00];
+  let recordHelper = context.SimRecordHelper;
+  let buf = context.Buf;
+  let ioHelper = context.ICCIOHelper;
+  let recordSize = ril.iccInfoPrivate.mwis.length;
+  let recordNum = 1;
+
+  ioHelper.updateLinearFixedEF = function(options) {
+    options.pathId = context.ICCFileHelper.getEFPath(options.fileId);
+    options.command = ICC_COMMAND_UPDATE_RECORD;
+    options.p1 = options.recordNumber;
+    options.p2 = READ_RECORD_ABSOLUTE_MODE;
+    options.p3 = recordSize;
+    ril.iccIO(options);
+  };
+
+  function do_test(isActive, count) {
+    let mwis = ril.iccInfoPrivate.mwis;
+    let isUpdated = false;
+
+    function buildMwisData() {
+      let result = mwis.slice(0);
+      result[0] = isActive? (mwis[0] | 0x01) : (mwis[0] & 0xFE);
+      result[1] = (count === GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN) ? 0 : count;
+
+      return result;
+    }
+
+    buf.sendParcel = function() {
+      isUpdated = true;
+
+      // Request Type.
+      do_check_eq(this.readInt32(), REQUEST_SIM_IO);
+
+      // Token : we don't care
+      this.readInt32();
+
+      // command.
+      do_check_eq(this.readInt32(), ICC_COMMAND_UPDATE_RECORD);
+
+      // fileId.
+      do_check_eq(this.readInt32(), ICC_EF_MWIS);
+
+      // pathId.
+      do_check_eq(this.readString(),
+                  EF_PATH_MF_SIM + ((ril.appType === CARD_APPTYPE_USIM) ? EF_PATH_ADF_USIM : EF_PATH_DF_GSM));
+
+      // p1.
+      do_check_eq(this.readInt32(), recordNum);
+
+      // p2.
+      do_check_eq(this.readInt32(), READ_RECORD_ABSOLUTE_MODE);
+
+      // p3.
+      do_check_eq(this.readInt32(), recordSize);
+
+      // data.
+      let strLen = this.readInt32();
+      do_check_eq(recordSize * 2, strLen);
+      let expectedMwis = buildMwisData();
+      for (let i = 0; i < recordSize; i++) {
+        do_check_eq(expectedMwis[i], pduHelper.readHexOctet());
+      }
+      this.readStringDelimiter(strLen);
+
+      // pin2.
+      do_check_eq(this.readString(), null);
+
+      if (!ril.v5Legacy) {
+        // AID. Ignore because it's from modem.
+        this.readInt32();
+      }
+    };
+
+    do_check_false(isUpdated);
+
+    recordHelper.updateMWIS({ active: isActive,
+                              msgCount: count });
+
+    do_check_true((ril.iccInfoPrivate.mwis) ? isUpdated : !isUpdated);
+  }
+
+  do_test(true, GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN);
+  do_test(true, 1);
+  do_test(true, 255);
+
+  do_test(false, 0);
+
+  // Test if Path ID is correct for SIM.
+  ril.appType = CARD_APPTYPE_SIM;
+  do_test(false, 0);
+
+  // Test if loadLinearFixedEF() is not invoked in updateMWIS() when
+  // EF_MWIS is not loaded/available.
+  delete ril.iccInfoPrivate.mwis;
+  do_test(false, 0);
+
+  run_next_test();
+});
+
+/**
+ * Verify the call flow of receiving Class 2 SMS stored in SIM:
+ * 1. UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM.
+ * 2. SimRecordHelper.readSMS().
+ * 3. sendChromeMessage() with rilMessageType == "sms-received".
+ */
+add_test(function test_read_new_sms_on_sim() {
+  // Instead of reusing newUint8Worker defined in this file,
+  // we define our own worker to fake the methods in WorkerBuffer dynamically.
+  function newSmsOnSimWorkerHelper() {
+    let _postedMessage;
+    let _worker = newWorker({
+      postRILMessage: function(data) {
+      },
+      postMessage: function(message) {
+        _postedMessage = message;
+      }
+    });
+
+    _worker.debug = do_print;
+
+    return {
+      get postedMessage() {
+        return _postedMessage;
+      },
+      get worker() {
+        return _worker;
+      },
+      fakeWokerBuffer: function() {
+        let context = _worker.ContextPool._contexts[0];
+        let index = 0; // index for read
+        let buf = [];
+        context.Buf.writeUint8 = function(value) {
+          buf.push(value);
+        };
+        context.Buf.readUint8 = function() {
+          return buf[index++];
+        };
+        context.Buf.seekIncoming = function(offset) {
+          index += offset;
+        };
+        context.Buf.getReadAvailable = function() {
+          return buf.length - index;
+        };
+      }
+    };
+  }
+
+  let workerHelper = newSmsOnSimWorkerHelper();
+  let worker = workerHelper.worker;
+  let context = worker.ContextPool._contexts[0];
+
+  context.ICCIOHelper.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) {
+      // SimStatus: Unread, SMSC:+0123456789, Sender: +9876543210, Text: How are you?
+      let SimSmsPduHex = "0306911032547698040A9189674523010000208062917314080CC8F71D14969741F977FD07"
+                       // In 4.2.25 EF_SMS Short Messages of 3GPP TS 31.102:
+                       // 1. Record length == 176 bytes.
+                       // 2. Any bytes in the record following the TPDU shall be filled with 'FF'.
+                       + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+                       + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+                       + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
+                       + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF";
+
+      workerHelper.fakeWokerBuffer();
+
+      context.Buf.writeString(SimSmsPduHex);
+
+      options.recordSize = 176; // Record length is fixed to 176 bytes.
+      if (options.callback) {
+        options.callback(options);
+      }
+  };
+
+  function newSmsOnSimParcel() {
+    let data = new Uint8Array(4 + 4); // Int32List with 1 element.
+    let offset = 0;
+
+    function writeInt(value) {
+      data[offset++] = value & 0xFF;
+      data[offset++] = (value >>  8) & 0xFF;
+      data[offset++] = (value >> 16) & 0xFF;
+      data[offset++] = (value >> 24) & 0xFF;
+    }
+
+    writeInt(1); // Length of Int32List
+    writeInt(1); // RecordNum = 1.
+
+    return newIncomingParcel(-1,
+                             RESPONSE_TYPE_UNSOLICITED,
+                             UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM,
+                             data);
+  }
+
+  function do_test() {
+    worker.onRILMessage(0, newSmsOnSimParcel());
+
+    let postedMessage = workerHelper.postedMessage;
+
+    do_check_eq("sms-received", postedMessage.rilMessageType);
+    do_check_eq("+0123456789", postedMessage.SMSC);
+    do_check_eq("+9876543210", postedMessage.sender);
+    do_check_eq("How are you?", postedMessage.body);
+  }
+
+  do_test();
+
+  run_next_test();
+});
+
+
--- a/dom/system/gonk/tests/test_ril_worker_mmi.js
+++ b/dom/system/gonk/tests/test_ril_worker_mmi.js
@@ -2,357 +2,32 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
 
 function run_test() {
   run_next_test();
 }
 
-function parseMMI(mmi) {
-  let worker = newWorker({
-    postRILMessage: function(data) {
-      // Do nothing
-    },
-    postMessage: function(message) {
-      // Do nothing
-    }
-  });
-  let context = worker.ContextPool._contexts[0];
-  return context.RIL._parseMMI(mmi);
-}
-
-function getWorker() {
-  let _postedMessage;
-  let _worker = newWorker({
-    postRILMessage: function(data) {
-    },
-    postMessage: function(message) {
-      _postedMessage = message;
-    },
-  });
-
-  return {
-    get postedMessage() {
-      return _postedMessage;
-    },
-    get worker() {
-      return _worker;
-    }
-  };
-}
-
 function testSendMMI(mmi, error) {
-  let workerhelper = getWorker();
+  let workerhelper = newInterceptWorker();
   let worker = workerhelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   do_print("worker.postMessage " + worker.postMessage);
 
   context.RIL.radioState = GECKO_RADIOSTATE_READY;
   context.RIL.sendMMI({rilMessageType: "sendMMI", mmi: mmi});
 
   let postedMessage = workerhelper.postedMessage;
 
   do_check_eq(postedMessage.rilMessageType, "sendMMI");
   do_check_eq(postedMessage.errorMsg, error);
 }
 
-add_test(function test_parseMMI_empty() {
-  let mmi = parseMMI("");
-
-  do_check_null(mmi);
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_undefined() {
-  let mmi = parseMMI();
-
-  do_check_null(mmi);
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_one_digit_short_code() {
-  let mmi = parseMMI("1");
-
-  do_check_eq(mmi.fullMMI, "1");
-  do_check_eq(mmi.procedure, undefined);
-  do_check_eq(mmi.serviceCode, undefined);
-  do_check_eq(mmi.sia, undefined);
-  do_check_eq(mmi.sib, undefined);
-  do_check_eq(mmi.sic, undefined);
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, undefined);
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_invalid_short_code() {
-  let mmi = parseMMI("11");
-
-  do_check_null(mmi);
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_short_code() {
-  let mmi = parseMMI("21");
-
-  do_check_eq(mmi.fullMMI, "21");
-  do_check_eq(mmi.procedure, undefined);
-  do_check_eq(mmi.serviceCode, undefined);
-  do_check_eq(mmi.sia, undefined);
-  do_check_eq(mmi.sib, undefined);
-  do_check_eq(mmi.sic, undefined);
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, undefined);
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_dial_string() {
-  let mmi = parseMMI("12345");
-
-  do_check_null(mmi);
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_USSD_without_asterisk_prefix() {
-  let mmi = parseMMI("123#");
-
-  do_check_eq(mmi.fullMMI, "123#");
-  do_check_eq(mmi.procedure, undefined);
-  do_check_eq(mmi.serviceCode, undefined);
-  do_check_eq(mmi.sia, undefined);
-  do_check_eq(mmi.sib, undefined);
-  do_check_eq(mmi.sic, undefined);
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, undefined);
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_USSD() {
-  let mmi = parseMMI("*123#");
-
-  do_check_eq(mmi.fullMMI, "*123#");
-  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
-  do_check_eq(mmi.serviceCode, "123");
-  do_check_eq(mmi.sia, undefined);
-  do_check_eq(mmi.sib, undefined);
-  do_check_eq(mmi.sic, undefined);
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, "");
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_sia() {
-  let mmi = parseMMI("*123*1#");
-
-  do_check_eq(mmi.fullMMI, "*123*1#");
-  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
-  do_check_eq(mmi.serviceCode, "123");
-  do_check_eq(mmi.sia, "1");
-  do_check_eq(mmi.sib, undefined);
-  do_check_eq(mmi.sic, undefined);
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, "");
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_sib() {
-  let mmi = parseMMI("*123**1#");
-
-  do_check_eq(mmi.fullMMI, "*123**1#");
-  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
-  do_check_eq(mmi.serviceCode, "123");
-  do_check_eq(mmi.sia, "");
-  do_check_eq(mmi.sib, "1");
-  do_check_eq(mmi.sic, undefined);
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, "");
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_sic() {
-  let mmi = parseMMI("*123***1#");
-
-  do_check_eq(mmi.fullMMI, "*123***1#");
-  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
-  do_check_eq(mmi.serviceCode, "123");
-  do_check_eq(mmi.sia, "");
-  do_check_eq(mmi.sib, "");
-  do_check_eq(mmi.sic, "1");
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, "");
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_sia_sib() {
-  let mmi = parseMMI("*123*1*1#");
-
-  do_check_eq(mmi.fullMMI, "*123*1*1#");
-  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
-  do_check_eq(mmi.serviceCode, "123");
-  do_check_eq(mmi.sia, "1");
-  do_check_eq(mmi.sib, "1");
-  do_check_eq(mmi.sic, undefined);
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, "");
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_sia_sic() {
-  let mmi = parseMMI("*123*1**1#");
-
-  do_check_eq(mmi.fullMMI, "*123*1**1#");
-  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
-  do_check_eq(mmi.serviceCode, "123");
-  do_check_eq(mmi.sia, "1");
-  do_check_eq(mmi.sib, "");
-  do_check_eq(mmi.sic, "1");
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, "");
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_sib_sic() {
-  let mmi = parseMMI("*123**1*1#");
-
-  do_check_eq(mmi.fullMMI, "*123**1*1#");
-  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
-  do_check_eq(mmi.serviceCode, "123");
-  do_check_eq(mmi.sia, "");
-  do_check_eq(mmi.sib, "1");
-  do_check_eq(mmi.sic, "1");
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, "");
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_pwd() {
-  let mmi = parseMMI("*123****1#");
-
-  do_check_eq(mmi.fullMMI, "*123****1#");
-  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
-  do_check_eq(mmi.serviceCode, "123");
-  do_check_eq(mmi.sia, "");
-  do_check_eq(mmi.sib, "");
-  do_check_eq(mmi.sic, "");
-  do_check_eq(mmi.pwd, "1");
-  do_check_eq(mmi.dialNumber, "");
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_dial_number() {
-  let mmi = parseMMI("*123#345");
-
-  do_check_eq(mmi.fullMMI, "*123#");
-  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
-  do_check_eq(mmi.serviceCode, "123");
-  do_check_eq(mmi.sia, undefined);
-  do_check_eq(mmi.sib, undefined);
-  do_check_eq(mmi.sic, undefined);
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, "345");
-
-  run_next_test();
-});
-
-
-/**
- * MMI procedures tests
- */
-
-add_test(function test_parseMMI_activation() {
-  let mmi = parseMMI("*00*12*34*56#");
-
-  do_check_eq(mmi.fullMMI, "*00*12*34*56#");
-  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
-  do_check_eq(mmi.serviceCode, "00");
-  do_check_eq(mmi.sia, "12");
-  do_check_eq(mmi.sib, "34");
-  do_check_eq(mmi.sic, "56");
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, "");
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_deactivation() {
-  let mmi = parseMMI("#00*12*34*56#");
-
-  do_check_eq(mmi.fullMMI, "#00*12*34*56#");
-  do_check_eq(mmi.procedure, MMI_PROCEDURE_DEACTIVATION);
-  do_check_eq(mmi.serviceCode, "00");
-  do_check_eq(mmi.sia, "12");
-  do_check_eq(mmi.sib, "34");
-  do_check_eq(mmi.sic, "56");
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, "");
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_interrogation() {
-  let mmi = parseMMI("*#00*12*34*56#");
-
-  do_check_eq(mmi.fullMMI, "*#00*12*34*56#");
-  do_check_eq(mmi.procedure, MMI_PROCEDURE_INTERROGATION);
-  do_check_eq(mmi.serviceCode, "00");
-  do_check_eq(mmi.sia, "12");
-  do_check_eq(mmi.sib, "34");
-  do_check_eq(mmi.sic, "56");
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, "");
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_registration() {
-  let mmi = parseMMI("**00*12*34*56#");
-
-  do_check_eq(mmi.fullMMI, "**00*12*34*56#");
-  do_check_eq(mmi.procedure, MMI_PROCEDURE_REGISTRATION);
-  do_check_eq(mmi.serviceCode, "00");
-  do_check_eq(mmi.sia, "12");
-  do_check_eq(mmi.sib, "34");
-  do_check_eq(mmi.sic, "56");
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, "");
-
-  run_next_test();
-});
-
-add_test(function test_parseMMI_erasure() {
-  let mmi = parseMMI("##00*12*34*56#");
-
-  do_check_eq(mmi.fullMMI, "##00*12*34*56#");
-  do_check_eq(mmi.procedure, MMI_PROCEDURE_ERASURE);
-  do_check_eq(mmi.serviceCode, "00");
-  do_check_eq(mmi.sia, "12");
-  do_check_eq(mmi.sib, "34");
-  do_check_eq(mmi.sic, "56");
-  do_check_eq(mmi.pwd, undefined);
-  do_check_eq(mmi.dialNumber, "");
-
-  run_next_test();
-});
-
 /**
  * sendMMI tests.
  */
 
 add_test(function test_sendMMI_empty() {
   testSendMMI("", MMI_ERROR_KS_ERROR);
 
   run_next_test();
@@ -366,17 +41,17 @@ add_test(function test_sendMMI_undefined
 
 add_test(function test_sendMMI_invalid() {
   testSendMMI("11", MMI_ERROR_KS_ERROR);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_short_code() {
-  let workerhelper = getWorker();
+  let workerhelper = newInterceptWorker();
   let worker = workerhelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   let ussdOptions;
 
   context.RIL.sendUSSD = function fakeSendUSSD(options){
     ussdOptions = options;
     context.RIL[REQUEST_SEND_USSD](0, {
@@ -398,161 +73,18 @@ add_test(function test_sendMMI_short_cod
 });
 
 add_test(function test_sendMMI_dial_string() {
   testSendMMI("123", MMI_ERROR_KS_ERROR);
 
   run_next_test();
 });
 
-function setCallForwardSuccess(mmi) {
-  let workerhelper = getWorker();
-  let worker = workerhelper.worker;
-  let context = worker.ContextPool._contexts[0];
-
-  context.RIL.setCallForward = function fakeSetCallForward(options) {
-    context.RIL[REQUEST_SET_CALL_FORWARD](0, {
-      rilRequestError: ERROR_SUCCESS
-    });
-  };
-
-  context.RIL.radioState = GECKO_RADIOSTATE_READY;
-  context.RIL.sendMMI({mmi: mmi});
-
-  let postedMessage = workerhelper.postedMessage;
-
-  do_check_eq(postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
-  do_check_true(postedMessage.success);
-}
-
-add_test(function test_sendMMI_call_forwarding_activation() {
-  setCallForwardSuccess("*21*12345*99*10#");
-
-  run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_deactivation() {
-  setCallForwardSuccess("#21*12345*99*10#");
-
-  run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_interrogation() {
-  let workerhelper = getWorker();
-  let worker = workerhelper.worker;
-  let context = worker.ContextPool._contexts[0];
-
-  context.Buf.readInt32 = function fakeReadUint32() {
-    return context.Buf.int32Array.pop();
-  };
-
-  context.Buf.readString = function fakeReadString() {
-    return "+34666222333";
-  };
-
-  context.RIL.queryCallForwardStatus = function fakeQueryCallForward(options) {
-    context.Buf.int32Array = [
-      0,   // rules.timeSeconds
-      145, // rules.toa
-      49,  // rules.serviceClass
-      CALL_FORWARD_REASON_UNCONDITIONAL, // rules.reason
-      1,   // rules.active
-      1    // rulesLength
-    ];
-    context.RIL[REQUEST_QUERY_CALL_FORWARD_STATUS](1, {
-      rilRequestError: ERROR_SUCCESS
-    });
-  };
-
-  context.RIL.radioState = GECKO_RADIOSTATE_READY;
-  context.RIL.sendMMI({mmi: "*#21#"});
-
-  let postedMessage = workerhelper.postedMessage;
-
-  do_check_eq(postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
-  do_check_true(postedMessage.success);
-  do_check_true(Array.isArray(postedMessage.rules));
-  do_check_eq(postedMessage.rules.length, 1);
-  do_check_true(postedMessage.rules[0].active);
-  do_check_eq(postedMessage.rules[0].reason, CALL_FORWARD_REASON_UNCONDITIONAL);
-  do_check_eq(postedMessage.rules[0].number, "+34666222333");
-  run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_interrogation_no_rules() {
-  let workerhelper = getWorker();
-  let worker = workerhelper.worker;
-  let context = worker.ContextPool._contexts[0];
-
-  context.Buf.readInt32 = function fakeReadUint32() {
-    return 0;
-  };
-
-  context.RIL.queryCallForwardStatus = function fakeQueryCallForward(options) {
-    context.RIL[REQUEST_QUERY_CALL_FORWARD_STATUS](1, {
-      rilRequestError: ERROR_SUCCESS
-    });
-  };
-
-  context.RIL.radioState = GECKO_RADIOSTATE_READY;
-  context.RIL.sendMMI({mmi: "*#21#"});
-
-  let postedMessage = workerhelper.postedMessage;
-
-  do_check_eq(postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE);
-  do_check_false(postedMessage.success);
-
-  run_next_test();
-});
-
-
-add_test(function test_sendMMI_call_forwarding_registration() {
-  setCallForwardSuccess("**21*12345*99*10#");
-
-  run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_erasure() {
-  setCallForwardSuccess("##21*12345*99#");
-
-  run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_CFB() {
-  setCallForwardSuccess("*67*12345*99*10#");
-
-  run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_CFNRy() {
-  setCallForwardSuccess("*61*12345*99*10#");
-
-  run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_CFNRc() {
-  setCallForwardSuccess("*62*12345*99*10#");
-
-  run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_CFAll() {
-  setCallForwardSuccess("*004*12345*99*10#");
-
-  run_next_test();
-});
-
-add_test(function test_sendMMI_call_forwarding_CFAllConditional() {
-  setCallForwardSuccess("*002*12345*99*10#");
-
-  run_next_test();
-});
-
 add_test(function test_sendMMI_change_PIN() {
-  let workerhelper = getWorker();
+  let workerhelper = newInterceptWorker();
   let worker = workerhelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.RIL.changeICCPIN = function fakeChangeICCPIN(options) {
     context.RIL[REQUEST_ENTER_SIM_PIN](0, {
       rilRequestError: ERROR_SUCCESS
     });
   };
@@ -588,17 +120,17 @@ add_test(function test_sendMMI_change_PI
 
 add_test(function test_sendMMI_change_PIN_new_PIN_mismatch() {
   testSendMMI("**04*4567*1234*4567#", MMI_ERROR_KS_MISMATCH_PIN);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_change_PIN2() {
-  let workerhelper = getWorker();
+  let workerhelper = newInterceptWorker();
   let worker = workerhelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.RIL.changeICCPIN2 = function fakeChangeICCPIN2(options){
     context.RIL[REQUEST_ENTER_SIM_PIN2](0, {
       rilRequestError: ERROR_SUCCESS
     });
   };
@@ -634,17 +166,17 @@ add_test(function test_sendMMI_change_PI
 
 add_test(function test_sendMMI_change_PIN2_new_PIN2_mismatch() {
   testSendMMI("**042*4567*1234*4567#", MMI_ERROR_KS_MISMATCH_PIN);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_unblock_PIN() {
-  let workerhelper = getWorker();
+  let workerhelper = newInterceptWorker();
   let worker = workerhelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.RIL.enterICCPUK = function fakeEnterICCPUK(options){
     context.RIL[REQUEST_ENTER_SIM_PUK](0, {
       rilRequestError: ERROR_SUCCESS
     });
   };
@@ -680,17 +212,17 @@ add_test(function test_sendMMI_unblock_P
 
 add_test(function test_sendMMI_unblock_PIN_new_PIN_mismatch() {
   testSendMMI("**05*4567*1234*4567#", MMI_ERROR_KS_MISMATCH_PIN);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_unblock_PIN2() {
-  let workerhelper = getWorker();
+  let workerhelper = newInterceptWorker();
   let worker = workerhelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.RIL.enterICCPUK2 = function fakeEnterICCPUK2(options){
     context.RIL[REQUEST_ENTER_SIM_PUK2](0, {
       rilRequestError: ERROR_SUCCESS
     });
   };
@@ -726,17 +258,17 @@ add_test(function test_sendMMI_unblock_P
 
 add_test(function test_sendMMI_unblock_PIN2_new_PIN_mismatch() {
   testSendMMI("**052*4567*1234*4567#", MMI_ERROR_KS_MISMATCH_PIN);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_get_IMEI() {
-  let workerhelper = getWorker();
+  let workerhelper = newInterceptWorker();
   let worker = workerhelper.worker;
   let context = worker.ContextPool._contexts[0];
   let mmiOptions;
 
   context.RIL.getIMEI = function getIMEI(options){
     mmiOptions = options;
     context.RIL[REQUEST_SEND_USSD](0, {
       rilRequestError: ERROR_SUCCESS,
@@ -750,17 +282,17 @@ add_test(function test_sendMMI_get_IMEI(
   do_check_neq(mmiOptions.mmi, null);
   do_check_eq (postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
   do_check_true(postedMessage.success);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_get_IMEI_error() {
-  let workerhelper = getWorker();
+  let workerhelper = newInterceptWorker();
   let worker = workerhelper.worker;
   let context = worker.ContextPool._contexts[0];
   let mmiOptions;
 
   context.RIL.getIMEI = function getIMEI(options){
     mmiOptions = options;
     context.RIL[REQUEST_SEND_USSD](0, {
       rilRequestError: ERROR_RADIO_NOT_AVAILABLE,
@@ -774,17 +306,17 @@ add_test(function test_sendMMI_get_IMEI_
   do_check_neq(mmiOptions.mmi, null);
   do_check_eq (postedMessage.errorMsg, GECKO_ERROR_RADIO_NOT_AVAILABLE);
   do_check_false(postedMessage.success);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_call_barring_BAIC_interrogation_voice() {
-  let workerhelper = getWorker();
+  let workerhelper = newInterceptWorker();
   let worker = workerhelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.Buf.readInt32List = function fakeReadUint32List() {
     return [1];
   };
 
   context.RIL.queryICCFacilityLock =
@@ -805,17 +337,17 @@ add_test(function test_sendMMI_call_barr
   do_check_eq(postedMessage.statusMessage,  MMI_SM_KS_SERVICE_ENABLED_FOR);
   do_check_true(Array.isArray(postedMessage.additionalInformation));
   do_check_eq(postedMessage.additionalInformation[0], "serviceClassVoice");
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_call_barring_BAIC_activation() {
-  let workerhelper = getWorker();
+  let workerhelper = newInterceptWorker();
   let worker = workerhelper.worker;
   let context = worker.ContextPool._contexts[0];
   let mmiOptions;
 
   context.RIL.setICCFacilityLock =
     function fakeSetICCFacilityLock(options){
       mmiOptions = options;
       context.RIL[REQUEST_SET_FACILITY_LOCK](0, {
@@ -833,17 +365,17 @@ add_test(function test_sendMMI_call_barr
   do_check_eq(mmiOptions.procedure, MMI_PROCEDURE_ACTIVATION);
   do_check_true(postedMessage.success);
   do_check_eq(postedMessage.statusMessage,  MMI_SM_KS_SERVICE_ENABLED);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_call_barring_BAIC_deactivation() {
-  let workerhelper = getWorker();
+  let workerhelper = newInterceptWorker();
   let worker = workerhelper.worker;
   let context = worker.ContextPool._contexts[0];
   let mmiOptions;
 
   context.RIL.setICCFacilityLock =
     function fakeSetICCFacilityLock(options){
       mmiOptions = options;
       context.RIL[REQUEST_SET_FACILITY_LOCK](0, {
@@ -867,17 +399,17 @@ add_test(function test_sendMMI_call_barr
 
 add_test(function test_sendMMI_call_barring_BAIC_procedure_not_supported() {
   testSendMMI("**33*0000#", MMI_ERROR_KS_NOT_SUPPORTED);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_USSD() {
-  let workerhelper = getWorker();
+  let workerhelper = newInterceptWorker();
   let worker = workerhelper.worker;
   let context = worker.ContextPool._contexts[0];
   let ussdOptions;
 
   context.RIL.sendUSSD = function fakeSendUSSD(options){
     ussdOptions = options;
     context.RIL[REQUEST_SEND_USSD](0, {
       rilRequestError: ERROR_SUCCESS
@@ -893,17 +425,17 @@ add_test(function test_sendMMI_USSD() {
   do_check_eq (postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
   do_check_true(postedMessage.success);
   do_check_true(context.RIL._ussdSession);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_USSD_error() {
-  let workerhelper = getWorker();
+  let workerhelper = newInterceptWorker();
   let worker = workerhelper.worker;
   let context = worker.ContextPool._contexts[0];
   let ussdOptions;
 
   context.RIL.sendUSSD = function fakeSendUSSD(options){
     ussdOptions = options;
     context.RIL[REQUEST_SEND_USSD](0, {
       rilRequestError: ERROR_GENERIC_FAILURE
@@ -919,17 +451,17 @@ add_test(function test_sendMMI_USSD_erro
   do_check_eq (postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE);
   do_check_false(postedMessage.success);
   do_check_false(context.RIL._ussdSession);
 
   run_next_test();
 });
 
 function setCallWaitingSuccess(mmi) {
-  let workerhelper = getWorker();
+  let workerhelper = newInterceptWorker();
   let worker = workerhelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.RIL.setCallWaiting = function fakeSetCallWaiting(options) {
     context.RIL[REQUEST_SET_CALL_WAITING](0, {
       rilRequestError: ERROR_SUCCESS
     });
   };
@@ -963,17 +495,17 @@ add_test(function test_sendMMI_call_wait
 
 add_test(function test_sendMMI_call_waiting_erasure() {
   testSendMMI("##43#", MMI_ERROR_KS_NOT_SUPPORTED);
 
   run_next_test();
 });
 
 add_test(function test_sendMMI_call_waiting_interrogation() {
-  let workerhelper = getWorker();
+  let workerhelper = newInterceptWorker();
   let worker = workerhelper.worker;
   let context = worker.ContextPool._contexts[0];
 
   context.Buf.readInt32 = function fakeReadUint32() {
     return context.Buf.int32Array.pop();
   };
 
   context.RIL.queryCallWaiting = function fakeQueryCallWaiting(options) {
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_mmi_cf.js
@@ -0,0 +1,151 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+function run_test() {
+  run_next_test();
+}
+
+function setCallForwardSuccess(mmi) {
+  let workerhelper = newInterceptWorker();
+  let worker = workerhelper.worker;
+  let context = worker.ContextPool._contexts[0];
+
+  context.RIL.setCallForward = function fakeSetCallForward(options) {
+    context.RIL[REQUEST_SET_CALL_FORWARD](0, {
+      rilRequestError: ERROR_SUCCESS
+    });
+  };
+
+  context.RIL.radioState = GECKO_RADIOSTATE_READY;
+  context.RIL.sendMMI({mmi: mmi});
+
+  let postedMessage = workerhelper.postedMessage;
+
+  do_check_eq(postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
+  do_check_true(postedMessage.success);
+}
+
+add_test(function test_sendMMI_call_forwarding_activation() {
+  setCallForwardSuccess("*21*12345*99*10#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_deactivation() {
+  setCallForwardSuccess("#21*12345*99*10#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_interrogation() {
+  let workerhelper = newInterceptWorker();
+  let worker = workerhelper.worker;
+  let context = worker.ContextPool._contexts[0];
+
+  context.Buf.readInt32 = function fakeReadUint32() {
+    return context.Buf.int32Array.pop();
+  };
+
+  context.Buf.readString = function fakeReadString() {
+    return "+34666222333";
+  };
+
+  context.RIL.queryCallForwardStatus = function fakeQueryCallForward(options) {
+    context.Buf.int32Array = [
+      0,   // rules.timeSeconds
+      145, // rules.toa
+      49,  // rules.serviceClass
+      CALL_FORWARD_REASON_UNCONDITIONAL, // rules.reason
+      1,   // rules.active
+      1    // rulesLength
+    ];
+    context.RIL[REQUEST_QUERY_CALL_FORWARD_STATUS](1, {
+      rilRequestError: ERROR_SUCCESS
+    });
+  };
+
+  context.RIL.radioState = GECKO_RADIOSTATE_READY;
+  context.RIL.sendMMI({mmi: "*#21#"});
+
+  let postedMessage = workerhelper.postedMessage;
+
+  do_check_eq(postedMessage.errorMsg, GECKO_ERROR_SUCCESS);
+  do_check_true(postedMessage.success);
+  do_check_true(Array.isArray(postedMessage.rules));
+  do_check_eq(postedMessage.rules.length, 1);
+  do_check_true(postedMessage.rules[0].active);
+  do_check_eq(postedMessage.rules[0].reason, CALL_FORWARD_REASON_UNCONDITIONAL);
+  do_check_eq(postedMessage.rules[0].number, "+34666222333");
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_interrogation_no_rules() {
+  let workerhelper = newInterceptWorker();
+  let worker = workerhelper.worker;
+  let context = worker.ContextPool._contexts[0];
+
+  context.Buf.readInt32 = function fakeReadUint32() {
+    return 0;
+  };
+
+  context.RIL.queryCallForwardStatus = function fakeQueryCallForward(options) {
+    context.RIL[REQUEST_QUERY_CALL_FORWARD_STATUS](1, {
+      rilRequestError: ERROR_SUCCESS
+    });
+  };
+
+  context.RIL.radioState = GECKO_RADIOSTATE_READY;
+  context.RIL.sendMMI({mmi: "*#21#"});
+
+  let postedMessage = workerhelper.postedMessage;
+
+  do_check_eq(postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE);
+  do_check_false(postedMessage.success);
+
+  run_next_test();
+});
+
+
+add_test(function test_sendMMI_call_forwarding_registration() {
+  setCallForwardSuccess("**21*12345*99*10#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_erasure() {
+  setCallForwardSuccess("##21*12345*99#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_CFB() {
+  setCallForwardSuccess("*67*12345*99*10#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_CFNRy() {
+  setCallForwardSuccess("*61*12345*99*10#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_CFNRc() {
+  setCallForwardSuccess("*62*12345*99*10#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_CFAll() {
+  setCallForwardSuccess("*004*12345*99*10#");
+
+  run_next_test();
+});
+
+add_test(function test_sendMMI_call_forwarding_CFAllConditional() {
+  setCallForwardSuccess("*002*12345*99*10#");
+
+  run_next_test();
+});
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_mmi_parseMMI.js
@@ -0,0 +1,317 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+function run_test() {
+  run_next_test();
+}
+
+let worker;
+function parseMMI(mmi) {
+  if (!worker) {
+    worker = newWorker({
+      postRILMessage: function(data) {
+        // Do nothing
+      },
+      postMessage: function(message) {
+        // Do nothing
+      }
+    });
+  }
+
+  let context = worker.ContextPool._contexts[0];
+  return context.RIL._parseMMI(mmi);
+}
+
+add_test(function test_parseMMI_empty() {
+  let mmi = parseMMI("");
+
+  do_check_null(mmi);
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_undefined() {
+  let mmi = parseMMI();
+
+  do_check_null(mmi);
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_one_digit_short_code() {
+  let mmi = parseMMI("1");
+
+  do_check_eq(mmi.fullMMI, "1");
+  do_check_eq(mmi.procedure, undefined);
+  do_check_eq(mmi.serviceCode, undefined);
+  do_check_eq(mmi.sia, undefined);
+  do_check_eq(mmi.sib, undefined);
+  do_check_eq(mmi.sic, undefined);
+  do_check_eq(mmi.pwd, undefined);
+  do_check_eq(mmi.dialNumber, undefined);
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_invalid_short_code() {
+  let mmi = parseMMI("11");
+
+  do_check_null(mmi);
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_short_code() {
+  let mmi = parseMMI("21");
+
+  do_check_eq(mmi.fullMMI, "21");
+  do_check_eq(mmi.procedure, undefined);
+  do_check_eq(mmi.serviceCode, undefined);
+  do_check_eq(mmi.sia, undefined);
+  do_check_eq(mmi.sib, undefined);
+  do_check_eq(mmi.sic, undefined);
+  do_check_eq(mmi.pwd, undefined);
+  do_check_eq(mmi.dialNumber, undefined);
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_dial_string() {
+  let mmi = parseMMI("12345");
+
+  do_check_null(mmi);
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_USSD_without_asterisk_prefix() {
+  let mmi = parseMMI("123#");
+
+  do_check_eq(mmi.fullMMI, "123#");
+  do_check_eq(mmi.procedure, undefined);
+  do_check_eq(mmi.serviceCode, undefined);
+  do_check_eq(mmi.sia, undefined);
+  do_check_eq(mmi.sib, undefined);
+  do_check_eq(mmi.sic, undefined);
+  do_check_eq(mmi.pwd, undefined);
+  do_check_eq(mmi.dialNumber, undefined);
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_USSD() {
+  let mmi = parseMMI("*123#");
+
+  do_check_eq(mmi.fullMMI, "*123#");
+  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+  do_check_eq(mmi.serviceCode, "123");
+  do_check_eq(mmi.sia, undefined);
+  do_check_eq(mmi.sib, undefined);
+  do_check_eq(mmi.sic, undefined);
+  do_check_eq(mmi.pwd, undefined);
+  do_check_eq(mmi.dialNumber, "");
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_sia() {
+  let mmi = parseMMI("*123*1#");
+
+  do_check_eq(mmi.fullMMI, "*123*1#");
+  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+  do_check_eq(mmi.serviceCode, "123");
+  do_check_eq(mmi.sia, "1");
+  do_check_eq(mmi.sib, undefined);
+  do_check_eq(mmi.sic, undefined);
+  do_check_eq(mmi.pwd, undefined);
+  do_check_eq(mmi.dialNumber, "");
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_sib() {
+  let mmi = parseMMI("*123**1#");
+
+  do_check_eq(mmi.fullMMI, "*123**1#");
+  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+  do_check_eq(mmi.serviceCode, "123");
+  do_check_eq(mmi.sia, "");
+  do_check_eq(mmi.sib, "1");
+  do_check_eq(mmi.sic, undefined);
+  do_check_eq(mmi.pwd, undefined);
+  do_check_eq(mmi.dialNumber, "");
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_sic() {
+  let mmi = parseMMI("*123***1#");
+
+  do_check_eq(mmi.fullMMI, "*123***1#");
+  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+  do_check_eq(mmi.serviceCode, "123");
+  do_check_eq(mmi.sia, "");
+  do_check_eq(mmi.sib, "");
+  do_check_eq(mmi.sic, "1");
+  do_check_eq(mmi.pwd, undefined);
+  do_check_eq(mmi.dialNumber, "");
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_sia_sib() {
+  let mmi = parseMMI("*123*1*1#");
+
+  do_check_eq(mmi.fullMMI, "*123*1*1#");
+  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+  do_check_eq(mmi.serviceCode, "123");
+  do_check_eq(mmi.sia, "1");
+  do_check_eq(mmi.sib, "1");
+  do_check_eq(mmi.sic, undefined);
+  do_check_eq(mmi.pwd, undefined);
+  do_check_eq(mmi.dialNumber, "");
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_sia_sic() {
+  let mmi = parseMMI("*123*1**1#");
+
+  do_check_eq(mmi.fullMMI, "*123*1**1#");
+  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+  do_check_eq(mmi.serviceCode, "123");
+  do_check_eq(mmi.sia, "1");
+  do_check_eq(mmi.sib, "");
+  do_check_eq(mmi.sic, "1");
+  do_check_eq(mmi.pwd, undefined);
+  do_check_eq(mmi.dialNumber, "");
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_sib_sic() {
+  let mmi = parseMMI("*123**1*1#");
+
+  do_check_eq(mmi.fullMMI, "*123**1*1#");
+  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+  do_check_eq(mmi.serviceCode, "123");
+  do_check_eq(mmi.sia, "");
+  do_check_eq(mmi.sib, "1");
+  do_check_eq(mmi.sic, "1");
+  do_check_eq(mmi.pwd, undefined);
+  do_check_eq(mmi.dialNumber, "");
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_pwd() {
+  let mmi = parseMMI("*123****1#");
+
+  do_check_eq(mmi.fullMMI, "*123****1#");
+  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+  do_check_eq(mmi.serviceCode, "123");
+  do_check_eq(mmi.sia, "");
+  do_check_eq(mmi.sib, "");
+  do_check_eq(mmi.sic, "");
+  do_check_eq(mmi.pwd, "1");
+  do_check_eq(mmi.dialNumber, "");
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_dial_number() {
+  let mmi = parseMMI("*123#345");
+
+  do_check_eq(mmi.fullMMI, "*123#");
+  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+  do_check_eq(mmi.serviceCode, "123");
+  do_check_eq(mmi.sia, undefined);
+  do_check_eq(mmi.sib, undefined);
+  do_check_eq(mmi.sic, undefined);
+  do_check_eq(mmi.pwd, undefined);
+  do_check_eq(mmi.dialNumber, "345");
+
+  run_next_test();
+});
+
+
+/**
+ * MMI procedures tests
+ */
+
+add_test(function test_parseMMI_activation() {
+  let mmi = parseMMI("*00*12*34*56#");
+
+  do_check_eq(mmi.fullMMI, "*00*12*34*56#");
+  do_check_eq(mmi.procedure, MMI_PROCEDURE_ACTIVATION);
+  do_check_eq(mmi.serviceCode, "00");
+  do_check_eq(mmi.sia, "12");
+  do_check_eq(mmi.sib, "34");
+  do_check_eq(mmi.sic, "56");
+  do_check_eq(mmi.pwd, undefined);
+  do_check_eq(mmi.dialNumber, "");
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_deactivation() {
+  let mmi = parseMMI("#00*12*34*56#");
+
+  do_check_eq(mmi.fullMMI, "#00*12*34*56#");
+  do_check_eq(mmi.procedure, MMI_PROCEDURE_DEACTIVATION);
+  do_check_eq(mmi.serviceCode, "00");
+  do_check_eq(mmi.sia, "12");
+  do_check_eq(mmi.sib, "34");
+  do_check_eq(mmi.sic, "56");
+  do_check_eq(mmi.pwd, undefined);
+  do_check_eq(mmi.dialNumber, "");
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_interrogation() {
+  let mmi = parseMMI("*#00*12*34*56#");
+
+  do_check_eq(mmi.fullMMI, "*#00*12*34*56#");
+  do_check_eq(mmi.procedure, MMI_PROCEDURE_INTERROGATION);
+  do_check_eq(mmi.serviceCode, "00");
+  do_check_eq(mmi.sia, "12");
+  do_check_eq(mmi.sib, "34");
+  do_check_eq(mmi.sic, "56");
+  do_check_eq(mmi.pwd, undefined);
+  do_check_eq(mmi.dialNumber, "");
+
+  run_next_test();
+});
+
+add_test(function test_parseMMI_registration() {
+  let mmi = parseMMI("**00*12*34*56#");
+
+  do_check_eq(mmi.fullMMI, "**00*1