Merge b2g-inbound to m-c.
authorRyan VanderMeulen <ryanvm@gmail.com>
Sat, 08 Mar 2014 01:23:46 -0800
changeset 173053 23005b395ae8e5589b0a37778747fc35be58a2ff
parent 173005 ea3a5092c05aae26968b2bdac61999527c450bd6 (current diff)
parent 173052 ad05d3ccbdebb53f106a880459de6d496dc44712 (diff)
child 173070 2d9cee99cdcb06b037b23fe0b48ad1ebaf716e74
child 173082 0a2dd29ce0a15e5e167726137fdd30072680232e
child 173126 1fe2de4278663300966d3297951bc3a48a21fe87
push id26386
push userryanvm@gmail.com
push dateTue, 11 Mar 2014 19:42:31 +0000
treeherdermozilla-central@23005b395ae8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone30.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge b2g-inbound to m-c.
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="456499c44d1ef39b602ea02e9ed460b6aab85b44"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="97a5b461686757dbb8ecab2aac5903e41d2e1afe">
     <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="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="a9e08b91e9cd1f0930f16cfc49ec72f63575d5fe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>
   <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="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <!-- Stock Android things -->
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="456499c44d1ef39b602ea02e9ed460b6aab85b44"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "remote": "", 
         "branch": "", 
         "revision": ""
     }, 
-    "revision": "c5bd933fe99317a7e99822f2d9345ae67a3043df", 
+    "revision": "93de9c5bcb90ae32bd3599b185f4bbf67e4529ff", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
   <!--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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <!-- 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
@@ -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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>
   <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
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <!-- 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
@@ -12,17 +12,17 @@
   <!--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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <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
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="97a5b461686757dbb8ecab2aac5903e41d2e1afe">
     <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="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
   <!--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="1ad48c4be51b279f7f63c1a13025b52fe087d231">
     <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="a351fe62c11737c722ad33aaff438f6ccd00bd4a"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="3005269d4dcabcc7d27eaf72bda44a969873af8c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="353d422fcbd0b41b76e1262f0992a832420a7567"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="cf1dcc0704c0c1845f8a0a0b44838f7e0c0362c9"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="485846b2a40d8ac7d6c1c5f8af6d15b0c10af19d"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/dom/bluetooth/tests/marionette/head.js
+++ b/dom/bluetooth/tests/marionette/head.js
@@ -4,22 +4,23 @@
  * 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/. */
 
 let Promise =
   SpecialPowers.Cu.import("resource://gre/modules/Promise.jsm").Promise;
 
 let bluetoothManager;
 
-/* Get mozSettings value specified by @aKey.
+/**
+ * Get mozSettings value specified by @aKey.
  *
  * Resolve if that mozSettings value is retrieved successfully, reject
  * otherwise.
  *
- * Forfill params:
+ * Fulfill params:
  *   The corresponding mozSettings value of the key.
  * Reject params: (none)
  *
  * @param aKey
  *        A string.
  *
  * @return A deferred promise.
  */
@@ -34,21 +35,22 @@ function getSettings(aKey) {
   request.addEventListener("error", function() {
     ok(false, "getSettings(" + aKey + ")");
     deferred.reject();
   });
 
   return deferred.promise;
 }
 
