Merge b2ginbound to m-c a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 01 May 2015 17:22:34 -0700
changeset 273409 767d72d50db81f48963cce3fb34ac544fb1a12df
parent 273386 3322c490317bdc5bc4dd49e9165ebdf797c444fc (current diff)
parent 273408 e99d30fb8fdc0bbef93e4dc45454d930d1cbd1ab (diff)
child 273410 1e8d30cb367ed15a889e307db47b94cc775233bf
child 273421 647d32b7a5a6d3c9bd3b30d84549917de96ce157
child 273480 76963a5d187792d7879600c9f1d09ac931874ff2
child 273501 a2bcc5840bd0d7cab902989bbc2ceb54d7d7be93
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone40.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 b2ginbound to m-c a=merge
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="2eda36a4795012a5d1275b77ebb20ac377c8cd26">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="173b3104bfcbd23fc9dccd4b0035fc49aae3d444">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="8c2d32bccc7061e9ca0165135457c3fd53e7107e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4efd19d199ae52656604f794c5a77518400220fd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>
   <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="2eda36a4795012a5d1275b77ebb20ac377c8cd26">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="173b3104bfcbd23fc9dccd4b0035fc49aae3d444">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9a9797062c6001d6346504161c51187a2968466b"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="8c2d32bccc7061e9ca0165135457c3fd53e7107e"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="2eda36a4795012a5d1275b77ebb20ac377c8cd26">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4efd19d199ae52656604f794c5a77518400220fd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "8e64346ce8197b50b815a294278797bc144aa3e6", 
+        "git_revision": "07a1a20b86931ee9911b16df94df60a178825bb2", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "1bbaa54b674c42e0d8b2fe31d8b0080901811fa0", 
+    "revision": "99b2099a5fa6ac2567993f2c859d651934556464", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4efd19d199ae52656604f794c5a77518400220fd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="8e64346ce8197b50b815a294278797bc144aa3e6"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="07a1a20b86931ee9911b16df94df60a178825bb2"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="d3868ff4bb3a4b81382795e2784258c210fe6cb8"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="adb24954bf8068f21705b570450475d183336b2d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0627790166dccd8dd370fa7d9f434ed9fc027fb4"/>
--- a/dom/bluetooth/BluetoothInterface.h
+++ b/dom/bluetooth/BluetoothInterface.h
@@ -883,16 +883,19 @@ public:
   virtual void DutModeRecvNotification(uint16_t aOpcode,
                                        const uint8_t* aBuf, uint8_t aLen) { }
   virtual void LeTestModeNotification(BluetoothStatus aStatus,
                                       uint16_t aNumPackets) { }
 
   virtual void EnergyInfoNotification(const BluetoothActivityEnergyInfo& aInfo)
   { }
 
+  virtual void BackendErrorNotification(bool aCrashed)
+  { }
+
 protected:
   BluetoothNotificationHandler()
   { }
 
   virtual ~BluetoothNotificationHandler();
 };
 
 class BluetoothResultHandler
--- a/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
@@ -533,16 +533,17 @@ BluetoothA2dpManager::Connect(const nsAS
 
   sBtA2dpInterface->Connect(aDeviceAddress, new ConnectResultHandler());
 }
 
 void
 BluetoothA2dpManager::OnDisconnectError()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  NS_ENSURE_TRUE_VOID(mController);
 
   mController->NotifyCompletion(NS_LITERAL_STRING(ERR_DISCONNECTION_FAILED));
 }
 
 class BluetoothA2dpManager::DisconnectResultHandler final
   : public BluetoothA2dpResultHandler
 {
 public:
@@ -577,17 +578,19 @@ BluetoothA2dpManager::Disconnect(Bluetoo
   }
 
   MOZ_ASSERT(!mDeviceAddress.IsEmpty());
 
   mController = aController;
 
   if (!sBtA2dpInterface) {
     BT_LOGR("sBluetoothA2dpInterface is null");
-    aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
+    if (aController) {
+      aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
+    }
     return;
   }
 
   sBtA2dpInterface->Disconnect(mDeviceAddress, new DisconnectResultHandler());
 }
 
 void
 BluetoothA2dpManager::OnConnect(const nsAString& aErrorStr)
--- a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp
@@ -19,16 +19,18 @@
 #include "mozilla/ipc/UnixSocketConnector.h"
 #include "mozilla/unused.h"
 #include "prrng.h"
 
 using namespace mozilla::ipc;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
+static const int sRetryInterval = 100; // ms
+
 //
 // Protocol initialization and setup
 //
 
 class BluetoothDaemonSetupModule
 {
 public:
   virtual nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) = 0;
@@ -1143,17 +1145,17 @@ private:
   {
   public:
     SspRequestInitOp(BluetoothDaemonPDU& aPDU)
     : PDUInitOp(aPDU)
     { }
 
     nsresult
     operator () (nsString& aArg1, nsString& aArg2, uint32_t& aArg3,
-                 BluetoothSspVariant aArg4, uint32_t& aArg5) const
+                 BluetoothSspVariant& aArg4, uint32_t& aArg5) const
     {
       BluetoothDaemonPDU& pdu = GetPDU();
 
       /* Read remote address */
       nsresult rv = UnpackPDU(
         pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg1));
       if (NS_FAILED(rv)) {
         return rv;
@@ -1744,16 +1746,30 @@ BluetoothDaemonChannel::GetIO()
 //
 
 /* returns the container structure of a variable; _t is the container's
  * type, _v the name of the variable, and _m is _v's field within _t
  */
 #define container(_t, _v, _m) \
   ( (_t*)( ((const unsigned char*)(_v)) - offsetof(_t, _m) ) )
 
+
+static bool
+IsDaemonRunning()
+{
+  char value[PROPERTY_VALUE_MAX];
+  NS_WARN_IF(property_get("init.svc.bluetoothd", value, "") < 0);
+  if (strcmp(value, "running")) {
+    BT_LOGR("[RESTART] Bluetooth daemon state <%s>", value);
+    return false;
+  }
+
+  return true;
+}
+
 BluetoothDaemonInterface*
 BluetoothDaemonInterface::GetInstance()
 {
   static BluetoothDaemonInterface* sBluetoothInterface;
 
   if (sBluetoothInterface) {
     return sBluetoothInterface;
   }
@@ -1764,16 +1780,52 @@ BluetoothDaemonInterface::GetInstance()
 }
 
 BluetoothDaemonInterface::BluetoothDaemonInterface()
 { }
 
 BluetoothDaemonInterface::~BluetoothDaemonInterface()
 { }
 
+class BluetoothDaemonInterface::StartDaemonTask final : public Task
+{
+public:
+  StartDaemonTask(BluetoothDaemonInterface* aInterface,
+                  const nsACString& aCommand)
+    : mInterface(aInterface)
+    , mCommand(aCommand)
+  {
+    MOZ_ASSERT(mInterface);
+  }
+
+  void Run() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    BT_LOGR("Start Daemon Task");
+    // Start Bluetooth daemon again
+    if (NS_WARN_IF(property_set("ctl.start", mCommand.get()) < 0)) {
+      mInterface->OnConnectError(CMD_CHANNEL);
+    }
+
+    // We're done if Bluetooth daemon is already running
+    if (IsDaemonRunning()) {
+      return;
+    }
+
+    // Otherwise try again later
+    MessageLoop::current()->PostDelayedTask(FROM_HERE,
+      new StartDaemonTask(mInterface, mCommand), sRetryInterval);
+  }
+
+private:
+  BluetoothDaemonInterface* mInterface;
+  nsCString mCommand;
+};
+
 class BluetoothDaemonInterface::InitResultHandler final
   : public BluetoothSetupResultHandler
 {
 public:
   InitResultHandler(BluetoothDaemonInterface* aInterface,
                     BluetoothResultHandler* aRes)
     : mInterface(aInterface)
     , mRes(aRes)
@@ -1826,16 +1878,29 @@ BluetoothDaemonInterface::OnConnectSucce
   switch (aChannel) {
     case LISTEN_SOCKET: {
         // Init, step 2: Start Bluetooth daemon */
         nsCString value("bluetoothd:-a ");
         value.Append(mListenSocketName);
         if (NS_WARN_IF(property_set("ctl.start", value.get()) < 0)) {
           OnConnectError(CMD_CHANNEL);
         }
+
+        /*
+         * If Bluetooth daemon is not running, retry to start it later.
+         *
+         * This condition happens when when we restart Bluetooth daemon
+         * immediately after it crashed, as the daemon state remains 'stopping'
+         * instead of 'stopped'. Due to the limitation of property service,
+         * hereby add delay. See Bug 1143925 Comment 41.
+         */
+        if (!IsDaemonRunning()) {
+          MessageLoop::current()->PostDelayedTask(FROM_HERE,
+              new StartDaemonTask(this, value), sRetryInterval);
+        }
       }
       break;
     case CMD_CHANNEL:
       // Init, step 3: Listen for notification channel...
       if (!mNtfChannel) {
         mNtfChannel = new BluetoothDaemonChannel(this, NTF_CHANNEL, mProtocol);
       } else if (
         NS_WARN_IF(mNtfChannel->GetConnectionStatus() == SOCKET_CONNECTED)) {
@@ -1885,50 +1950,71 @@ BluetoothDaemonInterface::OnConnectError
         if (res) {
           DispatchError(res, STATUS_FAIL);
         }
       }
       break;
   }
 }
 
