Merge b2g-inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 11 Feb 2014 14:57:31 -0500
changeset 168182 802d87c77e76506e7ff16b285f02d31d73f5c8d9
parent 168126 bd4f1281c3b756cbfb0a5de49110ef6e86b7a014 (current diff)
parent 168181 af7f0f64d659f52053e6380e3814ba8e31be5953 (diff)
child 168183 516b308b2d6d443967c165afe2294c5ae800ee88
child 168269 562a915cea9cfc51fdfbaaae02ce4b5c501aa488
child 168329 88b967f316b6988aa434c8fed852c264efc9a933
push id39655
push userryanvm@gmail.com
push dateTue, 11 Feb 2014 19:58:40 +0000
treeherdermozilla-inbound@516b308b2d6d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone30.0a1
first release with
nightly linux32
802d87c77e76 / 30.0a1 / 20140212030201 / files
nightly linux64
802d87c77e76 / 30.0a1 / 20140212030201 / files
nightly mac
802d87c77e76 / 30.0a1 / 20140212030201 / files
nightly win32
802d87c77e76 / 30.0a1 / 20140212030201 / files
nightly win64
802d87c77e76 / 30.0a1 / 20140212030201 / 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.
b2g/app/b2g.js
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -7,17 +7,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="87aa8679560ce09f6445621d6f370d9de722cdba"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -6,17 +6,17 @@
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="317f25e0a4cb3e8e86e2b76c37a14081372f0307">
     <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="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -7,17 +7,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="87aa8679560ce09f6445621d6f370d9de722cdba"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "052499d9ddb89a1168cb5fcd092c15095ef3a6a9", 
+    "revision": "01b437206d143e1632ee5a5fd49cc649aee2e970", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -6,17 +6,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -5,17 +5,17 @@
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <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/inari/sources.xml
+++ b/b2g/config/inari/sources.xml
@@ -7,17 +7,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/sources.xml
@@ -6,17 +6,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/sources.xml
@@ -6,17 +6,17 @@
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="317f25e0a4cb3e8e86e2b76c37a14081372f0307">
     <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="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -6,17 +6,17 @@
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <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="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <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="bbe0fd0ca135d089b662975eeced57530ebb7554"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4c6b5142d3b716f1c4ea502eeb92d3119f2b01c6"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="78b908b493bfe0b477e3d4f6edec8c46a2c0d096"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a314508e397c8f1814228d36259ea8708034444e"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/content/media/MediaCache.cpp
+++ b/content/media/MediaCache.cpp
@@ -376,17 +376,18 @@ MediaCacheStream::MediaCacheStream(Chann
     mCacheSuspended(false),
     mChannelEnded(false),
     mChannelOffset(0),
     mStreamLength(-1),
     mStreamOffset(0),
     mPlaybackBytesPerSecond(10000),
     mPinCount(0),
     mCurrentMode(MODE_PLAYBACK),
-    mMetadataInPartialBlockBuffer(false)
+    mMetadataInPartialBlockBuffer(false),
+    mPartialBlockBuffer(new int64_t[BLOCK_SIZE/sizeof(int64_t)])
 {
 }
 
 void MediaCacheStream::BlockList::AddFirstBlock(int32_t aBlock)
 {
   NS_ASSERTION(!mEntries.GetEntry(aBlock), "Block already in list");
   Entry* entry = mEntries.PutEntry(aBlock);
 
@@ -1730,22 +1731,22 @@ MediaCacheStream::NotifyDataReceived(int
       // mPartialBlockBuffer
       blockDataToStore = data;
     } else {
       if (blockOffset == 0) {
         // We've just started filling this buffer so now is a good time
         // to clear this flag.
         mMetadataInPartialBlockBuffer = false;
       }
-      memcpy(reinterpret_cast<char*>(mPartialBlockBuffer) + blockOffset,
+      memcpy(reinterpret_cast<char*>(mPartialBlockBuffer.get()) + blockOffset,
              data, chunkSize);
 
       if (blockOffset + chunkSize == BLOCK_SIZE) {
         // We completed a block, so lets write it out.
-        blockDataToStore = reinterpret_cast<char*>(mPartialBlockBuffer);
+        blockDataToStore = reinterpret_cast<char*>(mPartialBlockBuffer.get());
         if (mMetadataInPartialBlockBuffer) {
           mode = MODE_METADATA;
         }
       }
     }
 
     if (blockDataToStore) {
       gMediaCache->AllocateAndWriteBlock(this, blockDataToStore, mode);
@@ -1783,17 +1784,17 @@ MediaCacheStream::FlushPartialBlockInter
     CACHE_LOG(PR_LOG_DEBUG,
               ("Stream %p writing partial block: [%d] bytes; "
                "mStreamOffset [%lld] mChannelOffset[%lld] mStreamLength [%lld] "
                "notifying: [%s]",
                this, blockOffset, mStreamOffset, mChannelOffset, mStreamLength,
                aNotifyAll ? "yes" : "no"));
 
     // Write back the partial block
-    memset(reinterpret_cast<char*>(mPartialBlockBuffer) + blockOffset, 0,
+    memset(reinterpret_cast<char*>(mPartialBlockBuffer.get()) + blockOffset, 0,
            BLOCK_SIZE - blockOffset);
     gMediaCache->AllocateAndWriteBlock(this, mPartialBlockBuffer,
         mMetadataInPartialBlockBuffer ? MODE_METADATA : MODE_PLAYBACK);
     if (aNotifyAll) {
       // Wake up readers who may be waiting for this data
       mon.NotifyAll();
     }
   }
@@ -2177,17 +2178,17 @@ MediaCacheStream::Read(char* aBuffer, ui
         }
       }
       if (streamWithPartialBlock) {
         // We can just use the data in mPartialBlockBuffer. In fact we should
         // use it rather than waiting for the block to fill and land in
         // the cache.
         bytes = std::min<int64_t>(size, streamWithPartialBlock->mChannelOffset - mStreamOffset);
         memcpy(aBuffer,
-          reinterpret_cast<char*>(streamWithPartialBlock->mPartialBlockBuffer) + offsetInStreamBlock, bytes);
+          reinterpret_cast<char*>(streamWithPartialBlock->mPartialBlockBuffer.get()) + offsetInStreamBlock, bytes);
         if (mCurrentMode == MODE_METADATA) {
           streamWithPartialBlock->mMetadataInPartialBlockBuffer = true;
         }
         mStreamOffset += bytes;
         count = bytes;
         break;
       }
 
@@ -2272,17 +2273,17 @@ MediaCacheStream::ReadFromCache(char* aB
     uint32_t channelBlock = uint32_t(mChannelOffset/BLOCK_SIZE);
     int32_t cacheBlock = streamBlock < mBlocks.Length() ? mBlocks[streamBlock] : -1;
     if (channelBlock == streamBlock && streamOffset < mChannelOffset) {
       // We can just use the data in mPartialBlockBuffer. In fact we should
       // use it rather than waiting for the block to fill and land in
       // the cache.
       bytes = std::min<int64_t>(size, mChannelOffset - streamOffset);
       memcpy(aBuffer + count,
-        reinterpret_cast<char*>(mPartialBlockBuffer) + offsetInStreamBlock, bytes);
+        reinterpret_cast<char*>(mPartialBlockBuffer.get()) + offsetInStreamBlock, bytes);
     } else {
       if (cacheBlock < 0) {
         // We expect all blocks to be cached! Fail!
         return NS_ERROR_FAILURE;
       }
       int64_t offset = cacheBlock*BLOCK_SIZE + offsetInStreamBlock;
       NS_ABORT_IF_FALSE(size >= 0 && size <= INT32_MAX, "Size out of range.");
       nsresult rv = gMediaCache->ReadCacheFile(offset, aBuffer + count, int32_t(size), &bytes);
--- a/content/media/MediaCache.h
+++ b/content/media/MediaCache.h
@@ -494,14 +494,16 @@ private:
   // The following field is protected by the cache's monitor but are
   // only written on the main thread.
 
   // Data received for the block containing mChannelOffset. Data needs
   // to wait here so we can write back a complete block. The first
   // mChannelOffset%BLOCK_SIZE bytes have been filled in with good data,
   // the rest are garbage.
   // Use int64_t so that the data is well-aligned.
-  int64_t           mPartialBlockBuffer[BLOCK_SIZE/sizeof(int64_t)];
+  // Heap allocate this buffer since the exact power-of-2 will cause allocation
+  // slop when combined with the rest of the object members.
+  nsAutoArrayPtr<int64_t> mPartialBlockBuffer;
 };
 
 } // namespace mozilla
 
 #endif
--- a/content/media/MediaRecorder.cpp
+++ b/content/media/MediaRecorder.cpp
@@ -81,17 +81,17 @@ class MediaRecorder::Session: public nsI
     NS_IMETHODIMP Run()
     {
       MOZ_ASSERT(NS_IsMainThread());
 
       MediaRecorder *recorder = mSession->mRecorder;
       if (mSession->IsEncoderError()) {
         recorder->NotifyError(NS_ERROR_UNEXPECTED);
       }
-      nsresult rv = recorder->CreateAndDispatchBlobEvent(mSession);
+      nsresult rv = recorder->CreateAndDispatchBlobEvent(mSession->GetEncodedData());
       if (NS_FAILED(rv)) {
         recorder->NotifyError(rv);
       }
       return NS_OK;
     }
 
   private:
     nsRefPtr<Session> mSession;
@@ -539,18 +539,18 @@ void
 MediaRecorder::RequestData(ErrorResult& aResult)
 {
   if (mState != RecordingState::Recording) {
     aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   NS_DispatchToMainThread(
-    NS_NewRunnableMethodWithArg<Session *>(this,
-                                           &MediaRecorder::CreateAndDispatchBlobEvent, mSession),
+    NS_NewRunnableMethodWithArg<const already_AddRefed<nsIDOMBlob> >(this,
+      &MediaRecorder::CreateAndDispatchBlobEvent, mSession->GetEncodedData()),
     NS_DISPATCH_NORMAL);
 }
 
 JSObject*
 MediaRecorder::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return MediaRecorderBinding::Wrap(aCx, aScope, this);
 }
@@ -571,29 +571,29 @@ MediaRecorder::Constructor(const GlobalO
     return nullptr;
   }
 
   nsRefPtr<MediaRecorder> object = new MediaRecorder(aStream, ownerWindow);
   return object.forget();
 }
 
 nsresult