-/* Set mozSettings values.
+/**
+ * Set mozSettings values.
  *
  * Resolve if that mozSettings value is set successfully, reject otherwise.
  *
- * Forfill params: (none)
+ * Fulfill params: (none)
  * Reject params: (none)
  *
  * @param aSettings
  *        An object of format |{key1: value1, key2: value2, ...}|.
  *
  * @return A deferred promise.
  */
 function setSettings(aSettings) {
@@ -62,53 +64,56 @@ function setSettings(aSettings) {
   request.addEventListener("error", function() {
     ok(false, "setSettings(" + JSON.stringify(aSettings) + ")");
     deferred.reject();
   });
 
   return deferred.promise;
 }
 
-/* Get mozSettings value of 'bluetooth.enabled'.
+/**
+ * Get mozSettings value of 'bluetooth.enabled'.
  *
  * Resolve if that mozSettings value is retrieved successfully, reject
  * otherwise.
  *
- * Forfill params:
+ * Fulfill params:
  *   A boolean value.
  * Reject params: (none)
  *
  * @return A deferred promise.
  */
 function getBluetoothEnabled() {
   return getSettings("bluetooth.enabled");
 }
 
-/* Set mozSettings value of 'bluetooth.enabled'.
+/**
+ * Set mozSettings value of 'bluetooth.enabled'.
  *
  * Resolve if that mozSettings value is set successfully, reject otherwise.
  *
- * Forfill params: (none)
+ * Fulfill params: (none)
  * Reject params: (none)
  *
  * @param aEnabled
  *        A boolean value.
  *
  * @return A deferred promise.
  */
 function setBluetoothEnabled(aEnabled) {
   let obj = {};
   obj["bluetooth.enabled"] = aEnabled;
   return setSettings(obj);
 }
 
-/* Push required permissions and test if |navigator.mozBluetooth| exists.
+/**
+ * Push required permissions and test if |navigator.mozBluetooth| exists.
  * Resolve if it does, reject otherwise.
  *
- * Forfill params:
+ * Fulfill params:
  *   bluetoothManager -- an reference to navigator.mozBluetooth.
  * Reject params: (none)
  *
  * @param aPermissions
  *        Additional permissions to push before any test cases.  Could be either
  *        a string or an array of strings.
  *
  * @return A deferred promise.
@@ -146,43 +151,45 @@ function ensureBluetoothManager(aPermiss
     } else {
       deferred.reject();
     }
   });
 
   return deferred.promise;
 }
 
-/* Wait for one named BluetoothManager event.
+/**
+ * Wait for one named BluetoothManager event.
  *
  * Resolve if that named event occurs.  Never reject.
  *
- * Forfill params: the DOMEvent passed.
+ * Fulfill params: the DOMEvent passed.
  *
  * @return A deferred promise.
  */
 function waitForManagerEvent(aEventName) {
   let deferred = Promise.defer();
 
   bluetoothManager.addEventListener(aEventName, function onevent(aEvent) {
     bluetoothManager.removeEventListener(aEventName, onevent);
 
     ok(true, "BluetoothManager event '" + aEventName + "' got.");
     deferred.resolve(aEvent);
   });
 
   return deferred.promise;
 }
 
-/* Convenient function for setBluetoothEnabled and waitForManagerEvent
+/**
+ * Convenient function for setBluetoothEnabled and waitForManagerEvent
  * combined.
  *
  * Resolve if that named event occurs.  Reject if we can't set settings.
  *
- * Forfill params: the DOMEvent passed.
+ * Fulfill params: the DOMEvent passed.
  * Reject params: (none)
  *
  * @return A deferred promise.
  */
 function setBluetoothEnabledAndWait(aEnabled) {
   let promises = [];
 
   // Bug 969109 -  Intermittent test_dom_BluetoothManager_adapteradded.js
@@ -193,21 +200,22 @@ function setBluetoothEnabledAndWait(aEna
   // installing the event handler *before* we ever enable/disable Bluetooth. Or
   // we might just miss those events and get a timeout error.
   promises.push(waitForManagerEvent(aEnabled ? "enabled" : "disabled"));
   promises.push(setBluetoothEnabled(aEnabled));
 
   return Promise.all(promises);
 }
 
-/* Get default adapter.
+/**
+ * Get default adapter.
  *
  * Resolve if that default adapter is got, reject otherwise.
  *
- * Forfill params: a BluetoothAdapter instance.
+ * Fulfill params: a BluetoothAdapter instance.
  * Reject params: a DOMError, or null if if there is no adapter ready yet.
  *
  * @return A deferred promise.
  */
 function getDefaultAdapter() {
   let deferred = Promise.defer();
 
   let request = bluetoothManager.getDefaultAdapter();
@@ -232,17 +240,18 @@ function getDefaultAdapter() {
   request.onerror = function(aEvent) {
     ok(false, "Failed to get default adapter.");
     deferred.reject(aEvent.target.error);
   };
 
   return deferred.promise;
 }
 
-/* Flush permission settings and call |finish()|.
+/**
+ * Flush permission settings and call |finish()|.
  */
 function cleanUp() {
   SpecialPowers.flushPermissions(function() {
     // Use ok here so that we have at least one test run.
     ok(true, "permissions flushed");
 
     finish();
   });
new file mode 100644
--- /dev/null
+++ b/dom/mobileconnection/tests/marionette/head.js
@@ -0,0 +1,399 @@
+/* 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;
+
+const SETTINGS_KEY_DATA_ENABLED = "ril.data.enabled";
+const SETTINGS_KEY_DATA_ROAMING_ENABLED = "ril.data.roaming_enabled";
+const SETTINGS_KEY_DATA_APN_SETTINGS = "ril.data.apnSettings";
+
+let Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise;
+
+let _pendingEmulatorCmdCount = 0;
+
+/**
+ * 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.
+ *
+ * @param aCommand
+ *        A string command to be passed to emulator through its telnet console.
+ *
+ * @return A deferred promise.
+ */
+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[0] === "OK") {
+      deferred.resolve(aResult);
+    } else {
+      deferred.reject(aResult);
+    }
+  });
+
+  return deferred.promise;
+}
+
+/**
+ * Get mozSettings value specified by @aKey.
+ *
+ * Resolve if that mozSettings value is retrieved successfully, reject
+ * otherwise.
+ *
+ * Fulfill params:
+ *   The corresponding mozSettings value of the key.
+ * Reject params: (none)
+ *
+ * @param aKey
+ *        A string.
+ * @param aAllowError [optional]
+ *        A boolean value.  If set to true, an error response won't be treated
+ *        as test failure.  Default: false.
+ *
+ * @return A deferred promise.
+ */
+function getSettings(aKey, aAllowError) {
+  let deferred = Promise.defer();
+
+  let request = navigator.mozSettings.createLock().get(aKey);
+  request.addEventListener("success", function(aEvent) {
+    ok(true, "getSettings(" + aKey + ") - success");
+    deferred.resolve(aEvent.target.result[aKey]);
+  });
+  request.addEventListener("error", function() {
+    ok(aAllowError, "getSettings(" + aKey + ") - error");
+    deferred.reject();
+  });
+
+  return deferred.promise;
+}
+
+/**
+ * Set mozSettings values.
+ *
+ * Resolve if that mozSettings value is set successfully, reject otherwise.
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @param aSettings
+ *        An object of format |{key1: value1, key2: value2, ...}|.
+ * @param aAllowError [optional]
+ *        A boolean value.  If set to true, an error response won't be treated
+ *        as test failure.  Default: false.
+ *
+ * @return A deferred promise.
+ */
+function setSettings(aSettings, aAllowError) {
+  let deferred = Promise.defer();
+
+  let request = navigator.mozSettings.createLock().set(aSettings);
+  request.addEventListener("success", function() {
+    ok(true, "setSettings(" + JSON.stringify(aSettings) + ")");
+    deferred.resolve();
+  });
+  request.addEventListener("error", function() {
+    ok(aAllowError, "setSettings(" + JSON.stringify(aSettings) + ")");
+    deferred.reject();
+  });
+
+  return deferred.promise;
+}
+
+/**
+ * Set mozSettings value with only one key.
+ *
+ * Resolve if that mozSettings value is set successfully, reject otherwise.
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @param aKey
+ *        A string key.
+ * @param aValue
+ *        An object value.
+ * @param aAllowError [optional]
+ *        A boolean value.  If set to true, an error response won't be treated
+ *        as test failure.  Default: false.
+ *
+ * @return A deferred promise.
+ */
+function setSettings1(aKey, aValue, aAllowError) {
+  let settings = {};
+  settings[aKey] = aValue;
+  return setSettings(settings, aAllowError);
+}
+
+/**
+ * Convenient MozSettings getter for SETTINGS_KEY_DATA_ENABLED.
+ */
+function getDataEnabled(aAllowError) {
+  return getSettings(SETTINGS_KEY_DATA_ENABLED, aAllowError);
+}
+
+/**
+ * Convenient MozSettings setter for SETTINGS_KEY_DATA_ENABLED.
+ */
+function setDataEnabled(aEnabled, aAllowError) {
+  return setSettings1(SETTINGS_KEY_DATA_ENABLED, aEnabled, aAllowError);
+}
+
+/**
+ * Convenient MozSettings getter for SETTINGS_KEY_DATA_ROAMING_ENABLED.
+ */
+function getDataRoamingEnabled(aAllowError) {
+  return getSettings(SETTINGS_KEY_DATA_ROAMING_ENABLED, aAllowError);
+}
+
+/**
+ * Convenient MozSettings setter for SETTINGS_KEY_DATA_ROAMING_ENABLED.
+ */
+function setDataRoamingEnabled(aEnabled, aAllowError) {
+  return setSettings1(SETTINGS_KEY_DATA_ROAMING_ENABLED, aEnabled, aAllowError);
+}
+
+/**
+ * Convenient MozSettings getter for SETTINGS_KEY_DATA_APN_SETTINGS.
+ */
+function getDataApnSettings(aAllowError) {
+  return getSettings(SETTINGS_KEY_DATA_APN_SETTINGS, aAllowError);
+}
+
+/**
+ * Convenient MozSettings setter for SETTINGS_KEY_DATA_APN_SETTINGS.
+ */
+function setDataApnSettings(aApnSettings, aAllowError) {
+  return setSettings1(SETTINGS_KEY_DATA_APN_SETTINGS, aApnSettings, aAllowError);
+}
+
+let mobileConnection;
+
+/**
+ * Push required permissions and test if
+ * |navigator.mozMobileConnections[<aServiceId>]| exists. Resolve if it does,
+ * reject otherwise.
+ *
+ * Fulfill params:
+ *   mobileConnection -- an reference to navigator.mozMobileMessage.
+ *
+ * Reject params: (none)
+ *
+ * @param aAdditonalPermissions [optional]
+ *        An array of permission strings other than "mobileconnection" to be
+ *        pushed. Default: empty string.
+ * @param aServiceId [optional]
+ *        A numeric DSDS service id. Default: 0.
+ *
+ * @return A deferred promise.
+ */
+function ensureMobileConnection(aAdditionalPermissions, aServiceId) {
+  let deferred = Promise.defer();
+
+  aAdditionalPermissions = aAdditionalPermissions || [];
+  aServiceId = aServiceId || 0;
+
+  if (aAdditionalPermissions.indexOf("mobileconnection") < 0) {
+    aAdditionalPermissions.push("mobileconnection");
+  }
+  let permissions = [];
+  for (let perm of aAdditionalPermissions) {
+    permissions.push({ "type": perm, "allow": 1, "context": document });
+  }
+
+  SpecialPowers.pushPermissions(permissions, function() {
+    ok(true, "permissions pushed: " + JSON.stringify(permissions));
+
+    // Permission changes can't change existing Navigator.prototype
+    // objects, so grab our objects from a new Navigator.
+    let ifr = document.createElement("iframe");
+    ifr.addEventListener("load", function load() {
+      ifr.removeEventListener("load", load);
+
+      mobileConnection =
+        ifr.contentWindow.navigator.mozMobileConnections[aServiceId];
+
+      if (mobileConnection) {
+        log("navigator.mozMobileConnections[" + aServiceId + "] is instance of " +
+            mobileConnection.constructor);
+      } else {
+        log("navigator.mozMobileConnections[" + aServiceId + "] is undefined");
+      }
+
+      if (mobileConnection instanceof MozMobileConnection) {
+        deferred.resolve(mobileConnection);
+      } else {
+        deferred.reject();
+      }
+    });
+
+    document.body.appendChild(ifr);
+  });
+
+  return deferred.promise;
+}
+
+/**
+ * Wait for one named MobileConnection 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();
+
+  mobileConnection.addEventListener(aEventName, function onevent(aEvent) {
+    mobileConnection.removeEventListener(aEventName, onevent);
+
+    ok(true, "MobileConnection event '" + aEventName + "' got.");
+    deferred.resolve(aEvent);
+  });
+
+  return deferred.promise;
+}
+
+/**
+ * Set data connection enabling state and wait for "datachange" event.
+ *
+ * Resolve if data connection state changed to the expected one.  Never reject.
+ *
+ * Fulfill params: (none)
+ *
+ * @param aEnabled
+ *        A boolean state.
+ *
+ * @return A deferred promise.
+ */
+function setDataEnabledAndWait(aEnabled) {
+  let deferred = Promise.defer();
+
+  let promises = [];
+  promises.push(waitForManagerEvent("datachange"));
+  promises.push(setDataEnabled(aEnabled));
+  Promise.all(promises).then(function keepWaiting() {
+    // To ignore some transient states, we only resolve that deferred promise
+    // when the |connected| state equals to the expected one and never rejects.
+    let connected = mobileConnection.data.connected;
+    if (connected == aEnabled) {
+      deferred.resolve();
+      return;
+    }
+
+    return waitForManagerEvent("datachange").then(keepWaiting);
+  });
+
+  return deferred.promise;
+}
+
+/**
+ * Set voice/data roaming emulation and wait for state change.
+ *
+ * Fulfill params: (none)
+ *
+ * @param aRoaming
+ *        A boolean state.
+ *
+ * @return A deferred promise.
+ */
+function setEmulatorRoamingAndWait(aRoaming) {
+  function doSetAndWait(aWhich, aRoaming) {
+    let promises = [];
+    promises.push(waitForManagerEvent(aWhich + "change"));
+
+    let cmd = "gsm " + aWhich + " " + (aRoaming ? "roaming" : "home");
+    promises.push(runEmulatorCmdSafe(cmd));
+    return Promise.all(promises)
+      .then(() => is(mobileConnection[aWhich].roaming, aRoaming,
+                     aWhich + ".roaming"));
+  }
+
+  // Set voice registration state first and then data registration state.
+  return doSetAndWait("voice", aRoaming)
+    .then(() => doSetAndWait("data", aRoaming));
+}
+
+let _networkManager;
+
+/**
+ * Get internal NetworkManager service.
+ */
+function getNetworkManager() {
+  if (!_networkManager) {
+    _networkManager = Cc["@mozilla.org/network/manager;1"]
+                    .getService(Ci.nsINetworkManager);
+    ok(_networkManager, "NetworkManager");
+  }
+
+  return _networkManager;
+}
+
+/**
+ * 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;
+  });
+}
+
+/**
+ * Basic test routine helper for mobile connection tests.
+ *
+ * This helper does nothing but clean-ups.
+ *
+ * @param aTestCaseMain
+ *        A function that takes no parameter.
+ */
+function startTestBase(aTestCaseMain) {
+  Promise.resolve()
+    .then(aTestCaseMain)
+    .then(cleanUp, function() {
+      ok(false, 'promise rejects during test.');
+      cleanUp();
+    });
+}
+
+/**
+ * Common test routine helper for mobile connection tests.
+ *
+ * This function ensures global |mobileConnection| variable is available during
+ * the process and performs clean-ups as well.
+ *
+ * @param aTestCaseMain
+ *        A function that takes one parameter -- mobileConnection.
+ * @param aAdditonalPermissions [optional]
+ *        An array of permission strings other than "mobileconnection" to be
+ *        pushed. Default: empty string.
+ * @param aServiceId [optional]
+ *        A numeric DSDS service id. Default: 0.
+ */
+function startTestCommon(aTestCaseMain, aAdditionalPermissions, aServiceId) {
+  startTestBase(function() {
+    return ensureMobileConnection(aAdditionalPermissions, aServiceId)
+      .then(aTestCaseMain);
+  });
+}
--- a/dom/mobileconnection/tests/marionette/manifest.ini
+++ b/dom/mobileconnection/tests/marionette/manifest.ini
@@ -18,8 +18,10 @@ disabled = Bug 808783
 [test_mobile_roaming_preference.js]
 [test_call_barring_get_option.js]
 [test_call_barring_set_error.js]
 [test_call_barring_change_password.js]
 [test_mobile_set_radio.js]
 [test_mobile_last_known_network.js]
 [test_mobile_icc_change.js]
 [test_mobile_connections_array_uninitialized.js]