+/*
+ * Three cases for restarting:
+ * a) during startup
+ * b) during regular service
+ * c) during shutdown
+ * For (a)/(c) cases, mResultHandlerQ contains an element, but case (b)
+ * mResultHandlerQ shall be empty. The following procedure to recover from crashed
+ * consists of several steps for case (b).
+ * 1) Close listen socket.
+ * 2) Wait for all sockets disconnected and inform BluetoothServiceBluedroid to
+ * perform the regular stop bluetooth procedure.
+ * 3) When stop bluetooth procedures complete, fire
+ * AdapterStateChangedNotification to cleanup all necessary data members and
+ * deinit ProfileManagers.
+ * 4) After all resources cleanup, call |StartBluetooth|
+ */
 void
 BluetoothDaemonInterface::OnDisconnect(enum Channel aChannel)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (mResultHandlerQ.IsEmpty()) {
-    if (sNotificationHandler) {
-      // Bluetooth daemon crashed; clear state
-      sNotificationHandler->AdapterStateChangedNotification(false);
-      sNotificationHandler = nullptr;
-    }
-    return;
-  }
-
   switch (aChannel) {
     case CMD_CHANNEL:
       // We don't have to do anything here. Step 4 is triggered
       // by the daemon.
       break;
     case NTF_CHANNEL:
-      // Cleanup, step 4: Close listen socket
+      // Cleanup, step 4 (Recovery, step 1): Close listen socket
       mListenSocket->Close();
       break;
-    case LISTEN_SOCKET: {
+    case LISTEN_SOCKET:
+      if (!mResultHandlerQ.IsEmpty()) {
         nsRefPtr<BluetoothResultHandler> res = mResultHandlerQ.ElementAt(0);
         mResultHandlerQ.RemoveElementAt(0);
-
         // Cleanup, step 5: Signal success to caller
         if (res) {
           res->Cleanup();
         }
       }
       break;
   }
+
+  /* For recovery make sure all sockets disconnected, in order to avoid
+   * the remaining disconnects interfere with the restart procedure.
+   */
+  if (sNotificationHandler && mResultHandlerQ.IsEmpty()) {
+    if (mListenSocket->GetConnectionStatus() == SOCKET_DISCONNECTED &&
+        mCmdChannel->GetConnectionStatus() == SOCKET_DISCONNECTED &&
+        mNtfChannel->GetConnectionStatus() == SOCKET_DISCONNECTED) {
+      // Assume daemon crashed during regular service; notify
+      // BluetoothServiceBluedroid to prepare restart-daemon procedure
+      sNotificationHandler->BackendErrorNotification(true);
+      sNotificationHandler = nullptr;
+    }
+  }
 }
 
 class BluetoothDaemonSocketConnector final
   : public mozilla::ipc::UnixSocketConnector
 {
 public:
   BluetoothDaemonSocketConnector(const nsACString& aSocketName)
     : mSocketName(aSocketName)
@@ -2193,26 +2279,28 @@ private:
  *
  * Rolling-back half-completed cleanups is not possible. In the case of
  * an error, we simply push forward and try to recover during the next
  * initialization.
  */
 void
 BluetoothDaemonInterface::Cleanup(BluetoothResultHandler* aRes)
 {
+
   sNotificationHandler = nullptr;
 
-  mResultHandlerQ.AppendElement(aRes);
-
   // Cleanup, step 1: Unregister Socket module
   nsresult rv = mProtocol->UnregisterModuleCmd(
     0x02, new CleanupResultHandler(this));
   if (NS_FAILED(rv)) {
     DispatchError(aRes, rv);
+    return;
   }
+
+  mResultHandlerQ.AppendElement(aRes);
 }
 
 void
 BluetoothDaemonInterface::Enable(BluetoothResultHandler* aRes)
 {
   nsresult rv =
     static_cast<BluetoothDaemonCoreModule*>(mProtocol)->EnableCmd(aRes);
   if (NS_FAILED(rv)) {
--- a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h
@@ -19,21 +19,23 @@ class BluetoothDaemonHandsfreeInterface;
 class BluetoothDaemonProtocol;
 class BluetoothDaemonSocketInterface;
 
 class BluetoothDaemonInterface final : public BluetoothInterface
 {
 public:
   class CleanupResultHandler;
   class InitResultHandler;
+  class StartDaemonTask;
 
   friend class BluetoothDaemonListenSocket;
   friend class BluetoothDaemonChannel;
   friend class CleanupResultHandler;
   friend class InitResultHandler;
+  friend class StartDaemonTask;
 
   static BluetoothDaemonInterface* GetInstance();
 
   void Init(BluetoothNotificationHandler* aNotificationHandler,
             BluetoothResultHandler* aRes);
   void Cleanup(BluetoothResultHandler* aRes);
 
   void Enable(BluetoothResultHandler* aRes);
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
@@ -97,16 +97,18 @@ static InfallibleTArray<BluetoothNamedVa
 static nsTArray<int> sRequestedDeviceCountArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeAdapterStateRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sChangeDiscoveryRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sFetchUuidsRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
+static bool sIsRestart(false);
+static bool sIsFirstTimeToggleOffBt(false);
 
 /**
  *  Static callback functions
  */
 ControlPlayStatus
 BluetoothServiceBluedroid::PlayStatusStringToControlPlayStatus(
   const nsAString& aPlayStatus)
 {
@@ -593,16 +595,18 @@ static BluetoothInterface* sBtInterface;
 static nsTArray<nsRefPtr<BluetoothProfileController> > sControllerArray;
 static InfallibleTArray<BluetoothNamedValue> sRemoteDevicesPack;
 static nsTArray<int> sRequestedDeviceCountArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sSetPropertyRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sGetDeviceRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sBondingRunnableArray;
 static nsTArray<nsRefPtr<BluetoothReplyRunnable> > sUnbondingRunnableArray;
 static bool sAdapterDiscoverable(false);
+static bool sIsRestart(false);
+static bool sIsFirstTimeToggleOffBt(false);
 static uint32_t sAdapterDiscoverableTimeout(0);
 
 /**
  *  Static callback functions
  */
 void
 BluetoothServiceBluedroid::ClassToIcon(uint32_t aClass, nsAString& aRetIcon)
 {
@@ -2122,17 +2126,21 @@ public:
     if (!(--mNumProfiles)) {
       Proceed();
     }
   }
 
 private:
   void Proceed() const
   {
-    sBtInterface->Cleanup(nullptr);
+    if (!sIsRestart) {
+      sBtInterface->Cleanup(nullptr);
+    } else {
+      BT_LOGR("ProfileDeinitResultHandler::Proceed cancel cleanup() ");
+    }
   }
 
   unsigned char mNumProfiles;
 };
 
 class BluetoothServiceBluedroid::SetAdapterPropertyDiscoverableResultHandler
   final
   : public BluetoothResultHandler
@@ -2226,16 +2234,22 @@ BluetoothServiceBluedroid::AdapterStateC
     DispatchReplySuccess(sChangeAdapterStateRunnableArray[0]);
     sChangeAdapterStateRunnableArray.RemoveElementAt(0);
   }
 #else
   MOZ_ASSERT(NS_IsMainThread());
 
   BT_LOGR("BT_STATE: %d", aState);
 
+  if (sIsRestart && aState) {
+    // daemon restarted, reset flag
+    BT_LOGR("daemon restarted, reset flag");
+    sIsRestart = false;
+    sIsFirstTimeToggleOffBt = false;
+  }
   bool isBtEnabled = (aState == true);
 
   if (!isBtEnabled) {
     static void (* const sDeinitManager[])(BluetoothProfileResultHandler*) = {
       BluetoothHfpManager::DeinitHfpInterface,
       BluetoothA2dpManager::DeinitA2dpInterface
     };
 
@@ -2274,16 +2288,21 @@ BluetoothServiceBluedroid::AdapterStateC
     bs->TryFiringAdapterAdded();
 
     // Trigger BluetoothOppManager to listen
     BluetoothOppManager* opp = BluetoothOppManager::Get();
     if (!opp || !opp->Listen()) {
       BT_LOGR("Fail to start BluetoothOppManager listening");
     }
   }
+  // After ProfileManagers deinit and cleanup, now restarts bluetooth daemon
+  if (sIsRestart && !aState) {
+    BT_LOGR("sIsRestart and off, now restart");
+    StartBluetooth(false);
+  }
 #endif
 }
 
 /**
  * AdapterPropertiesNotification will be called after enable() but
  * before AdapterStateChangeCallback is called. At that moment, both
  * BluetoothManager and BluetoothAdapter, do not register observer
  * yet.
@@ -3069,8 +3088,44 @@ void
 BluetoothServiceBluedroid::EnergyInfoNotification(
   const BluetoothActivityEnergyInfo& aInfo)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // FIXME: This will be implemented in the later patchset
 }
 #endif
+
+void
+BluetoothServiceBluedroid::BackendErrorNotification(bool aCrashed)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+ // Recovery step 2 stop bluetooth
+ if (aCrashed) {
+  BT_LOGR("Set aRestart = true");
+  sIsRestart = true;
+  BT_LOGR("Reocvery step2: stop bluetooth");
+#ifdef MOZ_B2G_BT_API_V2
+  StopBluetooth(false, nullptr);
+#else
+  StopBluetooth(false);
+#endif
+ }
+}
+
+void
+BluetoothServiceBluedroid::CompleteToggleBt(bool aEnabled)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (sIsRestart && !aEnabled && sIsFirstTimeToggleOffBt) {
+    // Both StopBluetooth and AdapterStateChangedNotification
+    // trigger CompleteToggleBt. We don't need to call CompleteToggleBt again
+  } else if (sIsRestart && !aEnabled && !sIsFirstTimeToggleOffBt) {
+    // Recovery step 3: cleanup and deinit Profile managers
+    BT_LOGR("CompleteToggleBt set sIsFirstTimeToggleOffBt = true");
+    sIsFirstTimeToggleOffBt = true;
+    BluetoothService::CompleteToggleBt(aEnabled);
+    AdapterStateChangedNotification(false);
+  } else {
+    BluetoothService::CompleteToggleBt(aEnabled);
+  }
+}
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h
@@ -295,17 +295,19 @@ public:
                                            const nsAString& aRemoteBdAddr,
                                            bool aState) override;
 
   virtual void DutModeRecvNotification(uint16_t aOpcode,
                                        const uint8_t* aBuf,
                                        uint8_t aLen) override;
   virtual void LeTestModeNotification(BluetoothStatus aStatus,
                                       uint16_t aNumPackets) override;
+  virtual void BackendErrorNotification(bool aCrashed) override;
 
+  virtual void CompleteToggleBt(bool aEnabled) override;
 protected:
   static nsresult StartGonkBluetooth();
   static nsresult StopGonkBluetooth();
   static bool EnsureBluetoothHalLoad();
 
   static void ConnectDisconnect(bool aConnect,
                                 const nsAString& aDeviceAddress,
                                 BluetoothReplyRunnable* aRunnable,
@@ -522,16 +524,19 @@ public:
                                        const uint8_t* aBuf,
                                        uint8_t aLen) override;
   virtual void LeTestModeNotification(BluetoothStatus aStatus,
                                       uint16_t aNumPackets) override;
 
   virtual void EnergyInfoNotification(
     const BluetoothActivityEnergyInfo& aInfo) override;
 
+  virtual void BackendErrorNotification(bool aCrashed) override;
+  virtual void CompleteToggleBt(bool aEnabled) override;
+
 protected:
   static nsresult StartGonkBluetooth();
   static nsresult StopGonkBluetooth();
   static bool EnsureBluetoothHalLoad();
 
   static void ClassToIcon(uint32_t aClass, nsAString& aRetIcon);
 
   static ControlPlayStatus PlayStatusStringToControlPlayStatus(
--- a/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/bluedroid/hfp/BluetoothHfpManager.cpp
@@ -1278,16 +1278,17 @@ BluetoothHfpManager::Connect(const nsASt
   sBluetoothHfpInterface->Connect(mDeviceAddress,
                                   new ConnectResultHandler(this));
 }
 
 void
 BluetoothHfpManager::OnDisconnectError()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  NS_ENSURE_TRUE_VOID(mController);
 
   mController->NotifyCompletion(NS_LITERAL_STRING(ERR_CONNECTION_FAILED));
 }
 
 class BluetoothHfpManager::DisconnectResultHandler final
   : public BluetoothHandsfreeResultHandler
 {
 public:
--- a/dom/bluetooth/bluetooth1/BluetoothService.h
+++ b/dom/bluetooth/bluetooth1/BluetoothService.h
@@ -360,16 +360,19 @@ protected:
   StopInternal() = 0;
 
   /**
    * Called when XPCOM first creates this service.
    */
   virtual nsresult
   HandleStartup();
 
+  virtual void
+  CompleteToggleBt(bool aEnabled);
+
   /**
    * Called when the startup settings check has completed.
    */
   nsresult
   HandleStartupSettingsCheck(bool aEnable);
 
   /**
    * Called when "mozsettings-changed" observer topic fires.
@@ -386,17 +389,16 @@ protected:
   // Called by ToggleBtAck.
   void
   SetEnabled(bool aEnabled);
 
   // Called by Get().
   static BluetoothService*
   Create();
 
-  void CompleteToggleBt(bool aEnabled);
 
   typedef nsClassHashtable<nsStringHashKey, BluetoothSignalObserverList >
   BluetoothSignalObserverTable;
 
   BluetoothSignalObserverTable mBluetoothSignalObserverTable;
 
   bool mEnabled;
 
--- a/dom/bluetooth/bluetooth2/BluetoothGatt.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothGatt.cpp
@@ -251,16 +251,18 @@ BluetoothGatt::DiscoverServices(ErrorRes
     !mDiscoveringServices,
     promise,
     NS_ERROR_DOM_INVALID_STATE_ERR);
 
   BluetoothService* bs = BluetoothService::Get();
   BT_ENSURE_TRUE_REJECT(bs, promise, NS_ERROR_NOT_AVAILABLE);
 
   mDiscoveringServices = true;
+  mServices.Clear();
+  BluetoothGattBinding::ClearCachedServicesValue(this);
   nsRefPtr<BluetoothReplyRunnable> result =
     new BluetoothVoidReplyRunnable(nullptr /* DOMRequest */,
                                    promise,
                                    NS_LITERAL_STRING("DiscoverGattServices"));
   bs->DiscoverGattServicesInternal(mAppUuid, result);
 
   return promise.forget();
 }
@@ -287,16 +289,17 @@ BluetoothGatt::UpdateConnectionState(Blu
 void
 BluetoothGatt::HandleServicesDiscovered(const BluetoothValue& aValue)
 {
   MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothGattServiceId);
 
   const InfallibleTArray<BluetoothGattServiceId>& serviceIds =
     aValue.get_ArrayOfBluetoothGattServiceId();
 
+  mServices.Clear();
   for (uint32_t i = 0; i < serviceIds.Length(); i++) {
     mServices.AppendElement(new BluetoothGattService(
       GetParentObject(), mAppUuid, serviceIds[i]));
   }
 
   BluetoothGattBinding::ClearCachedServicesValue(this);
 }
 
--- a/dom/bluetooth/bluetooth2/BluetoothGattCharacteristic.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothGattCharacteristic.cpp
@@ -144,16 +144,17 @@ void
 BluetoothGattCharacteristic::HandleDescriptorsDiscovered(
   const BluetoothValue& aValue)
 {
   MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothGattId);
 
   const InfallibleTArray<BluetoothGattId>& descriptorIds =
     aValue.get_ArrayOfBluetoothGattId();
 
+  mDescriptors.Clear();
   for (uint32_t i = 0; i < descriptorIds.Length(); i++) {
     mDescriptors.AppendElement(new BluetoothGattDescriptor(
       GetParentObject(), this, descriptorIds[i]));
   }
 
   BluetoothGattCharacteristicBinding::ClearCachedDescriptorsValue(this);
 }
 
@@ -189,18 +190,16 @@ BluetoothGattCharacteristic::WrapObject(
 {
   return BluetoothGattCharacteristicBinding::Wrap(aContext, this, aGivenProto);
 }
 
 void
 BluetoothGattCharacteristic::GetValue(JSContext* cx,
                                       JS::MutableHandle<JSObject*> aValue) const
 {
-  MOZ_ASSERT(aValue);
-
   aValue.set(mValue.IsEmpty()
              ? nullptr
              : ArrayBuffer::Create(cx, mValue.Length(), mValue.Elements()));
 }
 
 void
 BluetoothGattCharacteristic::GetProperties(
   mozilla::dom::GattCharacteristicProperties& aProperties) const
--- a/dom/bluetooth/bluetooth2/BluetoothGattDescriptor.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothGattDescriptor.cpp
@@ -107,18 +107,16 @@ BluetoothGattDescriptor::WrapObject(JSCo
 {
   return BluetoothGattDescriptorBinding::Wrap(aContext, this, aGivenProto);
 }
 
 void
 BluetoothGattDescriptor::GetValue(JSContext* cx,
                                   JS::MutableHandle<JSObject*> aValue) const
 {
-  MOZ_ASSERT(aValue);
-
   aValue.set(mValue.IsEmpty()
              ? nullptr
              : ArrayBuffer::Create(cx, mValue.Length(), mValue.Elements()));
 }
 
 class ReadValueTask final : public BluetoothReplyRunnable
 {
 public:
--- a/dom/bluetooth/bluetooth2/BluetoothGattService.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothGattService.cpp
@@ -80,16 +80,17 @@ void
 BluetoothGattService::HandleIncludedServicesDiscovered(
   const BluetoothValue& aValue)
 {
   MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothGattServiceId);
 
   const InfallibleTArray<BluetoothGattServiceId>& includedServIds =
     aValue.get_ArrayOfBluetoothGattServiceId();
 
+  mIncludedServices.Clear();
   for (uint32_t i = 0; i < includedServIds.Length(); i++) {
     mIncludedServices.AppendElement(new BluetoothGattService(
       GetParentObject(), mAppUuid, includedServIds[i]));
   }
 
   BluetoothGattServiceBinding::ClearCachedIncludedServicesValue(this);
 }
 
@@ -98,16 +99,17 @@ BluetoothGattService::HandleCharacterist
   const BluetoothValue& aValue)
 {
   MOZ_ASSERT(aValue.type() ==
              BluetoothValue::TArrayOfBluetoothGattCharAttribute);
 
   const InfallibleTArray<BluetoothGattCharAttribute>& characteristics =
     aValue.get_ArrayOfBluetoothGattCharAttribute();
 
+  mCharacteristics.Clear();
   for (uint32_t i = 0; i < characteristics.Length(); i++) {
     mCharacteristics.AppendElement(new BluetoothGattCharacteristic(
       GetParentObject(), this, characteristics[i]));
   }
 
   BluetoothGattServiceBinding::ClearCachedCharacteristicsValue(this);
 }
 
--- a/dom/bluetooth/bluetooth2/BluetoothService.h
+++ b/dom/bluetooth/bluetooth2/BluetoothService.h
@@ -510,16 +510,19 @@ protected:
                      BluetoothReplyRunnable* aRunnable);
 
   /**
    * Called when XPCOM first creates this service.
    */
   virtual nsresult
   HandleStartup();
 