-MediaRecorder::CreateAndDispatchBlobEvent(Session *aSession)
+MediaRecorder::CreateAndDispatchBlobEvent(const already_AddRefed<nsIDOMBlob> &aBlob)
 {
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
 
   if (!CheckPrincipal()) {
     // Media is not same-origin, don't allow the data out.
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   BlobEventInit init;
   init.mBubbles = false;
   init.mCancelable = false;
-  init.mData = aSession->GetEncodedData();
+  init.mData = aBlob;
   nsRefPtr<BlobEvent> event =
     BlobEvent::Constructor(this,
                            NS_LITERAL_STRING("dataavailable"),
                            init);
   event->SetTrusted(true);
   return DispatchDOMEvent(nullptr, event, nullptr, nullptr);
 }
 
--- a/content/media/MediaRecorder.h
+++ b/content/media/MediaRecorder.h
@@ -80,17 +80,17 @@ public:
   IMPL_EVENT_HANDLER(dataavailable)
   IMPL_EVENT_HANDLER(error)
   IMPL_EVENT_HANDLER(stop)
   IMPL_EVENT_HANDLER(warning)
 
 protected:
   MediaRecorder& operator = (const MediaRecorder& x) MOZ_DELETE;
   // Create dataavailable event with Blob data and it runs in main thread
-  nsresult CreateAndDispatchBlobEvent(Session *session);
+  nsresult CreateAndDispatchBlobEvent(const already_AddRefed<nsIDOMBlob> &aBlob);
   // Creating a simple event to notify UA simple event.
   void DispatchSimpleEvent(const nsAString & aStr);
   // Creating a error event with message.
   void NotifyError(nsresult aRv);
   // Check if the recorder's principal is the subsume of mediaStream
   bool CheckPrincipal();
   // Set encoded MIME type.
   void SetMimeType(const nsString &aMimeType);
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -253,16 +253,17 @@ support-files =
 [test_source_media.html]
 [test_autoplay_contentEditable.html]
 [test_decoder_disable.html]
 [test_mediarecorder_record_no_timeslice.html]
 [test_mediarecorder_reload_crash.html]
 [test_mediarecorder_record_immediate_stop.html]
 [test_mediarecorder_record_session.html]
 [test_mediarecorder_record_startstopstart.html]
+[test_mediarecorder_getencodeddata.html]
 [test_mediarecorder_unsupported_src.html]
 [test_playback.html]
 [test_seekLies.html]
 [test_media_sniffer.html]
 [test_streams_srcObject.html]
 [test_reset_src.html]
 [test_streams_autoplay.html]
 [test_streams_element_capture.html]
new file mode 100644
--- /dev/null
+++ b/content/media/test/test_mediarecorder_getencodeddata.html
@@ -0,0 +1,68 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 957452 Test GetEncodedData problem on asan build</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+SimpleTest.waitForExplicitFinish();
+SpecialPowers.pushPrefEnv({"set": [["media.ogg.enabled", false]]},
+  function () {
+    var ac = new window.AudioContext();
+    var dest = ac.createMediaStreamDestination();
+    var stream = dest.stream;
+    var onErrorFired = false;
+    var expectedMimeType = '';
+    var ondataavailableFired = false;
+    setTimeout(function() {
+      var mediaRecorder = new MediaRecorder(stream);
+      mediaRecorder.onstop = function(e) {
+        is(e.target.state, 'inactive',
+           'Media recorder is inactive after being stopped');
+        ok(onErrorFired, 'onStop after onError');
+        ok(ondataavailableFired, 'ondataavailableFired');
+
+        SimpleTest.finish();
+      }
+      mediaRecorder.ondataavailable = function(evt) {
+        if (onErrorFired) {
+          ondataavailableFired = true;
+          ok(evt instanceof BlobEvent,
+             'Events fired from ondataavailable should be BlobEvent');
+          is(evt.type, 'dataavailable',
+             'Event type should dataavailable');
+          is(evt.data.size, 0,
+             'Blob data size received is equal to zero');
+          is(evt.data.type, expectedMimeType,
+             'Blob data received should have type = ' + expectedMimeType);
+          is(evt.target.mimeType, expectedMimeType,
+             'Mime type in ondataavailable = ' + expectedMimeType);
+        } else {
+          ok(false, 'should get onError first');
+        }
+      }
+      mediaRecorder.onerror = function(evt) {
+        ok(evt instanceof RecordErrorEvent,
+          'Events fired from onerror should be RecordErrorEvent');
+        is(evt.type, 'error',
+           'Event type should onerror');
+        is(evt.name, 'GenericError',
+           'Event name is GenericError');
+        onErrorFired = true;
+      }
+      mediaRecorder.start(0);
+      is(mediaRecorder.state, 'recording', 'Media recorder should be recording');
+      is(mediaRecorder.stream, stream,
+         'Media recorder stream = element stream at the start of recording');
+      mediaRecorder.requestData();
+      mediaRecorder.stop();
+    }, 100);
+  }
+);
+</script>
+</pre>
+</body>
+</html>
--- a/dom/contacts/fallback/ContactDB.jsm
+++ b/dom/contacts/fallback/ContactDB.jsm
@@ -15,34 +15,25 @@ const Cu = Components.utils;
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
 Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
 Cu.importGlobalProperties(["indexedDB"]);
 
-const DB_NAME = "contacts";
-const DB_VERSION = 18;
-const STORE_NAME = "contacts";
-const SAVED_GETALL_STORE_NAME = "getallcache";
+/* all exported symbols need to be bound to this on B2G - Bug 961777 */
+this.DB_NAME = "contacts";
+this.DB_VERSION = 19;
+this.STORE_NAME = "contacts";
+this.SAVED_GETALL_STORE_NAME = "getallcache";
 const CHUNK_SIZE = 20;
-const REVISION_STORE = "revision";
+this.REVISION_STORE = "revision";
 const REVISION_KEY = "revision";
 
-function optionalDate(aValue) {
-  if (aValue) {
-    if (!(aValue instanceof Date)) {
-      return new Date(aValue);
-    }
-    return aValue;
-  }
-  return undefined;
-}
-
 function exportContact(aRecord) {
   if (aRecord) {
     delete aRecord.search;
   }
   return aRecord;
 }
 
 function ContactDispatcher(aContacts, aFullContacts, aCallback, aNewTxn, aClearDispatcher, aFailureCb) {
@@ -177,17 +168,26 @@ ContactDB.prototype = {
       objectStore.createIndex("tel", "search.exactTel", { multiEntry: true });
       objectStore.createIndex("category", "properties.category", { multiEntry: true });
       objectStore.createIndex("email", "search.email", { multiEntry: true });
       objectStore.createIndex("telMatch", "search.parsedTel", {multiEntry: true});
       aDb.createObjectStore(SAVED_GETALL_STORE_NAME);
       aDb.createObjectStore(REVISION_STORE).put(0, REVISION_KEY);
     }
 
-    if (DEBUG) debug("upgrade schema from: " + aOldVersion + " to " + aNewVersion + " called!");
+    let valueUpgradeSteps = [];
+
+    function scheduleValueUpgrade(upgradeFunc) {
+      var length = valueUpgradeSteps.push(upgradeFunc);
+      if (DEBUG) debug("Scheduled a value upgrade function, index " + (length - 1));
+    }
+
+    // We always output this debug line because it's useful and the noise ratio
+    // very low.
+    debug("upgrade schema from: " + aOldVersion + " to " + aNewVersion + " called!");
     let db = aDb;
     let objectStore;
 
     if (aOldVersion === 0 && this.useFastUpgrade) {
       createFinalSchema();
       loadInitialContacts();
       return;
     }
@@ -486,274 +486,304 @@ ContactDB.prototype = {
           } else {
             next();
           }
         };
       },
       function upgrade12to13() {
         if (DEBUG) debug("Add phone substring to the search index if appropriate for country");
         if (this.substringMatching) {
-          if (!objectStore) {
-            objectStore = aTransaction.objectStore(STORE_NAME);
-          }
-          objectStore.openCursor().onsuccess = function(event) {
-            let cursor = event.target.result;
-            if (cursor) {
-              if (cursor.value.properties.tel) {
-                cursor.value.search.parsedTel = cursor.value.search.parsedTel || [];
-                cursor.value.properties.tel.forEach(
-                  function(tel) {
-                    let normalized = PhoneNumberUtils.normalize(tel.value.toString());
-                    if (normalized) {
-                      if (this.substringMatching && normalized.length > this.substringMatching) {
-                        let sub = normalized.slice(-this.substringMatching);
-                        if (cursor.value.search.parsedTel.indexOf(sub) === -1) {
-                          if (DEBUG) debug("Adding substring index: " + tel + ", " + sub);
-                          cursor.value.search.parsedTel.push(sub);
-                        }
+          scheduleValueUpgrade(function upgradeValue12to13(value) {
+            if (value.properties.tel) {
+              value.search.parsedTel = value.search.parsedTel || [];
+              value.properties.tel.forEach(
+                function(tel) {
+                  let normalized = PhoneNumberUtils.normalize(tel.value.toString());
+                  if (normalized) {
+                    if (this.substringMatching && normalized.length > this.substringMatching) {
+                      let sub = normalized.slice(-this.substringMatching);
+                      if (value.search.parsedTel.indexOf(sub) === -1) {
+                        if (DEBUG) debug("Adding substring index: " + tel + ", " + sub);
+                        value.search.parsedTel.push(sub);
                       }
                     }
-                  }.bind(this)
-                );
-                cursor.update(cursor.value);
-              }
-              cursor.continue();
+                  }
+                }.bind(this)
+              );
+              return true;
             } else {
-              next();
+              return false;
             }
-          }.bind(this);
-        } else {
-          next();
+          }.bind(this));
         }
+        next();
       },
       function upgrade13to14() {
         if (DEBUG) debug("Cleaning up empty substring entries in telMatch index");
-        if (!objectStore) {
-          objectStore = aTransaction.objectStore(STORE_NAME);
-        }
-        objectStore.openCursor().onsuccess = function(event) {
+        scheduleValueUpgrade(function upgradeValue13to14(value) {
           function removeEmptyStrings(value) {
             if (value) {
               const oldLength = value.length;
               for (let i = 0; i < value.length; ++i) {
                 if (!value[i] || value[i] == "null") {
                   value.splice(i, 1);
                 }
               }
               return oldLength !== value.length;
             }
           }
 
-          let cursor = event.target.result;
-          if (cursor) {
-            let modified = removeEmptyStrings(cursor.value.search.parsedTel);
-            let modified2 = removeEmptyStrings(cursor.value.search.tel);
-            if (modified || modified2) {
-              cursor.update(cursor.value);
-            }
-            cursor.continue();
-          } else {
-            next();
-          }
-        };
+          let modified = removeEmptyStrings(value.search.parsedTel);
+          let modified2 = removeEmptyStrings(value.search.tel);
+          return (modified || modified2);
+        });
+
+        next();
       },
       function upgrade14to15() {
         if (DEBUG) debug("Fix array properties saved as scalars");
-        if (!objectStore) {
-          objectStore = aTransaction.objectStore(STORE_NAME);
-        }
         const ARRAY_PROPERTIES = ["photo", "adr", "email", "url", "impp", "tel",
                                  "name", "honorificPrefix", "givenName",
                                  "additionalName", "familyName", "honorificSuffix",
                                  "nickname", "category", "org", "jobTitle",
                                  "note", "key"];
         const PROPERTIES_WITH_TYPE = ["adr", "email", "url", "impp", "tel"];
-        objectStore.openCursor().onsuccess = function(event) {
-          let cursor = event.target.result;
+
+        scheduleValueUpgrade(function upgradeValue14to15(value) {
           let changed = false;
-          if (cursor) {
-            let props = cursor.value.properties;
-            for (let prop of ARRAY_PROPERTIES) {
-              if (props[prop]) {
-                if (!Array.isArray(props[prop])) {
-                  cursor.value.properties[prop] = [props[prop]];
-                  changed = true;
-                }
-                if (PROPERTIES_WITH_TYPE.indexOf(prop) !== -1) {
-                  let subprop = cursor.value.properties[prop];
-                  for (let i = 0; i < subprop.length; ++i) {
-                    if (!Array.isArray(subprop[i].type)) {
-                      cursor.value.properties[prop][i].type = [subprop[i].type];
-                      changed = true;
-                    }
+
+          let props = value.properties;
+          for (let prop of ARRAY_PROPERTIES) {
+            if (props[prop]) {
+              if (!Array.isArray(props[prop])) {
+                value.properties[prop] = [props[prop]];
+                changed = true;
+              }
+              if (PROPERTIES_WITH_TYPE.indexOf(prop) !== -1) {
+                let subprop = value.properties[prop];
+                for (let i = 0; i < subprop.length; ++i) {
+                  if (!Array.isArray(subprop[i].type)) {
+                    value.properties[prop][i].type = [subprop[i].type];
+                    changed = true;
                   }
                 }
               }
             }
-            if (changed) {
-              cursor.update(cursor.value);
-            }
-            cursor.continue();
-          } else {
-           next();
           }
-        };
+
+          return changed;
+        });
+
+        next();
       },
       function upgrade15to16() {
         if (DEBUG) debug("Fix Date properties");
-        if (!objectStore) {
-          objectStore = aTransaction.objectStore(STORE_NAME);
-        }
         const DATE_PROPERTIES = ["bday", "anniversary"];
-        objectStore.openCursor().onsuccess = function(event) {
-          let cursor = event.target.result;
+
+        scheduleValueUpgrade(function upgradeValue15to16(value) {
           let changed = false;
-          if (cursor) {
-            let props = cursor.value.properties;
-            for (let prop of DATE_PROPERTIES) {
-              if (props[prop] && !(props[prop] instanceof Date)) {
-                cursor.value.properties[prop] = new Date(props[prop]);
-                changed = true;
-              }
+          let props = value.properties;
+          for (let prop of DATE_PROPERTIES) {
+            if (props[prop] && !(props[prop] instanceof Date)) {
+              value.properties[prop] = new Date(props[prop]);
+              changed = true;
             }
-            if (changed) {
-              cursor.update(cursor.value);
-            }
-            cursor.continue();
-          } else {
-           next();
           }
-        };
+
+          return changed;
+        });
+
+        next();
       },
       function upgrade16to17() {
         if (DEBUG) debug("Fix array with null values");
-        if (!objectStore) {
-          objectStore = aTransaction.objectStore(STORE_NAME);
-        }
         const ARRAY_PROPERTIES = ["photo", "adr", "email", "url", "impp", "tel",
                                  "name", "honorificPrefix", "givenName",
                                  "additionalName", "familyName", "honorificSuffix",
                                  "nickname", "category", "org", "jobTitle",
                                  "note", "key"];
 
         const PROPERTIES_WITH_TYPE = ["adr", "email", "url", "impp", "tel"];
 
         const DATE_PROPERTIES = ["bday", "anniversary"];
 
-        objectStore.openCursor().onsuccess = function(event) {
+        scheduleValueUpgrade(function upgradeValue16to17(value) {
+          let changed;
+
           function filterInvalidValues(val) {
             let shouldKeep = val != null; // null or undefined
             if (!shouldKeep) {
               changed = true;
             }
             return shouldKeep;
           }
 
           function filteredArray(array) {
             return array.filter(filterInvalidValues);
           }
 
-          let cursor = event.target.result;
-          let changed = false;
-          if (cursor) {
-            let props = cursor.value.properties;
+          let props = value.properties;
 
-            for (let prop of ARRAY_PROPERTIES) {
+          for (let prop of ARRAY_PROPERTIES) {
 
-              // properties that were empty strings weren't converted to arrays
-              // in upgrade14to15
-              if (props[prop] != null && !Array.isArray(props[prop])) {
-                props[prop] = [props[prop]];
-                changed = true;
-              }
+            // properties that were empty strings weren't converted to arrays
+            // in upgrade14to15
+            if (props[prop] != null && !Array.isArray(props[prop])) {
+              props[prop] = [props[prop]];
+              changed = true;
+            }
 
-              if (props[prop] && props[prop].length) {
-                props[prop] = filteredArray(props[prop]);
+            if (props[prop] && props[prop].length) {
+              props[prop] = filteredArray(props[prop]);
 
-                if (PROPERTIES_WITH_TYPE.indexOf(prop) !== -1) {
-                  let subprop = props[prop];
+              if (PROPERTIES_WITH_TYPE.indexOf(prop) !== -1) {
+                let subprop = props[prop];
 
-                  for (let i = 0; i < subprop.length; ++i) {
-                    let curSubprop = subprop[i];
-                    // upgrade14to15 transformed type props into an array
-                    // without checking invalid values
-                    if (curSubprop.type) {
-                      curSubprop.type = filteredArray(curSubprop.type);
-                    }
+                for (let i = 0; i < subprop.length; ++i) {
+                  let curSubprop = subprop[i];
+                  // upgrade14to15 transformed type props into an array
+                  // without checking invalid values
+                  if (curSubprop.type) {
+                    curSubprop.type = filteredArray(curSubprop.type);
                   }
                 }
               }
             }
-
-            for (let prop of DATE_PROPERTIES) {
-              if (props[prop] != null && !(props[prop] instanceof Date)) {
-                // props[prop] is probably '' and wasn't converted
-                // in upgrade15to16
-                props[prop] = null;
-                changed = true;
-              }
-            }
+          }
 
-            if (changed) {
-              cursor.value.properties = props;
-              cursor.update(cursor.value);
+          for (let prop of DATE_PROPERTIES) {
+            if (props[prop] != null && !(props[prop] instanceof Date)) {
+              // props[prop] is probably '' and wasn't converted
+              // in upgrade15to16
+              props[prop] = null;
+              changed = true;
             }
-            cursor.continue();
+          }
+
+          if (changed) {
+            value.properties = props;
+            return true;
           } else {
-           next();
+            return false;
           }
-        }
+        });
+
+        next();
       },
       function upgrade17to18() {
+        // this upgrade function has been moved to the next upgrade path because
+        // a previous version of it had a bug
+        next();
+      },
+      function upgrade18to19() {
         if (DEBUG) {
           debug("Adding the name index");
         }
 
         if (!objectStore) {
           objectStore = aTransaction.objectStore(STORE_NAME);
         }
 
-        objectStore.createIndex("name", "properties.name", { multiEntry: true });
-        objectStore.createIndex("nameLowerCase", "search.name", { multiEntry: true });
+        // an earlier version of this code could have run, so checking whether
+        // the index exists
+        if (!objectStore.indexNames.contains("name")) {
+          objectStore.createIndex("name", "properties.name", { multiEntry: true });
+          objectStore.createIndex("nameLowerCase", "search.name", { multiEntry: true });
+        }
 
-        objectStore.openCursor().onsuccess = function(event) {
-          let cursor = event.target.result;
-          if (cursor) {
-            let value = cursor.value;
-            value.search.name = [];
-            if (value.properties.name) {
-              value.properties.name.forEach(function addNameIndex(name) {
-                value.search.name.push(name.toLowerCase());
-              });
-            }
-            cursor.update(value);
-          } else {
-            next();
+        scheduleValueUpgrade(function upgradeValue18to19(value) {
+          value.search.name = [];
+          if (value.properties.name) {
+            value.properties.name.forEach(function addNameIndex(name) {
+              var lowerName = name.toLowerCase();
+              // an earlier version of this code could have added it already
+              if (value.search.name.indexOf(lowerName) === -1) {
+                value.search.name.push(lowerName);
+              }
+            });
           }
-        };
+          return true;
+        });
+
+        next();
       },
     ];
 
     let index = aOldVersion;
     let outer = this;
+
+    /* This function runs all upgrade functions that are in the
+     * valueUpgradeSteps array. These functions have the following properties:
+     * - they must be synchronous
+     * - they must take the value as parameter and modify it directly. They
+     *   must not create a new object.
+     * - they must return a boolean true/false; true if the value was actually
+     *   changed
+     */
+    function runValueUpgradeSteps(done) {
+      if (DEBUG) debug("Running the value upgrade functions.");
+      if (!objectStore) {
+        objectStore = aTransaction.objectStore(STORE_NAME);
+      }
+      objectStore.openCursor().onsuccess = function(event) {
+        let cursor = event.target.result;
+        if (cursor) {
+          let changed = false;
+          let oldValue;
+          let value = cursor.value;
+          if (DEBUG) {
+            oldValue = JSON.stringify(value);
+          }
+          valueUpgradeSteps.forEach(function(upgradeFunc, i) {
+            if (DEBUG) debug("Running upgrade function " + i);
+            changed = upgradeFunc(value) || changed;
+          });
+
+          if (changed) {
+            cursor.update(value);
+          } else if (DEBUG) {
+            let newValue = JSON.stringify(value);
+            if (newValue !== oldValue) {
+              // oops something went wrong
+              debug("upgrade: `changed` was false and still the value changed! Aborting.");
+              aTransaction.abort();
+              return;
+            }
+          }
+          cursor.continue();
+        } else {
+          done();
+        }
+      };
+    }
+
+    function finish() {
+      // We always output this debug line because it's useful and the noise ratio
+      // very low.
+      debug("Upgrade finished");
+
+      outer.incrementRevision(aTransaction);
+    }
+
     function next() {
       if (index == aNewVersion) {
-        outer.incrementRevision(aTransaction);
+        runValueUpgradeSteps(finish);
         return;
       }
+
       try {
         var i = index++;
         if (DEBUG) debug("Upgrade step: " + i + "\n");
         steps[i].call(outer);
       } catch(ex) {
         dump("Caught exception" + ex);
         aTransaction.abort();
         return;
       }
-    };
+    }
 
     function fail(why) {
       why = why || "";
       if (this.error) {
         why += " (root cause: " + this.error.name + ")";
       }
 
       debug("Contacts DB upgrade error: " + why);
@@ -1159,17 +1189,17 @@ ContactDB.prototype = {
   },
 
   _findWithIndex: function _findWithIndex(txn, store, options) {
     if (DEBUG) debug("_findWithIndex: " + options.filterValue +" " + options.filterOp + " " + options.filterBy + " ");
     let fields = options.filterBy;
     for (let key in fields) {
       if (DEBUG) debug("key: " + fields[key]);
       if (!store.indexNames.contains(fields[key]) && fields[key] != "id") {
-        if (DEBUG) debug("Key not valid!" + fields[key] + ", " + store.indexNames);
+        if (DEBUG) debug("Key not valid!" + fields[key] + ", " + JSON.stringify(store.indexNames));
         txn.abort();
         return;
       }
     }
 
     // lookup for all keys
     if (options.filterBy.length == 0) {
       if (DEBUG) debug("search in all fields!" + JSON.stringify(store.indexNames));
--- a/dom/contacts/fallback/ContactService.jsm
+++ b/dom/contacts/fallback/ContactService.jsm
@@ -17,17 +17,19 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/ContactDB.jsm");
 Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIMessageListenerManager");
 
-let ContactService = {
+
+/* all exported symbols need to be bound to this on B2G - Bug 961777 */
+let ContactService = this.ContactService = {
   init: function() {
     if (DEBUG) debug("Init");
     this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:GetAll:SendNow",
                       "Contacts:Clear", "Contact:Save",
                       "Contact:Remove", "Contacts:RegisterForMessages",
                       "child-process-shutdown", "Contacts:GetRevision",
                       "Contacts:GetCount"];
     this._children = [];
--- a/dom/contacts/tests/mochitest.ini
+++ b/dom/contacts/tests/mochitest.ini
@@ -5,8 +5,13 @@
 [test_contacts_basics2.html]
 [test_contacts_blobs.html]
 [test_contacts_events.html]
 [test_contacts_getall.html]
 [test_contacts_getall2.html]
 [test_contacts_international.html]
 [test_contacts_substringmatching.html]
 [test_contacts_substringmatchingVE.html]
+[test_migration.html]
+  support-files =
+    test_migration_chrome.js
+  skip-if = os == "android"
+
--- a/dom/contacts/tests/shared.js
+++ b/dom/contacts/tests/shared.js
@@ -384,17 +384,17 @@ function checkCount(count, msg, then) {
   };
   request.onerror = onFailure;
 }
 
 // Helper functions to run tests
 var index = 0;
 
 function next() {
-  ok(true, "Begin!");
+  info("Step " + index);
   if (index >= steps.length) {
     ok(false, "Shouldn't get here!");
     return;
   }
   try {
     var i = index++;
     steps[i]();
   } catch(ex) {
--- a/dom/contacts/tests/test_contacts_substringmatching.html
+++ b/dom/contacts/tests/test_contacts_substringmatching.html
@@ -290,17 +290,18 @@ var steps = [
     req.onsuccess = function () {
       ok(true, "Deleted the database");
       next();
     }
     req.onerror = onFailure;
   },
   function () {
     ok(true, "all done!\n");
-    SpecialPowers.setIntPref("dom.phonenumber.substringmatching.BR", -1);
+    SpecialPowers.clearUserPref("dom.phonenumber.substringmatching.BR");
+    SpecialPowers.clearUserPref("ril.lastKnownSimMcc");
     SimpleTest.finish();
   }
 ];
 
 start_tests();
 </script>
 </pre>
 </body>
--- a/dom/contacts/tests/test_contacts_substringmatchingVE.html
+++ b/dom/contacts/tests/test_contacts_substringmatchingVE.html
@@ -119,17 +119,18 @@ var steps = [
     req.onsuccess = function () {
       ok(true, "Deleted the database");
       next();
     }
     req.onerror = onFailure;
   },
   function () {
     ok(true, "all done!\n");
-    SpecialPowers.setIntPref("dom.phonenumber.substringmatching.VE", -1);
+    SpecialPowers.clearUserPref("dom.phonenumber.substringmatching.BR");
+    SpecialPowers.clearUserPref("ril.lastKnownSimMcc");
     SimpleTest.finish();
   }
 ];
 
 start_tests();
 </script>
 </pre>
 </body>
new file mode 100644
--- /dev/null
+++ b/dom/contacts/tests/test_migration.html
@@ -0,0 +1,210 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <title>Migration tests</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<h1>migration tests</h1>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script type="text/javascript;version=1.8" src="shared.js"></script>
+<script class="testbody" type="text/javascript">
+"use strict";
+
+var backend, contactsCount, allContacts;
+function loadChromeScript() {
+  var url = SimpleTest.getTestFileURL("test_migration_chrome.js");
+  backend = SpecialPowers.loadChromeScript(url);
+}
+
+function addBackendEvents() {
+  backend.addMessageListener("createDB.success", function(count) {
+    contactsCount = count;
+    ok(true, "Created the database");
+    next();
+  });
+  backend.addMessageListener("createDB.error", function(err) {
+    ok(false, err);
+    next();
+  });
+
+  backend.addMessageListener("deleteDB.success", function() {
+    ok(true, "Deleted the database");
+    next();
+  });
+  backend.addMessageListener("deleteDB.error", function(err) {
+    ok(false, err);
+    next();
+  });
+}
+
+function createDB(version) {
+  info("Will create the DB at version " + version);
+  backend.sendAsyncMessage("createDB", version);
+}
+
+function deleteDB() {
+  info("Will delete the DB.");
+  backend.sendAsyncMessage("deleteDB");
+}
+
+function setSubstringMatching(value) {
+  info("Setting substring matching to " + value);
+
+  if (value) {
+    SpecialPowers.setIntPref("dom.phonenumber.substringmatching.BR", value);
+
+    // this is the Mcc for Brazil, so that we trigger the previous pref
+    SpecialPowers.setCharPref("ril.lastKnownSimMcc", "724");
+  } else {
+    SpecialPowers.clearUserPref("dom.phonenumber.substringmatching.BR");
+    SpecialPowers.clearUserPref("ril.lastKnownSimMcc");
+  }
+
+  next();
+}
+
+var steps = [
+  function setupChromeScript() {
+    loadChromeScript();
+    addBackendEvents();
+    next();
+  },
+
+  deleteDB, // let's be sure the DB does not exist yet
+  createDB.bind(null, 12),
+  setSubstringMatching.bind(null, 7),
+
+  function testAccessMozContacts() {
+    info("Checking we have the right number of contacts: " + contactsCount);
+    var req = mozContacts.getCount();
+    req.onsuccess = function onsuccess() {
+      ok(true, "Could access the mozContacts API");
+      ise(this.result, contactsCount, "Contacts count is correct");
+      next();
+    };
+
+    req.onerror = function onerror() {
+      ok(false, "Couldn't access the mozContacts API");
+      next();
+    };
+  },
+
+  function testRetrieveAllContacts() {
+    /* if the migration does not work right, either we'll have an error, or the
+       contacts won't be migrated properly and thus will fail WebIDL conversion,
+       which will manifest as a timeout */
+    info("Checking the contacts are corrected to obey WebIDL constraints.  (upgrades 14 to 17)");
+    var req = mozContacts.find();
+    req.onsuccess = function onsuccess() {
+      if (this.result) {
+        ise(this.result.length, contactsCount, "Contacts array length is correct");
+        allContacts = this.result;
+        next();
+      } else {
+        ok(false, "Could access the mozContacts API but got no contacts!");
+        next();
+      }
+    };
+
+    req.onerror = function onerror() {
+      ok(false, "Couldn't access the mozContacts API");
+      next();
+    };
+  },
+
+  function checkNameIndex() {
+    info("Checking name index migration (upgrades 17 to 19).");
+    if (!allContacts) {
+      next();
+    }
+
+    var count = allContacts.length;
+
+    function finishRequest() {
+      count--;
+      if (!count) {
+        next();
+      }
+    }
+
+    allContacts.forEach(function(contact) {
+      var name = contact.name && contact.name[0];
+      if (!name) {
+        count--;
+        return;
+      }
+
+      var req = mozContacts.find({
+        filterBy: ["name"],
+        filterValue: name,
+        filterOp: "equals"
+      });
+
+      req.onsuccess = function onsuccess() {
+        if (this.result) {
+          info("Found contact '" + name + "', checking it's the correct one.");
+          checkContacts(this.result[0], contact);
+        } else {
+          ok(false, "Could not find contact with name '" + name + "'");
+        }
+
+        finishRequest();
+      };
+
+      req.onerror = function onerror() {
+        ok(false, "Error while finding contact with name '" + name + "'!");
+        finishRequest();
+      }
+    });
+
+    if (!count) {
+      ok(false, "No contact had a name, this is unexpected.");
+      next();
+    }
+  },
+
+  function checkSubstringMatching() {
+    var subject = "0004567890"; // the last 7 digits are the same that at least one contact
+    info("Looking for a contact matching " + subject);
+    var req = mozContacts.find({
+      filterValue: subject,
+      filterOp: "match",
+      filterBy: ["tel"],
+      filterLimit: 1
+    });
+
+    req.onsuccess = function onsuccess() {
+      if (this.result && this.result[0]) {
+        ok(true, "Found a contact with number " + this.result[0].tel[0].value);
+      }
+      next();
+    };
+
+    req.onerror = function onerror() {
+      ok(false, "Error while finding contact for substring matching check!");
+      next();
+    };
+  },
+
+  deleteDB,
+  setSubstringMatching.bind(null, null),
+
+  function finish() {
+    backend.destroy();
+    info("all done!\n");
+    SimpleTest.finish();
+  }
+];
+
+start_tests();
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/contacts/tests/test_migration_chrome.js
@@ -0,0 +1,331 @@
+/* global
+    sendAsyncMessage,
+    addMessageListener,
+    indexedDB
+ */
+"use strict";
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+let imports = {};
+
+Cu.import("resource://gre/modules/ContactDB.jsm", imports);
+Cu.import("resource://gre/modules/ContactService.jsm", imports);
+Cu.import("resource://gre/modules/Promise.jsm", imports);
+Cu.importGlobalProperties(["indexedDB"]);
+
+const {
+  STORE_NAME,
+  SAVED_GETALL_STORE_NAME,
+  REVISION_STORE,
+  DB_NAME,
+  ContactService,
+  Promise
+} = imports;
+
+let DEBUG = false;
+function debug(str) {
+  if (DEBUG){
+    dump("-*- TestMigrationChromeScript: " + str + "\n");
+  }
+}
+
+const DATA = {
+  12: {
+    SCHEMA: function createSchema12(db, transaction) {
+      let objectStore = db.createObjectStore(STORE_NAME, {keyPath: "id"});
+      objectStore.createIndex("familyName", "properties.familyName", { multiEntry: true });
+      objectStore.createIndex("givenName",  "properties.givenName",  { multiEntry: true });
+      objectStore.createIndex("familyNameLowerCase", "search.familyName", { multiEntry: true });
+      objectStore.createIndex("givenNameLowerCase",  "search.givenName",  { multiEntry: true });
+      objectStore.createIndex("telLowerCase",        "search.tel",        { multiEntry: true });
+      objectStore.createIndex("emailLowerCase",      "search.email",      { multiEntry: true });
+      objectStore.createIndex("tel", "search.exactTel", { multiEntry: true });
+      objectStore.createIndex("category", "properties.category", { multiEntry: true });
+      objectStore.createIndex("email", "search.email", { multiEntry: true });
+      objectStore.createIndex("telMatch", "search.parsedTel", {multiEntry: true});
+      db.createObjectStore(SAVED_GETALL_STORE_NAME);
+      db.createObjectStore(REVISION_STORE).put(0, "revision");
+    },
+    BAD: [
+      {
+        // this contact is bad because its "name" property is not an array and
+        // is the empty string (upgrade 16 to 17)
+        "properties": {
+          "name": "",
+          "email": [],
+          "url": [{
+            "type": ["source"],
+            "value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654"
+          }],
+          "category": ["gmail"],
+          "adr": [],
+          "tel": [{
+            "type": ["mobile"],
+            "value": "+7 123 456-78-90"
+          }],
+          "sex": "undefined",
+          "genderIdentity": "undefined"
+        },
+        "search": {
+          "givenName": [],
+          "familyName": [],
+          "email": [],
+          "category": ["gmail"],
+          "tel": ["+71234567890","71234567890","1234567890","234567890","34567890",
+            "4567890","567890","67890","7890","890","90","0","81234567890"],
+          "exactTel": ["+71234567890"],
+          "parsedTel": ["+71234567890","1234567890","81234567890","34567890"]
+        },
+        "updated": new Date("2013-07-27T16:47:40.974Z"),
+        "published": new Date("2013-07-27T16:47:40.974Z"),
+        "id": "bad-1"
+      },
+      {
+        // This contact is bad because its "name" property is not an array
+        // (upgrade 14 to 15)
+        "properties": {
+          "name": "name-bad-2",
+          "email": [],
+          "url": [{
+            "type": ["source"],
+            "value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654"
+          }],
+          "category": ["gmail"],
+          "adr": [],
+          "tel": [{
+            "type": ["mobile"],
+            "value": "+7 123 456-78-90"
+          }],
+          "sex": "undefined",
+          "genderIdentity": "undefined"
+        },
+        "search": {
+          "givenName": [],
+          "familyName": [],
+          "email": [],
+          "category": ["gmail"],
+          "tel": ["+71234567890","71234567890","1234567890","234567890","34567890",
+            "4567890","567890","67890","7890","890","90","0","81234567890"],
+          "exactTel": ["+71234567890"],
+          "parsedTel": ["+71234567890","1234567890","81234567890","34567890"]
+        },
+        "updated": new Date("2013-07-27T16:47:40.974Z"),
+        "published": new Date("2013-07-27T16:47:40.974Z"),
+        "id": "bad-2"
+      },
+      {
+        // This contact is bad because its bday property is a String (upgrade 15
+        // to 16), and its anniversary property is an empty string (upgrade 16
+        // to 17)
+        "properties": {
+          "name": ["name-bad-3"],
+          "email": [],
+          "url": [{
+            "type": ["source"],
+            "value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654"
+          }],
+          "category": ["gmail"],
+          "adr": [],
+          "tel": [{
+            "type": ["mobile"],
+            "value": "+7 123 456-78-90"
+          }],
+          "sex": "undefined",
+          "genderIdentity": "undefined",
+          "bday": "2013-07-27T16:47:40.974Z",
+          "anniversary": ""
+        },
+        "search": {
+          "givenName": [],
+          "familyName": [],
+          "email": [],
+          "category": ["gmail"],
+          "tel": ["+71234567890","71234567890","1234567890","234567890","34567890",
+            "4567890","567890","67890","7890","890","90","0","81234567890"],
+          "exactTel": ["+71234567890"],
+          "parsedTel": ["+71234567890","1234567890","81234567890","34567890"]
+        },
+        "updated": new Date("2013-07-27T16:47:40.974Z"),
+        "published": new Date("2013-07-27T16:47:40.974Z"),
+        "id": "bad-3"
+      },
+      {
+        // This contact is bad because its tel property has a tel.type null
+        // value (upgrade 16 to 17), and email.type not array value (upgrade 14
+        // to 15)
+        "properties": {
+          "name": ["name-bad-4"],
+          "email": [{
+            "value": "toto@toto.com",
+            "type": "home"
+          }],
+          "url": [{
+            "type": ["source"],
+            "value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654"
+          }],
+          "category": ["gmail"],
+          "adr": [],
+          "tel": [{
+            "type": null,
+            "value": "+7 123 456-78-90"
+          }],
+          "sex": "undefined",
+          "genderIdentity": "undefined"
+        },
+        "search": {
+          "givenName": [],
+          "familyName": [],
+          "email": [],
+          "category": ["gmail"],
+          "tel": ["+71234567890","71234567890","1234567890","234567890","34567890",
+            "4567890","567890","67890","7890","890","90","0","81234567890"],
+          "exactTel": ["+71234567890"],
+          "parsedTel": ["+71234567890","1234567890","81234567890","34567890"]
+        },
+        "updated": new Date("2013-07-27T16:47:40.974Z"),
+        "published": new Date("2013-07-27T16:47:40.974Z"),
+        "id": "bad-4"
+      }
+    ],
+    GOOD: [
+      {
+        "properties": {
+          "name": ["name-good-1"],
+          "email": [],
+          "url": [{
+            "type": ["source"],
+            "value": "urn:service:gmail:uid:http://www.google.com/m8/feeds/contacts/XXX/base/4567894654"
+          }],
+          "category": ["gmail"],
+          "adr": [],
+          "tel": [{
+            "type": ["mobile"],
+            "value": "+7 123 456-78-90"
+          }],
+          "sex": "undefined",
+          "genderIdentity": "undefined"
+        },
+        "search": {
+          "givenName": [],
+          "familyName": [],
+          "email": [],
+          "category": ["gmail"],
+          "tel": ["+71234567890","71234567890","1234567890","234567890","34567890",
+            "4567890","567890","67890","7890","890","90","0","81234567890"],
+          "exactTel": ["+71234567890"],
+          "parsedTel": ["+71234567890","1234567890","81234567890","34567890"]
+        },
+        "updated": new Date("2013-07-27T16:47:40.974Z"),
+        "published": new Date("2013-07-27T16:47:40.974Z"),
+        "id": "good-1"
+      }
+    ]
+  }
+};
+
+function DataManager(version) {
+  if (!(version in DATA)) {
+    throw new Error("Version " + version + " can't be found in our test datas.");
+  }
+
+  this.version = version;
+  this.data = DATA[version];
+}
+
+DataManager.prototype = {
+  open: function() {
+    debug("opening for version " + this.version);
+    var deferred = Promise.defer();
+
+    let req = indexedDB.open(DB_NAME, this.version);
+    req.onupgradeneeded = function() {
+      let db = req.result;
+      let transaction = req.transaction;
+      this.createSchema(db, transaction);
+      this.addContacts(db, transaction);
+    }.bind(this);
+
+    req.onsuccess = function() {
+      debug("succeeded opening the db, let's close it now");
+      req.result.close();
+      deferred.resolve(this.contactsCount());
+    }.bind(this);
+
+    req.onerror = function() {
+      deferred.reject(this.error);
+    };
+
+    return deferred.promise;
+  },
+
+  createSchema: function(db, transaction) {
+    debug("createSchema for version " + this.version);
+    this.data.SCHEMA(db, transaction);
+  },
+
+  addContacts: function(db, transaction) {
+    debug("adding contacts for version " + this.version);
+    var os = transaction.objectStore(STORE_NAME);
+
+    this.data.GOOD.forEach(function(contact) {
+      os.put(contact);
+    });
+    this.data.BAD.forEach(function(contact) {
+      os.put(contact);
+    });
+  },
+
+  contactsCount: function() {
+    return this.data.BAD.length + this.data.GOOD.length;
+  }
+};
+
+DataManager.delete = function() {
+  debug("Deleting the database");
+  var deferred = Promise.defer();
+
+  /* forcibly close the db before deleting it */
+  ContactService._db.close();
+
+  var req = indexedDB.deleteDatabase(DB_NAME);
+  req.onsuccess = function() {
+    debug("Successfully deleted!");
+    deferred.resolve();
+  };
+
+  req.onerror = function() {
+    debug("Not deleted, error is " + this.error.name);
+    deferred.reject(this.error);
+  };
+
+  req.onblocked = function() {
+    debug("Waiting for the current users");
+  };
+
+  return deferred.promise;
+};
+
+addMessageListener("createDB", function(version) {
+  // Promises help handling gracefully exceptions
+  Promise.resolve().then(function() {
+    return new DataManager(version);
+  }).then(function(manager) {
+    return manager.open();
+  }).then(function onSuccess(count) {
+    sendAsyncMessage("createDB.success", count);
+  }, function onError(err) {
+    sendAsyncMessage("createDB.error", "Failed to create the DB: " +
+      "(" + err.name + ") " + err.message);
+  });
+});
+
+addMessageListener("deleteDB", function() {
+  Promise.resolve().then(
+    DataManager.delete
+  ).then(function onSuccess() {
+    sendAsyncMessage("deleteDB.success");
+  }, function onError(err) {
+    sendAsyncMessage("deleteDB.error", "Failed to delete the DB:" + err.name);
+  });
+});
--- a/dom/identity/DOMIdentity.jsm
+++ b/dom/identity/DOMIdentity.jsm
@@ -1,31 +1,32 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
 const PREF_FXA_ENABLED = "identity.fxaccounts.enabled";
 let _fxa_enabled = false;
 try {
   if (Services.prefs.getPrefType(PREF_FXA_ENABLED) === Ci.nsIPrefBranch.PREF_BOOL) {
     _fxa_enabled = Services.prefs.getBoolPref(PREF_FXA_ENABLED);
   }
 } catch(noPref) {
 }
 const FXA_ENABLED = _fxa_enabled;
 
 // This is the parent process corresponding to nsDOMIdentity.
 this.EXPORTED_SYMBOLS = ["DOMIdentity"];
 
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
 XPCOMUtils.defineLazyModuleGetter(this, "objectCopy",
                                   "resource://gre/modules/identity/IdentityUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "IdentityService",
 #ifdef MOZ_B2G_VERSION
                                   "resource://gre/modules/identity/MinimalIdentity.jsm");
 #else
                                   "resource://gre/modules/identity/Identity.jsm");
--- a/dom/system/gonk/NetworkUtils.cpp
+++ b/dom/system/gonk/NetworkUtils.cpp
@@ -226,16 +226,25 @@ static void split(char* str, const char*
 {
   char *s = strtok(str, sep);
   while (s != nullptr) {
     result.AppendElement(s);
     s = strtok(nullptr, sep);
   }
 }
 
+static void split(char* str, const char* sep, nsTArray<nsString>& result)
+{
+  char *s = strtok(str, sep);
+  while (s != nullptr) {
+    result.AppendElement(NS_ConvertUTF8toUTF16(s));
+    s = strtok(nullptr, sep);
+  }
+}
+
 /**
  * Helper function that implement join function.
  */
 static void join(nsTArray<nsCString>& array, const char* sep, const uint32_t maxlen, char* result)
 {
 #define CHECK_LENGTH(len, add, max)  len += add;          \
                                      if (len > max - 1)   \
                                        return;            \
--- a/dom/system/gonk/NetworkUtils.h
+++ b/dom/system/gonk/NetworkUtils.h
@@ -70,22 +70,22 @@ public:
     mPreExternalIfname = aOther.mPreExternalIfname;
     mCurInternalIfname = aOther.mCurInternalIfname;
     mCurExternalIfname = aOther.mCurExternalIfname;
     mThreshold = aOther.mThreshold;
   }
 
   NetworkParams(const NetworkCommandOptions& aOther) {
 
-#define COPY_SEQUENCE_FIELD(prop)                                                            \
+#define COPY_SEQUENCE_FIELD(prop, type)                                                      \
     if (aOther.prop.WasPassed()) {                                                           \
-      mozilla::dom::Sequence<nsString > const & currentValue = aOther.prop.InternalValue();  \
+      mozilla::dom::Sequence<type > const & currentValue = aOther.prop.InternalValue();      \
       uint32_t length = currentValue.Length();                                               \
       for (uint32_t idx = 0; idx < length; idx++) {                                          \
-        mHostnames.AppendElement(currentValue[idx]);                                         \
+        prop.AppendElement(currentValue[idx]);                                               \
       }                                                                                      \
     }
 
 #define COPY_OPT_STRING_FIELD(prop, defaultValue)       \
     if (aOther.prop.WasPassed()) {                      \
       if (aOther.prop.Value().EqualsLiteral("null")) {  \
         prop = defaultValue;                            \
       } else {                                          \
@@ -105,17 +105,17 @@ public:
 #define COPY_FIELD(prop) prop = aOther.prop;
 
     COPY_FIELD(mId)
     COPY_FIELD(mCmd)
     COPY_OPT_STRING_FIELD(mDns1_str, EmptyString())
     COPY_OPT_STRING_FIELD(mDns2_str, EmptyString())
     COPY_OPT_STRING_FIELD(mGateway, EmptyString())
     COPY_OPT_STRING_FIELD(mGateway_str, EmptyString())
-    COPY_SEQUENCE_FIELD(mHostnames)
+    COPY_SEQUENCE_FIELD(mHostnames, nsString)
     COPY_OPT_STRING_FIELD(mIfname, EmptyString())
     COPY_OPT_STRING_FIELD(mIp, EmptyString())
     COPY_OPT_STRING_FIELD(mNetmask, EmptyString())
     COPY_OPT_STRING_FIELD(mOldIfname, EmptyString())
     COPY_OPT_STRING_FIELD(mMode, EmptyString())
     COPY_OPT_FIELD(mReport, false)
     COPY_OPT_FIELD(mIsAsync, true)
     COPY_OPT_FIELD(mEnabled, false)
@@ -123,17 +123,17 @@ public:
     COPY_OPT_STRING_FIELD(mInternalIfname, EmptyString())
     COPY_OPT_STRING_FIELD(mExternalIfname, EmptyString())
     COPY_OPT_FIELD(mEnable, false)
     COPY_OPT_STRING_FIELD(mSsid, EmptyString())
     COPY_OPT_STRING_FIELD(mSecurity, EmptyString())
     COPY_OPT_STRING_FIELD(mKey, EmptyString())
     COPY_OPT_STRING_FIELD(mPrefix, EmptyString())
     COPY_OPT_STRING_FIELD(mLink, EmptyString())
-    COPY_SEQUENCE_FIELD(mInterfaceList)
+    COPY_SEQUENCE_FIELD(mInterfaceList, nsString)
     COPY_OPT_STRING_FIELD(mWifiStartIp, EmptyString())
     COPY_OPT_STRING_FIELD(mWifiEndIp, EmptyString())
     COPY_OPT_STRING_FIELD(mUsbStartIp, EmptyString())
     COPY_OPT_STRING_FIELD(mUsbEndIp, EmptyString())
     COPY_OPT_STRING_FIELD(mDns1, EmptyString())
     COPY_OPT_STRING_FIELD(mDns2, EmptyString())
     COPY_OPT_FIELD(mRxBytes, -1)
     COPY_OPT_FIELD(mTxBytes, -1)
@@ -173,17 +173,17 @@ public:
   nsString mInternalIfname;
   nsString mExternalIfname;
   bool mEnable;
   nsString mSsid;
   nsString mSecurity;
   nsString mKey;
   nsString mPrefix;
   nsString mLink;
-  nsTArray<nsCString> mInterfaceList;
+  nsTArray<nsString> mInterfaceList;
   nsString mWifiStartIp;
   nsString mWifiEndIp;
   nsString mUsbStartIp;
   nsString mUsbEndIp;
   nsString mDns1;
   nsString mDns2;
   float mRxBytes;
   float mTxBytes;
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -921,23 +921,23 @@ XPCOMUtils.defineLazyGetter(this, "gData
           let network = subject.QueryInterface(Ci.nsINetworkInterface);
           // DSDS: setup pending data connection when switching the default id
           // for data call. We can not use network.type to tell if it's
           // NETWORK_TYPE_MOBILE, since the type is removed from
           // RILNetworkInterface.connectedTypes on disconnect().
           if (network.state == Ci.nsINetworkInterface.NETWORK_STATE_UNKNOWN) {
             let connHandler = this._connectionHandlers[this._currentDataClientId];
             let radioInterface = connHandler.radioInterface;
-            if (!connHandler.allDataDisconnected() &&
+            if (connHandler.allDataDisconnected() &&
                 typeof this._pendingDataCallRequest === "function") {
               if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) {
                 radioInterface.setDataRegistration(false);
               }
               if (DEBUG) {
-                debug("All data calls disconnected, setup pending data call.");
+                this.debug("All data calls disconnected, setup pending data call.");
               }
               this._pendingDataCallRequest();
               this._pendingDataCallRequest = null;
             }
           }
           break;
         case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
           this._shutdown();