+[test_mobile_data_ipv6.js]
+disabled = Bug 978071
new file mode 100644
--- /dev/null
+++ b/dom/mobileconnection/tests/marionette/test_mobile_data_ipv6.js
@@ -0,0 +1,112 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = "head.js";
+
+/**
+ * Test resulting IP address format with given APN settings.
+ *
+ * This test utility function performs following steps:
+ *
+ *   1) set "ril.data.apnSettings" to a given settings object,
+ *   2) enable data connection and wait for a "datachange" event,
+ *   3) check the IP address type of the active network interface,
+ *   4) disable data connection.
+ *
+ * Fulfill params: (none)
+ * Reject params: (none)
+ *
+ * @param aApnSettings
+ *        An APN settings value.
+ * @param aIsIPv6
+ *        A boolean value indicating whether we're expecting an IPv6 address.
+ *
+ * @return A deferred promise.
+ */
+function doTest(aApnSettings, aIsIPv6) {
+  return setDataApnSettings([])
+    .then(() => setDataApnSettings(aApnSettings))
+    .then(() => setDataEnabledAndWait(true))
+    .then(function() {
+      let nm = getNetworkManager();
+      let active = nm.active;
+      ok(active, "Active network interface");
+
+      log("  Interface: " + active.name);
+      log("  Address: " + active.ip);
+      if (aIsIPv6) {
+        ok(active.ip.indexOf(":") > 0, "IPv6 address");
+      } else {
+        ok(active.ip.indexOf(":") < 0, "IPv4 address");
+      }
+    })
+    .then(() => setDataEnabledAndWait(false));
+}
+
+function doTestHome(aApnSettings, aProtocol) {
+  log("Testing \"" + aProtocol + "\"@HOME... ");
+
+  // aApnSettings is a double-array of per PDP context settings.  The first
+  // index is a DSDS service ID, and the second one is the index of pre-defined
+  // PDP context settings of a specified radio interface.  We use 0 for both as
+  // default here.
+  aApnSettings[0][0].protocol = aProtocol;
+  delete aApnSettings[0][0].roaming_protocol;
+
+  return doTest(aApnSettings, aProtocol === "IPV6");
+}
+
+function doTestRoaming(aApnSettings, aRoaminProtocol) {
+  log("Testing \"" + aRoaminProtocol + "\"@ROMAING... ");
+
+  // aApnSettings is a double-array of per PDP context settings.  The first
+  // index is a DSDS service ID, and the second one is the index of pre-defined
+  // PDP context settings of a specified radio interface.  We use 0 for both as
+  // default here.
+  delete aApnSettings[0][0].protocol;
+  aApnSettings[0][0].roaming_protocol = aRoaminProtocol;
+
+  return doTest(aApnSettings, aRoaminProtocol === "IPV6");
+}
+
+startTestCommon(function() {
+  let origApnSettings;
+
+  return setDataRoamingEnabled(true)
+    .then(getDataApnSettings)
+    .then(function(aResult) {
+      // If already set, then save original APN settings.
+      origApnSettings = JSON.parse(JSON.stringify(aResult));
+      return aResult;
+    }, function() {
+      // Return our own default value.
+      return [[{ "carrier": "T-Mobile US",
+                 "apn": "epc.tmobile.com",
+                 "mmsc": "http://mms.msg.eng.t-mobile.com/mms/wapenc",
+                 "types": ["default", "supl", "mms"] }]];
+    })
+
+    .then(function(aApnSettings) {
+      return Promise.resolve()
+
+        .then(() => doTestHome(aApnSettings, "NoSuchProtocol"))
+        .then(() => doTestHome(aApnSettings, "IP"))
+        .then(() => doTestHome(aApnSettings, "IPV6"))
+
+        .then(() => setEmulatorRoamingAndWait(true))
+
+        .then(() => doTestRoaming(aApnSettings, "NoSuchProtocol"))
+        .then(() => doTestRoaming(aApnSettings, "IP"))
+        .then(() => doTestRoaming(aApnSettings, "IPV6"))
+
+        .then(() => setEmulatorRoamingAndWait(false));
+    })
+
+    .then(() => setDataRoamingEnabled(false))
+    .then(function() {
+      if (origApnSettings) {
+        return setDataApnSettings(origApnSettings);
+      }
+    });
+}, ["settings-read", "settings-write"]);
--- a/dom/mobilemessage/tests/marionette/head.js
+++ b/dom/mobilemessage/tests/marionette/head.js
@@ -1,16 +1,17 @@
 /* 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.mozMobileMessage| exists.
+/**
+ * Push required permissions and test if |navigator.mozMobileMessage| exists.
  * Resolve if it does, reject otherwise.
  *
  * Fulfill params:
  *   manager -- an reference to navigator.mozMobileMessage.
  *
  * Reject params: (none)
  *
  * @return A deferred promise.
@@ -39,17 +40,18 @@ function ensureMobileMessage() {
     } else {
       deferred.reject();
     }
   });
 
   return deferred.promise;
 }
 
-/* Send a SMS message to a single receiver.  Resolve if it succeeds, reject
+/**
+ * Send a SMS message to a single receiver.  Resolve if it succeeds, reject
  * otherwise.
  *
  * Fulfill params:
  *   message -- the sent SmsMessage.
  *
  * Reject params:
  *   error -- a DOMError.
  *
@@ -67,17 +69,18 @@ function sendSmsWithSuccess(aReceiver, a
   };
   request.onerror = function(event) {
     deferred.reject(event.target.error);
   };
 
   return deferred.promise;
 }
 
-/* Send a MMS message with specified parameters.  Resolve if it fails, reject
+/**
+ * Send a MMS message with specified parameters.  Resolve if it fails, reject
  * otherwise.
  *
  * Fulfill params:
  *   message -- the failed MmsMessage
  *
  * Reject params: (none)
  *
  * @param aMmsParameters a MmsParameters instance.
@@ -95,17 +98,18 @@ function sendMmsWithFailure(aMmsParamete
   let request = manager.sendMMS(aMmsParameters);
   request.onsuccess = function(event) {
     deferred.reject();
   };
 
   return deferred.promise;
 }
 
-/* Retrieve messages from database.
+/**
+ * Retrieve messages from database.
  *
  * Fulfill params:
  *   messages -- an array of {Sms,Mms}Message instances.
  *
  * Reject params:
  *   event -- a DOMEvent
  *
  * @param aFilter an optional MozSmsFilter instance.
@@ -131,31 +135,33 @@ function getMessages(aFilter, aReverse) 
 
     deferred.resolve(messages);
   };
   cursor.onerror = deferred.reject.bind(deferred);
 
   return deferred.promise;
 }
 
-/* Retrieve all messages from database.
+/**
+ * Retrieve all messages from database.
  *
  * Fulfill params:
  *   messages -- an array of {Sms,Mms}Message instances.
  *
  * Reject params:
  *   event -- a DOMEvent
  *
  * @return A deferred promise.
  */
 function getAllMessages() {
   return getMessages(null, false);
 }
 
