Merge m-c to inbound a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 01 May 2015 17:23:32 -0700
changeset 242115 76963a5d187792d7879600c9f1d09ac931874ff2
parent 242114 f8235c9b93e8c487cfd95e1fe959412b6237e041 (current diff)
parent 242044 767d72d50db81f48963cce3fb34ac544fb1a12df (diff)
child 242116 81650de20da11896eb11a06136d9bad9afe76702
push id28679
push userphilringnalda@gmail.com
push dateSat, 02 May 2015 17:02:29 +0000
treeherdermozilla-central@0f5eacc986e8 [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 m-c to inbound a=merge
layout/base/nsDisplayList.cpp
--- 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/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -95,17 +95,17 @@ nsContextMenu.prototype = {
 
     if (this.isTextSelected && !this.onLink &&
         this.selectionInfo && this.selectionInfo.linkURL) {
       this.linkURL = this.selectionInfo.linkURL;
       try {
         this.linkURI = makeURI(this.linkURL);
       } catch (ex) {}
 
-      this.linkText = this.selectionInfo.linkText;
+      this.linkTextStr = this.selectionInfo.linkText;
       this.onPlainTextLink = true;
     }
 
     var shouldShow = this.onSaveableLink || isMailtoInternal || this.onPlainTextLink;
     var isWindowPrivate = PrivateBrowsingUtils.isWindowPrivate(window);
     this.showItem("context-openlink", shouldShow && !isWindowPrivate);
     this.showItem("context-openlinkprivate", shouldShow);
     this.showItem("context-openlinkintab", shouldShow);
@@ -519,17 +519,17 @@ nsContextMenu.prototype = {
     this.onKeywordField    = false;
     this.mediaURL          = "";
     this.onLink            = false;
     this.onMailtoLink      = false;
     this.onSaveableLink    = false;
     this.link              = null;
     this.linkURL           = "";
     this.linkURI           = null;
-    this.linkText          = "";
+    this.linkTextStr       = "";
     this.linkProtocol      = "";
     this.linkDownload      = "";
     this.linkHasNoReferrer = false;
     this.onMathML          = false;
     this.inFrame           = false;
     this.inSrcdocFrame     = false;
     this.inSyntheticDoc    = false;
     this.hasBGImage        = false;
@@ -695,17 +695,17 @@ nsContextMenu.prototype = {
 
           // Target is a link or a descendant of a link.
           this.onLink = true;
 
           // Remember corresponding element.
           this.link = elem;
           this.linkURL = this.getLinkURL();
           this.linkURI = this.getLinkURI();
-          this.linkText = this.getLinkText();
+          this.linkTextStr = this.getLinkText();
           this.linkProtocol = this.getLinkProtocol();
           this.onMailtoLink = (this.linkProtocol == "mailto");
           this.onSaveableLink = this.isLinkSaveable( this.link );
           this.linkHasNoReferrer = BrowserUtils.linkHasNoReferrer(elem);
           try {
             if (elem.download) {
               // Ignore download attribute on cross-origin links
               this.principal.checkMayLoad(this.linkURI, false, true);
@@ -1276,17 +1276,17 @@ nsContextMenu.prototype = {
 
     // kick off the channel with our proxy object as the listener
     channel.asyncOpen(new saveAsListener(), null);
   },
 
   // Save URL of clicked-on link.
   saveLink: function() {
     urlSecurityCheck(this.linkURL, this.principal);
-    this.saveHelper(this.linkURL, this.linkText, null, true, this.ownerDoc,
+    this.saveHelper(this.linkURL, this.linkTextStr, null, true, this.ownerDoc,
                     gContextMenuContentData.documentURIObject,
                     gContextMenuContentData.frameOuterWindowID,
                     this.linkDownload);
   },
 
   // Backwards-compatibility wrapper
   saveImage : function() {
     if (this.onCanvas || this.onImage)
@@ -1491,16 +1491,21 @@ nsContextMenu.prototype = {
         if (!text || !text.match(/\S/))
           text = this.linkURL;
       }
     }
 
     return text;
   },
 
+  // Kept for addon compat
+  linkText: function() {
+    return this.linkTextStr;
+  },
+
   isMediaURLReusable: function(aURL) {
     return !/^(?:blob|mediasource):/.test(aURL);
   },
 
   toString: function () {
     return "contextMenu.target     = " + this.target + "\n" +
            "contextMenu.onImage    = " + this.onImage + "\n" +
            "contextMenu.onLink     = " + this.onLink + "\n" +
@@ -1558,17 +1563,17 @@ nsContextMenu.prototype = {
   },
 
   bookmarkThisPage: function CM_bookmarkThisPage() {
     window.top.PlacesCommandHook.bookmarkPage(this.browser, PlacesUtils.bookmarksMenuFolderId, true);
   },
 
   bookmarkLink: function CM_bookmarkLink() {
     window.top.PlacesCommandHook.bookmarkLink(PlacesUtils.bookmarksMenuFolderId,
-                                              this.linkURL, this.linkText);
+                                              this.linkURL, this.linkTextStr);
   },
 
   addBookmarkForFrame: function CM_addBookmarkForFrame() {
     var doc = this.target.ownerDocument;
     var uri = doc.documentURIObject;
 
     var itemId = PlacesUtils.getMostRecentBookmarkForURI(uri);
     if (itemId == -1) {
@@ -1652,17 +1657,17 @@ nsContextMenu.prototype = {
     if (this.onImage)
       return this.mediaURL;
     return "";
   },
 
   // Formats the 'Search <engine> for "<selection or link text>"' context menu.
   formatSearchContextItem: function() {
     var menuItem = document.getElementById("context-searchselect");
-    let selectedText = this.isTextSelected ? this.textSelected : this.linkText;
+    let selectedText = this.isTextSelected ? this.textSelected : this.linkTextStr;
 
     // Store searchTerms in context menu item so we know what to search onclick
     menuItem.searchTerms = selectedText;
 
     // If the JS character after our truncation point is a trail surrogate,
     // include it in the truncated string to avoid splitting a surrogate pair.
     if (selectedText.length > 15) {
       let truncLength = 15;
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -3342,49 +3342,60 @@
               } else if (event.type == "TabRemotenessChange") {
                 this.onRemotenessChange(event.target);
               }
 
               this.postActions();
             },
 
             /*
-             * Telemetry related helpers for recording tab switch timing.
+             * Telemetry and Profiler related helpers for recording tab switch
+             * timing.
              */
 
             startTabSwitch: function () {
               TelemetryStopwatch.start("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
+              this.addMarker("AsyncTabSwitch:Start");
             },
 
             finishTabSwitch: function () {
               if (this.requestedTab && this.getTabState(this.requestedTab) == this.STATE_LOADED) {
                 let time = TelemetryStopwatch.timeElapsed("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
                 if (time != -1) {
                   TelemetryStopwatch.finish("FX_TAB_SWITCH_TOTAL_E10S_MS", window);
                   this.log("DEBUG: tab switch time = " + time);
+                  this.addMarker("AsyncTabSwitch:Finish");
                 }
               }
             },
 
             spinnerDisplayed: function () {
               if (this.spinnerTab) {
                 TelemetryStopwatch.start("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window);
+                this.addMarker("AsyncTabSwitch:SpinnerShown");
               }
             },
 
             spinnerHidden: function () {
               if (this.spinnerTab) {
                 this.log("DEBUG: spinner time = " +
                          TelemetryStopwatch.timeElapsed("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window));
                 TelemetryStopwatch.finish("FX_TAB_SWITCH_SPINNER_VISIBLE_MS", window);
+                this.addMarker("AsyncTabSwitch:SpinnerHidden");
                 // we do not get a onPaint after displaying the spinner
                 this.finishTabSwitch();
               }
             },
 
+            addMarker: function(marker) {
+              if (Services.profiler) {
+                Services.profiler.AddMarker(marker);
+              }
+            },
+
             /*
              * Debug related logging for switcher.
              */
 
             _useDumpForLogging: false,
             _logInit: false,
 
             logging: function () {
--- a/browser/base/content/test/social/browser_social_activation.js
+++ b/browser/base/content/test/social/browser_social_activation.js
@@ -84,28 +84,25 @@ function activateIFrameProvider(domain, 
     sendActivationEvent(tab, callback, false);
   });
 }
 
 function waitForProviderLoad(cb) {
     waitForCondition(function() {
       let sbrowser = document.getElementById("social-sidebar-browser");
       let provider = SocialSidebar.provider;
-      let postActivation = provider && gBrowser.contentDocument.location.href == provider.origin + "/browser/browser/base/content/test/social/social_postActivation.html";
+      let postActivation = provider && gBrowser.contentDocument &&
+                            gBrowser.contentDocument.location.href == provider.origin + "/browser/browser/base/content/test/social/social_postActivation.html";
 
-      return provider &&
-             provider.profile &&
-             provider.profile.displayName &&
-             postActivation &&
-             sbrowser.docShellIsActive;
+      return postActivation && sbrowser.docShellIsActive;
     }, function() {
       // executeSoon to let the browser UI observers run first
       executeSoon(cb);
     },
-    "waitForProviderLoad: provider profile was not set");
+    "waitForProviderLoad: provider was not loaded");
 }
 
 
 function getAddonItemInList(aId, aList) {
   var item = aList.firstChild;
   while (item) {
     if ("mAddon" in item && item.mAddon.id == aId) {
       aList.ensureElementIsVisible(item);
@@ -173,32 +170,29 @@ function activateOneProvider(manifest, f
   });
 }
 
 let gTestDomains = ["https://example.com", "https://test1.example.com", "https://test2.example.com"];
 let gProviders = [
   {
     name: "provider 1",
     origin: "https://example.com",
-    sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar.html?provider1",
-    workerURL: "https://example.com/browser/browser/base/content/test/social/social_worker.js#no-profile,no-recommend",
+    sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar_empty.html?provider1",
     iconURL: "chrome://branding/content/icon48.png"
   },
   {
     name: "provider 2",
     origin: "https://test1.example.com",
-    sidebarURL: "https://test1.example.com/browser/browser/base/content/test/social/social_sidebar.html?provider2",
-    workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js#no-profile,no-recommend",
+    sidebarURL: "https://test1.example.com/browser/browser/base/content/test/social/social_sidebar_empty.html?provider2",
     iconURL: "chrome://branding/content/icon64.png"
   },
   {
     name: "provider 3",
     origin: "https://test2.example.com",
-    sidebarURL: "https://test2.example.com/browser/browser/base/content/test/social/social_sidebar.html?provider2",
-    workerURL: "https://test2.example.com/browser/browser/base/content/test/social/social_worker.js#no-profile,no-recommend",
+    sidebarURL: "https://test2.example.com/browser/browser/base/content/test/social/social_sidebar_empty.html?provider2",
     iconURL: "chrome://branding/content/about-logo.png"
   }
 ];
 
 
 function test() {
   waitForExplicitFinish();
   runSocialTests(tests, undefined, postTestCleanup);
--- a/browser/components/loop/modules/LoopRooms.jsm
+++ b/browser/components/loop/modules/LoopRooms.jsm
@@ -213,21 +213,16 @@ let LoopRoomsInternal = {
       serverRoomData.roomName = roomData.decryptedContext.roomName;
 
       return {
         all: roomData,
         encrypted: serverRoomData
       };
     }
 
-    // For now, disable encryption/context if context is disabled
-    if (!MozLoopService.getLoopPref("contextInConverations.enabled")) {
-      return getUnencryptedData();
-    }
-
     var newRoomData = extend({}, roomData);
 
     if (!newRoomData.context) {
       newRoomData.context = {};
     }
 
     // First get the room key.
     let key = yield this.promiseGetOrCreateRoomKey(newRoomData);
@@ -695,17 +690,18 @@ let LoopRoomsInternal = {
       let {all, encrypted} = yield this.promiseEncryptRoomData(roomData);
 
       // For patch, we only send the context data.
       let sendData = {
         context: encrypted.context
       };
 
       // If we're not encrypting currently, then only send the roomName.
-      if (!Services.prefs.getBoolPref("loop.contextInConverations.enabled")) {
+      // XXX This should go away once bug 1153788 is fixed.
+      if (!sendData.context) {
         sendData = {
           roomName: newRoomName
         };
       }
 
       let response = yield MozLoopService.hawkRequest(this.sessionType,
           url, "PATCH", sendData);
 
--- a/browser/components/loop/test/xpcshell/test_looprooms.js
+++ b/browser/components/loop/test/xpcshell/test_looprooms.js
@@ -6,18 +6,16 @@
 
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource:///modules/loop/LoopRooms.jsm");
 Cu.import("resource:///modules/Chat.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 
 let openChatOrig = Chat.open;
 
-const kContextEnabledPref = "loop.contextInConverations.enabled";
-
 const kGuestKey = "uGIs-kGbYt1hBBwjyW7MLQ";
 
 // Rooms details as responded by the server.
 const kRoomsResponses = new Map([
   ["_nxD4V4FflQ", {
     roomToken: "_nxD4V4FflQ",
     // Encrypted with roomKey "FliIGLUolW-xkKZVWstqKw".
     // roomKey is wrapped with kGuestKey.
@@ -294,24 +292,20 @@ add_task(function* setup_server() {
   loopServer.registerPathHandler("/rooms", (req, res) => {
     res.setStatusLine(null, 200, "OK");
 
     if (req.method == "POST") {
       Assert.ok(req.bodyInputStream, "POST request should have a payload");
       let body = CommonUtils.readBytesFromInputStream(req.bodyInputStream);
       let data = JSON.parse(body);
 
-      if (Services.prefs.getBoolPref(kContextEnabledPref)) {
-        Assert.equal(data.roomOwner, kCreateRoomProps.roomOwner);
-        Assert.equal(data.maxSize, kCreateRoomProps.maxSize);
-        Assert.ok(!("decryptedContext" in data), "should not have any decrypted data");
-        Assert.ok("context" in data, "should have context");
-      } else {
-        Assert.deepEqual(data, kCreateRoomUnencryptedProps);
-      }
+      Assert.equal(data.roomOwner, kCreateRoomProps.roomOwner);
+      Assert.equal(data.maxSize, kCreateRoomProps.maxSize);
+      Assert.ok(!("decryptedContext" in data), "should not have any decrypted data");
+      Assert.ok("context" in data, "should have context");
 
       res.write(JSON.stringify(kCreateRoomData));
     } else {
       if (req.queryString) {
         let qs = parseQueryString(req.queryString);
         let room = kRoomsResponses.get("_nxD4V4FflQ");
         room.participants = kRoomUpdates[qs.version].participants;
         room.deleted = kRoomUpdates[qs.version].deleted;
@@ -348,25 +342,21 @@ add_task(function* setup_server() {
       if (req.method == "POST") {
         let data = getJSONData(req.bodyInputStream);
         res.setStatusLine(null, 200, "OK");
         res.write(JSON.stringify(data));
         res.processAsync();
         res.finish();
       } else if (req.method == "PATCH") {
         let data = getJSONData(req.bodyInputStream);
-        if (Services.prefs.getBoolPref(kContextEnabledPref)) {
-          Assert.ok("context" in data, "should have encrypted context");
-          // We return a fake encrypted name here as the context is
-          // encrypted.
-          returnRoomDetails(res, "fakeEncrypted");
-        } else {
-          Assert.ok(!("context" in data), "should not have encrypted context");
-          returnRoomDetails(res, data.roomName);
-        }
+
+        Assert.ok("context" in data, "should have encrypted context");
+        // We return a fake encrypted name here as the context is
+        // encrypted.
+        returnRoomDetails(res, "fakeEncrypted");
       } else {
         roomDetail.context = room.context;
         res.setStatusLine(null, 200, "OK");
         res.write(JSON.stringify(roomDetail));
         res.processAsync();
         res.finish();
       }
     });
@@ -410,30 +400,16 @@ add_task(function* test_getRoom() {
 // Test if fetching a room with incorrect token or return values yields an error.
 add_task(function* test_errorStates() {
   yield Assert.rejects(LoopRooms.promise("get", "error401"), /Not Found/, "Fetching a non-existent room should fail");
   yield Assert.rejects(LoopRooms.promise("get", "errorMalformed"), /SyntaxError/, "Wrong message format should reject");
 });
 
 // Test if creating a new room works as expected.
 add_task(function* test_createRoom() {
-  Services.prefs.setBoolPref(kContextEnabledPref, true);
-
-  var expectedRoom = extend({}, kCreateRoomProps);
-  expectedRoom.roomToken = kCreateRoomData.roomToken;
-
-  gExpectedAdds.push(expectedRoom);
-  let room = yield LoopRooms.promise("create", kCreateRoomProps);
-  compareRooms(room, expectedRoom);
-});
-
-// XXX Test unencrypted rooms. This will go away once we switch encryption on.
-add_task(function* test_createRoom_unencrypted() {
-  Services.prefs.setBoolPref(kContextEnabledPref, false);
-
   var expectedRoom = extend({}, kCreateRoomProps);
   expectedRoom.roomToken = kCreateRoomData.roomToken;
 
   gExpectedAdds.push(expectedRoom);
   let room = yield LoopRooms.promise("create", kCreateRoomProps);
   compareRooms(room, expectedRoom);
 });
 
@@ -596,29 +572,21 @@ add_task(function* test_sendConnectionSt
 
   extraData.action = "status";
   extraData.sessionToken = "fakeStatusSessionToken";
   Assert.deepEqual(statusData, extraData);
 });
 
 // Test if renaming a room works as expected.
 add_task(function* test_renameRoom() {
-  Services.prefs.setBoolPref(kContextEnabledPref, true);
   let roomToken = "_nxD4V4FflQ";
   let renameData = yield LoopRooms.promise("rename", roomToken, "fakeName");
   Assert.equal(renameData.roomName, "fakeEncrypted", "should have set the new name");
 });
 
-add_task(function* test_renameRoom_unencrpyted() {
-  Services.prefs.setBoolPref(kContextEnabledPref, false);
-  let roomToken = "_nxD4V4FflQ";
-  let renameData = yield LoopRooms.promise("rename", roomToken, "fakeName");
-  Assert.equal(renameData.roomName, "fakeName", "should have set the new name");
-});
-
 add_task(function* test_roomDeleteNotifications() {
   gExpectedDeletes.push("_nxD4V4FflQ");
   roomsPushNotification("5", kChannelGuest);
   yield waitForCondition(() => gExpectedDeletes.length === 0);
 });
 
 // Test if deleting a room works as expected.
 add_task(function* test_deleteRoom() {
@@ -652,17 +620,16 @@ function run_test() {
   LoopRooms.on("delete", onRoomDeleted);
   LoopRooms.on("joined", onRoomJoined);
   LoopRooms.on("left", onRoomLeft);
   LoopRooms.on("refresh", onRefresh);
 
   do_register_cleanup(function () {
     // Revert original Chat.open implementation
     Chat.open = openChatOrig;
-    Services.prefs.clearUserPref(kContextEnabledPref);
     Services.prefs.clearUserPref("loop.key");
 
     MozLoopServiceInternal.fxAOAuthTokenData = null;
     MozLoopServiceInternal.fxAOAuthProfile = null;
 
     LoopRooms.off("add", onRoomAdded);
     LoopRooms.off("update", onRoomUpdated);
     LoopRooms.off("delete", onRoomDeleted);
--- a/browser/devtools/markupview/markup-view.js
+++ b/browser/devtools/markupview/markup-view.js
@@ -1824,17 +1824,25 @@ MarkupContainer.prototype = {
       return;
     }
 
     // target is the MarkupContainer itself.
     this._isMouseDown = true;
     this.hovered = false;
     this.markup.navigate(this);
     event.stopPropagation();
-    event.preventDefault();
+
+    // Preventing the default behavior will avoid the body to gain focus on
+    // mouseup (through bubbling) when clicking on a non focusable node in the
+    // line. So, if the click happened outside of a focusable element, do
+    // prevent the default behavior, so that the tagname or textcontent gains
+    // focus.
+    if (!target.closest(".open [tabindex]")) {
+      event.preventDefault();
+    }
 
     // Start dragging the container after a delay.
     this.markup._dragStartEl = target;
     setTimeout(() => {
       // Make sure the mouse is still down and on target.
       if (!this._isMouseDown || this.markup._dragStartEl !== target ||
           this.node.isPseudoElement || this.node.isAnonymous ||
           !this.win.getSelection().isCollapsed) {
--- a/browser/devtools/markupview/test/browser_markupview_keybindings_03.js
+++ b/browser/devtools/markupview/test/browser_markupview_keybindings_03.js
@@ -3,17 +3,17 @@
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 // Tests that selecting a node with the mouse (by clicking on the line) focuses
 // the first focusable element in the corresponding MarkupContainer so that the
 // keyboard can be used immediately.
 
-const TEST_URL = "data:text/html;charset=utf8,<div></div>Text node";
+const TEST_URL = "data:text/html;charset=utf8,<div class='test-class'></div>Text node";
 
 add_task(function*() {
   let {inspector, toolbox} = yield addTab(TEST_URL).then(openInspector);
   let {walker} = inspector;
 
   info("Select the test node to have the 2 test containers visible");
   yield selectNode("div", inspector);
 
@@ -26,9 +26,23 @@ add_task(function*() {
      getContainerForNodeFront(textFront, inspector).editor.value,
      "The currently focused element is the node's text content");
 
   info("Click on the MarkupContainer element for the <div> node");
   yield clickContainer(divFront, inspector);
   is(inspector.markup.doc.activeElement,
      getContainerForNodeFront(divFront, inspector).editor.tag,
      "The currently focused element is the div's tagname");
+
+  info("Click on the test-class attribute, to make sure it gets focused");
+  let editor = getContainerForNodeFront(divFront, inspector).editor;
+  let attributeEditor = editor.attrElements.get("class").querySelector(".editable");
+
+  let onFocus = once(attributeEditor, "focus");
+  EventUtils.synthesizeMouseAtCenter(attributeEditor, {type: "mousedown"},
+    inspector.markup.doc.defaultView);
+  EventUtils.synthesizeMouseAtCenter(attributeEditor, {type: "mouseup"},
+    inspector.markup.doc.defaultView);
+  yield onFocus;
+
+  is(inspector.markup.doc.activeElement, attributeEditor,
+     "The currently focused element is the div's class attribute");
 });
--- a/browser/devtools/performance/modules/graphs.js
+++ b/browser/devtools/performance/modules/graphs.js
@@ -261,30 +261,30 @@ GraphsController.prototype = {
     }
 
     // If there was rendering, wait until the most recent render cycle
     // has finished
     if (this._rendering) {
       yield this._rendering.promise;
     }
 
-    for (let graphName in this._graphs) {
-      yield this._graphs[graphName].destroy();
+    for (let graph of this.getWidgets()) {
+      yield graph.destroy();
     }
   }),
 
   /**
    * Applies the theme to the underlying graphs. Optionally takes
    * a `redraw` boolean in the options to force redraw.
    */
   setTheme: function (options={}) {
     let theme = options.theme || this._getTheme();
-    for (let graph in this._graphs) {
-      this._graphs[graph].setTheme(theme);
-      this._graphs[graph].refresh({ force: options.redraw });
+    for (let graph of this.getWidgets()) {
+      graph.setTheme(theme);
+      graph.refresh({ force: options.redraw });
     }
   },
 
   /**
    * Sets up the graph, if needed. Returns a promise resolving
    * to the graph if it is enabled once it's ready, or otherwise returns
    * null if disabled.
    */
@@ -344,16 +344,24 @@ GraphsController.prototype = {
     return this._getPrimaryLink().setMappedSelection(selection, { mapStart, mapEnd });
   },
 
   getMappedSelection: function ({ mapStart, mapEnd }) {
     return this._getPrimaryLink().getMappedSelection({ mapStart, mapEnd });
   },
 
   /**
+   * Returns an array of graphs that have been created, not necessarily
+   * enabled currently.
+   */
+  getWidgets: function () {
+    return Object.keys(this._graphs).map(name => this._graphs[name]);
+  },
+
+  /**
    * Drops the selection.
    */
   dropSelection: function () {
     if (this._getPrimaryLink()) {
       return this._getPrimaryLink().dropSelection();
     }
   },
 
--- a/browser/devtools/performance/test/browser.ini
+++ b/browser/devtools/performance/test/browser.ini
@@ -38,16 +38,17 @@ support-files =
 [browser_perf-details-memory-calltree-render.js]
 [browser_perf-details-memory-flamegraph-render.js]
 [browser_perf-details-waterfall-render.js]
 [browser_perf-details-01.js]
 [browser_perf-details-02.js]
 [browser_perf-details-03.js]
 [browser_perf-details-04.js]
 [browser_perf-details-05.js]
+[browser_perf-details-06.js]
 [browser_perf-events-calltree.js]
 [browser_perf-front-basic-profiler-01.js]
 [browser_perf-front-basic-timeline-01.js]
 #[browser_perf-front-profiler-01.js] bug 1077464
 [browser_perf-front-profiler-02.js]
 [browser_perf-front-profiler-03.js]
 [browser_perf-front-profiler-04.js]
 #[browser_perf-front-profiler-05.js] bug 1077464
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_perf-details-06.js
@@ -0,0 +1,61 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests that the views with `shouldUpdateWhileMouseIsActive` works as intended.
+ */
+function spawnTest () {
+  let { panel } = yield initPerformance(SIMPLE_URL);
+  let { EVENTS, PerformanceController, OverviewView, DetailsView, WaterfallView, JsFlameGraphView } = panel.panelWin;
+
+  yield startRecording(panel);
+  yield stopRecording(panel);
+
+  // Set the debounce on WaterfallView and JsFlameGraphView to 0
+  WaterfallView.rangeChangeDebounceTime = 0;
+  JsFlameGraphView.rangeChangeDebounceTime = 0;
+
+  yield DetailsView.selectView("js-flamegraph");
+  let duration = PerformanceController.getCurrentRecording().getDuration();
+
+  // Fake an active mouse
+  Object.defineProperty(OverviewView, "isMouseActive", { value: true });
+
+  // Flame Graph should update on every selection, debounced, while mouse is down
+  let flamegraphRendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
+  OverviewView.emit(EVENTS.OVERVIEW_RANGE_SELECTED, { startTime: 0, endTime: duration });
+  yield flamegraphRendered;
+  ok(true, "FlameGraph rerenders when mouse is active (1)");
+
+  flamegraphRendered = once(JsFlameGraphView, EVENTS.JS_FLAMEGRAPH_RENDERED);
+  OverviewView.emit(EVENTS.OVERVIEW_RANGE_SELECTED, { startTime: 0, endTime: duration });
+  yield flamegraphRendered;
+  ok(true, "FlameGraph rerenders when mouse is active (2)");
+
+  ok(OverviewView.isMouseActive, "Fake mouse is still active");
+
+  // Fake an inactive mouse for rerender
+  Object.defineProperty(OverviewView, "isMouseActive", { value: false });
+  yield DetailsView.selectView("waterfall");
+
+  // Fake an active mouse for rerender
+  Object.defineProperty(OverviewView, "isMouseActive", { value: true });
+
+  let oneSecondElapsed = false;
+  let waterfallRendered = false;
+
+  WaterfallView.on(EVENTS.WATERFALL_RENDERED, () => waterfallRendered = true);
+
+  // Keep firing range selection events for one second
+  idleWait(1000).then(() => oneSecondElapsed = true);
+  yield waitUntil(() => {
+    OverviewView.emit(EVENTS.OVERVIEW_RANGE_SELECTED, { startTime: 0, endTime: duration });
+    return oneSecondElapsed;
+  });
+
+  ok(OverviewView.isMouseActive, "Fake mouse is still active");
+  ok(!waterfallRendered, "the waterfall view should not have been rendered while mouse is active.");
+
+  yield teardown(panel);
+  finish();
+}
--- a/browser/devtools/performance/views/overview.js
+++ b/browser/devtools/performance/views/overview.js
@@ -92,19 +92,20 @@ let OverviewView = {
     yield this.graphs.destroy();
   }),
 
   /**
    * Returns true if any of the overview graphs have mouse dragging active,
    * false otherwise.
    */
   get isMouseActive() {
-    return (this.markersOverview && this.markersOverview.isMouseActive) ||
-           (this.memoryOverview && this.memoryOverview.isMouseActive) ||
-           (this.framerateGraph && this.framerateGraph.isMouseActive);
+    // Fetch all graphs currently stored in the GraphsController.
+    // These graphs are not necessarily active, but will not have
+    // an active mouse, in that case.
+    return !!this.graphs.getWidgets().some(e => e.isMouseActive);
   },
 
   /**
    * Disabled in the event we're using a Timeline mock, so we'll have no
    * timeline, ticks or memory data to show, so just block rendering and hide
    * the panel.
    */
   disable: function () {
--- a/browser/devtools/responsivedesign/test/browser_responsiveuiaddcustompreset.js
+++ b/browser/devtools/responsivedesign/test/browser_responsiveuiaddcustompreset.js
@@ -114,17 +114,19 @@ function test() {
     is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
 
     instance = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
 
     let customPresetIndex = getPresetIndex("456" + "\u00D7" + "123 (Testing preset)");
     info(customPresetIndex);
     ok(customPresetIndex >= 0, "is the previously added preset (idx = " + customPresetIndex + ") in the list of items");
 
+    let resizePromise = instance._test_notifyOnResize();
     instance.menulist.selectedIndex = customPresetIndex;
+    yield resizePromise;
 
     is(content.innerWidth, 456, "add preset, and selected in the list, dimension valid (width)");
     is(content.innerHeight, 123, "add preset, and selected in the list, dimension valid (height)");
 
     instance.removebutton.doCommand();
 
     instance.menulist.selectedIndex = 2;
     deletedPresetA = instance.menulist.selectedItem.getAttribute("label");
--- a/browser/devtools/shared/profiler/frame-utils.js
+++ b/browser/devtools/shared/profiler/frame-utils.js
@@ -49,25 +49,40 @@ exports.parseLocation = function parseLo
     hostName: hostName,
     url: url,
     line: line,
     column: column
   };
 },
 
 /**
+ * Determines if the given frame is the (root) frame.
+ *
+ * @param object frame
+ * @return boolean
+ */
+exports.isRoot = function isRoot({ location }) {
+  return location === "(root)";
+};
+
+/**
 * Checks if the specified function represents a chrome or content frame.
 *
 * @param object frame
 *        The { category, location } properties of the frame.
 * @return boolean
 *         True if a content frame, false if a chrome frame.
 */
-exports.isContent = function isContent ({ category, location }) {
+exports.isContent = function isContent (frame) {
+  if (exports.isRoot(frame)) {
+    return true;
+  }
+
   // Only C++ stack frames have associated category information.
+  const { category, location } = frame;
   return !!(!category &&
     !CHROME_SCHEMES.find(e => location.includes(e)) &&
     CONTENT_SCHEMES.find(e => location.includes(e)));
 }
 
 /**
  * This filters out platform data frames in a sample. With latest performance
  * tool in Fx40, when displaying only content, we still filter out all platform data,
--- a/browser/devtools/shared/profiler/tree-model.js
+++ b/browser/devtools/shared/profiler/tree-model.js
@@ -88,25 +88,30 @@ ThreadNode.prototype = {
     let optimizations = options.optimizations;
     let sampleTime = sample.time;
     if (!sampleTime || sampleTime < startTime || sampleTime > endTime) {
       return;
     }
 
     let sampleFrames = sample.frames;
 
+    if (!options.invertTree) {
+      // Remove the (root) node if the tree is not inverted: we will synthesize
+      // our own root in the view. However, for inverted trees, we wish to be
+      // able to differentiate between (root)->A->B->C and (root)->B->C stacks,
+      // so we need the root node in that case.
+      sampleFrames = sampleFrames.slice(1);
+    }
+
     // Filter out platform frames if only content-related function calls
     // should be taken into consideration.
     if (options.contentOnly) {
-      // The (root) node is not considered a content function, it'll be removed.
       sampleFrames = FrameUtils.filterPlatformData(sampleFrames);
-    } else {
-      // Remove the (root) node manually.
-      sampleFrames = sampleFrames.slice(1);
     }
+
     // If no frames remain after filtering, then this is a leaf node, no need
     // to continue.
     if (!sampleFrames.length) {
       return;
     }
     // Invert the tree after filtering, if preferred.
     if (options.invertTree) {
       sampleFrames.reverse();
--- a/browser/devtools/webconsole/test/browser_bug_865871_variables_view_close_on_esc_key.js
+++ b/browser/devtools/webconsole/test/browser_bug_865871_variables_view_close_on_esc_key.js
@@ -15,84 +15,61 @@ function test()
   let hud;
 
   Task.spawn(runner).then(finishTest);
 
   function* runner() {
     let {tab} = yield loadTab(TEST_URI);
     hud = yield openConsole(tab);
     let jsterm = hud.jsterm;
-
-    let msg = yield execute("fooObj");
-    ok(msg, "output message found");
-
-    let anchor = msg.querySelector("a");
-    let body = msg.querySelector(".message-body");
-    ok(anchor, "object anchor");
-    ok(body, "message body");
-    ok(body.textContent.includes('testProp: "testValue"'), "message text check");
+    let result;
+    let vview;
+    let msg;
 
-    msg.scrollIntoView();
-    executeSoon(() => {
-      EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow);
-    });
-
-    let vviewVar = yield jsterm.once("variablesview-fetched");
-    let vview = vviewVar._variablesView;
-    ok(vview, "variables view object");
-
-    let [result] = yield findVariableViewProperties(vviewVar, [
-      { name: "testProp", value: "testValue" },
-    ], { webconsole: hud });
+    yield openSidebar("fooObj",
+                      'testProp: "testValue"',
+                      { name: "testProp", value: "testValue" });
 
     let prop = result.matchedProp;
     ok(prop, "matched the |testProp| property in the variables view");
 
     vview.window.focus();
 
-    executeSoon(() => {
-      EventUtils.synthesizeKey("VK_ESCAPE", {});
-    });
-    yield jsterm.once("sidebar-closed");
+    let sidebarClosed = jsterm.once("sidebar-closed");
+    EventUtils.synthesizeKey("VK_ESCAPE", {});
+    yield sidebarClosed;
 
     jsterm.clearOutput();
 
-    msg = yield execute("window.location");
-    ok(msg, "output message found");
-
-    body = msg.querySelector(".message-body");
-    ok(body, "message body");
-    anchor = msg.querySelector("a");
-    ok(anchor, "object anchor");
-    ok(body.textContent.includes("Location \u2192 http://example.com/browser/"),
-       "message text check");
-
-    msg.scrollIntoView();
-    executeSoon(() => {
-      EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow)
-    });
-    vviewVar = yield jsterm.once("variablesview-fetched");
-
-    vview = vviewVar._variablesView;
-    ok(vview, "variables view object");
-
-    yield findVariableViewProperties(vviewVar, [
-      { name: "host", value: "example.com" },
-    ], { webconsole: hud });
+    yield openSidebar("window.location",
+                      "Location \u2192 http://example.com/browser/",
+                      { name: "host", value: "example.com" });
 
     vview.window.focus();
 
     msg.scrollIntoView();
-    executeSoon(() => {
-      EventUtils.synthesizeKey("VK_ESCAPE", {});
-    });
+    sidebarClosed = jsterm.once("sidebar-closed");
+    EventUtils.synthesizeKey("VK_ESCAPE", {});
+    yield sidebarClosed;
 
-    yield jsterm.once("sidebar-closed");
-  }
+    function* openSidebar(objName, expectedText, expectedObj) {
+      msg = yield jsterm.execute(objName);
+      ok(msg, "output message found");
 
-  function execute(str) {
-    let deferred = promise.defer();
-    hud.jsterm.execute(str, (msg) => {
-      deferred.resolve(msg);
-    });
-    return deferred.promise;
+      let anchor = msg.querySelector("a");
+      let body = msg.querySelector(".message-body");
+      ok(anchor, "object anchor");
+      ok(body, "message body");
+      ok(body.textContent.includes(expectedText), "message text check");
+
+      msg.scrollIntoView();
+      yield EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow);
+
+      let vviewVar = yield jsterm.once("variablesview-fetched");
+      vview = vviewVar._variablesView;
+      ok(vview, "variables view object exists");
+
+      [result] = yield findVariableViewProperties(vviewVar, [
+        expectedObj,
+      ], { webconsole: hud });
+    }
   }
 }
--- a/browser/devtools/webconsole/test/browser_console_clear_on_reload.js
+++ b/browser/devtools/webconsole/test/browser_console_clear_on_reload.js
@@ -1,43 +1,54 @@
 /*
  * Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 // Check that clear output on page reload works - bug 705921.
+// Check that clear output and page reload remove the sidebar - bug 971967.
 
 "use strict";
 
 let test = asyncTest(function*() {
   const PREF = "devtools.webconsole.persistlog";
   const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console.html";
 
   Services.prefs.setBoolPref(PREF, false);
   registerCleanupFunction(() => Services.prefs.clearUserPref(PREF));
 
   yield loadTab(TEST_URI);
 
   let hud = yield openConsole();
   ok(hud, "Web Console opened");
 
+  yield openSidebar("fooObj", { name: "testProp", value: "testValue" });
+
+  let sidebarClosed = hud.jsterm.once("sidebar-closed");
   hud.jsterm.clearOutput();
+  yield sidebarClosed;
+
   hud.jsterm.execute("console.log('foobarz1')");
 
   yield waitForMessages({
     webconsole: hud,
     messages: [{
       text: "foobarz1",
       category: CATEGORY_WEBDEV,
       severity: SEVERITY_LOG,
     }],
   });
 
+  yield openSidebar("fooObj", { name: "testProp", value: "testValue" });
+
   BrowserReload();
-  yield loadBrowser(gBrowser.selectedBrowser);
+
+  sidebarClosed = hud.jsterm.once("sidebar-closed");
+  loadBrowser(gBrowser.selectedBrowser);
+  yield sidebarClosed;
 
   hud.jsterm.execute("console.log('foobarz2')");
 
   yield waitForMessages({
     webconsole: hud,
     messages: [{
       text: "test-console.html",
       category: CATEGORY_NETWORK,
@@ -46,9 +57,29 @@ let test = asyncTest(function*() {
       text: "foobarz2",
       category: CATEGORY_WEBDEV,
       severity: SEVERITY_LOG,
     }],
   });
 
   is(hud.outputNode.textContent.indexOf("foobarz1"), -1,
      "foobarz1 has been removed from output");
+
+  function* openSidebar(objName, expectedObj) {
+    let msg = yield hud.jsterm.execute(objName);
+    ok(msg, "output message found");
+
+    let anchor = msg.querySelector("a");
+    let body = msg.querySelector(".message-body");
+    ok(anchor, "object anchor");
+    ok(body, "message body");
+
+    yield EventUtils.synthesizeMouse(anchor, 2, 2, {}, hud.iframeWindow);
+
+    let vviewVar = yield hud.jsterm.once("variablesview-fetched");
+    let vview = vviewVar._variablesView;
+    ok(vview, "variables view object exists");
+
+    yield findVariableViewProperties(vviewVar, [
+      expectedObj,
+    ], { webconsole: hud });
+  }
 });
--- a/browser/devtools/webconsole/test/test-console.html
+++ b/browser/devtools/webconsole/test/test-console.html
@@ -1,13 +1,17 @@
 <!DOCTYPE HTML>
 <html dir="ltr" xml:lang="en-US" lang="en-US"><head>
     <meta charset="utf-8">
     <title>Console test</title>
     <script type="text/javascript">
+      var fooObj = {
+        testProp: "testValue"
+      };
+
       function test() {
         var str = "Dolske Digs Bacon, Now and Forevermore."
         for (var i=0; i < 5; i++) {
           console.log(str);
         }
       }
       console.info("INLINE SCRIPT:");
       test();
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -3974,16 +3974,18 @@ JSTerm.prototype = {
     hud._outputQueue = [];
     hud._networkRequests = {};
     hud._repeatNodes = {};
 
     if (aClearStorage) {
       this.webConsoleClient.clearMessagesCache();
     }
 
+    this._sidebarDestroy();
+
     this.emit("messages-cleared");
   },
 
   /**
    * Remove all of the private messages from the Web Console output.
    *
    * This method emits the "private-messages-cleared" notification.
    */
--- 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/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1845,16 +1845,18 @@ MediaManager::GetUserMedia(
       // the requesting document is not from a host on the whitelist, or
       // we're on Mac OSX 10.6 and WinXP until proved that they work
       if (!Preferences::GetBool(((src == dom::MediaSourceEnum::Browser)?
                                 "media.getusermedia.browser.enabled" :
                                 "media.getusermedia.screensharing.enabled"),
                                 false) ||
 #if defined(XP_MACOSX) || defined(XP_WIN)
           (
+            // Allow tab sharing for all platforms including XP and OSX 10.6
+            (src != dom::MediaSourceEnum::Browser) &&
             !Preferences::GetBool("media.getusermedia.screensharing.allow_on_old_platforms",
                                   false) &&
 #if defined(XP_MACOSX)
             !nsCocoaFeatures::OnLionOrLater()
 #endif
 #if defined (XP_WIN)
             !IsVistaOrLater()
 #endif
--- 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/gfx/layers/apz/util/APZCCallbackHelper.cpp
+++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp
@@ -13,16 +13,17 @@
 #include "nsIScrollableFrame.h"
 #include "nsLayoutUtils.h"
 #include "nsIDOMElement.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsIContent.h"
 #include "nsIDocument.h"
 #include "nsIDOMWindow.h"
 #include "nsRefreshDriver.h"
+#include "nsView.h"
 
 #define APZCCH_LOG(...)
 // #define APZCCH_LOG(...) printf_stderr("APZCCH: " __VA_ARGS__)
 
 namespace mozilla {
 namespace layers {
 
 using dom::TabParent;
@@ -494,33 +495,52 @@ GetDisplayportElementFor(nsIScrollableFr
   // nearest ancestor scrollable frame. The element corresponding to this
   // frame should be the one with the displayport set on it, so find that
   // element and return it.
   nsIContent* content = scrolledFrame->GetContent();
   MOZ_ASSERT(content->IsElement()); // roc says this must be true
   return content->AsElement();
 }
 
+
+static dom::Element*
+GetRootDocumentElementFor(nsIWidget* aWidget)
+{
+  // This returns the root element that ChromeProcessController sets the
+  // displayport on during initialization.
+  if (nsView* view = nsView::GetViewFor(aWidget)) {
+    if (nsIPresShell* shell = view->GetPresShell()) {
+      MOZ_ASSERT(shell->GetDocument());
+      return shell->GetDocument()->GetDocumentElement();
+    }
+  }
+  return nullptr;
+}
+
 // Determine the scrollable target frame for the given point and add it to
 // the target list. If the frame doesn't have a displayport, set one.
 // Return whether or not a displayport was set.
 static bool
 PrepareForSetTargetAPZCNotification(nsIWidget* aWidget,
                                     const ScrollableLayerGuid& aGuid,
                                     nsIFrame* aRootFrame,
                                     const LayoutDeviceIntPoint& aRefPoint,
                                     nsTArray<ScrollableLayerGuid>* aTargets)
 {
   ScrollableLayerGuid guid(aGuid.mLayersId, 0, FrameMetrics::NULL_SCROLL_ID);
   nsPoint point =
     nsLayoutUtils::GetEventCoordinatesRelativeTo(aWidget, aRefPoint, aRootFrame);
   nsIFrame* target =
     nsLayoutUtils::GetFrameForPoint(aRootFrame, point, nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME);
   nsIScrollableFrame* scrollAncestor = GetScrollableAncestorFrame(target);
-  nsCOMPtr<dom::Element> dpElement = GetDisplayportElementFor(scrollAncestor);
+
+  // Assuming that if there's no scrollAncestor, there's already a displayPort.
+  nsCOMPtr<dom::Element> dpElement = scrollAncestor
+    ? GetDisplayportElementFor(scrollAncestor)
+    : GetRootDocumentElementFor(aWidget);
 
   nsAutoString dpElementDesc;
   if (dpElement) {
     dpElement->Describe(dpElementDesc);
   }
   APZCCH_LOG("For event at %s found scrollable element %p (%s)\n",
       Stringify(aRefPoint).c_str(), dpElement.get(),
       NS_LossyConvertUTF16toASCII(dpElementDesc).get());
@@ -529,16 +549,17 @@ PrepareForSetTargetAPZCNotification(nsIW
     dpElement, &(guid.mPresShellId), &(guid.mScrollId));
   aTargets->AppendElement(guid);
 
   if (!guidIsValid || nsLayoutUtils::GetDisplayPort(dpElement, nullptr)) {
     return false;
   }
 
   APZCCH_LOG("%p didn't have a displayport, so setting one...\n", dpElement.get());
+  MOZ_ASSERT(scrollAncestor);
   return nsLayoutUtils::CalculateAndSetDisplayPortMargins(
       scrollAncestor, nsLayoutUtils::RepaintMode::Repaint);
 }
 
 static void
 SendLayersDependentApzcTargetConfirmation(nsIPresShell* aShell, uint64_t aInputBlockId,
                                           const nsTArray<ScrollableLayerGuid>& aTargets)
 {
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -601,16 +601,27 @@ AsyncCompositionManager::ApplyAsyncConte
     }
 
     const FrameMetrics& metrics = aLayer->GetFrameMetrics(i);
     ScreenPoint offset(0, 0);
     // TODO: When we enable APZ on Fennec, we'll need to call SyncFrameMetrics here.
     // When doing so, it might be useful to look at how it was called here before
     // bug 1036967 removed the (dead) call.
 
+#if defined(MOZ_ANDROID_APZ)
+    if (mIsFirstPaint) {
+      CSSToLayerScale geckoZoom = metrics.LayersPixelsPerCSSPixel().ToScaleFactor();
+      LayerIntPoint scrollOffsetLayerPixels = RoundedToInt(metrics.GetScrollOffset() * geckoZoom);
+      mContentRect = metrics.GetScrollableRect();
+      SetFirstPaintViewport(scrollOffsetLayerPixels,
+                            geckoZoom,
+                            mContentRect);
+    }
+#endif
+
     mIsFirstPaint = false;
     mLayersUpdated = false;
 
     // Apply the render offset
     mLayerManager->GetCompositor()->SetScreenRenderOffset(offset);
 
     combinedAsyncTransformWithoutOverscroll *= asyncTransformWithoutOverscroll;
     combinedAsyncTransform *= (Matrix4x4(asyncTransformWithoutOverscroll) * overscrollTransform);
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1516,22 +1516,22 @@ already_AddRefed<LayerManager> nsDisplay
     bool isRoot = presContext->IsRootContentDocument();
 
     nsRect viewport(aBuilder->ToReferenceFrame(frame), frame->GetSize());
 
     nsIFrame* scrollFrame = presShell->GetRootScrollFrame();
     nsIContent* content = nullptr;
     if (scrollFrame) {
       content = scrollFrame->GetContent();
-    } else if (!gfxPrefs::LayoutUseContainersForRootFrames()) {
-      // If there is no root scroll frame, and we're using containerless
-      // scrolling, pick the document element instead.
-      // On Android we want the root xul document to get a null scroll id
-      // so that the root content document gets the first non-null scroll id.
-#ifndef MOZ_WIDGET_ANDROID
+    } else {
+      // If there is no root scroll frame, pick the document element instead.
+      // The only case we don't want to do this is in non-APZ fennec, where
+      // we want the root xul document to get a null scroll id so that the root
+      // content document gets the first non-null scroll id.
+#if !defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ)
       content = document->GetDocumentElement();
 #endif
     }
 
     root->SetFrameMetrics(
       nsLayoutUtils::ComputeFrameMetrics(frame,
                          presShell->GetRootScrollFrame(),
                          content,
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -3110,16 +3110,27 @@ nsLayoutUtils::PaintFrame(nsRenderingCon
     ViewID id = FrameMetrics::NULL_SCROLL_ID;
     if (ignoreViewportScrolling && presContext->IsRootContentDocument()) {
       if (nsIFrame* rootScrollFrame = presShell->GetRootScrollFrame()) {
         if (nsIContent* content = rootScrollFrame->GetContent()) {
           id = nsLayoutUtils::FindOrCreateIDFor(content);
         }
       }
     }
+#if !defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ)
+    else if (presShell->GetDocument() && presShell->GetDocument()->IsRootDisplayDocument()) {
+      // In cases where the root document is a XUL document, we want to take
+      // the ViewID from the root element, as that will be the ViewID of the
+      // root APZC in the tree.
+      if (dom::Element* element = presShell->GetDocument()->GetDocumentElement()) {
+        id = nsLayoutUtils::FindOrCreateIDFor(element);
+      }
+    }
+#endif
+
     nsDisplayListBuilder::AutoCurrentScrollParentIdSetter idSetter(&builder, id);
 
     PROFILER_LABEL("nsLayoutUtils", "PaintFrame::BuildDisplayList",
       js::ProfileEntry::Category::GRAPHICS);
 
     aFrame->BuildDisplayListForStackingContext(&builder, dirtyRect, &list);
   }
   const bool paintAllContinuations = aFlags & PAINT_ALL_CONTINUATIONS;
--- a/mobile/android/base/tabqueue/TabQueueDispatcher.java
+++ b/mobile/android/base/tabqueue/TabQueueDispatcher.java
@@ -33,17 +33,17 @@ public class TabQueueDispatcher extends 
         super.onCreate(savedInstanceState);
 
         GeckoAppShell.ensureCrashHandling();
 
         ContextUtils.SafeIntent intent = new ContextUtils.SafeIntent(getIntent());
 
         // For the moment lets exit early and start fennec as normal if we're not in nightly with
         // the tab queue build flag.
-        if (!AppConstants.MOZ_ANDROID_TAB_QUEUE) {
+        if (!AppConstants.MOZ_ANDROID_TAB_QUEUE || !AppConstants.NIGHTLY_BUILD) {
             loadNormally(intent.getUnsafe());
             return;
         }
 
         // The URL is usually hiding somewhere in the extra text. Extract it.
         final String dataString = intent.getDataString();
         if (TextUtils.isEmpty(dataString)) {
             abortDueToNoURL(dataString);
--- a/mobile/android/base/tests/StringHelper.java
+++ b/mobile/android/base/tests/StringHelper.java
@@ -85,16 +85,17 @@ public class StringHelper {
     public final String ROBOCOP_POPUP_URL = "/robocop/robocop_popup.html";
     public final String ROBOCOP_OFFLINE_STORAGE_URL = "/robocop/robocop_offline_storage.html";
     public final String ROBOCOP_PICTURE_LINK_URL = "/robocop/robocop_picture_link.html";
     public final String ROBOCOP_SEARCH_URL = "/robocop/robocop_search.html";
     public final String ROBOCOP_TEXT_PAGE_URL = "/robocop/robocop_text_page.html";
     public final String ROBOCOP_ADOBE_FLASH_URL = "/robocop/robocop_adobe_flash.html";
     public final String ROBOCOP_INPUT_URL = "/robocop/robocop_input.html";
     public final String ROBOCOP_READER_MODE_BASIC_ARTICLE = "/robocop/reader_mode_pages/basic_article.html";
+    public final String ROBOCOP_LINK_TO_SLOW_LOADING = "/robocop/robocop_link_to_slow_loading.html";
 
     private final String ROBOCOP_JS_HARNESS_URL = "/robocop/robocop_javascript.html";
 
     // Robocop page titles
     public final String ROBOCOP_BIG_LINK_TITLE = "Big Link";
     public final String ROBOCOP_BIG_MAILTO_TITLE = "Big Mailto";
     public final String ROBOCOP_BLANK_PAGE_01_TITLE = "Browser Blank Page 01";
     public final String ROBOCOP_BLANK_PAGE_02_TITLE = "Browser Blank Page 02";
--- a/mobile/android/base/tests/UITest.java
+++ b/mobile/android/base/tests/UITest.java
@@ -9,16 +9,17 @@ import org.mozilla.gecko.Assert;
 import org.mozilla.gecko.BrowserApp;
 import org.mozilla.gecko.Driver;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.tests.components.AboutHomeComponent;
 import org.mozilla.gecko.tests.components.AppMenuComponent;
 import org.mozilla.gecko.tests.components.BaseComponent;
 import org.mozilla.gecko.tests.components.GeckoViewComponent;
+import org.mozilla.gecko.tests.components.TabStripComponent;
 import org.mozilla.gecko.tests.components.ToolbarComponent;
 import org.mozilla.gecko.tests.helpers.HelperInitializer;
 
 import android.content.Intent;
 import android.content.res.Resources;
 import android.text.TextUtils;
 
 import com.jayway.android.robotium.solo.Solo;
@@ -36,16 +37,17 @@ abstract class UITest extends BaseRoboco
                       implements UITestContext {
 
     private static final String JUNIT_FAILURE_MSG = "A JUnit method was called. Make sure " +
         "you are using AssertionHelper to make assertions. Try `fAssert*(...);`";
 
     protected AboutHomeComponent mAboutHome;
     protected AppMenuComponent mAppMenu;
     protected GeckoViewComponent mGeckoView;
+    protected TabStripComponent mTabStrip;
     protected ToolbarComponent mToolbar;
 
     @Override
     protected void setUp() throws Exception {
         super.setUp();
 
         // Helpers depend on components so initialize them first.
         initComponents();
@@ -88,16 +90,17 @@ abstract class UITest extends BaseRoboco
             throw t;
         }
     }
 
     private void initComponents() {
         mAboutHome = new AboutHomeComponent(this);
         mAppMenu = new AppMenuComponent(this);
         mGeckoView = new GeckoViewComponent(this);
+        mTabStrip = new TabStripComponent(this);
         mToolbar = new ToolbarComponent(this);
     }
 
     private void initHelpers() {
         HelperInitializer.init(this);
     }
 
     @Override
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/tests/components/TabStripComponent.java
@@ -0,0 +1,56 @@
+package org.mozilla.gecko.tests.components;
+
+import android.view.View;
+
+import com.jayway.android.robotium.solo.Condition;
+
+import org.mozilla.gecko.tests.UITestContext;
+import org.mozilla.gecko.tests.helpers.DeviceHelper;
+import org.mozilla.gecko.tests.helpers.WaitHelper;
+import org.mozilla.gecko.widget.TwoWayView;
+
+import static org.mozilla.gecko.tests.helpers.AssertionHelper.*;
+
+/**
+ * A class representing any interactions that take place on the tablet tab strip.
+ */
+public class TabStripComponent extends BaseComponent {
+    // Using a text id because the layout and therefore the id might be stripped from the (non-tablet) build
+    private static final String TAB_STRIP_ID = "tab_strip";
+
+    public TabStripComponent(final UITestContext testContext) {
+        super(testContext);
+    }
+
+    public void switchToTab(int index) {
+        // The tab strip is only available on tablets
+        DeviceHelper.assertIsTablet();
+
+        View tabView = waitForTabView(index);
+        fAssertNotNull(String.format("Tab at index %d is not null", index), tabView);
+
+        mSolo.clickOnView(tabView);
+    }
+
+    private View waitForTabView(final int index) {
+        final TwoWayView tabStrip = getTabStripView();
+        final View[] tabView = new View[1];
+
+        WaitHelper.waitFor(String.format("Tab at index %d to be visible", index), new Condition() {
+            @Override
+            public boolean isSatisfied() {
+                return (tabView[0] = tabStrip.getChildAt(index)) != null;
+            }
+        });
+
+        return tabView[0];
+    }
+
+    private TwoWayView getTabStripView() {
+        TwoWayView tabStrip = (TwoWayView) mSolo.getView("tab_strip");
+
+        fAssertNotNull("Tab strip is not null", tabStrip);
+
+        return tabStrip;
+    }
+}
--- a/mobile/android/base/tests/components/ToolbarComponent.java
+++ b/mobile/android/base/tests/components/ToolbarComponent.java
@@ -79,16 +79,21 @@ public class ToolbarComponent extends Ba
         return this;
     }
 
     public ToolbarComponent assertIsUrlEditTextNotSelected() {
         fAssertFalse("The edit text is not selected", isUrlEditTextSelected());
         return this;
     }
 
+    public ToolbarComponent assertBackButtonIsNotEnabled() {
+        fAssertFalse("The back button is not enabled", isBackButtonEnabled());
+        return this;
+    }
+
     /**
      * Returns the root View for the browser toolbar.
      */
     private View getToolbarView() {
         mSolo.waitForView(R.id.browser_toolbar);
         return mSolo.getView(R.id.browser_toolbar);
     }
 
@@ -301,9 +306,13 @@ public class ToolbarComponent extends Ba
         }, READER_MODE_WAIT_MS);
 
         return readerModeButton[0];
     }
 
     private boolean isUrlEditTextSelected() {
         return getUrlEditText().isSelected();
     }
+
+    private boolean isBackButtonEnabled() {
+        return getBackButton().isEnabled();
+    }
 }
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/tests/helpers/GeckoClickHelper.java
@@ -0,0 +1,50 @@
+package org.mozilla.gecko.tests.helpers;
+
+import android.app.Activity;
+import android.util.DisplayMetrics;
+
+import com.jayway.android.robotium.solo.Solo;
+
+import org.mozilla.gecko.Driver;
+import org.mozilla.gecko.tests.StringHelper;
+import org.mozilla.gecko.tests.UITestContext;
+
+/**
+ * Provides helper functions for clicking elements rendered by the Gecko engine.
+ */
+public class GeckoClickHelper {
+    private static Solo sSolo;
+    private static Activity sActivity;
+    private static Driver sDriver;
+
+    protected static void init(final UITestContext context) {
+        sSolo = context.getSolo();
+        sActivity = context.getActivity();
+        sDriver = context.getDriver();
+    }
+
+    private GeckoClickHelper() { /* To disallow instantiation. */ }
+
+    /**
+     * Long press the link and select "Open Link in New Tab" from the context menu.
+     *
+     * The link should be positioned at the top of the page, at least 60px high and
+     * aligned to the middle.
+     */
+    public static void openCentralizedLinkInNewTab() {
+        openLinkContextMenu();
+
+        // Click on "Open Link in New Tab"
+        sSolo.clickOnText(StringHelper.get().CONTEXT_MENU_ITEMS_IN_NORMAL_TAB[0]);
+    }
+
+    private static void openLinkContextMenu() {
+        DisplayMetrics dm = new DisplayMetrics();
+        sActivity.getWindowManager().getDefaultDisplay().getMetrics(dm);
+
+        sSolo.clickLongOnScreen(
+                sDriver.getGeckoLeft() + sDriver.getGeckoWidth() / 2,
+                sDriver.getGeckoTop() + 30 * dm.density
+        );
+    }
+}
--- a/mobile/android/base/tests/helpers/HelperInitializer.java
+++ b/mobile/android/base/tests/helpers/HelperInitializer.java
@@ -15,14 +15,15 @@ public final class HelperInitializer {
 
     private HelperInitializer() { /* To disallow instantiation. */ }
 
     public static void init(final UITestContext context) {
         // Other helpers make assertions so init AssertionHelper first.
         AssertionHelper.init(context);
 
         DeviceHelper.init(context);
+        GeckoClickHelper.init(context);
         GeckoHelper.init(context);
         JavascriptBridge.init(context);
         NavigationHelper.init(context);
         WaitHelper.init(context);
     }
 }
--- a/mobile/android/base/tests/robocop.ini
+++ b/mobile/android/base/tests/robocop.ini
@@ -161,16 +161,17 @@ skip-if = android_version == "18"
 # disabled on Android 2.3, 4.3; bug 1025968
 skip-if = android_version == "10" || android_version == "18"
 [testJavascriptBridge]
 [testNativeCrypto]
 [testReaderModeTitle]
 [testSessionHistory]
 # disabled on Android 4.3, bug 1144879
 skip-if = android_version == "18"
+[testStateWhileLoading]
 
 # testSelectionHandler disabled on Android 2.3 by trailing skip-if, due to bug 980074
 # also disabled on Android 4.3, bug 1144882
 [testSelectionHandler]
 skip-if = android_version == "10" || android_version == "18"
 
 # testInputSelections disabled on Android 2.3 by trailing skip-if, due to bug 980074
 [testInputSelections]
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/tests/robocop_link_to_slow_loading.html
@@ -0,0 +1,12 @@
+<html>
+<head>
+    <title>Link</title>
+    <meta name="viewport" content="initial-scale=1.0"/>
+    <meta charset="utf-8">
+</head>
+<body style="margin: 0; padding: 0">
+<div style="text-align: center; margin: 0; padding: 0">
+    <a style="font-size: 60px" href="robocop_slow_loading.html">Slow Loading Page</a>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/tests/robocop_slow_loading.html
@@ -0,0 +1,23 @@
+<html>
+<head>
+    <title>Slow Loading</title>
+    <meta name="viewport" content="initial-scale=1.0"/>
+    <meta charset="utf-8">
+    <script type="text/javascript">
+
+        // Busy wait (There's no sleep function in JavaScript)
+        var waitForMilliseconds = 10000;
+        var start = new Date();
+        var now = null;
+        do {
+            now = new Date();
+        } while (now - start < waitForMilliseconds);
+
+    </script>
+</head>
+<body style="margin: 0; padding: 0">
+<div style="text-align: center; margin: 0; padding: 0">
+    <h1>This page is loading very slow.</h1>
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/tests/testStateWhileLoading.java
@@ -0,0 +1,40 @@
+package org.mozilla.gecko.tests;
+
+import org.mozilla.gecko.tests.helpers.DeviceHelper;
+import org.mozilla.gecko.tests.helpers.GeckoClickHelper;
+import org.mozilla.gecko.tests.helpers.GeckoHelper;
+import org.mozilla.gecko.tests.helpers.NavigationHelper;
+import org.mozilla.gecko.tests.helpers.WaitHelper;
+
+/**
+ * This test ensures the back/forward state is correct when switching to loading pages
+ * to prevent regressions like Bug 1124190.
+ */
+public class testStateWhileLoading extends UITest {
+    public void testStateWhileLoading() {
+        if (!DeviceHelper.isTablet()) {
+            // This test case only covers tablets currently.
+            return;
+        }
+
+        GeckoHelper.blockForReady();
+
+        NavigationHelper.enterAndLoadUrl(mStringHelper.ROBOCOP_LINK_TO_SLOW_LOADING);
+
+        GeckoClickHelper.openCentralizedLinkInNewTab();
+
+        WaitHelper.waitForPageLoad(new Runnable() {
+            @Override
+            public void run() {
+                mTabStrip.switchToTab(1);
+
+                // Assert that the state of the back button is correct
+                // after switching to the new (still loading) tab.
+                mToolbar.assertBackButtonIsNotEnabled();
+            }
+        });
+
+        // Assert that the state of the back button is still correct after the page has loaded.
+        mToolbar.assertBackButtonIsNotEnabled();
+    }
+}
--- 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/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -1055,20 +1055,17 @@ let loadManifestFromDir = Task.async(fun
     addon.size = getFileSize(aDir);
 
     file = aDir.clone();
     file.append("chrome.manifest");
     let chromeManifest = ChromeManifestParser.parseSync(Services.io.newFileURI(file));
     addon.hasBinaryComponents = ChromeManifestParser.hasType(chromeManifest,
                                                              "binary-component");
 
-    if (SIGNED_TYPES.has(addon.type))
-      addon.signedState = yield verifyDirSignedState(aDir, addon.id);
-    else
-      addon.signedState = AddonManager.SIGNEDSTATE_MISSING;
+    addon.signedState = yield verifyDirSignedState(aDir, addon);
 
     addon.appDisabled = !isUsableAddon(addon);
     return addon;
   }
   finally {
     bis.close();
     fis.close();
   }
@@ -1103,20 +1100,17 @@ let loadManifestFromZipReader = Task.asy
       uri = buildJarURI(aZipReader.file, "chrome.manifest");
       let chromeManifest = ChromeManifestParser.parseSync(uri);
       addon.hasBinaryComponents = ChromeManifestParser.hasType(chromeManifest,
                                                                "binary-component");
     } else {
       addon.hasBinaryComponents = false;
     }
 
-    if (SIGNED_TYPES.has(addon.type))
-      addon.signedState = yield verifyZipSignedState(aZipReader.file, addon.id, addon.version);
-    else
-      addon.signedState = AddonManager.SIGNEDSTATE_MISSING;
+    addon.signedState = yield verifyZipSignedState(aZipReader.file, addon);
 
     addon.appDisabled = !isUsableAddon(addon);
     return addon;
   }
   finally {
     bis.close();
     zis.close();
   }
@@ -1320,66 +1314,72 @@ function getSignedStatus(aRv, aCert, aEx
 }
 
 /**
  * Verifies that a zip file's contents are all correctly signed by an
  * AMO-issued certificate
  *
  * @param  aFile
  *         the xpi file to check
- * @param  aExpectedID
- *         the expected ID of the signature
+ * @param  aAddon
+ *         the add-on object to verify
  * @return a Promise that resolves to an AddonManager.SIGNEDSTATE_* constant.
  */
-function verifyZipSignedState(aFile, aExpectedID, aVersion) {
+function verifyZipSignedState(aFile, aAddon) {
+  if (!SIGNED_TYPES.has(aAddon.type))
+    return Promise.resolve(undefined);
+
   let certDB = Cc["@mozilla.org/security/x509certdb;1"]
                .getService(Ci.nsIX509CertDB);
 
   let root = Ci.nsIX509CertDB.AddonsPublicRoot;
   if (!REQUIRE_SIGNING && Preferences.get(PREF_XPI_SIGNATURES_DEV_ROOT, false))
     root = Ci.nsIX509CertDB.AddonsStageRoot;
 
   return new Promise(resolve => {
     certDB.openSignedAppFileAsync(root, aFile, (aRv, aZipReader, aCert) => {
       if (aZipReader)
         aZipReader.close();
-      resolve(getSignedStatus(aRv, aCert, aExpectedID));
+      resolve(getSignedStatus(aRv, aCert, aAddon.id));
     });
   });
 }
 
 /**
  * Verifies that a directory's contents are all correctly signed by an
  * AMO-issued certificate
  *
  * @param  aDir
  *         the directory to check
- * @param  aExpectedID
- *         the expected ID of the signature
+ * @param  aAddon
+ *         the add-on object to verify
  * @return a Promise that resolves to an AddonManager.SIGNEDSTATE_* constant.
  */
-function verifyDirSignedState(aDir, aExpectedID) {
+function verifyDirSignedState(aDir, aAddon) {
+  if (!SIGNED_TYPES.has(aAddon.type))
+    return Promise.resolve(undefined);
+
   // TODO: Get the certificate for an unpacked add-on (bug 1038072)
   return Promise.resolve(AddonManager.SIGNEDSTATE_MISSING);
 }
 
 /**
  * Verifies that a bundle's contents are all correctly signed by an
  * AMO-issued certificate
  *
  * @param  aBundle
  *         the nsIFile for the bundle to check, either a directory or zip file
- * @param  aExpectedID
- *         the expected ID of the signature
+ * @param  aAddon
+ *         the add-on object to verify
  * @return a Promise that resolves to an AddonManager.SIGNEDSTATE_* constant.
  */
-function verifyBundleSignedState(aBundle, aExpectedID) {
+function verifyBundleSignedState(aBundle, aAddon) {
   if (aBundle.isFile())
-    return verifyZipSignedState(aBundle, aExpectedID);
-  return verifyDirSignedState(aBundle, aExpectedID);
+    return verifyZipSignedState(aBundle, aAddon);
+  return verifyDirSignedState(aBundle, aAddon);
 }
 
 /**
  * Replaces %...% strings in an addon url (update and updateInfo) with
  * appropriate values.
  *
  * @param  aAddon
  *         The AddonInternal representing the add-on
@@ -2517,29 +2517,29 @@ this.XPIProvider = {
     Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS,
                                !XPIDatabase.writeAddonsList());
   },
 
   /**
    * Verifies that all installed add-ons are still correctly signed.
    */
   verifySignatures: function XPI_verifySignatures() {
-    XPIDatabase.getAddonList(addon => SIGNED_TYPES.has(addon.type), (addons) => {
+    XPIDatabase.getAddonList(a => true, (addons) => {
       Task.spawn(function*() {
         let changes = {
           enabled: [],
           disabled: []
         };
 
         for (let addon of addons) {
           // The add-on might have vanished, we'll catch that on the next startup
           if (!addon._sourceBundle.exists())
             continue;
 
-          let signedState = yield verifyBundleSignedState(addon._sourceBundle, addon.id);
+          let signedState = yield verifyBundleSignedState(addon._sourceBundle, addon);
           if (signedState == addon.signedState)
             continue;
 
           addon.signedState = signedState;
           AddonManagerPrivate.callAddonListeners("onPropertyChanged",
                                                  createWrapper(addon),
                                                  ["signedState"]);
 
@@ -3163,17 +3163,17 @@ this.XPIProvider = {
         let wasDisabled = aOldAddon.disabled;
         let wasAppDisabled = aOldAddon.appDisabled;
         let wasUserDisabled = aOldAddon.userDisabled;
         let wasSoftDisabled = aOldAddon.softDisabled;
         let updateDB = false;
 
         // If updating from a version of the app that didn't support signedState
         // then fetch that property now
-        if (aOldAddon.signedState === undefined) {
+        if (aOldAddon.signedState === undefined && SIGNED_TYPES.has(aOldAddon.type)) {
           let file = aInstallLocation.getLocationForID(aOldAddon.id);
           let manifest = syncLoadManifestFromFile(file);
           aOldAddon.signedState = manifest.signedState;
           updateDB = true;
         }
         // This updates the addon's JSON cached data in place
         applyBlocklistChanges(aOldAddon, aOldAddon, aOldAppVersion,
                               aOldPlatformVersion);
@@ -5413,17 +5413,18 @@ AddonInstall.prototype = {
         if (state == AddonManager.SIGNEDSTATE_MISSING)
           return Promise.reject([AddonManager.ERROR_SIGNEDSTATE_REQUIRED,
                                  "signature is required but missing"])
 
         return Promise.reject([AddonManager.ERROR_CORRUPT_FILE,
                                "signature verification failed"])
       }
     }
-    else if (this.addon.signedState == AddonManager.SIGNEDSTATE_UNKNOWN) {
+    else if (this.addon.signedState == AddonManager.SIGNEDSTATE_UNKNOWN ||
+             this.addon.signedState == undefined) {
       // Check object signing certificate, if any
       let x509 = zipreader.getSigningCert(null);
       if (x509) {
         logger.debug("Verifying XPI signature");
         if (verifyZipSigning(zipreader, x509)) {
           this.certificate = x509;
           if (this.certificate.commonName.length > 0) {
             this.certName = this.certificate.commonName;
--- a/toolkit/mozapps/extensions/test/xpcshell/test_theme.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_theme.js
@@ -90,33 +90,36 @@ function run_test() {
 
   AddonManager.getAddonsByIDs(["default@tests.mozilla.org",
                                "theme1@tests.mozilla.org",
                                "theme2@tests.mozilla.org"],
                                function([d, t1, t2]) {
     do_check_neq(d, null);
     do_check_false(d.skinnable);
     do_check_false(d.foreignInstall);
+    do_check_eq(d.signedState, undefined);
 
     do_check_neq(t1, null);
     do_check_false(t1.userDisabled);
     do_check_false(t1.appDisabled);
+    do_check_eq(t1.signedState, undefined);
     do_check_true(t1.isActive);
     do_check_true(t1.skinnable);
     do_check_true(t1.foreignInstall);
     do_check_eq(t1.screenshots, null);
     do_check_true(isThemeInAddonsList(profileDir, t1.id));
     do_check_false(hasFlag(t1.permissions, AddonManager.PERM_CAN_DISABLE));
     do_check_false(hasFlag(t1.permissions, AddonManager.PERM_CAN_ENABLE));
     do_check_eq(t1.operationsRequiringRestart, AddonManager.OP_NEEDS_RESTART_UNINSTALL |
                                                AddonManager.OP_NEEDS_RESTART_DISABLE);
 
     do_check_neq(t2, null);
     do_check_true(t2.userDisabled);
     do_check_false(t2.appDisabled);
+    do_check_eq(t2.signedState, undefined);
     do_check_false(t2.isActive);
     do_check_false(t2.skinnable);
     do_check_true(t2.foreignInstall);
     do_check_eq(t2.screenshots, null);
     do_check_false(isThemeInAddonsList(profileDir, t2.id));
     do_check_false(hasFlag(t2.permissions, AddonManager.PERM_CAN_DISABLE));
     do_check_true(hasFlag(t2.permissions, AddonManager.PERM_CAN_ENABLE));
     do_check_eq(t2.operationsRequiringRestart, AddonManager.OP_NEEDS_RESTART_ENABLE);
--- a/toolkit/themes/shared/aboutReader.css
+++ b/toolkit/themes/shared/aboutReader.css
@@ -35,18 +35,18 @@ body.dark *::-moz-selection {
   background-color: #FFFFFF;
   color: #0095DD;
 }
 body.dark a::-moz-selection {
   color: #DD4800;
 }
 
 body.sepia {
-  color: #333333;
-  background-color: #f0ece7;
+  color: #5b4636;
+  background-color: #f4ecd8;
 }
 
 body.sans-serif,
 body.sans-serif .remove-button {
   font-family: Helvetica, Arial, sans-serif;
 }
 
 body.serif,
@@ -87,29 +87,35 @@ body.serif .remove-button  {
 }
 
 #container.font-size9 {
   font-size: 28px;
 }
 
 /* Override some controls and content styles based on color scheme */
 
-body.light > .container > .header > .domain,
+body.light > .container > .header > .domain {
+  border-bottom-color: #333333 !important;
+}
+
 body.sepia > .container > .header > .domain {
-  border-bottom-color: #333333 !important;
+  border-bottom-color: #5b4636 !important;
 }
 
 body.dark > .container > .header > .domain {
   border-bottom-color: #eeeeee !important;
 }
 
 body.sepia > .container > .footer {
   background-color: #dedad4 !important;
 }
 
-body.light blockquote,
+body.light blockquote {
+  -moz-border-start: 2px solid #333333 !important;
+}
+
 body.sepia blockquote {
-  -moz-border-start: 2px solid #333333 !important;
+  -moz-border-start: 2px solid #5b4636 !important;
 }
 
 body.dark blockquote {
   -moz-border-start: 2px solid #eeeeee !important;
 }
--- a/toolkit/themes/shared/aboutReaderControls.css
+++ b/toolkit/themes/shared/aboutReaderControls.css
@@ -8,18 +8,18 @@
 }
 
 .dark-button {
   color: #eeeeee;
   background-color: #333333;
 }
 
 .sepia-button {
-  color: #333333;
-  background-color: #f0ece7;
+  color: #5b4636;
+  background-color: #f4ecd8;
 }
 
 .sans-serif-button {
   font-family: Helvetica, Arial, sans-serif;
 }
 
 .serif-button {
   font-family: Georgia, "Times New Roman", serif;
--- 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;
 
   /**