+  virtual void
+  CompleteToggleBt(bool aEnabled);
+
   /**
    * Called when the startup settings check has completed.
    */
   nsresult
   HandleStartupSettingsCheck(bool aEnable);
 
   /**
    * Called when "mozsettings-changed" observer topic fires.
@@ -536,19 +539,16 @@ protected:
   // Called by ToggleBtAck.
   void
   SetEnabled(bool aEnabled);
 
   // Called by Get().
   static BluetoothService*
   Create();
 
-  void
-  CompleteToggleBt(bool aEnabled);
-
   typedef nsClassHashtable<nsStringHashKey, BluetoothSignalObserverList >
   BluetoothSignalObserverTable;
 
   BluetoothSignalObserverTable mBluetoothSignalObserverTable;
 
   nsTArray<BluetoothSignal> mPendingPairReqSignals;
 
   bool mEnabled;
--- a/dom/media/fmp4/MP4Reader.cpp
+++ b/dom/media/fmp4/MP4Reader.cpp
@@ -372,17 +372,18 @@ MP4Reader::ExtractCryptoInitData(nsTArra
     aInitData.AppendElements(psshs[i].data);
   }
 }
 
 bool
 MP4Reader::IsSupportedAudioMimeType(const nsACString& aMimeType)
 {
   return (aMimeType.EqualsLiteral("audio/mpeg") ||
-          aMimeType.EqualsLiteral("audio/mp4a-latm")) &&
+          aMimeType.EqualsLiteral("audio/mp4a-latm") ||
+          aMimeType.EqualsLiteral("audio/3gpp")) &&
          mPlatform->SupportsMimeType(aMimeType);
 }
 
 bool
 MP4Reader::IsSupportedVideoMimeType(const nsACString& aMimeType)
 {
   return (aMimeType.EqualsLiteral("video/mp4") ||
           aMimeType.EqualsLiteral("video/mp4v-es") ||
--- a/dom/media/fmp4/gonk/GonkAudioDecoderManager.cpp
+++ b/dom/media/fmp4/gonk/GonkAudioDecoderManager.cpp
@@ -45,63 +45,68 @@ GonkAudioDecoderManager::GonkAudioDecode
   , mAudioChannels(aConfig.mChannels)
   , mAudioRate(aConfig.mRate)
   , mAudioProfile(aConfig.mProfile)
   , mUseAdts(true)
   , mAudioBuffer(nullptr)
 {
   MOZ_COUNT_CTOR(GonkAudioDecoderManager);
   MOZ_ASSERT(mAudioChannels);
-  mUserData.AppendElements(aConfig.mCodecSpecificConfig->Elements(),
-                           aConfig.mCodecSpecificConfig->Length());
+  mCodecSpecificData = aConfig.mCodecSpecificConfig;
+  mMimeType = aConfig.mMimeType;
+
   // Pass through mp3 without applying an ADTS header.
   if (!aConfig.mMimeType.EqualsLiteral("audio/mp4a-latm")) {
       mUseAdts = false;
   }
 }
 
 GonkAudioDecoderManager::~GonkAudioDecoderManager()
 {
   MOZ_COUNT_DTOR(GonkAudioDecoderManager);
 }
 
 android::sp<MediaCodecProxy>
 GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
 {
+  status_t rv = OK;
   if (mLooper != nullptr) {
     return nullptr;
   }
   // Create ALooper
   mLooper = new ALooper;
   mLooper->setName("GonkAudioDecoderManager");
   mLooper->start();
 
-  mDecoder = MediaCodecProxy::CreateByType(mLooper, "audio/mp4a-latm", false, nullptr);
+  mDecoder = MediaCodecProxy::CreateByType(mLooper, mMimeType.get(), false, nullptr);
   if (!mDecoder.get()) {
     return nullptr;
   }
   if (!mDecoder->AskMediaCodecAndWait())
   {
     mDecoder = nullptr;
     return nullptr;
   }
   sp<AMessage> format = new AMessage;
   // Fixed values
-  GADM_LOG("Init Audio channel no:%d, sample-rate:%d", mAudioChannels, mAudioRate);
-  format->setString("mime", "audio/mp4a-latm");
+  GADM_LOG("Configure audio mime type:%s, chan no:%d, sample-rate:%d", mMimeType.get(), mAudioChannels, mAudioRate);
+  format->setString("mime", mMimeType.get());
   format->setInt32("channel-count", mAudioChannels);
   format->setInt32("sample-rate", mAudioRate);
   format->setInt32("aac-profile", mAudioProfile);
   format->setInt32("is-adts", true);
   status_t err = mDecoder->configure(format, nullptr, nullptr, 0);
   if (err != OK || !mDecoder->Prepare()) {
     return nullptr;
   }
-  status_t rv = mDecoder->Input(mUserData.Elements(), mUserData.Length(), 0,
-                                android::MediaCodec::BUFFER_FLAG_CODECCONFIG);
+
+  if (mMimeType.EqualsLiteral("audio/mp4a-latm")) {
+    rv = mDecoder->Input(mCodecSpecificData->Elements(), mCodecSpecificData->Length(), 0,
+                         android::MediaCodec::BUFFER_FLAG_CODECCONFIG);
+  }
 
   if (rv == OK) {
     return mDecoder;
   } else {
     GADM_LOG("Failed to input codec specific data!");
     return nullptr;
   }
 }
--- a/dom/media/fmp4/gonk/GonkAudioDecoderManager.h
+++ b/dom/media/fmp4/gonk/GonkAudioDecoderManager.h
@@ -46,17 +46,16 @@ private:
 
   void ReleaseAudioBuffer();
   // MediaCodedc's wrapper that performs the decoding.
   android::sp<MediaCodecProxy> mDecoder;
 
   const uint32_t mAudioChannels;
   const uint32_t mAudioRate;
   const uint32_t mAudioProfile;
-  nsTArray<uint8_t> mUserData;
   bool mUseAdts;
 
   MediaDataDecoderCallback*  mReaderCallback;
   android::MediaBuffer* mAudioBuffer;
   android::sp<ALooper> mLooper;
 };
 
 } // namespace mozilla
--- a/dom/media/fmp4/gonk/GonkDecoderModule.cpp
+++ b/dom/media/fmp4/gonk/GonkDecoderModule.cpp
@@ -60,13 +60,14 @@ GonkDecoderModule::DecoderNeedsConversio
     return kNeedNone;
   }
 }
 
 bool
 GonkDecoderModule::SupportsMimeType(const nsACString& aMimeType)
 {
   return aMimeType.EqualsLiteral("audio/mp4a-latm") ||
+    aMimeType.EqualsLiteral("audio/3gpp") ||
     aMimeType.EqualsLiteral("video/mp4") ||
     aMimeType.EqualsLiteral("video/mp4v-es") ||
     aMimeType.EqualsLiteral("video/avc");
 }
 } // namespace mozilla
--- a/dom/media/fmp4/gonk/GonkMediaDataDecoder.h
+++ b/dom/media/fmp4/gonk/GonkMediaDataDecoder.h
@@ -64,16 +64,20 @@ protected:
   virtual android::status_t SendSampleToOMX(MediaRawData* aSample) = 0;
 
   // An queue with the MP4 samples which are waiting to be sent into OMX.
   // If an element is an empty MP4Sample, that menas EOS. There should not
   // any sample be queued after EOS.
   nsTArray<nsRefPtr<MediaRawData>> mQueueSample;
 
   RefPtr<MediaTaskQueue> mTaskQueue;
+
+  nsRefPtr<MediaByteBuffer> mCodecSpecificData;
+
+  nsAutoCString mMimeType;
 };
 
 // Samples are decoded using the GonkDecoder (MediaCodec)
 // created by the GonkDecoderManager. This class implements
 // the higher-level logic that drives mapping the Gonk to the async
 // MediaDataDecoder interface. The specifics of decoding the exact stream
 // type are handled by GonkDecoderManager and the GonkDecoder it creates.
 class GonkMediaDataDecoder : public MediaDataDecoder {
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.cpp
@@ -489,17 +489,17 @@ GonkVideoDecoderManager::Flush()
 void
 GonkVideoDecoderManager::codecReserved()
 {
   GVDM_LOG("codecReserved");
   sp<AMessage> format = new AMessage;
   sp<Surface> surface;
   status_t rv = OK;
   // Fixed values
-  GVDM_LOG("Configure mime type: %s, widht:%d, height:%d", mMimeType.get(), mVideoWidth, mVideoHeight);
+  GVDM_LOG("Configure video mime type: %s, widht:%d, height:%d", mMimeType.get(), mVideoWidth, mVideoHeight);
   format->setString("mime", mMimeType.get());
   format->setInt32("width", mVideoWidth);
   format->setInt32("height", mVideoHeight);
   if (mNativeWindow != nullptr) {
     surface = new Surface(mNativeWindow->getBufferQueue());
   }
   mDecoder->configure(format, surface, nullptr, 0);
   mDecoder->Prepare();
--- a/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
+++ b/dom/media/fmp4/gonk/GonkVideoDecoderManager.h
@@ -142,17 +142,16 @@ private:
   nsIntRect mPicture;
   nsIntSize mInitialFrame;
 
   android::sp<MediaCodecProxy> mDecoder;
   nsRefPtr<layers::ImageContainer> mImageContainer;
 
   android::MediaBuffer* mVideoBuffer;
 
-  nsRefPtr<MediaByteBuffer>  mCodecSpecificData;
   MediaDataDecoderCallback*  mReaderCallback;
   MediaInfo mInfo;
   android::sp<VideoResourceListener> mVideoListener;
   android::sp<MessageHandler> mHandler;
   android::sp<ALooper> mLooper;
   android::sp<ALooper> mManagerLooper;
   FrameInfo mFrameInfo;
 
@@ -173,14 +172,13 @@ private:
   };
 
   // Hold video's MediaBuffers that are released.
   // The holded MediaBuffers are released soon after flush.
   Vector<android::MediaBuffer*> mPendingVideoBuffers;
   // The lock protects mPendingVideoBuffers.
   Mutex mPendingVideoBuffersLock;
 
-  nsAutoCString mMimeType;
 };
 
 } // namespace mozilla
 
 #endif // GonkVideoDecoderManager_h_
new file mode 100644
--- /dev/null
+++ b/dom/mobilemessage/Assertions.cpp
@@ -0,0 +1,47 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/MozMobileMessageManagerBinding.h"
+#include "nsISmsService.h"
+
+namespace mozilla {
+namespace dom {
+namespace mobilemessage {
+
+#define ASSERT_SMS_EQUALITY(webidlType, webidlState, xpidlState) \
+  static_assert(static_cast<uint32_t>(webidlType::webidlState) == nsISmsService::xpidlState, \
+  #webidlType "::" #webidlState " should equal to nsISmsService::" #xpidlState)
+
+/**
+ * Enum TypeOfNumber
+ */
+#define ASSERT_SMS_TYPE_OF_NUMBER_EQUALITY(webidlState, xpidlState) \
+  ASSERT_SMS_EQUALITY(TypeOfNumber, webidlState, xpidlState)
+
+ASSERT_SMS_TYPE_OF_NUMBER_EQUALITY(Unknown, TYPE_OF_NUMBER_UNKNOWN);
+ASSERT_SMS_TYPE_OF_NUMBER_EQUALITY(International, TYPE_OF_NUMBER_INTERNATIONAL);
+ASSERT_SMS_TYPE_OF_NUMBER_EQUALITY(National, TYPE_OF_NUMBER_NATIONAL);
+ASSERT_SMS_TYPE_OF_NUMBER_EQUALITY(Network_specific, TYPE_OF_NUMBER_NETWORK_SPECIFIC);
+ASSERT_SMS_TYPE_OF_NUMBER_EQUALITY(Dedicated_access_short_code, TYPE_OF_NUMBER_DEDICATED_ACCESS_SHORT_CODE);
+
+#undef ASSERT_SMS_TYPE_OF_NUMBER_EQUALITY
+
+/**
+ * Enum NumberPlanIdentification
+ */
+#define ASSERT_SMS_NUMBER_PLAN_IDENTIFICATION_EQUALITY(webidlState, xpidlState) \
+  ASSERT_SMS_EQUALITY(NumberPlanIdentification, webidlState, xpidlState)
+
+ASSERT_SMS_NUMBER_PLAN_IDENTIFICATION_EQUALITY(Unknown, NUMBER_PLAN_IDENTIFICATION_UNKNOWN);
+ASSERT_SMS_NUMBER_PLAN_IDENTIFICATION_EQUALITY(Isdn, NUMBER_PLAN_IDENTIFICATION_ISDN);
+ASSERT_SMS_NUMBER_PLAN_IDENTIFICATION_EQUALITY(Data, NUMBER_PLAN_IDENTIFICATION_DATA);
+ASSERT_SMS_NUMBER_PLAN_IDENTIFICATION_EQUALITY(Telex, NUMBER_PLAN_IDENTIFICATION_TELEX);
+ASSERT_SMS_NUMBER_PLAN_IDENTIFICATION_EQUALITY(National, NUMBER_PLAN_IDENTIFICATION_NATIONAL);
+ASSERT_SMS_NUMBER_PLAN_IDENTIFICATION_EQUALITY(Private, NUMBER_PLAN_IDENTIFICATION_PRIVATE);
+
+#undef ASSERT_SMS_EQUALITY
+
+} // namespace mobilemessage
+} // namespace dom
+} // namespace mozilla
--- a/dom/mobilemessage/MobileMessageCallback.cpp
+++ b/dom/mobilemessage/MobileMessageCallback.cpp
@@ -12,16 +12,17 @@
 #include "nsPIDOMWindow.h"
 #include "MmsMessage.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "jsapi.h"
 #include "xpcpublic.h"
 #include "nsServiceManagerUtils.h"
 #include "nsTArrayHelpers.h"
 #include "DOMMobileMessageError.h"