-/* Retrieve all threads from database.
+/**
+ * Retrieve all threads from database.
  *
  * Fulfill params:
  *   threads -- an array of MozMobileMessageThread instances.
  *
  * Reject params:
  *   event -- a DOMEvent
  *
  * @return A deferred promise.
@@ -174,17 +180,18 @@ function getAllThreads() {
 
     deferred.resolve(threads);
   };
   cursor.onerror = deferred.reject.bind(deferred);
 
   return deferred.promise;
 }
 
-/* Retrieve a single specified thread from database.
+/**
+ * Retrieve a single specified thread from database.
  *
  * Fulfill params:
  *   thread -- a MozMobileMessageThread instance.
  *
  * Reject params:
  *   event -- a DOMEvent if an error occurs in the retrieving process, or
  *            undefined if there's no such thread.
  *
@@ -199,17 +206,18 @@ function getThreadById(aThreadId) {
         if (thread.id === aThreadId) {
           return thread;
         }
       }
       throw undefined;
     });
 }
 
-/* Delete messages specified from database.
+/**
+ * Delete messages specified from database.
  *
  * Fulfill params:
  *   result -- an array of boolean values indicating whether delesion was
  *             actually performed on the message record with corresponding id.
  *
  * Reject params:
  *   event -- a DOMEvent.
  *
@@ -229,17 +237,18 @@ function deleteMessagesById(aMessageIds)
   request.onsuccess = function(event) {
     deferred.resolve(event.target.result);
   };
   request.onerror = deferred.reject.bind(deferred);
 
   return deferred.promise;
 }
 
-/* Delete messages specified from database.
+/**
+ * Delete messages specified from database.
  *
  * Fulfill params:
  *   result -- an array of boolean values indicating whether delesion was
  *             actually performed on the message record with corresponding id.
  *
  * Reject params:
  *   event -- a DOMEvent.
  *
@@ -247,34 +256,36 @@ function deleteMessagesById(aMessageIds)
  *
  * @return A deferred promise.
  */
 function deleteMessages(aMessages) {
   let ids = messagesToIds(aMessages);
   return deleteMessagesById(ids);
 }
 
-/* Delete all messages from database.
+/**
+ * Delete all messages from database.
  *
  * Fulfill params:
  *   ids -- an array of numeric values identifying those deleted
  *          {Sms,Mms}Messages.
  *
  * Reject params:
  *   event -- a DOMEvent.
  *
  * @return A deferred promise.
  */
 function deleteAllMessages() {
   return getAllMessages().then(deleteMessages);
 }
 
 let pendingEmulatorCmdCount = 0;
 
-/* Send emulator command with safe guard.
+/**
+ * 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.
  *
@@ -296,64 +307,68 @@ function runEmulatorCmdSafe(aCommand) {
     } else {
       deferred.reject(aResult);
     }
   });
 
   return deferred.promise;
 }
 
-/* Send simple text SMS to emulator.
+/**
+ * Send simple text SMS to emulator.
  *
  * Fulfill params:
  *   result -- an array of emulator response lines.
  *
  * Reject params:
  *   result -- an array of emulator response lines.
  *
  * @return A deferred promise.
  */
 function sendTextSmsToEmulator(aFrom, aText) {
   let command = "sms send " + aFrom + " " + aText;
   return runEmulatorCmdSafe(command);
 }
 
-/* Send raw SMS TPDU to emulator.
+/**
+ * Send raw SMS TPDU to emulator.
  *
  * Fulfill params:
  *   result -- an array of emulator response lines.
  *
  * Reject params:
  *   result -- an array of emulator response lines.
  *
  * @return A deferred promise.
  */
 function sendRawSmsToEmulator(aPdu) {
   let command = "sms pdu " + aPdu;
   return runEmulatorCmdSafe(command);
 }
 