+#include "mozilla/dom/Promise.h"
 
 namespace mozilla {
 namespace dom {
 namespace mobilemessage {
 
 static nsAutoString
 ConvertErrorCodeToErrorString(int32_t aError)
 {
@@ -75,16 +76,21 @@ NS_INTERFACE_MAP_BEGIN(MobileMessageCall
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 MobileMessageCallback::MobileMessageCallback(DOMRequest* aDOMRequest)
   : mDOMRequest(aDOMRequest)
 {
 }
 
+MobileMessageCallback::MobileMessageCallback(Promise* aPromise)
+  : mPromise(aPromise)
+{
+}
+
 MobileMessageCallback::~MobileMessageCallback()
 {
 }
 
 
 nsresult
 MobileMessageCallback::NotifySuccess(JS::Handle<JS::Value> aResult, bool aAsync)
 {
@@ -275,11 +281,26 @@ MobileMessageCallback::NotifyGetSmscAddr
 }
 
 NS_IMETHODIMP
 MobileMessageCallback::NotifyGetSmscAddressFailed(int32_t aError)
 {
   return NotifyError(aError);
 }
 
+NS_IMETHODIMP
+MobileMessageCallback::NotifySetSmscAddress()
+{
+  mPromise->MaybeResolve(JS::UndefinedHandleValue);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+MobileMessageCallback::NotifySetSmscAddressFailed(int32_t aError)
+{
+  const nsAString& errorStr = ConvertErrorCodeToErrorString(aError);
+  mPromise->MaybeRejectBrokenly(errorStr);
+  return NS_OK;
+}
+
 } // namesapce mobilemessage
 } // namespace dom
 } // namespace mozilla
--- a/dom/mobilemessage/MobileMessageCallback.h
+++ b/dom/mobilemessage/MobileMessageCallback.h
@@ -5,32 +5,36 @@
 
 #ifndef mozilla_dom_mobilemessage_MobileMessageCallback_h
 #define mozilla_dom_mobilemessage_MobileMessageCallback_h
 
 #include "nsIMobileMessageCallback.h"
 #include "nsCOMPtr.h"
 #include "DOMRequest.h"
 
+class Promise;
+
 namespace mozilla {
 namespace dom {
 namespace mobilemessage {
 
 class MobileMessageCallback final : public nsIMobileMessageCallback
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIMOBILEMESSAGECALLBACK
 
   explicit MobileMessageCallback(DOMRequest* aDOMRequest);
+  explicit MobileMessageCallback(Promise* aPromise);
 
 private:
   ~MobileMessageCallback();
 
   nsRefPtr<DOMRequest> mDOMRequest;
+  nsRefPtr<Promise> mPromise;
 
   nsresult NotifySuccess(JS::Handle<JS::Value> aResult, bool aAsync = false);
   nsresult NotifySuccess(nsISupports *aMessage, bool aAsync = false);
   nsresult NotifyError(int32_t aError, DOMError *aDetailedError = nullptr, bool aAsync = false);
 };
 
 } // namespace mobilemessage
 } // namespace dom
--- a/dom/mobilemessage/MobileMessageManager.cpp
+++ b/dom/mobilemessage/MobileMessageManager.cpp
@@ -10,16 +10,17 @@
 #include "DOMRequest.h"
 #include "MobileMessageCallback.h"
 #include "MobileMessageCursorCallback.h"
 #include "mozilla/dom/mobilemessage/Constants.h" // For kSms*ObserverTopic
 #include "mozilla/dom/MozMessageDeletedEvent.h"
 #include "mozilla/dom/MozMmsEvent.h"
 #include "mozilla/dom/MozMobileMessageManagerBinding.h"
 #include "mozilla/dom/MozSmsEvent.h"
+#include "mozilla/dom/Promise.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "nsIDOMMozMmsMessage.h"
 #include "nsIDOMMozSmsMessage.h"
 #include "nsIMmsService.h"
 #include "nsIMobileMessageCallback.h"
 #include "nsIMobileMessageDatabaseService.h"
@@ -692,16 +693,82 @@ MobileMessageManager::GetSmscAddress(con
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return nullptr;
   }
 
   return request.forget();
 }
 
+already_AddRefed<Promise>
+MobileMessageManager::SetSmscAddress(const SmscAddress& aSmscAddress,
+                                     const Optional<uint32_t>& aServiceId,
+                                     ErrorResult& aRv)
+{
+  nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
+  if (!smsService) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  // Use the default one unless |serviceId| is available.
+  uint32_t serviceId;
+  nsresult rv;
+  if (aServiceId.WasPassed()) {
+    serviceId = aServiceId.Value();
+  } else {
+    rv = smsService->GetSmsDefaultServiceId(&serviceId);
+    if (NS_FAILED(rv)) {
+      aRv.Throw(rv);
+      return nullptr;
+    }
+  }
+
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
+  if (!global) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
+  nsRefPtr<Promise> promise = Promise::Create(global, aRv);
+  if (aRv.Failed()) {
+    return nullptr;
+  }
+
+  if (!aSmscAddress.mAddress.WasPassed()) {
+    NS_WARNING("SmscAddress.address is a mandatory field and can not be omitted.");
+    promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
+    return promise.forget();
+  }
+
+  nsString address = aSmscAddress.mAddress.Value();
+  TypeOfNumber ton = aSmscAddress.mTypeOfAddress.mTypeOfNumber;
+  NumberPlanIdentification npi =
+    aSmscAddress.mTypeOfAddress.mNumberPlanIdentification;
+
+  // If the address begins with +, set TON to international no matter what has
+  // passed in.
+  if (!address.IsEmpty() && address[0] == '+') {
+    ton = TypeOfNumber::International;
+  }
+
+  nsCOMPtr<nsIMobileMessageCallback> msgCallback =
+    new MobileMessageCallback(promise);
+
+  rv = smsService->SetSmscAddress(serviceId, address,
+    static_cast<uint32_t>(ton), static_cast<uint32_t>(npi), msgCallback);
+  if (NS_FAILED(rv)) {
+    promise->MaybeReject(rv);
+    return promise.forget();
+  }
+
+  return promise.forget();
+}
+
+
 } // namespace dom
 } // namespace mozilla
 
 already_AddRefed<nsISmsService>
 NS_CreateSmsService()
 {
   nsCOMPtr<nsISmsService> smsService;
 
--- a/dom/mobilemessage/MobileMessageManager.h
+++ b/dom/mobilemessage/MobileMessageManager.h
@@ -8,27 +8,29 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/DOMEventTargetHelper.h"
 #include "nsIObserver.h"
 
 class nsISmsService;
 class nsIDOMMozSmsMessage;
 class nsIDOMMozMmsMessage;
+class Promise;
 
 namespace mozilla {
 namespace dom {
 
 class DOMRequest;
 class DOMCursor;
 struct MmsParameters;
 struct MmsSendParameters;
 struct MobileMessageFilter;
 class OwningLongOrMozSmsMessageOrMozMmsMessage;
 struct SmsSendParameters;
+struct SmscAddress;
 
 class MobileMessageManager final : public DOMEventTargetHelper
                                  , public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIOBSERVER
 
@@ -110,16 +112,21 @@ public:
   already_AddRefed<DOMRequest>
   RetrieveMMS(nsIDOMMozMmsMessage* aMessage,
               ErrorResult& aRv);
 
   already_AddRefed<DOMRequest>
   GetSmscAddress(const Optional<uint32_t>& aServiceId,
                  ErrorResult& aRv);
 
+  already_AddRefed<Promise>
+  SetSmscAddress(const SmscAddress& aSmscAddress,
+                 const Optional<uint32_t>& aServiceId,
+                 ErrorResult& aRv);
+
   IMPL_EVENT_HANDLER(received)
   IMPL_EVENT_HANDLER(retrieving)
   IMPL_EVENT_HANDLER(sending)
   IMPL_EVENT_HANDLER(sent)
   IMPL_EVENT_HANDLER(failed)
   IMPL_EVENT_HANDLER(deliverysuccess)
   IMPL_EVENT_HANDLER(deliveryerror)
   IMPL_EVENT_HANDLER(readsuccess)
--- a/dom/mobilemessage/android/SmsService.cpp
+++ b/dom/mobilemessage/android/SmsService.cpp
@@ -64,14 +64,27 @@ SmsService::RemoveSilentNumber(const nsA
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 SmsService::GetSmscAddress(uint32_t aServiceId,
                            nsIMobileMessageCallback *aRequest)
 {
   // TODO: bug 878016 - Android backend: implement getSMSCAddress/setSMSCAddress
-  return NS_OK;
+  NS_NOTYETIMPLEMENTED("Implement me!");
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+SmsService::SetSmscAddress(uint32_t aServiceId,
+                           const nsAString& aNumber,
+                           uint32_t aTypeOfNumber,
+                           uint32_t aNumberPlanIdentification,
+                           nsIMobileMessageCallback* aRequest)
+{
+  // TODO: bug 878016 - Android backend: implement getSMSCAddress/setSMSCAddress
+  NS_NOTYETIMPLEMENTED("Implement me!");
+  return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 } // namespace mobilemessage
 } // namespace dom
 } // namespace mozilla
--- a/dom/mobilemessage/gonk/SmsService.js
+++ b/dom/mobilemessage/gonk/SmsService.js
@@ -797,17 +797,17 @@ SmsService.prototype = {
       this._smsStorageAvailable = aIsAvailable;
       for (let serviceId = 0; serviceId < gRadioInterfaces.length; serviceId++) {
         gRadioInterfaces[serviceId]
           .sendWorkerMessage("reportSmsMemoryStatus", { isAvailable: aIsAvailable });
       }
     }
   },
 
-  // An array of slient numbers.
+  // An array of silent numbers.
   _silentNumbers: null,
   _isSilentNumber: function(aNumber) {
     return this._silentNumbers.indexOf(aNumber) >= 0;
   },
 
   /**
    * nsISmsService interface
    */
@@ -985,16 +985,40 @@ SmsService.prototype = {
         aRequest.notifyGetSmscAddress(aResponse.smscAddress);
       } else {
         aRequest.notifyGetSmscAddressFailed(
           Ci.nsIMobileMessageCallback.NOT_FOUND_ERROR);
       }
     });
   },
 