-/* Name space for MobileMessageDB.jsm.  Only initialized after first call to
+/**
+ * Name space for MobileMessageDB.jsm.  Only initialized after first call to
  * newMobileMessageDB.
  */
 let MMDB;
 
 // Create a new MobileMessageDB instance.
 function newMobileMessageDB() {
   if (!MMDB) {
     MMDB = Cu.import("resource://gre/modules/MobileMessageDB.jsm", {});
     is(typeof MMDB.MobileMessageDB, "function", "MMDB.MobileMessageDB");
   }
 
   let mmdb = new MMDB.MobileMessageDB();
   ok(mmdb, "MobileMessageDB instance");
   return mmdb;
 }
 
-/* Initialize a MobileMessageDB.  Resolve if initialized with success, reject
+/**
+ * Initialize a MobileMessageDB.  Resolve if initialized with success, reject
  * otherwise.
  *
  * Fulfill params: a MobileMessageDB instance.
  * Reject params: a MobileMessageDB instance.
  *
  * @param aMmdb
  *        A MobileMessageDB instance.
  * @param aDbName
@@ -373,80 +388,101 @@ function initMobileMessageDB(aMmdb, aDbN
     } else {
       deferred.resolve(aMmdb);
     }
   });
 
   return deferred.promise;
 }
 
-/* Close a MobileMessageDB.
+/**
+ * Close a MobileMessageDB.
  *
  * @return The passed MobileMessageDB instance.
  */
 function closeMobileMessageDB(aMmdb) {
   aMmdb.close();
   return aMmdb;
 }
 
-/* Create a new array of id attribute of input messages.
+/**
+ * Create a new array of id attribute of input messages.
  *
  * @param aMessages an array of {Sms,Mms}Message instances.
  *
  * @return an array of numeric values.
  */
 function messagesToIds(aMessages) {
   let ids = [];
   for (let message of aMessages) {
     ids.push(message.id);
   }
   return ids;
 }
 
 // A reference to a nsIUUIDGenerator service.
 let uuidGenerator;
 
-/* Generate a new UUID.
+/**
+ * Generate a new UUID.
  *
  * @return A UUID string.
  */
 function newUUID() {
   if (!uuidGenerator) {
     uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
                     .getService(Ci.nsIUUIDGenerator);
     ok(uuidGenerator, "uuidGenerator");
   }
 
   return uuidGenerator.generateUUID().toString();
 }
 
-/* Flush permission settings and call |finish()|.
+/**
+ * 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;
   });
 }
 
+/**
+ * Basic test routine helper for mobile message tests.
+ *
+ * This helper does nothing but clean-ups.
+ *
+ * @param aTestCaseMain
+ *        A function that takes no parameter.
+ */
 function startTestBase(aTestCaseMain) {
   Promise.resolve()
          .then(aTestCaseMain)
          .then(cleanUp, function() {
            ok(false, 'promise rejects during test.');
            cleanUp();
          });
 }
 
+/**
+ * Common test routine helper for mobile message tests.
+ *
+ * This function ensures global |manager| variable is available during the
+ * process and performs clean-ups as well.
+ *
+ * @param aTestCaseMain
+ *        A function that takes no parameter.
+ */
 function startTestCommon(aTestCaseMain) {
   startTestBase(function() {
     return ensureMobileMessage()
       .then(deleteAllMessages)
       .then(aTestCaseMain)
       .then(deleteAllMessages);
   });
 }
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -47,16 +47,20 @@ function debug(s) {
 let RILQUIRKS_DATA_REGISTRATION_ON_DEMAND =
   libcutils.property_get("ro.moz.ril.data_reg_on_demand", "false") == "true";
 
 // Ril quirk to always turn the radio off for the client without SIM card
 // except hw default client.
 let RILQUIRKS_RADIO_OFF_WO_CARD =
   libcutils.property_get("ro.moz.ril.radio_off_wo_card", "false") == "true";
 
+// Ril quirk to enable IPv6 protocol/roaming protocol in APN settings.
+let RILQUIRKS_HAVE_IPV6 =
+  libcutils.property_get("ro.moz.ril.ipv6", "false") == "true";
+
 const RADIOINTERFACELAYER_CID =
   Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}");
 const RADIOINTERFACE_CID =
   Components.ID("{6a7c91f0-a2b3-4193-8562-8969296c0b54}");
 const RILNETWORKINTERFACE_CID =
   Components.ID("{3bdd52a9-3965-4130-b569-0ac5afed045e}");
 const GSMICCINFO_CID =
   Components.ID("{d90c4261-a99d-47bc-8b05-b057bb7e8f8a}");