+  setSmscAddress: function(aServiceId, aNumber, aTypeOfNumber,
+                      aNumberPlanIdentification, aRequest) {
+    if (aServiceId > (gRadioInterfaces.length - 1)) {
+      throw Cr.NS_ERROR_INVALID_ARG;
+    }
+
+    let options = {
+      smscAddress: aNumber,
+      typeOfNumber: aTypeOfNumber,
+      numberPlanIdentification: aNumberPlanIdentification
+    };
+
+    gRadioInterfaces[aServiceId].sendWorkerMessage("setSmscAddress",
+                                                   options,
+                                                   (aResponse) => {
+      if (!aResponse.errorMsg) {
+        aRequest.notifySetSmscAddress();
+      } else {
+        aRequest.notifySetSmscAddressFailed(
+          Ci.nsIMobileMessageCallback.INVALID_ADDRESS_ERROR);
+      }
+    });
+  },
+
   /**
    * nsIGonkSmsService interface
    */
   notifyMessageReceived: function(aServiceId, aSMSC, aSentTimestamp,
                                   aSender, aPid, aEncoding, aMessageClass,
                                   aLanguage, aSegmentRef, aSegmentSeq,
                                   aSegmentMaxSeq, aOriginatorPort,
                                   aDestinationPort, aMwiPresent, aMwiDiscard,
--- a/dom/mobilemessage/interfaces/nsIGonkSmsService.idl
+++ b/dom/mobilemessage/interfaces/nsIGonkSmsService.idl
@@ -5,17 +5,17 @@
 #include "domstubs.idl"
 #include "nsISmsService.idl"
 
 %{C++
 #define GONK_SMSSERVICE_CONTRACTID \
         "@mozilla.org/sms/gonksmsservice;1"
 %}
 
-[scriptable, uuid(4dda515e-05ec-47b1-b750-e42c74576c43)]
+[scriptable, uuid(76681431-8261-4540-bab8-24ef3866e8b6)]
 interface nsIGonkSmsService : nsISmsService
 {
   const unsigned short SMS_MESSAGE_ENCODING_7BITS_ALPHABET = 0x00;
   const unsigned short SMS_MESSAGE_ENCODING_8BITS_ALPHABET = 0x04;
   const unsigned short SMS_MESSAGE_ENCODING_16BITS_ALPHABET = 0x08;
 
   const unsigned long SMS_APPLICATION_PORT_INVALID = 0xFFFFFFFF;
 
--- a/dom/mobilemessage/interfaces/nsIMobileMessageCallback.idl
+++ b/dom/mobilemessage/interfaces/nsIMobileMessageCallback.idl
@@ -1,15 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsISupports.idl"
 
-[scriptable, uuid(35279dbc-9f1d-419f-b17a-230fcf49f0c7)]
+[scriptable, uuid(b1367554-51c6-4153-b20a-effec50ca827)]
 interface nsIMobileMessageCallback : nsISupports
 {
   /**
    * All SMS related errors.
    * Make sure to keep this list in sync with the list in:
    * embedding/android/GeckoSmsManager.java
    */
   const unsigned short SUCCESS_NO_ERROR          = 0;
@@ -49,9 +49,11 @@ interface nsIMobileMessageCallback : nsI
                                    in long charsAvailableInLastSegment);
   void notifyGetSegmentInfoForTextFailed(in long error);
 
   /**
    *  SMSC Address get/set result
    */
   void notifyGetSmscAddress(in DOMString aSmscAddress);
   void notifyGetSmscAddressFailed(in long error);
+  void notifySetSmscAddress();
+  void notifySetSmscAddressFailed(in long error);
 };
--- a/dom/mobilemessage/interfaces/nsISmsService.idl
+++ b/dom/mobilemessage/interfaces/nsISmsService.idl
@@ -7,17 +7,17 @@
 interface nsIDOMMozSmsMessage;
 interface nsIMobileMessageCallback;
 
 %{C++
 #define SMS_SERVICE_CID { 0xbada3cb8, 0xa568, 0x4dff, { 0xb5, 0x43, 0x52, 0xbb, 0xb3, 0x14, 0x31, 0x21 } }
 #define SMS_SERVICE_CONTRACTID "@mozilla.org/sms/smsservice;1"
 %}
 
-[scriptable, uuid(ae688bca-00c9-4d08-945d-e8a5272ad5b1)]
+[scriptable, uuid(c8ca5f06-ad76-44b0-a324-9e2910fd37da)]
 interface nsISmsService : nsISupports
 {
   /**
    * Constant definitions of predefined GSM Message Class
    * See 3GPP TS 23.038 clause 4 SMS Data Coding Scheme
    */
   const unsigned short MESSAGE_CLASS_TYPE_CLASS_0 = 0;
   const unsigned short MESSAGE_CLASS_TYPE_CLASS_1 = 1;
@@ -36,32 +36,141 @@ interface nsISmsService : nsISupports
   /**
    * Constant definitions of SMS Delivery Status
    */
   const unsigned short DELIVERY_STATUS_TYPE_NOT_APPLICABLE = 0;
   const unsigned short DELIVERY_STATUS_TYPE_SUCCESS        = 1;
   const unsigned short DELIVERY_STATUS_TYPE_PENDING        = 2;
   const unsigned short DELIVERY_STATUS_TYPE_ERROR          = 3;
 
+  /**
+   * Constant definitions of SM-RP type of number as defined in
+   * |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
+   */
+  const unsigned short TYPE_OF_NUMBER_UNKNOWN                     = 0;
+  const unsigned short TYPE_OF_NUMBER_INTERNATIONAL               = 1;
+  const unsigned short TYPE_OF_NUMBER_NATIONAL                    = 2;
+  const unsigned short TYPE_OF_NUMBER_NETWORK_SPECIFIC            = 3;
+  const unsigned short TYPE_OF_NUMBER_DEDICATED_ACCESS_SHORT_CODE = 4;
+
+  /**
+   * Constant definitions of SM-RP number plan identification as defined in
+   * |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
+   */
+  const unsigned short NUMBER_PLAN_IDENTIFICATION_UNKNOWN  = 0;
+  const unsigned short NUMBER_PLAN_IDENTIFICATION_ISDN     = 1;
+  const unsigned short NUMBER_PLAN_IDENTIFICATION_DATA     = 2;
+  const unsigned short NUMBER_PLAN_IDENTIFICATION_TELEX    = 3;
+  const unsigned short NUMBER_PLAN_IDENTIFICATION_NATIONAL = 4;
+  const unsigned short NUMBER_PLAN_IDENTIFICATION_PRIVATE  = 5;
+
+  /**
+   * The default RIL service ID used for SMS.
+   */
   readonly attribute unsigned long smsDefaultServiceId;
 
+  /**
+   * Get the information necessary to create a multi-part SMS for a given text.
+   *
+   * @param text
+   *        The text message content.
+   * @param request
+   *        The callback object to use. It invokes
+   *        |notifySegmentInfoForTextGot| on success, or
+   *        |notifyGetSegmentInfoForTextFailed| on failure.
+   */
   void getSegmentInfoForText(in DOMString text,
                              in nsIMobileMessageCallback request);
 
+  /**
+   * Send a SMS.
+   *
+   * @param serviceId
+   *        The ID of RIL service to use.
+   * @param number
+   *        Destination number in string.
+   * @param message
+   *        The text message content.
+   * @param silent
+   *        |true| to send a silent message. It's used to make a SMS based
+   *        authentication for some services such as mobile billing.
+   * @param request
+   *        The callback object to use. It invokes |notifyMessageSent| on
+   *        success, or |notifySendMessageFailed| on failure.
+   * @throws NS_ERROR_INVALID_ARG
+   *         If |serviceId| exceeds the max value of available IDs.
+   */
   void send(in unsigned long serviceId,
             in DOMString number,
             in DOMString message,
             in boolean silent,
             in nsIMobileMessageCallback request);
 
+  /**
+   * Add a number to the list of silent message originators. When receiving a
+   * SMS sent from one of the numbers in the list, |SmsService| will notify
+   * observers through the topic "silent-sms-received".
+   *
+   * It's used when a SMS based authentication has been initiated and the client
+   * is waiting for an incoming silent message containing the authentication
+   * result.
+   *
+   * @param number
+   *        Originator number in string.
+   * @throw NS_ERROR_UNEXPECTED
+   *        If the given number has already been added before.
+   */
   void addSilentNumber(in DOMString number);
+
+  /**
+   * Remove a number from the silent message originator list.
+   *
+   * @param number
+   *        Originator number in string.
+   * @throws NS_ERROR_INVALID_ARG
+   *         If the number doesn't exist in the list.
+   */
   void removeSilentNumber(in DOMString number);
 
+  /**
+   * Get the short message service center address of given |serviceId|.
+   *
+   * @param serviceId
+   *        The ID of RIL service to use.
+   * @param request
+   *        The callback object to use. It invokes |notifyGetSmscAddress| on
+   *        success, or |notifyGetSmscAddressFailed| on failure.
+   * @throws NS_ERROR_INVALID_ARG
+   *         If |serviceId| exceeds the max value of available IDs.
+   */
   void getSmscAddress(in unsigned long serviceId,
                       in nsIMobileMessageCallback request);
+
+  /**
+   * Set the short message service center address of given |serviceId|.
+   *
+   * @param serviceId
+   *        The ID of RIL service to use.
+   * @param number
+   *        Number part of the SMSC address.
+   * @param typeOfNumber
+   *        Type of number of the SMSC address.
+   * @param numberPlanIdentification
+   *        Number plan identification of the SMSC address.
+   * @param request
+   *        The callback object to use. It invokes |notifySetSmscAddress| on
+   *        success, or |notifySetSmscAddressFailed| on failure.
+   * @throws NS_ERROR_INVALID_ARG
+   *         If |serviceId| exceeds the max value of available IDs.
+   */
+  void setSmscAddress(in unsigned long serviceId,
+                      in DOMString number,
+                      in unsigned long typeOfNumber,
+                      in unsigned long numberPlanIdentification,
+                      in nsIMobileMessageCallback request);
 };
 
 %{C++
 template<typename T> struct already_AddRefed;
 
 already_AddRefed<nsISmsService>
 NS_CreateSmsService();
 %}
--- a/dom/mobilemessage/ipc/PSms.ipdl
+++ b/dom/mobilemessage/ipc/PSms.ipdl
@@ -74,25 +74,34 @@ struct CreateThreadCursorRequest
 {
 };
 
 struct GetSmscAddressRequest
 {
   uint32_t serviceId;
 };
 
+struct SetSmscAddressRequest
+{
+  uint32_t serviceId;
+  nsString number;
+  uint32_t typeOfNumber;
+  uint32_t numberPlanIdentification;
+};
+
 union IPCSmsRequest
 {
   SendMessageRequest;
   RetrieveMessageRequest;
   GetMessageRequest;
   DeleteMessageRequest;
   MarkMessageReadRequest;
   GetSegmentInfoForTextRequest;
   GetSmscAddressRequest;
+  SetSmscAddressRequest;
 };
 
 union IPCMobileMessageCursor
 {
   CreateMessageCursorRequest;
   CreateThreadCursorRequest;
 };
 
--- a/dom/mobilemessage/ipc/PSmsRequest.ipdl
+++ b/dom/mobilemessage/ipc/PSmsRequest.ipdl
@@ -89,27 +89,38 @@ struct ReplyGetSmscAddress
   nsString smscAddress;
 };
 
 struct ReplyGetSmscAddressFail
 {
   int32_t error;
 };
 
+struct ReplySetSmscAddress
+{
+};
+
+struct ReplySetSmscAddressFail
+{
+  int32_t error;
+};
+
 union MessageReply
 {
   ReplyMessageSend;
   ReplyMessageSendFail;
   ReplyGetMessage;
   ReplyGetMessageFail;
   ReplyMessageDelete;
   ReplyMessageDeleteFail;
   ReplyMarkeMessageRead;
   ReplyMarkeMessageReadFail;
   ReplyGetSegmentInfoForText;
   ReplyGetSegmentInfoForTextFail;
   ReplyGetSmscAddress;
   ReplyGetSmscAddressFail;
+  ReplySetSmscAddress;
+  ReplySetSmscAddressFail;
 };
 
 } // namespace mobilemessage
 } // namespace dom
 } // namespace mozilla
--- a/dom/mobilemessage/ipc/SmsChild.cpp
+++ b/dom/mobilemessage/ipc/SmsChild.cpp
@@ -257,16 +257,22 @@ SmsRequestChild::Recv__delete__(const Me
         aReply.get_ReplyGetSegmentInfoForTextFail().error());
       break;
     case MessageReply::TReplyGetSmscAddress:
       mReplyRequest->NotifyGetSmscAddress(aReply.get_ReplyGetSmscAddress().smscAddress());
       break;
     case MessageReply::TReplyGetSmscAddressFail:
       mReplyRequest->NotifyGetSmscAddressFailed(aReply.get_ReplyGetSmscAddressFail().error());
       break;
+    case MessageReply::TReplySetSmscAddress:
+      mReplyRequest->NotifySetSmscAddress();
+      break;
+    case MessageReply::TReplySetSmscAddressFail:
+      mReplyRequest->NotifySetSmscAddressFailed(aReply.get_ReplySetSmscAddressFail().error());
+      break;
     default:
       MOZ_CRASH("Received invalid response parameters!");
   }
 
   return true;
 }
 
 /*******************************************************************************
--- a/dom/mobilemessage/ipc/SmsIPCService.cpp
+++ b/dom/mobilemessage/ipc/SmsIPCService.cpp
@@ -176,16 +176,31 @@ SmsIPCService::GetSegmentInfoForText(con
 
 NS_IMETHODIMP
 SmsIPCService::GetSmscAddress(uint32_t aServiceId,
                               nsIMobileMessageCallback* aRequest)
 {
   return SendRequest(GetSmscAddressRequest(aServiceId), aRequest);
 }
 
+
+NS_IMETHODIMP
+SmsIPCService::SetSmscAddress(uint32_t aServiceId,
+                              const nsAString& aNumber,
+                              uint32_t aTypeOfNumber,
+                              uint32_t aNumberPlanIdentification,
+                              nsIMobileMessageCallback* aRequest)
+{
+  return SendRequest(SetSmscAddressRequest(aServiceId,
+                                           nsString(aNumber),
+                                           aTypeOfNumber,
+                                           aNumberPlanIdentification),
+                     aRequest);
+}
+
 NS_IMETHODIMP
 SmsIPCService::Send(uint32_t aServiceId,
                     const nsAString& aNumber,
                     const nsAString& aMessage,
                     bool aSilent,
                     nsIMobileMessageCallback* aRequest)
 {
   return SendRequest(SendMessageRequest(SendSmsMessageRequest(aServiceId,
--- a/dom/mobilemessage/ipc/SmsParent.cpp
+++ b/dom/mobilemessage/ipc/SmsParent.cpp
@@ -401,16 +401,18 @@ SmsParent::RecvPSmsRequestConstructor(PS
     case IPCSmsRequest::TDeleteMessageRequest:
       return actor->DoRequest(aRequest.get_DeleteMessageRequest());
     case IPCSmsRequest::TMarkMessageReadRequest:
       return actor->DoRequest(aRequest.get_MarkMessageReadRequest());
     case IPCSmsRequest::TGetSegmentInfoForTextRequest:
       return actor->DoRequest(aRequest.get_GetSegmentInfoForTextRequest());
     case IPCSmsRequest::TGetSmscAddressRequest:
       return actor->DoRequest(aRequest.get_GetSmscAddressRequest());
+    case IPCSmsRequest::TSetSmscAddressRequest:
+      return actor->DoRequest(aRequest.get_SetSmscAddressRequest());
     default:
       MOZ_CRASH("Unknown type!");
   }
 
   return false;
 }
 
 PSmsRequestParent*
@@ -570,16 +572,39 @@ SmsRequestParent::DoRequest(const GetSms
   if (NS_FAILED(rv)) {
     return NS_SUCCEEDED(NotifyGetSmscAddressFailed(nsIMobileMessageCallback::INTERNAL_ERROR));
   }
 
   return true;
 }
 
 bool
+SmsRequestParent::DoRequest(const SetSmscAddressRequest& aRequest)
+{
+  nsresult rv = NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsISmsService> smsService = do_GetService(SMS_SERVICE_CONTRACTID);
+  if (smsService) {
+    rv = smsService->SetSmscAddress(aRequest.serviceId(),
+                                    aRequest.number(),
+                                    aRequest.typeOfNumber(),
+                                    aRequest.numberPlanIdentification(),
+                                    this);
+  } else {
+    return NS_SUCCEEDED(NotifySetSmscAddressFailed(nsIMobileMessageCallback::INTERNAL_ERROR));
+  }
+
+  if (NS_FAILED(rv)) {
+    return NS_SUCCEEDED(NotifySetSmscAddressFailed(nsIMobileMessageCallback::INTERNAL_ERROR));
+  }
+
+  return true;
+}
+
+bool
 SmsRequestParent::DoRequest(const DeleteMessageRequest& aRequest)
 {
   nsresult rv = NS_ERROR_FAILURE;
 
   nsCOMPtr<nsIMobileMessageDatabaseService> dbService =
     do_GetService(MOBILE_MESSAGE_DATABASE_SERVICE_CONTRACTID);
   if (dbService) {
     const InfallibleTArray<int32_t>& messageIds = aRequest.messageIds();
@@ -741,16 +766,28 @@ SmsRequestParent::NotifyGetSmscAddress(c
 }
 
 NS_IMETHODIMP
 SmsRequestParent::NotifyGetSmscAddressFailed(int32_t aError)
 {
   return SendReply(ReplyGetSmscAddressFail(aError));
 }
 
+NS_IMETHODIMP
+SmsRequestParent::NotifySetSmscAddress()
+{
+  return SendReply(ReplySetSmscAddress());
+}
+
+NS_IMETHODIMP
+SmsRequestParent::NotifySetSmscAddressFailed(int32_t aError)
+{
+  return SendReply(ReplySetSmscAddressFail(aError));
+}
+
 /*******************************************************************************
  * MobileMessageCursorParent
  ******************************************************************************/
 
 NS_IMPL_ISUPPORTS(MobileMessageCursorParent, nsIMobileMessageCursorCallback)
 
 void
 MobileMessageCursorParent::ActorDestroy(ActorDestroyReason aWhy)