@@ -4520,22 +4524,35 @@ RILNetworkInterface.prototype = {
     // Use the default authType if the value in database is invalid.
     // For the case that user might not select the authentication type.
     if (authType == -1) {
       if (DEBUG) {
         this.debug("Invalid authType " + this.apnSetting.authtype);
       }
       authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(RIL.GECKO_DATACALL_AUTH_DEFAULT);
     }
+    let pdpType = RIL.GECKO_DATACALL_PDP_TYPE_IP;
+    if (RILQUIRKS_HAVE_IPV6) {
+      pdpType = !radioInterface.rilContext.data.roaming
+              ? this.apnSetting.protocol
+              : this.apnSetting.roaming_protocol;
+      if (RIL.RIL_DATACALL_PDP_TYPES.indexOf(pdpType) < 0) {
+        if (DEBUG) {
+          this.debug("Invalid pdpType '" + pdpType + "', using '" +
+                     RIL.GECKO_DATACALL_PDP_TYPE_DEFAULT + "'");
+        }
+        pdpType = RIL.GECKO_DATACALL_PDP_TYPE_DEFAULT;
+      }
+    }
     radioInterface.setupDataCall(radioTechnology,
                                  this.apnSetting.apn,
                                  this.apnSetting.user,
                                  this.apnSetting.password,
                                  authType,
-                                 "IP");
+                                 pdpType);
     this.connecting = true;
   },
 
   reset: function() {
     let apnRetryTimer;
     this.connecting = false;
     // We will retry the connection in increasing times
     // based on the function: time = A * numer_of_retries^2 + B
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -2356,16 +2356,25 @@ this.GECKO_DATACALL_AUTH_PAP_OR_CHAP = "
 this.GECKO_DATACALL_AUTH_DEFAULT = GECKO_DATACALL_AUTH_PAP_OR_CHAP;
 this.RIL_DATACALL_AUTH_TO_GECKO = [
   GECKO_DATACALL_AUTH_NONE,         // DATACALL_AUTH_NONE
   GECKO_DATACALL_AUTH_PAP,          // DATACALL_AUTH_PAP
   GECKO_DATACALL_AUTH_CHAP,         // DATACALL_AUTH_CHAP
   GECKO_DATACALL_AUTH_PAP_OR_CHAP   // DATACALL_AUTH_PAP_OR_CHAP
 ];
 
+this.GECKO_DATACALL_PDP_TYPE_IP = "IP";
+this.GECKO_DATACALL_PDP_TYPE_IPV6 = "IPV6";
+this.GECKO_DATACALL_PDP_TYPE_DEFAULT = GECKO_DATACALL_PDP_TYPE_IP;
+this.RIL_DATACALL_PDP_TYPES = [
+  GECKO_DATACALL_PDP_TYPE_IP,
+  GECKO_DATACALL_PDP_TYPE_IPV6,
+  // TODO: Bug 978711 - Support IPV4V6
+];
+
 this.DATACALL_PROFILE_DEFAULT = 0;
 this.DATACALL_PROFILE_TETHERED = 1;
 this.DATACALL_PROFILE_OEM_BASE = 1000;
 
 this.DATACALL_DEACTIVATE_NO_REASON = 0;
 this.DATACALL_DEACTIVATE_RADIO_SHUTDOWN = 1;
 
 this.DATACALL_ACTIVE_UNKNOWN = -1;
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -3957,18 +3957,19 @@ RilObject.prototype = {
         continue;
       }
       // Minor change, just update and notify.
       if (DEBUG) {
         this.context.debug("Data link minor change, just update and notify.");
       }
       currentDataCall.gw = updatedDataCall.gw;
       if (updatedDataCall.dns) {
-        currentDataCall.dns[0] = updatedDataCall.dns[0];
-        currentDataCall.dns[1] = updatedDataCall.dns[1];
+        currentDataCall.dns = updatedDataCall.dns.slice();
+      } else {
+        currentDataCall.dns = [];
       }
       currentDataCall.rilMessageType = "datacallstatechange";
       this.sendChromeMessage(currentDataCall);
     }
 
     for each (let newDataCall in datacalls) {
       if (!newDataCall.ifname) {
         continue;
--- a/testing/xpcshell/mach_commands.py
+++ b/testing/xpcshell/mach_commands.py
@@ -6,31 +6,41 @@
 
 from __future__ import unicode_literals, print_function
 
 import mozpack.path
 import logging
 import os
 import shutil
 import sys
+import urllib2
 
 from StringIO import StringIO
 
 from mozbuild.base import (
     MachCommandBase,
     MozbuildObject,
     MachCommandConditions as conditions,
 )
 
 from mach.decorators import (
     CommandArgument,
     CommandProvider,
     Command,
 )
 
+ADB_NOT_FOUND = '''
+The %s command requires the adb binary to be on your path.
+
+If you have a B2G build, this can be found in
+'%s/out/host/<platform>/bin'.
+'''.lstrip()
+
+BUSYBOX_URL = 'http://www.busybox.net/downloads/binaries/latest/busybox-armv7l'
+
 
 if sys.version_info[0] < 3:
     unicode_type = unicode
 else:
     unicode_type = str
 
 # Simple filter to omit the message emitted as a test file begins.
 class TestStartFilter(logging.Filter):
@@ -269,19 +279,109 @@ class AndroidXPCShellRunner(MozbuildObje
                       mobileArgs=xpcshell.mobileArgs,
                       **options.__dict__)
 
         self.log_manager.terminal_handler.removeFilter(xpcshell_filter)
         self.log_manager.disable_unstructured()
 
         return int(not result)
 
+class B2GXPCShellRunner(MozbuildObject):
+    def __init__(self, *args, **kwargs):
+        MozbuildObject.__init__(self, *args, **kwargs)
+
+        # TODO Bug 794506 remove once mach integrates with virtualenv.
+        build_path = os.path.join(self.topobjdir, 'build')
+        if build_path not in sys.path:
+            sys.path.append(build_path)
+
+        build_path = os.path.join(self.topsrcdir, 'build')
+        if build_path not in sys.path:
+            sys.path.append(build_path)
+
+        self.tests_dir = os.path.join(self.topobjdir, '_tests')
+        self.xpcshell_dir = os.path.join(self.tests_dir, 'xpcshell')
+        self.bin_dir = os.path.join(self.distdir, 'bin')
+
+    def _download_busybox(self, b2g_home):
+        system_bin = os.path.join(b2g_home, 'out', 'target', 'product', 'generic', 'system', 'bin')
+        busybox_path = os.path.join(system_bin, 'busybox')
+
+        if os.path.isfile(busybox_path):
+            return busybox_path
+
+        if not os.path.isdir(system_bin):
+            os.makedirs(system_bin)
+
+        try:
+            data = urllib2.urlopen(BUSYBOX_URL)
+        except urllib2.URLError:
+            print('There was a problem downloading busybox. Proceeding without it,' \
+                  'initial setup will be slow.')
+            return
+
+        with open(busybox_path, 'wb') as f:
+            f.write(data.read())
+        return busybox_path
+
+    def run_test(self, test_file, b2g_home=None, busybox=None,
+                 # ignore parameters from other platforms' options
+                 **kwargs):
+        try:
+            import which
+            which.which('adb')
+        except which.WhichError:
+            # TODO Find adb automatically if it isn't on the path
+            print(ADB_NOT_FOUND % ('mochitest-remote', b2g_home))
+            sys.exit(1)
+
+        test_path = None
+        if test_file:
+            test_path = self._wrap_path_argument(test_file).relpath()
+
+        import runtestsb2g
+        parser = runtestsb2g.B2GOptions()
+        options, args = parser.parse_args([])
+
+        options.b2g_path = b2g_home
+        options.busybox = busybox or os.environ.get('BUSYBOX')
+        options.emulator = 'arm'
+        options.localLib = self.bin_dir
+        options.localBin = self.bin_dir
+        options.logcat_dir = self.xpcshell_dir
+        options.manifest = os.path.join(self.xpcshell_dir, 'xpcshell_b2g.ini')
+        options.mozInfo = os.path.join(self.topobjdir, 'mozinfo.json')
+        options.objdir = self.topobjdir
+        options.symbolsPath = os.path.join(self.distdir, 'crashreporter-symbols'),
+        options.testingModulesDir = os.path.join(self.tests_dir, 'modules')
+        options.testsRootDir = self.xpcshell_dir
+        options.testPath = test_path
+        options.use_device_libs = True
+
+        if not options.busybox:
+            options.busybox = self._download_busybox(b2g_home)
+
+        return runtestsb2g.run_remote_xpcshell(parser, options, args)
+
+def is_platform_supported(cls):
+    """Must have a Firefox, Android or B2G build."""
+    return conditions.is_android(cls) or \
+           conditions.is_b2g(cls) or \
+           conditions.is_firefox(cls)
+
 @CommandProvider
 class MachCommands(MachCommandBase):
+    def __init__(self, context):
+        MachCommandBase.__init__(self, context)
+
+        for attr in ('b2g_home', 'device_name'):
+            setattr(self, attr, getattr(context, attr, None))
+
     @Command('xpcshell-test', category='testing',
+        conditions=[is_platform_supported],
         description='Run XPCOM Shell tests.')
     @CommandArgument('test_file', default='all', nargs='?', metavar='TEST',
         help='Test to run. Can be specified as a single JS file, a directory, '
              'or omitted. If omitted, the entire test suite is executed.')
     @CommandArgument("--debugger", default=None, metavar='DEBUGGER',
                      help = "Run xpcshell under the given debugger.")
     @CommandArgument("--debugger-args", default=None, metavar='ARGS', type=str,
                      dest = "debuggerArgs",
@@ -308,29 +408,34 @@ class MachCommands(MachCommandBase):
     @CommandArgument('--port', type=int, default=20701,
         help='(Android) Port of device')
     @CommandArgument('--remote_test_root', type=str, default=None,
         help='(Android) Remote test root such as /mnt/sdcard or /data/local')
     @CommandArgument('--no-setup', action='store_true',
         help='(Android) Do not copy files to device')
     @CommandArgument('--local-apk', type=str, default=None,
         help='(Android) Use specified Fennec APK')
+    @CommandArgument('--busybox', type=str, default=None,
+        help='(B2G) Path to busybox binary (speeds up installation of tests).')
     def run_xpcshell_test(self, **params):
         from mozbuild.controller.building import BuildDriver
 
         # We should probably have a utility function to ensure the tree is
         # ready to run tests. Until then, we just create the state dir (in
         # case the tree wasn't built with mach).
         self._ensure_state_subdir_exists('.')
 
         driver = self._spawn(BuildDriver)
         driver.install_tests(remove=False)
 
         if conditions.is_android(self):
             xpcshell = self._spawn(AndroidXPCShellRunner)
+        elif conditions.is_b2g(self):
+            xpcshell = self._spawn(B2GXPCShellRunner)
+            params['b2g_home'] = self.b2g_home
         else:
             xpcshell = self._spawn(XPCShellRunner)
         xpcshell.cwd = self._mach_context.cwd
 
         try:
             return xpcshell.run_test(**params)
         except InvalidTestPathError as e:
             print(e.message)
--- a/testing/xpcshell/runtestsb2g.py
+++ b/testing/xpcshell/runtestsb2g.py
@@ -148,19 +148,17 @@ class B2GOptions(RemoteXPCShellOptions):
 
         if options.geckoPath and not options.emulator:
             self.error("You must specify --emulator if you specify --gecko-path")
 
         if options.logcat_dir and not options.emulator:
             self.error("You must specify --emulator if you specify --logcat-dir")
         return RemoteXPCShellOptions.verifyRemoteOptions(self, options)
 
-def main():
-    parser = B2GOptions()
-    options, args = parser.parse_args()
+def run_remote_xpcshell(parser, options, args):
     options = parser.verifyRemoteOptions(options)
 
     # Create the Marionette instance
     kwargs = {}
     if options.emulator:
         kwargs['emulator'] = options.emulator
         if options.no_window:
             kwargs['noWindow'] = True
@@ -207,16 +205,21 @@ def main():
                                  mobileArgs=xpcsh.mobileArgs,
                                  **options.__dict__):
             sys.exit(1)
     except:
         print "Automation Error: Exception caught while running tests"
         traceback.print_exc()
         sys.exit(1)
 
+def main():
+    parser = B2GOptions()
+    options, args = parser.parse_args()
+
+    run_remote_xpcshell(parser, options, args)
 
 # You usually run this like :
 # python runtestsb2g.py --emulator arm --b2gpath $B2GPATH --manifest $MANIFEST [--xre-path $MOZ_HOST_BIN
 #                                                                               --adbpath $ADB_PATH
 #                                                                               ...]
 #
 # For xUnit output you should also pass in --tests-root-dir ..objdir-gecko/_tests
 #                                          --xunit-file ..objdir_gecko/_tests/results.xml