--- a/dom/mobilemessage/ipc/SmsParent.h
+++ b/dom/mobilemessage/ipc/SmsParent.h
@@ -112,16 +112,19 @@ protected:
   DoRequest(const MarkMessageReadRequest& aRequest);
 
   bool
   DoRequest(const GetSegmentInfoForTextRequest& aRequest);
 
   bool
   DoRequest(const GetSmscAddressRequest& aRequest);
 
+  bool
+  DoRequest(const SetSmscAddressRequest& aRequest);
+
   nsresult
   SendReply(const MessageReply& aReply);
 };
 
 class MobileMessageCursorParent : public PMobileMessageCursorParent
                                 , public nsIMobileMessageCursorCallback
 {
   friend class SmsParent;
--- a/dom/mobilemessage/moz.build
+++ b/dom/mobilemessage/moz.build
@@ -45,16 +45,17 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'go
 EXPORTS.mozilla.dom += [
     'DOMMobileMessageError.h',
     'MmsMessage.h',
     'MobileMessageManager.h',
     'SmsMessage.h',
 ]
 
 UNIFIED_SOURCES += [
+    'Assertions.cpp',
     'Constants.cpp',
     'DeletedMessageInfo.cpp',
     'DOMMobileMessageError.cpp',
     'ipc/SmsChild.cpp',
     'ipc/SmsIPCService.cpp',
     'ipc/SmsParent.cpp',
     'MmsMessage.cpp',
     'MobileMessageCallback.cpp',
--- a/dom/mobilemessage/tests/marionette/manifest.ini
+++ b/dom/mobilemessage/tests/marionette/manifest.ini
@@ -47,8 +47,9 @@ qemu = true
 [test_replace_short_message_type.js]
 [test_mt_sms_concatenation.js]
 [test_error_of_mms_manual_retrieval.js]
 [test_error_of_mms_send.js]
 [test_error_of_sms_send.js]
 [test_ondeleted_event.js]
 [test_decode_spanish_fallback.js]
 [test_update_gsm_nl_on_mcc_chanages.js]
+[test_set_smsc_address.js]
new file mode 100644
--- /dev/null
+++ b/dom/mobilemessage/tests/marionette/test_set_smsc_address.js
@@ -0,0 +1,72 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+MARIONETTE_TIMEOUT = 60000;
+MARIONETTE_HEAD_JS = 'head.js';
+
+const SMSC_ATT = '+13123149810';
+const SMSC_ATT_TYPO = '+++1312@@@314$$$9,8,1,0';
+const SMSC_ATT_TEXT = '"+13123149810",145';
+const SMSC_O2 = '+447802000332';
+const SMSC_O2_TEXT = '"+447802000332",145';
+const SMSC_DEF = '+123456789';
+const SMSC_DEF_TEXT = '"+123456789",145';
+const SMSC_TON_UNKNOWN = '0407485455'
+const SMSC_TON_UNKNOWN_TEXT = '"0407485455",129';
+
+function getSmscAddress() {
+  return new Promise((resolve, reject) => {
+    let req = manager.getSmscAddress();
+    if (!req) {
+      reject("manager.getSmscAddress() returns null.");
+    }
+
+    req.onsuccess = function() {
+      resolve(this.result);
+    };
+
+    req.onerror = function() {
+      reject(this.error);
+    };
+  });
+};
+
+startTestBase(function testCaseMain() {
+  return ensureMobileMessage()
+
+  // Verify setting AT&T SMSC address.
+  .then(() => manager.setSmscAddress({ address:SMSC_ATT }))
+  .then(() => getSmscAddress())
+  .then((result) => is(result, SMSC_ATT_TEXT))
+
+  // Verify setting O2 SMSC address.
+  .then(() => manager.setSmscAddress({ address:SMSC_O2 }))
+  .then(() => getSmscAddress())
+  .then((result) => is(result, SMSC_O2_TEXT))
+
+  // Verify setting AT&T SMSC address with extra illegal characters.
+  .then(() => manager.setSmscAddress({ address:SMSC_ATT_TYPO }))
+  .then(() => getSmscAddress())
+  .then((result) => is(result, SMSC_ATT_TEXT))
+
+  // Verify setting a SMSC address with TON=unknown.
+  .then(() => manager.setSmscAddress({ address:SMSC_TON_UNKNOWN }))
+  .then(() => getSmscAddress())
+  .then((result) => is(result, SMSC_TON_UNKNOWN_TEXT))
+
+  // Verify setting invalid SMSC address.
+  .then(() => manager.setSmscAddress({}))
+  .then(() => Promise.reject("Expect for an error."),
+    (err) => log("Got expected error: " + err))
+  .then(() => manager.setSmscAddress({ address:"" }))
+  .then(() => Promise.reject("Expect for an error."),
+    (err) => log("Got expected error: " + err))
+  .then(() => manager.setSmscAddress({ address:"???" }))
+  .then(() => Promise.reject("Expect for an error."),
+    (err) => log("Got expected error: " + err))
+
+  // Restore to default emulator SMSC address.
+  .then(() => manager.setSmscAddress({ address:SMSC_DEF }))
+  .then(() => getSmscAddress())
+  .then((result) => is(result, SMSC_DEF_TEXT));
+});
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -1489,16 +1489,18 @@ WorkerMessenger.prototype = {
         simAppStateExtraFields:
           libcutils.property_get("ro.moz.ril.simstate_extra_field", "false") === "true",
         extraUint2ndCall:
           libcutils.property_get("ro.moz.ril.extra_int_2nd_call", "false") == "true",
         haveQueryIccLockRetryCount:
           libcutils.property_get("ro.moz.ril.query_icc_count", "false") == "true",
         sendStkProfileDownload:
           libcutils.property_get("ro.moz.ril.send_stk_profile_dl", "false") == "true",
+        smscAddressFormat:
+          libcutils.property_get("ro.moz.ril.smsc_address_format", "text"),
         dataRegistrationOnDemand: RILQUIRKS_DATA_REGISTRATION_ON_DEMAND,
         subscriptionControl: RILQUIRKS_SUBSCRIPTION_CONTROL,
         signalExtraInt: RILQUIRKS_SIGNAL_EXTRA_INT32
       }
     };
 
     this.send(null, "setInitialOptions", options);
   },
--- a/dom/system/gonk/ril_consts.js
+++ b/dom/system/gonk/ril_consts.js
@@ -1402,16 +1402,40 @@ this.CB_ETWS_WARNING_TYPE_NAMES = [
 
 // UMTS Message Type
 // see 3GPP TS 25.324 section 11.1
 this.CB_UMTS_MESSAGE_TYPE_CBS      = 1;
 this.CB_UMTS_MESSAGE_TYPE_SCHEDULE = 2;
 this.CB_UMTS_MESSAGE_TYPE_CBS41    = 3;
 
 /**
+ * Number plan identification defined in
+ * |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
+ */
+this.CALLED_PARTY_BCD_NPI_UNKNOWN  = 0;
+this.CALLED_PARTY_BCD_NPI_ISDN     = 1;
+this.CALLED_PARTY_BCD_NPI_DATA     = 3;
+this.CALLED_PARTY_BCD_NPI_TELEX    = 4;
+this.CALLED_PARTY_BCD_NPI_NATIONAL = 8;
+this.CALLED_PARTY_BCD_NPI_PRIVATE  = 9;
+
+/**
+ * Array of number plan identification values which can be used to map an
+ * enumeration to the corresponding value.
+ */
+this.CALLED_PARTY_BCD_NPI = [
+  CALLED_PARTY_BCD_NPI_UNKNOWN,
+  CALLED_PARTY_BCD_NPI_ISDN,
+  CALLED_PARTY_BCD_NPI_DATA,
+  CALLED_PARTY_BCD_NPI_TELEX,
+  CALLED_PARTY_BCD_NPI_NATIONAL,
+  CALLED_PARTY_BCD_NPI_PRIVATE
+];
+
+/**
  * GSM PDU constants
  */
 
 // PDU TYPE-OF-ADDRESS
 this.PDU_TOA_UNKNOWN       = 0x80; // Unknown. This is used when the user or
                                     // network has no a priori information
                                     // about the numbering plan.
 this.PDU_TOA_ISDN          = 0x81; // ISDN/Telephone numbering
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -81,16 +81,19 @@ let RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD;
 // Ril quirk to attach data registration on demand.
 let RILQUIRKS_DATA_REGISTRATION_ON_DEMAND;
 
 // Ril quirk to control the uicc/data subscription.
 let RILQUIRKS_SUBSCRIPTION_CONTROL;
 
 let RILQUIRKS_SIGNAL_EXTRA_INT32;
 
+// Ril quirk to describe the SMSC address format.
+let RILQUIRKS_SMSC_ADDRESS_FORMAT;
+
 /**
  * The RIL state machine.
  *
  * This object communicates with rild via parcels and with the main thread
  * via post messages. It maintains state about the radio, ICC, calls, etc.
  * and acts upon state changes accordingly.
  */
 function RilObject(aContext) {
@@ -1723,22 +1726,101 @@ RilObject.prototype = {
     options.smscAddress = this.SMSC;
     this.sendChromeMessage(options);
   },
 
   /**
    * Set the Short Message Service Center address.
    *
    * @param smscAddress
-   *        Short Message Service Center address in PDU format.
+   *        Number part of the SMSC address.
+   * @param typeOfNumber
+   *        Type of number in integer, as defined in
+   *        |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
+   * @param numberPlanIdentification
+   *        Number plan identification in integer, as defined in
+   *        |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
    */
   setSmscAddress: function(options) {
+    let ton = options.typeOfNumber;
+    let npi = CALLED_PARTY_BCD_NPI[options.numberPlanIdentification];
+
+    // If any of the mandatory arguments is not available, return an error
+    // immediately.
+    if (ton === undefined || npi === undefined || !options.smscAddress) {
+      options.errorMsg = GECKO_ERROR_INVALID_PARAMETER;
+      this.sendChromeMessage(options);
+      return;
+    }
+
+    // Remove all illegal characters in the number string for user-input fault
+    // tolerance.
+    let numStart = options.smscAddress[0] === "+" ? 1 : 0;
+    let number = options.smscAddress.substring(0, numStart) +
+                 options.smscAddress.substring(numStart)
+                                    .replace(/[^0-9*#abc]/ig, "");
+
+    // If the filtered number is an empty string, return an error immediately.
+    if (number.length === 0) {
+      options.errorMsg = GECKO_ERROR_INVALID_PARAMETER;
+      this.sendChromeMessage(options);
+      return;
+    }
+
+    // Init parcel.
+    this.SMSC = null;
     let Buf = this.context.Buf;
     Buf.newParcel(REQUEST_SET_SMSC_ADDRESS, options);
-    Buf.writeString(options.smscAddress);
+
+    // +---+-----------+---------------+
+    // | 1 |    TON    |      NPI      |
+    // +---+-----------+---------------+
+    let tosca = (0x1 << 7) + (ton << 4) + npi;
+    if (RILQUIRKS_SMSC_ADDRESS_FORMAT === "pdu") {
+      let pduHelper = this.context.GsmPDUHelper;
+
+      // Remove the preceding '+', and covert the special BCD digits defined in
+      // |Called party BCD number| of 3GPP TS 24.008 to corresponding
+      // hexadecimal values (refer the following table).
+      //
+      // +=========+=======+=====+
+      // |  value  | digit | hex |
+      // +========================
+      // | 1 0 1 0 |   *   | 0xA |
+      // | 1 0 1 1 |   #   | 0xB |
+      // | 1 1 0 0 |   a   | 0xC |
+      // | 1 1 0 1 |   b   | 0xD |
+      // | 1 1 1 0 |   c   | 0xE |
+      // +=========+=======+=====+
+      //
+      // The replace order is reversed intentionally, because if the digits are
+      // replaced in ascending order, "#" will be converted to "b" and then be
+      // converted again to "d", which generates incorrect result.
+      let pureNumber = number.substring(numStart)
+                             .replace(/c/ig, "e")
+                             .replace(/b/ig, "d")
+                             .replace(/a/ig, "c")
+                             .replace(/\#/g, "b")
+                             .replace(/\*/g, "a");
+
+      // address length and string length
+      let length = Math.ceil(pureNumber.length / 2) + 1; // +1 octet for TOA
+      let strlen = length * 2 + 2; // +2 semi-octets for length octet
+
+      Buf.writeInt32(strlen);
+      pduHelper.writeHexOctet(length);
+      pduHelper.writeHexOctet(tosca);
+      pduHelper.writeSwappedNibbleBCD(pureNumber);
+      Buf.writeStringDelimiter(strlen);
+    } else /* RILQUIRKS_SMSC_ADDRESS_FORMAT === "text" */ {
+      let sca;
+      sca = '"' + number + '"' + ',' + tosca;
+      Buf.writeString(sca);
+    }
+
     Buf.sendParcel();
   },
 
   /**
    * Setup a data call.
    *
    * @param radioTech
    *        Integer to indicate radio technology.
@@ -5501,17 +5583,27 @@ RilObject.prototype[REQUEST_GET_SMSC_ADD
 
   if (!options.rilMessageType || options.rilMessageType !== "getSmscAddress") {
     return;
   }
 
   options.smscAddress = this.SMSC;
   this.sendChromeMessage(options);
 };
-RilObject.prototype[REQUEST_SET_SMSC_ADDRESS] = null;
+RilObject.prototype[REQUEST_SET_SMSC_ADDRESS] = function REQUEST_SET_SMSC_ADDRESS(length, options) {
+  if (!options.rilMessageType || options.rilMessageType !== "setSmscAddress") {
+    return;
+  }
+
+  if (options.rilRequestError) {
+    optioins.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
+  }
+
+  this.sendChromeMessage(options);
+};
 RilObject.prototype[REQUEST_REPORT_SMS_MEMORY_STATUS] = function REQUEST_REPORT_SMS_MEMORY_STATUS(length, options) {
   this.pendingToReportSmsMemoryStatus = !!options.errorMsg;
 };
 RilObject.prototype[REQUEST_REPORT_STK_SERVICE_IS_RUNNING] = null;
 RilObject.prototype[REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE] = null;
 RilObject.prototype[REQUEST_ISIM_AUTHENTICATION] = null;
 RilObject.prototype[REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU] = null;
 RilObject.prototype[REQUEST_STK_SEND_ENVELOPE_WITH_STATUS] = function REQUEST_STK_SEND_ENVELOPE_WITH_STATUS(length, options) {
@@ -15393,16 +15485,17 @@ let ContextPool = {
     RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = quirks.requestUseDialEmergencyCall;
     RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS = quirks.simAppStateExtraFields;
     RILQUIRKS_EXTRA_UINT32_2ND_CALL = quirks.extraUint2ndCall;
     RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT = quirks.haveQueryIccLockRetryCount;
     RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD = quirks.sendStkProfileDownload;
     RILQUIRKS_DATA_REGISTRATION_ON_DEMAND = quirks.dataRegistrationOnDemand;
     RILQUIRKS_SUBSCRIPTION_CONTROL = quirks.subscriptionControl;
     RILQUIRKS_SIGNAL_EXTRA_INT32 = quirks.signalExtraInt;
+    RILQUIRKS_SMSC_ADDRESS_FORMAT = quirks.smscAddressFormat;
   },
 
   setDebugFlag: function(aOptions) {
     DEBUG = DEBUG_WORKER || aOptions.debug;
   },
 
   registerClient: function(aOptions) {
     let clientId = aOptions.clientId;
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_smsc_address.js
@@ -0,0 +1,71 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+const SMSC_ATT = '+13123149810';
+const SMSC_ATT_TYPO = '+++1312@@@314$$$9,8,1,0';
+const SMSC_ATT_TEXT = '"+13123149810",145';
+const SMSC_ATT_PDU = '07913121139418F0';
+const SMSC_O2 = '+447802000332';
+const SMSC_O2_TEXT = '"+447802000332",145';
+const SMSC_O2_PDU = '0791448720003023';
+const SMSC_TON_UNKNOWN = '0407485455'
+const SMSC_TON_UNKNOWN_TEXT = '"0407485455",129';
+const SMSC_TON_UNKNOWN_PDU = '06814070844555';
+
+function run_test() {
+  run_next_test();
+}
+
+function setSmsc(context, smsc, ton, npi, expected) {
+  context.Buf.sendParcel = function() {
+    equal(this.readString(), expected);
+  };
+
+  context.RIL.setSmscAddress({
+      smscAddress: smsc,
+      typeOfNumber: ton,
+      numberPlanIdentification: npi
+  });
+}
+
+add_test(function test_setSmscAddress() {
+  let worker = newUint8Worker();
+  let context = worker.ContextPool._contexts[0];
+  let parcelTypes = [];
+  context.Buf.newParcel = (type, options) => parcelTypes.push(type);
+
+  // Test text mode.
+  worker.RILQUIRKS_SMSC_ADDRESS_FORMAT = "text";
+
+  setSmsc(context, SMSC_ATT, 1, 1, SMSC_ATT_TEXT);
+  equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
+
+  setSmsc(context, SMSC_O2, 1, 1, SMSC_O2_TEXT);
+  equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
+
+  setSmsc(context, SMSC_ATT_TYPO, 1, 1, SMSC_ATT_TEXT);
+  equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
+
+  setSmsc(context, SMSC_TON_UNKNOWN, 0, 1, SMSC_TON_UNKNOWN_TEXT);
+  equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
+
+  // Test pdu mode.
+  worker.RILQUIRKS_SMSC_ADDRESS_FORMAT = "pdu";
+
+  setSmsc(context, SMSC_ATT, 1, 1, SMSC_ATT_PDU);
+  equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
+
+  setSmsc(context, SMSC_O2, 1, 1, SMSC_O2_PDU);
+  equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
+
+  setSmsc(context, SMSC_ATT_TYPO, 1, 1, SMSC_ATT_PDU);
+  equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
+
+  setSmsc(context, SMSC_TON_UNKNOWN, 0, 1, SMSC_TON_UNKNOWN_PDU);
+  equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS);
+
+  run_next_test();
+});
+
--- a/dom/system/gonk/tests/xpcshell.ini
+++ b/dom/system/gonk/tests/xpcshell.ini
@@ -17,16 +17,17 @@ tail =
 [test_ril_worker_sms.js]
 # Bug 916067 - B2G RIL: test_ril_worker_sms.js takes too long to finish
 skip-if = true
 [test_ril_worker_sms_cdma.js]
 [test_ril_worker_sms_cdmapduhelper.js]
 [test_ril_worker_sms_nl_tables.js]
 [test_ril_worker_sms_gsmpduhelper.js]
 [test_ril_worker_sms_segment_info.js]
+[test_ril_worker_smsc_address.js]
 [test_ril_worker_mmi.js]
 [test_ril_worker_mmi_cf.js]
 [test_ril_worker_cf.js]
 [test_ril_worker_cellbroadcast_config.js]
 [test_ril_worker_cellbroadcast.js]
 [test_ril_worker_ruim.js]
 [test_ril_worker_cw.js]
 [test_ril_worker_clir.js]
--- a/dom/webidl/MozMobileMessageManager.webidl
+++ b/dom/webidl/MozMobileMessageManager.webidl
@@ -70,16 +70,55 @@ dictionary MobileMessageFilter
 
   // Filtering by whether a message has been read or not.
   boolean? read = null;
 
   // Filtering by a message's threadId attribute.
   [EnforceRange] unsigned long long? threadId = 0;
 };
 
+/**
+ * TON defined in |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
+ * It's used in SM-RL originator / destination address element as defined in
+ * |8.2.5.2 Destination address element| of 3GPP TS 24.011.
+ */
+enum TypeOfNumber { "unknown", "international", "national", "network-specific",
+  "dedicated-access-short-code" };
+
+/**
+ * NPI defined in |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008.
+ * It's used in SM-RL originator / destination address element as defined in
+ * |8.2.5.2 Destination address element| of 3GPP TS 24.011.
+ */
+enum NumberPlanIdentification { "unknown", "isdn", "data", "telex", "national",
+  "private" };
+
+/**
+ * Type of address used in SmscAddress.
+ *
+ * As described in |3.1 Parameters Definitions| of 3GPP TS 27.005, the default
+ * value of <tosca> should be 129 (typeOfNumber=unknown,
+ * numberPlanIdentification=isdn) if the number does not begin with '+'.
+ *
+ * |setSmscAddress| updates typeOfNumber to international automatically if the
+ * given number begins with '+'.
+ */
+dictionary TypeOfAddress {
+  TypeOfNumber typeOfNumber = "unknown";
+  NumberPlanIdentification numberPlanIdentification = "isdn";
+};
+
+/**
+ * SMSC address.
+ */
+dictionary SmscAddress {
+  DOMString address;
+  TypeOfAddress typeOfAddress;
+};
+
 [Pref="dom.sms.enabled",
  CheckPermissions="sms",
  AvailableIn="CertifiedApps"]
 interface MozMobileMessageManager : EventTarget
 {
   [Throws]
   DOMRequest getSegmentInfoForText(DOMString text);
 
@@ -152,16 +191,32 @@ interface MozMobileMessageManager : Even
   [Throws]
   DOMRequest retrieveMMS(long id);
   [Throws]
   DOMRequest retrieveMMS(MozMmsMessage message);
 
   [Throws]
   DOMRequest getSmscAddress(optional unsigned long serviceId);
 
+  /**
+   * Set the SMSC address.
+   *
+   * @param smscAddress
+   *        SMSC address to use.
+   *        Reject if smscAddress.address does not present.
+   * @param serviceId (optional)
+   *        The ID of the RIL service which needs to be specified under
+   *        the multi-sim scenario.
+   * @return a Promise
+   *         Resolve if success. Otherwise, reject with error cause.
+   */
+  [NewObject]
+  Promise<void> setSmscAddress(optional SmscAddress smscAddress,
+                               optional unsigned long serviceId);
+
   attribute EventHandler onreceived;
   attribute EventHandler onretrieving;
   attribute EventHandler onsending;
   attribute EventHandler onsent;
   attribute EventHandler onfailed;
   attribute EventHandler ondeliverysuccess;
   attribute EventHandler ondeliveryerror;
   attribute EventHandler onreadsuccess;
--- a/embedding/nsIWindowCreator2.idl
+++ b/embedding/nsIWindowCreator2.idl
@@ -16,17 +16,17 @@
  */
 
 #include "nsIWindowCreator.idl"
 
 interface nsITabParent;
 interface nsIURI;
 interface nsIWebBrowserChrome;
 
-[scriptable, uuid(e28f810b-9b49-4927-a4be-62a74fadfe21)]
+[scriptable, uuid(b6c44689-f97e-4f32-a723-29eeddfbdc53)]
 
 interface nsIWindowCreator2 : nsIWindowCreator {
 
   /**
    * Definitions for contextFlags
    */
 
   // Likely that the window is an advertising popup. 
@@ -54,9 +54,19 @@ interface nsIWindowCreator2 : nsIWindowC
       @return the new window. Will be null if canceled or an error occurred.
   */
   nsIWebBrowserChrome createChromeWindow2(in nsIWebBrowserChrome parent,
                                           in uint32_t chromeFlags,
                                           in uint32_t contextFlags,
                                           in nsIURI uri,
                                           in nsITabParent aOpeningTab,
                                           out boolean cancel);
+
+  /**
+   * B2G multi-screen support. When open another top-level window on b2g,
+   * a screen ID is needed for identifying which screen this window is
+   * opened to.
+   * @param aScreenId Differentiate screens of windows. It is platform-
+   *                  specific due to the hardware limitation for now.
+   */
+  [noscript]
+  void setScreenId(in uint32_t aScreenId);
 };
--- a/toolkit/components/startup/nsAppStartup.cpp
+++ b/toolkit/components/startup/nsAppStartup.cpp
@@ -610,16 +610,27 @@ nsAppStartup::CreateChromeWindow(nsIWebB
 }
 
 
 //
 // nsAppStartup->nsIWindowCreator2
 //
 
 NS_IMETHODIMP
+nsAppStartup::SetScreenId(uint32_t aScreenId)
+{
+  nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
+  if (!appShell) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return appShell->SetScreenId(aScreenId);
+}
+
+NS_IMETHODIMP
 nsAppStartup::CreateChromeWindow2(nsIWebBrowserChrome *aParent,
                                   uint32_t aChromeFlags,
                                   uint32_t aContextFlags,
                                   nsIURI *aURI,
                                   nsITabParent *aOpeningTab,
                                   bool *aCancel,
                                   nsIWebBrowserChrome **_retval)
 {
--- a/widget/gonk/libdisplay/BootAnimation.cpp
+++ b/widget/gonk/libdisplay/BootAnimation.cpp
@@ -634,17 +634,16 @@ AnimationThread(void *)
 
 void
 StartBootAnimation()
 {
     sRunAnimation = true;
     pthread_create(&sAnimationThread, nullptr, AnimationThread, nullptr);
 }
 
-
 void
 StopBootAnimation()
 {
     if (sRunAnimation) {
         sRunAnimation = false;
         pthread_join(sAnimationThread, nullptr);
     }
 }
--- a/widget/gonk/libdisplay/GonkDisplayJB.cpp
+++ b/widget/gonk/libdisplay/GonkDisplayJB.cpp
@@ -123,55 +123,58 @@ GonkDisplayJB::GonkDisplayJB()
     mDispSurface = new FramebufferSurface(0, mWidth, mHeight, surfaceformat, consumer);
 
 #if ANDROID_VERSION == 17
     sp<SurfaceTextureClient> stc = new SurfaceTextureClient(
         static_cast<sp<ISurfaceTexture> >(mDispSurface->getBufferQueue()));
 #else
     sp<Surface> stc = new Surface(producer);
 #endif
+    mSTClient = stc;
+    mList = (hwc_display_contents_1_t *)malloc(sizeof(*mList) + (sizeof(hwc_layer_1_t)*2));
 
-    mSTClient = stc;
-    mSTClient->perform(mSTClient.get(), NATIVE_WINDOW_SET_BUFFER_COUNT, 2);
-    mSTClient->perform(mSTClient.get(), NATIVE_WINDOW_SET_USAGE,
-                                        GRALLOC_USAGE_HW_FB |
-                                        GRALLOC_USAGE_HW_RENDER |
-                                        GRALLOC_USAGE_HW_COMPOSER);
-
-    mList = (hwc_display_contents_1_t *)malloc(sizeof(*mList) + (sizeof(hwc_layer_1_t)*2));
-    if (mHwc) {
+    uint32_t usage = GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER;
+    if (mFBDevice) {
+        // If device uses fb, they can not use single buffer for boot animation
+        mSTClient->perform(mSTClient.get(), NATIVE_WINDOW_SET_BUFFER_COUNT, 2);
+        mSTClient->perform(mSTClient.get(), NATIVE_WINDOW_SET_USAGE, usage);
+    } else if (mHwc) {
 #if ANDROID_VERSION >= 21
         if (mHwc->common.version >= HWC_DEVICE_API_VERSION_1_4) {
             mHwc->setPowerMode(mHwc, HWC_DISPLAY_PRIMARY, HWC_POWER_MODE_NORMAL);
         } else {
             mHwc->blank(mHwc, HWC_DISPLAY_PRIMARY, 0);
         }
 #else
         mHwc->blank(mHwc, HWC_DISPLAY_PRIMARY, 0);
 #endif
+        // For devices w/ hwc v1.0 or no hwc, this buffer can not be created,
+        // only create this buffer for devices w/ hwc version > 1.0.
+        mBootAnimBuffer = mAlloc->createGraphicBuffer(mWidth, mHeight, surfaceformat, usage, &err);
     }
 
-
     ALOGI("Starting bootanimation with (%d) format framebuffer", surfaceformat);
     StartBootAnimation();
 }
 
 GonkDisplayJB::~GonkDisplayJB()
 {
     if (mHwc)
         hwc_close_1(mHwc);
     if (mFBDevice)
         framebuffer_close(mFBDevice);
     free(mList);
 }
 
 ANativeWindow*
 GonkDisplayJB::GetNativeWindow()
 {
-    StopBootAnimation();
+    if (!mBootAnimBuffer.get()) {
+        StopBootAnimation();
+    }
     return mSTClient.get();
 }
 
 void
 GonkDisplayJB::SetEnabled(bool enabled)
 {
     if (enabled) {
         autosuspend_disable();
@@ -227,16 +230,21 @@ void*
 GonkDisplayJB::GetDispSurface()
 {
     return mDispSurface.get();
 }
 
 bool
 GonkDisplayJB::SwapBuffers(EGLDisplay dpy, EGLSurface sur)
 {
+    if (mBootAnimBuffer.get()) {
+        StopBootAnimation();
+        mBootAnimBuffer = nullptr;
+    }
+
     // Should be called when composition rendering is complete for a frame.
     // Only HWC v1.0 needs this call.
     // HWC > v1.0 case, do not call compositionComplete().
     // mFBDevice is present only when HWC is v1.0.
     if (mFBDevice && mFBDevice->compositionComplete) {
         mFBDevice->compositionComplete(mFBDevice);
     }
     return Post(mDispSurface->lastHandle, mDispSurface->GetPrevDispAcquireFd());
@@ -302,33 +310,42 @@ GonkDisplayJB::Post(buffer_handle_t buf,
     if (mList->retireFenceFd >= 0)
         close(mList->retireFenceFd);
     return !err;
 }
 
 ANativeWindowBuffer*
 GonkDisplayJB::DequeueBuffer()
 {
+    if (mBootAnimBuffer.get()) {
+        return static_cast<ANativeWindowBuffer*>(mBootAnimBuffer.get());
+    }
     ANativeWindowBuffer *buf;
     mSTClient->dequeueBuffer(mSTClient.get(), &buf, &mFence);
     return buf;
 }
 
 bool
 GonkDisplayJB::QueueBuffer(ANativeWindowBuffer* buf)
 {
     bool success = Post(buf->handle, -1);
-    int error = mSTClient->queueBuffer(mSTClient.get(), buf, mFence);
-
+    int error = 0;
+    if (!mBootAnimBuffer.get()) {
+        error = mSTClient->queueBuffer(mSTClient.get(), buf, mFence);
+    }
     return error == 0 && success;
 }
 
 void
 GonkDisplayJB::UpdateDispSurface(EGLDisplay dpy, EGLSurface sur)
 {
+    if (mBootAnimBuffer.get()) {
+        StopBootAnimation();
+        mBootAnimBuffer = nullptr;
+    }
     eglSwapBuffers(dpy, sur);
 }
 
 void
 GonkDisplayJB::SetDispReleaseFd(int fd)
 {
     mDispSurface->setReleaseFenceFd(fd);
 }
--- a/widget/gonk/libdisplay/GonkDisplayJB.h
+++ b/widget/gonk/libdisplay/GonkDisplayJB.h
@@ -58,16 +58,17 @@ private:
     hw_module_t const*        mModule;
     hw_module_t const*        mFBModule;
     hwc_composer_device_1_t*  mHwc;
     framebuffer_device_t*     mFBDevice;
     power_module_t*           mPowerModule;
     android::sp<android::DisplaySurface> mDispSurface;
     android::sp<ANativeWindow> mSTClient;
     android::sp<android::IGraphicBufferAlloc> mAlloc;
+    android::sp<android::GraphicBuffer> mBootAnimBuffer;
     int mFence;
     hwc_display_contents_1_t* mList;
     uint32_t mWidth;
     uint32_t mHeight;
     OnEnabledCallbackType mEnabledCallback;
 };
 
 }
--- a/widget/gonk/nsAppShell.cpp
+++ b/widget/gonk/nsAppShell.cpp
@@ -311,17 +311,17 @@ KeyEventDispatcher::DispatchKeyEventInte
     event.mKeyNameIndex = mDOMKeyNameIndex;
     if (mDOMPrintableKeyValue) {
         event.mKeyValue = mDOMPrintableKeyValue;
     }
     event.mCodeNameIndex = mDOMCodeNameIndex;
     event.modifiers = getDOMModifiers(mData.metaState);
     event.location = mDOMKeyLocation;
     event.time = mData.timeMs;
-    return nsWindow::DispatchInputEvent(event);
+    return nsWindow::DispatchKeyInput(event);
 }
 
 void
 KeyEventDispatcher::Dispatch()
 {
     // XXX Even if unknown key is pressed, DOM key event should be
     //     dispatched since Gecko for the other platforms are implemented
     //     as so.
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -40,17 +40,17 @@
 #include "nsTArray.h"
 #include "nsWindow.h"
 #include "nsIWidgetListener.h"
 #include "cutils/properties.h"
 #include "ClientLayerManager.h"
 #include "BasicLayers.h"
 #include "libdisplay/GonkDisplay.h"
 #include "pixelflinger/format.h"
-#include "mozilla/BasicEvents.h"
+#include "mozilla/TextEvents.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/Logging.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/APZThreadUtils.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/InputAPZContext.h"
 #include "mozilla/MouseEvents.h"
 #include "mozilla/TouchEvents.h"
@@ -193,17 +193,17 @@ nsWindow::DoDraw(void)
 
 void
 nsWindow::ConfigureAPZControllerThread()
 {
     APZThreadUtils::SetControllerThread(CompositorParent::CompositorLoop());
 }
 
 /*static*/ nsEventStatus
-nsWindow::DispatchInputEvent(WidgetGUIEvent& aEvent)
+nsWindow::DispatchKeyInput(WidgetKeyboardEvent& aEvent)
 {
     if (!gFocusedWindow) {
         return nsEventStatus_eIgnore;
     }
 
     gFocusedWindow->UserActivity();
 
     nsEventStatus status;
--- a/widget/gonk/nsWindow.h
+++ b/widget/gonk/nsWindow.h
@@ -34,17 +34,17 @@ class nsScreenGonk;
 class nsWindow : public nsBaseWidget
 {
 public:
     nsWindow();
 
     NS_DECL_ISUPPORTS_INHERITED
 
     static void DoDraw(void);
-    static nsEventStatus DispatchInputEvent(mozilla::WidgetGUIEvent& aEvent);
+    static nsEventStatus DispatchKeyInput(mozilla::WidgetKeyboardEvent& aEvent);
     static void DispatchTouchInput(mozilla::MultiTouchInput& aInput);
 
     NS_IMETHOD Create(nsIWidget *aParent,
                       void *aNativeParent,
                       const nsIntRect &aRect,
                       nsWidgetInitData *aInitData);
     NS_IMETHOD Destroy(void);
 
--- a/widget/nsWidgetInitData.h
+++ b/widget/nsWidgetInitData.h
@@ -89,18 +89,19 @@ enum nsBorderStyle {
  */
 
 struct nsWidgetInitData {
   nsWidgetInitData() :
       mWindowType(eWindowType_child),
       mBorderStyle(eBorderStyle_default),
       mPopupHint(ePopupTypePanel),
       mPopupLevel(ePopupLevelTop),
-      clipChildren(false), 
-      clipSiblings(false), 
+      mScreenId(0),
+      clipChildren(false),
+      clipSiblings(false),
       mDropShadow(false),
       mListenForResizes(false),
       mUnicode(true),
       mRTL(false),
       mNoAutoHide(false),
       mIsDragPopup(false),
       mIsAnimationSuppressed(false),
       mSupportTranslucency(false),
@@ -108,16 +109,20 @@ struct nsWidgetInitData {
       mMultiProcessWindow(false)
   {
   }
 
   nsWindowType  mWindowType;
   nsBorderStyle mBorderStyle;
   nsPopupType   mPopupHint;
   nsPopupLevel  mPopupLevel;
+  // B2G multi-screen support. Screen ID is for differentiating screens of
+  // windows, and due to the hardware limitation, it is platform-specific for
+  // now, which align with the value of display type defined in HWC.
+  uint32_t      mScreenId;
   // when painting exclude area occupied by child windows and sibling windows
   bool          clipChildren, clipSiblings, mDropShadow;
   bool          mListenForResizes;
   bool          mUnicode;
   bool          mRTL;
   bool          mNoAutoHide; // true for noautohide panels
   bool          mIsDragPopup;  // true for drag feedback panels
   // true if window creation animation is suppressed, e.g. for session restore
--- a/xpfe/appshell/nsAppShellService.cpp
+++ b/xpfe/appshell/nsAppShellService.cpp
@@ -53,21 +53,22 @@
 
 using namespace mozilla;
 
 // Default URL for the hidden window, can be overridden by a pref on Mac
 #define DEFAULT_HIDDENWINDOW_URL "resource://gre-resources/hiddenWindow.html"
 
 class nsIAppShell;
 
-nsAppShellService::nsAppShellService() : 
+nsAppShellService::nsAppShellService() :
   mXPCOMWillShutDown(false),
   mXPCOMShuttingDown(false),
   mModalWindowCount(0),
-  mApplicationProvidedHiddenWindow(false)
+  mApplicationProvidedHiddenWindow(false),
+  mScreenId(0)
 {
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
 
   if (obs) {
     obs->AddObserver(this, "xpcom-will-shutdown", false);
     obs->AddObserver(this, "xpcom-shutdown", false);
   }
 }
@@ -85,16 +86,23 @@ NS_IMPL_ISUPPORTS(nsAppShellService,
                   nsIObserver)
 
 NS_IMETHODIMP
 nsAppShellService::CreateHiddenWindow()
 {
   return CreateHiddenWindowHelper(false);
 }
 
+NS_IMETHODIMP
+nsAppShellService::SetScreenId(uint32_t aScreenId)
+{
+  mScreenId = aScreenId;
+  return NS_OK;
+}
+
 void
 nsAppShellService::EnsurePrivateHiddenWindow()
 {
   if (!mHiddenPrivateWindow) {
     CreateHiddenWindowHelper(true);
   }
 }
 
@@ -595,16 +603,23 @@ nsAppShellService::JustCreateTopWindow(n
   if (reg) {
     nsAutoCString package;
     package.AssignLiteral("global");
     bool isRTL = false;
     reg->IsLocaleRTL(package, &isRTL);
     widgetInitData.mRTL = isRTL;
   }
 
+#ifdef MOZ_WIDGET_GONK
+  // B2G multi-screen support. Screen ID is for differentiating screens of
+  // windows, and due to the hardware limitation, it is platform-specific for
+  // now, which align with the value of display type defined in HWC.
+  widgetInitData.mScreenId = mScreenId;
+#endif
+
   nsresult rv = window->Initialize(parent, center ? aParent : nullptr,
                                    aUrl, aInitialWidth, aInitialHeight,
                                    aIsHiddenWindow, aOpeningTab, widgetInitData);
 
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Enforce the Private Browsing autoStart pref first.
   bool isPrivateBrowsingWindow =
--- a/xpfe/appshell/nsAppShellService.h
+++ b/xpfe/appshell/nsAppShellService.h
@@ -46,11 +46,12 @@ protected:
   uint32_t CalculateWindowZLevel(nsIXULWindow *aParent, uint32_t aChromeMask);
 
   nsRefPtr<nsWebShellWindow>  mHiddenWindow;
   nsRefPtr<nsWebShellWindow>  mHiddenPrivateWindow;
   bool                        mXPCOMWillShutDown;
   bool                        mXPCOMShuttingDown;
   uint16_t                    mModalWindowCount;
   bool                        mApplicationProvidedHiddenWindow;
+  uint32_t                    mScreenId;
 };
 
 #endif
--- a/xpfe/appshell/nsIAppShellService.idl
+++ b/xpfe/appshell/nsIAppShellService.idl
@@ -13,17 +13,17 @@ interface nsIAppShell;
 interface nsITabParent;
 
 [ptr] native JSContext(JSContext);
 
 %{C++
 #include "js/TypeDecls.h"
 %}
 
-[scriptable, uuid(41a2f0c6-3ca1-44f9-8efa-744a43aa399d)]
+[scriptable, uuid(83f23c7e-6ce0-433f-9fe2-f287ae8c6e0c)]
 interface nsIAppShellService : nsISupports
 {
   /**
    * Create a window, which will be initially invisible.
    * @param aParent the parent window.  Can be null.
    * @param aUrl the contents of the new window.
    * @param aChromeMask chrome flags affecting the kind of OS border
    *                    given to the window. see nsIBrowserWindow for
@@ -56,16 +56,26 @@ interface nsIAppShellService : nsISuppor
   nsIWebNavigation createWindowlessBrowser([optional] in bool aIsChrome);
 
   [noscript]
   void createHiddenWindow();
 
   void destroyHiddenWindow();
 
   /**
+   * B2G multi-screen support. When open another top-level window on b2g,
+   * a screen ID is needed for identifying which screen this window is
+   * opened to.
+   * @param aScreenId Differentiate screens of windows. It is platform-
+   *                  specific due to the hardware limitation for now.
+   */
+  [noscript]
+  void setScreenId(in uint32_t aScreenId);
+
+  /**
    * Return the (singleton) application hidden window, automatically created
    * and maintained by this AppShellService.
    * @param aResult the hidden window.  Do not unhide hidden window.
    *                Do not taunt hidden window.
    */
   readonly attribute nsIXULWindow hiddenWindow;
 
   /**