Merge b2ginbound to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Fri, 21 Aug 2015 08:39:53 -0700
changeset 258801 22c34579ae0720e7d3dc39a22b9d33f13bc0198b
parent 258800 0fd54ce01b937c51891b2f43a1810e28e8032f2b (current diff)
parent 258766 38170851395b39d43709ba0156c295a8319f78bc (diff)
child 258802 1c77317dd842d0cbb427bbbf984ce33cb62b1c8b
child 258887 455e01b30a1b3bfd487fd49fbbab55cb4a1ceb46
child 258930 047240fb3b4c21d68d02de0737bc6a8c9b130b14
push id64042
push userkwierso@gmail.com
push dateFri, 21 Aug 2015 17:07:01 +0000
treeherdermozilla-inbound@1c77317dd842 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone43.0a1
first release with
nightly linux32
22c34579ae07 / 43.0a1 / 20150822030206 / files
nightly linux64
22c34579ae07 / 43.0a1 / 20150822030206 / files
nightly mac
22c34579ae07 / 43.0a1 / 20150822030206 / files
nightly win32
22c34579ae07 / 43.0a1 / 20150822030206 / files
nightly win64
22c34579ae07 / 43.0a1 / 20150822030206 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge b2ginbound to central, a=merge
--- a/b2g/chrome/content/settings.js
+++ b/b2g/chrome/content/settings.js
@@ -570,17 +570,17 @@ let settingsToObserve = {
     defaultValue: 'Firefox OS'
   },
   'devtools.eventlooplag.threshold': 100,
   'devtools.remote.wifi.visible': {
     resetToPref: true
   },
   'dom.mozApps.use_reviewer_certs': false,
   'dom.mozApps.signed_apps_installable_from': 'https://marketplace.firefox.com',
-  'dom.presentation.discovery.enabled': true,
+  'dom.presentation.discovery.enabled': false,
   'dom.presentation.discoverable': false,
   'dom.serviceWorkers.interception.enabled': true,
   'dom.serviceWorkers.testing.enabled': false,
   'gfx.layerscope.enabled': false,
   'layers.draw-borders': false,
   'layers.draw-tile-borders': false,
   'layers.dump': false,
   'layers.enable-tiles': true,
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -7,20 +7,20 @@
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <!--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="aacd9b12da7fc3c8f4deaaa8eedfbb158f4fefe7">
+  <project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="c6705f739fb605031eb2a0b943ba55c64bee5a03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="f6cde6b8a2af2d2cfa3ce9b7f4cda2daab9174a8"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="bfdb6348725a33bdcdc4e17999cb500be6beedb5"/>
   <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="a6f9a1245d98c51172c15afecb9ade1a6ca511e2"/>
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -7,20 +7,20 @@
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <!--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="aacd9b12da7fc3c8f4deaaa8eedfbb158f4fefe7">
+  <project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="c6705f739fb605031eb2a0b943ba55c64bee5a03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="f6cde6b8a2af2d2cfa3ce9b7f4cda2daab9174a8"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="bfdb6348725a33bdcdc4e17999cb500be6beedb5"/>
   <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="a6f9a1245d98c51172c15afecb9ade1a6ca511e2"/>
--- 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="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <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="c6705f739fb605031eb2a0b943ba55c64bee5a03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f6cde6b8a2af2d2cfa3ce9b7f4cda2daab9174a8"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d70e4bfdcb65e7514de0f9315b74aea1c811678d"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="bfdb6348725a33bdcdc4e17999cb500be6beedb5"/>
   <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="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <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="c6705f739fb605031eb2a0b943ba55c64bee5a03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="f6cde6b8a2af2d2cfa3ce9b7f4cda2daab9174a8"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="bfdb6348725a33bdcdc4e17999cb500be6beedb5"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a6f9a1245d98c51172c15afecb9ade1a6ca511e2"/>
   <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
@@ -7,20 +7,20 @@
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <!--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="aacd9b12da7fc3c8f4deaaa8eedfbb158f4fefe7">
+  <project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="c6705f739fb605031eb2a0b943ba55c64bee5a03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="f6cde6b8a2af2d2cfa3ce9b7f4cda2daab9174a8"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="bfdb6348725a33bdcdc4e17999cb500be6beedb5"/>
   <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="a6f9a1245d98c51172c15afecb9ade1a6ca511e2"/>
--- 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="05a36844c1046a1eb07d5b1325f85ed741f961ea">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="c6705f739fb605031eb2a0b943ba55c64bee5a03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="f6cde6b8a2af2d2cfa3ce9b7f4cda2daab9174a8"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="bfdb6348725a33bdcdc4e17999cb500be6beedb5"/>
   <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="a6f9a1245d98c51172c15afecb9ade1a6ca511e2"/>
--- 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="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <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="c6705f739fb605031eb2a0b943ba55c64bee5a03"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="f6cde6b8a2af2d2cfa3ce9b7f4cda2daab9174a8"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="2d58f4b9206b50b8fda0d5036da6f0c62608db7c"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d70e4bfdcb65e7514de0f9315b74aea1c811678d"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="bfdb6348725a33bdcdc4e17999cb500be6beedb5"/>
   <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
@@ -7,20 +7,20 @@
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <!--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="aacd9b12da7fc3c8f4deaaa8eedfbb158f4fefe7">
+  <project name="platform_build" path="build" remote="b2g" revision="e935894ef5f27e2f04b9e929a45a958e6288a223">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="c6705f739fb605031eb2a0b943ba55c64bee5a03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="f6cde6b8a2af2d2cfa3ce9b7f4cda2daab9174a8"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="bfdb6348725a33bdcdc4e17999cb500be6beedb5"/>
   <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="a6f9a1245d98c51172c15afecb9ade1a6ca511e2"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "c6705f739fb605031eb2a0b943ba55c64bee5a03", 
+        "git_revision": "f6cde6b8a2af2d2cfa3ce9b7f4cda2daab9174a8", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "69fd2d2a3adce973a5e86ea2f96d1e311e11239d", 
+    "revision": "9b8b1ae55ed0ab8411fb71e451aa7cf58065985b", 
     "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="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <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="c6705f739fb605031eb2a0b943ba55c64bee5a03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="f6cde6b8a2af2d2cfa3ce9b7f4cda2daab9174a8"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="bfdb6348725a33bdcdc4e17999cb500be6beedb5"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="a6f9a1245d98c51172c15afecb9ade1a6ca511e2"/>
   <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="05a36844c1046a1eb07d5b1325f85ed741f961ea">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="c6705f739fb605031eb2a0b943ba55c64bee5a03"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="f6cde6b8a2af2d2cfa3ce9b7f4cda2daab9174a8"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="bfdb6348725a33bdcdc4e17999cb500be6beedb5"/>
   <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="a6f9a1245d98c51172c15afecb9ade1a6ca511e2"/>
--- a/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp
@@ -1842,17 +1842,17 @@ public:
       return rv;
     }
     /* Read server interface */
     rv = UnpackPDU(pdu, aArg2);
     if (NS_FAILED(rv)) {
       return rv;
     }
     /* Read connected */
-    rv = UnpackPDU(pdu, aArg3);
+    rv = UnpackPDU(pdu, UnpackConversion<int32_t, bool>(aArg3));
     if (NS_FAILED(rv)) {
       return rv;
     }
     /* Read address */
     rv = UnpackPDU(
       pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg4));
     if (NS_FAILED(rv)) {
       return rv;
--- a/dom/bluetooth/bluedroid/BluetoothGattManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothGattManager.cpp
@@ -9,39 +9,43 @@
 #include "BluetoothInterface.h"
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothService.h"
 #include "BluetoothUtils.h"
 #include "MainThreadUtils.h"
 #include "mozilla/dom/bluetooth/BluetoothCommon.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
+#include "nsDataHashtable.h"
 #include "nsIObserverService.h"
 #include "nsThreadUtils.h"
 
-#define ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(runnable)                       \
+#define ENSURE_GATT_INTF_IS_READY_VOID(runnable)                              \
   do {                                                                        \
     if (!sBluetoothGattInterface) {                                           \
       DispatchReplyError(runnable,                                            \
-        NS_LITERAL_STRING("BluetoothGattClientInterface is not ready"));      \
+        NS_LITERAL_STRING("BluetoothGattInterface is not ready"));            \
       return;                                                                 \
     }                                                                         \
   } while(0)
 
 using namespace mozilla;
 USING_BLUETOOTH_NAMESPACE
 
+class BluetoothGattServer;
+
 namespace {
   StaticRefPtr<BluetoothGattManager> sBluetoothGattManager;
   static BluetoothGattInterface* sBluetoothGattInterface;
 } // namespace
 
 bool BluetoothGattManager::mInShutdown = false;
 
 static StaticAutoPtr<nsTArray<nsRefPtr<BluetoothGattClient> > > sClients;
+static StaticAutoPtr<nsTArray<nsRefPtr<BluetoothGattServer> > > sServers;
 
 struct BluetoothGattClientReadCharState
 {
   bool mAuthRetry;
   nsRefPtr<BluetoothReplyRunnable> mRunnable;
 
   void Assign(bool aAuthRetry,
               BluetoothReplyRunnable* aRunnable)
@@ -197,34 +201,72 @@ public:
 
 private:
   ~BluetoothGattClient()
   { }
 };
 
 NS_IMPL_ISUPPORTS0(BluetoothGattClient)
 
+class BluetoothGattServer final : public nsISupports
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  BluetoothGattServer(const nsAString& aAppUuid)
+  : mAppUuid(aAppUuid)
+  , mServerIf(0)
+  { }
+
+  nsString mAppUuid;
+  int mServerIf;
+
+  nsRefPtr<BluetoothReplyRunnable> mConnectPeripheralRunnable;
+  nsRefPtr<BluetoothReplyRunnable> mDisconnectPeripheralRunnable;
+  nsRefPtr<BluetoothReplyRunnable> mUnregisterServerRunnable;
+
+  // Map connection id from device address
+  nsDataHashtable<nsStringHashKey, int> mConnectionMap;
+private:
+  ~BluetoothGattServer()
+  { }
+};
+
+NS_IMPL_ISUPPORTS0(BluetoothGattServer)
+
 class UuidComparator
 {
 public:
   bool Equals(const nsRefPtr<BluetoothGattClient>& aClient,
               const nsAString& aAppUuid) const
   {
     return aClient->mAppUuid.Equals(aAppUuid);
   }
+
+  bool Equals(const nsRefPtr<BluetoothGattServer>& aServer,
+              const nsAString& aAppUuid) const
+  {
+    return aServer->mAppUuid.Equals(aAppUuid);
+  }
 };
 
-class ClientIfComparator
+class InterfaceIdComparator
 {
 public:
   bool Equals(const nsRefPtr<BluetoothGattClient>& aClient,
               int aClientIf) const
   {
     return aClient->mClientIf == aClientIf;
   }
+
+  bool Equals(const nsRefPtr<BluetoothGattServer>& aServer,
+              int aServerIf) const
+  {
+    return aServer->mServerIf == aServerIf;
+  }
 };
 
 class ConnIdComparator
 {
 public:
   bool Equals(const nsRefPtr<BluetoothGattClient>& aClient,
               int aConnId) const
   {
@@ -300,16 +342,20 @@ BluetoothGattManager::InitGattInterface(
     }
     return;
   }
 
   if (!sClients) {
     sClients = new nsTArray<nsRefPtr<BluetoothGattClient> >;
   }
 
+  if (!sServers) {
+    sServers = new nsTArray<nsRefPtr<BluetoothGattServer> >;
+  }
+
   BluetoothGattManager* gattManager = BluetoothGattManager::Get();
   sBluetoothGattInterface->Init(gattManager,
                                 new InitGattResultHandler(aRes));
 }
 
 class BluetoothGattManager::CleanupResultHandler final
   : public BluetoothGattResultHandler
 {
@@ -326,16 +372,17 @@ public:
       mRes->OnError(NS_ERROR_FAILURE);
     }
   }
 
   void Cleanup() override
   {
     sBluetoothGattInterface = nullptr;
     sClients = nullptr;
+    sServers = nullptr;
 
     if (mRes) {
       mRes->Deinit();
     }
   }
 
 private:
   nsRefPtr<BluetoothProfileResultHandler> mRes;
@@ -429,20 +476,18 @@ public:
 
   void UnregisterClient() override
   {
     MOZ_ASSERT(mClient->mUnregisterClientRunnable);
     BluetoothService* bs = BluetoothService::Get();
     NS_ENSURE_TRUE_VOID(bs);
 
     // Notify BluetoothGatt to clear the clientIf
-    bs->DistributeSignal(
-      NS_LITERAL_STRING("ClientUnregistered"),
-      mClient->mAppUuid,
-      BluetoothValue(true));
+    bs->DistributeSignal(NS_LITERAL_STRING("ClientUnregistered"),
+                         mClient->mAppUuid);
 
     // Resolve the unregister request
     DispatchReplySuccess(mClient->mUnregisterClientRunnable);
     mClient->mUnregisterClientRunnable = nullptr;
 
     sClients->RemoveElement(mClient);
   }
 
@@ -464,20 +509,20 @@ private:
 
 void
 BluetoothGattManager::UnregisterClient(int aClientIf,
                                        BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRunnable);
 
-  ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
 
   size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
-                                   ClientIfComparator());
+                                   InterfaceIdComparator());
   if (NS_WARN_IF(index == sClients->NoIndex)) {
     DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
     return;
   }
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
   client->mUnregisterClientRunnable = aRunnable;
 
@@ -564,17 +609,17 @@ private:
 
 void
 BluetoothGattManager::StartLeScan(const nsTArray<nsString>& aServiceUuids,
                                   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRunnable);
 
-  ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
 
   nsString appUuidStr;
   GenerateUuid(appUuidStr);
 
   size_t index = sClients->IndexOf(appUuidStr, 0 /* Start */, UuidComparator());
 
   // Reject the startLeScan request if the clientIf is being used.
   if (NS_WARN_IF(index != sClients->NoIndex)) {
@@ -598,17 +643,17 @@ BluetoothGattManager::StartLeScan(const 
 
 void
 BluetoothGattManager::StopLeScan(const nsAString& aScanUuid,
                                  BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRunnable);
 
-  ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
 
   size_t index = sClients->IndexOf(aScanUuid, 0 /* Start */, UuidComparator());
   if (NS_WARN_IF(index == sClients->NoIndex)) {
     // Reject the stop LE scan request
     DispatchReplyError(aRunnable, NS_LITERAL_STRING("StopLeScan failed"));
     return;
   }
 
@@ -657,17 +702,17 @@ private:
 void
 BluetoothGattManager::Connect(const nsAString& aAppUuid,
                               const nsAString& aDeviceAddr,
                               BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRunnable);
 
-  ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
 
   size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
   if (index == sClients->NoIndex) {
     index = sClients->Length();
     sClients->AppendElement(new BluetoothGattClient(aAppUuid, aDeviceAddr));
   }
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
@@ -727,17 +772,17 @@ private:
 void
 BluetoothGattManager::Disconnect(const nsAString& aAppUuid,
                                  const nsAString& aDeviceAddr,
                                  BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRunnable);
 
-  ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
 
   size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
   if (NS_WARN_IF(index == sClients->NoIndex)) {
     DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
     return;
   }
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
@@ -774,17 +819,17 @@ private:
 
 void
 BluetoothGattManager::Discover(const nsAString& aAppUuid,
                                BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRunnable);
 
-  ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
 
   size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
   if (NS_WARN_IF(index == sClients->NoIndex)) {
     DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
     return;
   }
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
@@ -845,20 +890,20 @@ private:
 void
 BluetoothGattManager::ReadRemoteRssi(int aClientIf,
                                      const nsAString& aDeviceAddr,
                                      BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRunnable);
 
-  ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
 
   size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
-                                   ClientIfComparator());
+                                   InterfaceIdComparator());
   if (NS_WARN_IF(index == sClients->NoIndex)) {
     DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
     return;
   }
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
   client->mReadRemoteRssiRunnable = aRunnable;
 
@@ -913,17 +958,17 @@ private:
 void
 BluetoothGattManager::RegisterNotifications(
   const nsAString& aAppUuid, const BluetoothGattServiceId& aServId,
   const BluetoothGattId& aCharId, BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRunnable);
 
-  ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
 
   size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
   if (NS_WARN_IF(index == sClients->NoIndex)) {
     DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
     return;
   }
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
@@ -989,17 +1034,17 @@ private:
 void
 BluetoothGattManager::DeregisterNotifications(
   const nsAString& aAppUuid, const BluetoothGattServiceId& aServId,
   const BluetoothGattId& aCharId, BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRunnable);
 
-  ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
 
   size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
   if (NS_WARN_IF(index == sClients->NoIndex)) {
     DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
     return;
   }
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
@@ -1052,17 +1097,17 @@ BluetoothGattManager::ReadCharacteristic
   const nsAString& aAppUuid,
   const BluetoothGattServiceId& aServiceId,
   const BluetoothGattId& aCharacteristicId,
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRunnable);
 
-  ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
 
   size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
   if (NS_WARN_IF(index == sClients->NoIndex)) {
     DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
     return;
   }
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
@@ -1132,17 +1177,17 @@ BluetoothGattManager::WriteCharacteristi
   const BluetoothGattId& aCharacteristicId,
   const BluetoothGattWriteType& aWriteType,
   const nsTArray<uint8_t>& aValue,
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRunnable);
 
-  ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
 
   size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
   if (NS_WARN_IF(index == sClients->NoIndex)) {
     DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
     return;
   }
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
@@ -1214,17 +1259,17 @@ BluetoothGattManager::ReadDescriptorValu
   const BluetoothGattServiceId& aServiceId,
   const BluetoothGattId& aCharacteristicId,
   const BluetoothGattId& aDescriptorId,
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRunnable);
 
-  ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
 
   size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
   if (NS_WARN_IF(index == sClients->NoIndex)) {
     DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
     return;
   }
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
@@ -1295,17 +1340,17 @@ BluetoothGattManager::WriteDescriptorVal
   const BluetoothGattId& aCharacteristicId,
   const BluetoothGattId& aDescriptorId,
   const nsTArray<uint8_t>& aValue,
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aRunnable);
 
-  ENSURE_GATT_CLIENT_INTF_IS_READY_VOID(aRunnable);
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
 
   size_t index = sClients->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
   if (NS_WARN_IF(index == sClients->NoIndex)) {
     DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
     return;
   }
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
@@ -1337,16 +1382,288 @@ BluetoothGattManager::WriteDescriptorVal
     aCharacteristicId,
     aDescriptorId,
     GATT_WRITE_TYPE_NORMAL,
     GATT_AUTH_REQ_NONE,
     aValue,
     new WriteDescriptorValueResultHandler(client));
 }
 
+class BluetoothGattManager::RegisterServerResultHandler final
+  : public BluetoothGattResultHandler
+{
+public:
+  RegisterServerResultHandler(BluetoothGattServer* aServer)
+  : mServer(aServer)
+  {
+    MOZ_ASSERT(mServer);
+  }
+
+  void OnError(BluetoothStatus aStatus) override
+  {
+    BT_WARNING("BluetoothGattServerInterface::RegisterServer failed: %d",
+               (int)aStatus);
+
+    BluetoothService* bs = BluetoothService::Get();
+    NS_ENSURE_TRUE_VOID(bs);
+
+    // Reject the connect request
+    if (mServer->mConnectPeripheralRunnable) {
+      DispatchReplyError(mServer->mConnectPeripheralRunnable,
+                         NS_LITERAL_STRING("Register GATT server failed"));
+      mServer->mConnectPeripheralRunnable = nullptr;
+    }
+
+    sServers->RemoveElement(mServer);
+  }
+
+private:
+  nsRefPtr<BluetoothGattServer> mServer;
+};
+
+class BluetoothGattManager::ConnectPeripheralResultHandler final
+  : public BluetoothGattResultHandler
+{
+public:
+  ConnectPeripheralResultHandler(BluetoothGattServer* aServer,
+                                 const nsAString& aDeviceAddr)
+  : mServer(aServer)
+  , mDeviceAddr(aDeviceAddr)
+  {
+    MOZ_ASSERT(mServer);
+    MOZ_ASSERT(!mDeviceAddr.IsEmpty());
+  }
+
+  void OnError(BluetoothStatus aStatus) override
+  {
+    BT_WARNING("BluetoothGattServerInterface::ConnectPeripheral failed: %d",
+               (int)aStatus);
+    MOZ_ASSERT(mServer->mConnectPeripheralRunnable);
+
+    BluetoothService* bs = BluetoothService::Get();
+    NS_ENSURE_TRUE_VOID(bs);
+
+    DispatchReplyError(mServer->mConnectPeripheralRunnable,
+                       NS_LITERAL_STRING("ConnectPeripheral failed"));
+    mServer->mConnectPeripheralRunnable = nullptr;
+    mServer->mConnectionMap.Remove(mDeviceAddr);
+  }
+
+private:
+  nsRefPtr<BluetoothGattServer> mServer;
+  nsString mDeviceAddr;
+};
+
+void
+BluetoothGattManager::ConnectPeripheral(
+  const nsAString& aAppUuid,
+  const nsAString& aAddress,
+  BluetoothReplyRunnable* aRunnable)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aRunnable);
+
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
+
+  size_t index = sServers->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
+  if (index == sServers->NoIndex) {
+    index = sServers->Length();
+    sServers->AppendElement(new BluetoothGattServer(aAppUuid));
+  }
+  nsRefPtr<BluetoothGattServer> server = (*sServers)[index];
+
+  /**
+   * Early resolve or reject the request based on the current status before
+   * sending a request to bluetooth stack.
+   *
+   * case 1) Connecting/Disconnecting: If connect/disconnect peripheral
+   *         runnable exists, reject the request since the local GATT server is
+   *         busy connecting or disconnecting to a device.
+   * case 2) Connected: If there is an entry whose key is |aAddress| in the
+   *         connection map, resolve the request. Since disconnected devices
+   *         will not be in the map, all entries in the map are connected
+   *         devices.
+   */
+  if (server->mConnectPeripheralRunnable ||
+      server->mDisconnectPeripheralRunnable) {
+    DispatchReplyError(aRunnable, STATUS_BUSY);
+    return;
+  }
+
+  int connId = 0;
+  if (server->mConnectionMap.Get(aAddress, &connId)) {
+    MOZ_ASSERT(connId > 0);
+    DispatchReplySuccess(aRunnable);
+    return;
+  }
+
+  server->mConnectionMap.Put(aAddress, 0);
+  server->mConnectPeripheralRunnable = aRunnable;
+
+  if (server->mServerIf > 0) {
+    sBluetoothGattInterface->ConnectPeripheral(
+      server->mServerIf,
+      aAddress,
+      true, // direct connect
+      TRANSPORT_AUTO,
+      new ConnectPeripheralResultHandler(server, aAddress));
+  } else {
+    BluetoothUuid uuid;
+    StringToUuid(NS_ConvertUTF16toUTF8(aAppUuid).get(), uuid);
+
+    // connect will be proceeded after server registered
+    sBluetoothGattInterface->RegisterServer(
+      uuid, new RegisterServerResultHandler(server));
+  }
+}
+
+class BluetoothGattManager::DisconnectPeripheralResultHandler final
+  : public BluetoothGattResultHandler
+{
+public:
+  DisconnectPeripheralResultHandler(BluetoothGattServer* aServer)
+  : mServer(aServer)
+  {
+    MOZ_ASSERT(mServer);
+  }
+
+  void OnError(BluetoothStatus aStatus) override
+  {
+    BT_WARNING("BluetoothGattServerInterface::DisconnectPeripheral failed: %d",
+               (int)aStatus);
+    MOZ_ASSERT(mServer->mDisconnectPeripheralRunnable);
+
+    BluetoothService* bs = BluetoothService::Get();
+    NS_ENSURE_TRUE_VOID(bs);
+
+    // Reject the disconnect request
+    DispatchReplyError(mServer->mDisconnectPeripheralRunnable,
+                       NS_LITERAL_STRING("DisconnectPeripheral failed"));
+    mServer->mDisconnectPeripheralRunnable = nullptr;
+  }
+
+private:
+  nsRefPtr<BluetoothGattServer> mServer;
+};
+
+void
+BluetoothGattManager::DisconnectPeripheral(
+  const nsAString& aAppUuid,
+  const nsAString& aAddress,
+  BluetoothReplyRunnable* aRunnable)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aRunnable);
+
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
+
+  size_t index = sServers->IndexOf(aAppUuid, 0 /* Start */, UuidComparator());
+  if (NS_WARN_IF(index == sServers->NoIndex)) {
+    DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
+    return;
+  }
+  nsRefPtr<BluetoothGattServer> server = (*sServers)[index];
+
+  if (NS_WARN_IF(server->mServerIf <= 0)) {
+    DispatchReplyError(aRunnable,
+                       NS_LITERAL_STRING("Disconnect failed"));
+    return;
+  }
+
+  // Reject the request if there is an ongoing connect/disconnect request.
+  if (server->mConnectPeripheralRunnable ||
+      server->mDisconnectPeripheralRunnable) {
+    DispatchReplyError(aRunnable, STATUS_BUSY);
+    return;
+  }
+
+  // Resolve the request if the device is not connected.
+  int connId = 0;
+  if (!server->mConnectionMap.Get(aAddress, &connId)) {
+    DispatchReplySuccess(aRunnable);
+    return;
+  }
+
+  server->mDisconnectPeripheralRunnable = aRunnable;
+
+  sBluetoothGattInterface->DisconnectPeripheral(
+    server->mServerIf,
+    aAddress,
+    connId,
+    new DisconnectPeripheralResultHandler(server));
+}
+
+class BluetoothGattManager::UnregisterServerResultHandler final
+  : public BluetoothGattResultHandler
+{
+public:
+  UnregisterServerResultHandler(BluetoothGattServer* aServer)
+  : mServer(aServer)
+  {
+    MOZ_ASSERT(mServer);
+  }
+
+  void UnregisterServer() override
+  {
+    BluetoothService* bs = BluetoothService::Get();
+    NS_ENSURE_TRUE_VOID(bs);
+
+    // Notify BluetoothGattServer to clear the serverIf
+    bs->DistributeSignal(NS_LITERAL_STRING("ServerUnregistered"),
+                         mServer->mAppUuid);
+
+    // Resolve the unregister request
+    if (mServer->mUnregisterServerRunnable) {
+      DispatchReplySuccess(mServer->mUnregisterServerRunnable);
+      mServer->mUnregisterServerRunnable = nullptr;
+    }
+
+    sServers->RemoveElement(mServer);
+  }
+
+  void OnError(BluetoothStatus aStatus) override
+  {
+    BT_WARNING("BluetoothGattServerInterface::UnregisterServer failed: %d",
+               (int)aStatus);
+
+    // Reject the unregister request
+    if (mServer->mUnregisterServerRunnable) {
+      DispatchReplyError(mServer->mUnregisterServerRunnable,
+                         NS_LITERAL_STRING("Unregister GATT Server failed"));
+      mServer->mUnregisterServerRunnable = nullptr;
+    }
+  }
+
+private:
+  nsRefPtr<BluetoothGattServer> mServer;
+};
+
+void
+BluetoothGattManager::UnregisterServer(int aServerIf,
+                                       BluetoothReplyRunnable* aRunnable)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  ENSURE_GATT_INTF_IS_READY_VOID(aRunnable);
+
+  size_t index = sServers->IndexOf(aServerIf, 0 /* Start */,
+                                   InterfaceIdComparator());
+  if (NS_WARN_IF(index == sServers->NoIndex)) {
+    DispatchReplyError(aRunnable, STATUS_PARM_INVALID);
+    return;
+  }
+
+  nsRefPtr<BluetoothGattServer> server = (*sServers)[index];
+  server->mUnregisterServerRunnable = aRunnable;
+
+  sBluetoothGattInterface->UnregisterServer(
+    aServerIf,
+    new UnregisterServerResultHandler(server));
+}
+
 //
 // Notification Handlers
 //
 void
 BluetoothGattManager::RegisterClientNotification(BluetoothGattStatus aStatus,
                                                  int aClientIf,
                                                  const BluetoothUuid& aAppUuid)
 {
@@ -1481,17 +1798,17 @@ BluetoothGattManager::ConnectNotificatio
                                           const nsAString& aDeviceAddr)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   BluetoothService* bs = BluetoothService::Get();
   NS_ENSURE_TRUE_VOID(bs);
 
   size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
-                                   ClientIfComparator());
+                                   InterfaceIdComparator());
   NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
 
   if (aStatus != GATT_STATUS_SUCCESS) {
     BT_LOGD("Connect failed: clientIf = %d, connId = %d, status = %d",
             aClientIf, aConnId, aStatus);
 
@@ -1533,17 +1850,17 @@ BluetoothGattManager::DisconnectNotifica
                                              const nsAString& aDeviceAddr)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   BluetoothService* bs = BluetoothService::Get();
   NS_ENSURE_TRUE_VOID(bs);
 
   size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
-                                   ClientIfComparator());
+                                   InterfaceIdComparator());
   NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
 
   if (aStatus != GATT_STATUS_SUCCESS) {
     // Notify BluetoothGatt that the client remains connected
     bs->DistributeSignal(
       NS_LITERAL_STRING(GATT_CONNECTION_STATE_CHANGED_ID),
@@ -2059,17 +2376,17 @@ BluetoothGattManager::ReadRemoteRssiNoti
                                                  BluetoothGattStatus aStatus)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   BluetoothService* bs = BluetoothService::Get();
   NS_ENSURE_TRUE_VOID(bs);
 
   size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
-                                   ClientIfComparator());
+                                   InterfaceIdComparator());
   NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
 
   if (aStatus != GATT_STATUS_SUCCESS) { // operation failed
     BT_LOGD("ReadRemoteRssi failed: clientIf = %d, bdAddr = %s, rssi = %d, " \
             "status = %d", aClientIf, NS_ConvertUTF16toUTF8(aBdAddr).get(),
             aRssi, (int)aStatus);
@@ -2092,16 +2409,120 @@ BluetoothGattManager::ReadRemoteRssiNoti
   }
 }
 
 void
 BluetoothGattManager::ListenNotification(BluetoothGattStatus aStatus,
                                          int aServerIf)
 { }
 
+void
+BluetoothGattManager::RegisterServerNotification(BluetoothGattStatus aStatus,
+                                                 int aServerIf,
+                                                 const BluetoothUuid& aAppUuid)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsString uuid;
+  UuidToString(aAppUuid, uuid);
+
+  size_t index = sServers->IndexOf(uuid, 0 /* Start */, UuidComparator());
+  NS_ENSURE_TRUE_VOID(index != sServers->NoIndex);
+
+  nsRefPtr<BluetoothGattServer> server = (*sServers)[index];
+
+  BluetoothService* bs = BluetoothService::Get();
+  NS_ENSURE_TRUE_VOID(bs);
+
+  if (aStatus != GATT_STATUS_SUCCESS) {
+    BT_LOGD("RegisterServer failed: serverIf = %d, status = %d, appUuid = %s",
+             aServerIf, aStatus, NS_ConvertUTF16toUTF8(uuid).get());
+
+    if (server->mConnectPeripheralRunnable) {
+      // Reject the connect peripheral request
+      DispatchReplyError(
+        server->mConnectPeripheralRunnable,
+        NS_LITERAL_STRING(
+          "ConnectPeripheral failed due to registration failed"));
+      server->mConnectPeripheralRunnable = nullptr;
+    }
+
+    sServers->RemoveElement(server);
+  }
+
+  server->mServerIf = aServerIf;
+
+  // Notify BluetoothGattServer to update the serverIf
+  bs->DistributeSignal(
+    NS_LITERAL_STRING("ServerRegistered"),
+    uuid, BluetoothValue(uint32_t(aServerIf)));
+
+  if (server->mConnectPeripheralRunnable) {
+    // Only one entry exists in the map during first connect peripheral request
+    nsString deviceAddr(server->mConnectionMap.Iter().Key());
+
+    sBluetoothGattInterface->ConnectPeripheral(
+      aServerIf, deviceAddr, true /* direct connect */, TRANSPORT_AUTO,
+      new ConnectPeripheralResultHandler(server, deviceAddr));
+  }
+}
+
+void
+BluetoothGattManager::ConnectionNotification(int aConnId,
+                                             int aServerIf,
+                                             bool aConnected,
+                                             const nsAString& aBdAddr)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  BluetoothService* bs = BluetoothService::Get();
+  NS_ENSURE_TRUE_VOID(bs);
+
+  size_t index = sServers->IndexOf(aServerIf, 0 /* Start */,
+                                   InterfaceIdComparator());
+  NS_ENSURE_TRUE_VOID(index != sServers->NoIndex);
+
+  nsRefPtr<BluetoothGattServer> server = (*sServers)[index];
+
+  // Update the connection map based on the connection status
+  if (aConnected) {
+    server->mConnectionMap.Put(aBdAddr, aConnId);
+  } else {
+    server->mConnectionMap.Remove(aBdAddr);
+  }
+
+  // Notify BluetoothGattServer that connection status changed
+  InfallibleTArray<BluetoothNamedValue> props;
+  BT_APPEND_NAMED_VALUE(props, "Connected", aConnected);
+  BT_APPEND_NAMED_VALUE(props, "Address", nsString(aBdAddr));
+  bs->DistributeSignal(
+    NS_LITERAL_STRING(GATT_CONNECTION_STATE_CHANGED_ID),
+    server->mAppUuid,
+    BluetoothValue(props));
+
+  // Resolve or reject connect/disconnect peripheral requests
+  if (server->mConnectPeripheralRunnable) {
+    if (aConnected) {
+      DispatchReplySuccess(server->mConnectPeripheralRunnable);
+    } else {
+      DispatchReplyError(server->mConnectPeripheralRunnable,
+                         NS_LITERAL_STRING("ConnectPeripheral failed"));
+    }
+    server->mConnectPeripheralRunnable = nullptr;
+  } else if (server->mDisconnectPeripheralRunnable) {
+    if (!aConnected) {
+      DispatchReplySuccess(server->mDisconnectPeripheralRunnable);
+    } else {
+      DispatchReplyError(server->mDisconnectPeripheralRunnable,
+                         NS_LITERAL_STRING("DisconnectPeripheral failed"));
+    }
+    server->mDisconnectPeripheralRunnable = nullptr;
+  }
+}
+
 BluetoothGattManager::BluetoothGattManager()
 { }
 
 BluetoothGattManager::~BluetoothGattManager()
 {
   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
   NS_ENSURE_TRUE_VOID(obs);
   if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
@@ -2127,16 +2548,17 @@ BluetoothGattManager::Observe(nsISupport
 
 void
 BluetoothGattManager::HandleShutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
   mInShutdown = true;
   sBluetoothGattManager = nullptr;
   sClients = nullptr;
+  sServers = nullptr;
 }
 
 void
 BluetoothGattManager::ProceedDiscoverProcess(
   BluetoothGattClient* aClient,
   const BluetoothGattServiceId& aServiceId)
 {
   /**
--- a/dom/bluetooth/bluedroid/BluetoothGattManager.h
+++ b/dom/bluetooth/bluedroid/BluetoothGattManager.h
@@ -85,16 +85,29 @@ public:
   void WriteDescriptorValue(
     const nsAString& aAppUuid,
     const BluetoothGattServiceId& aServiceId,
     const BluetoothGattId& aCharacteristicId,
     const BluetoothGattId& aDescriptorId,
     const nsTArray<uint8_t>& aValue,
     BluetoothReplyRunnable* aRunnable);
 
+  void ConnectPeripheral(
+    const nsAString& aAppUuid,
+    const nsAString& aAddress,
+    BluetoothReplyRunnable* aRunnable);
+
+  void DisconnectPeripheral(
+    const nsAString& aAppUuid,
+    const nsAString& aAddress,
+    BluetoothReplyRunnable* aRunnable);
+
+  void UnregisterServer(int aServerIf,
+                        BluetoothReplyRunnable* aRunnable);
+
 private:
   ~BluetoothGattManager();
 
   class CleanupResultHandler;
   class CleanupResultHandlerRunnable;
   class InitGattResultHandler;
   class RegisterClientResultHandler;
   class UnregisterClientResultHandler;
@@ -107,16 +120,21 @@ private:
   class RegisterNotificationsResultHandler;
   class DeregisterNotificationsResultHandler;
   class ReadCharacteristicValueResultHandler;
   class WriteCharacteristicValueResultHandler;
   class ReadDescriptorValueResultHandler;
   class WriteDescriptorValueResultHandler;
   class ScanDeviceTypeResultHandler;
 
+  class RegisterServerResultHandler;
+  class ConnectPeripheralResultHandler;
+  class DisconnectPeripheralResultHandler;
+  class UnregisterServerResultHandler;
+
   BluetoothGattManager();
 
   void HandleShutdown();
 
   void RegisterClientNotification(BluetoothGattStatus aStatus,
                                   int aClientIf,
                                   const BluetoothUuid& aAppUuid) override;
 
@@ -195,14 +213,23 @@ private:
                                   BluetoothGattStatus aStatus) override;
 
   void ListenNotification(BluetoothGattStatus aStatus,
                           int aServerIf) override;
 
   void ProceedDiscoverProcess(BluetoothGattClient* aClient,
                               const BluetoothGattServiceId& aServiceId);
 
+  void RegisterServerNotification(BluetoothGattStatus aStatus,
+                                  int aServerIf,
+                                  const BluetoothUuid& aAppUuid) override;
+
+  void ConnectionNotification(int aConnId,
+                              int aServerIf,
+                              bool aConnected,
+                              const nsAString& aBdAddr) override;
+
   static bool mInShutdown;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif // mozilla_dom_bluetooth_bluedroid_BluetoothGattManager_h
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
@@ -547,16 +547,61 @@ BluetoothServiceBluedroid::GattClientWri
 
   BluetoothGattManager* gatt = BluetoothGattManager::Get();
   ENSURE_GATT_MGR_IS_READY_VOID(gatt, aRunnable);
 
   gatt->WriteDescriptorValue(aAppUuid, aServiceId, aCharacteristicId,
                              aDescriptorId, aValue, aRunnable);
 }
 
+// GATT Server
+void
+BluetoothServiceBluedroid::GattServerConnectPeripheralInternal(
+  const nsAString& aAppUuid, const nsAString& aAddress,
+  BluetoothReplyRunnable* aRunnable)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable);
+
+  BluetoothGattManager* gatt = BluetoothGattManager::Get();
+  ENSURE_GATT_MGR_IS_READY_VOID(gatt, aRunnable);
+
+  gatt->ConnectPeripheral(aAppUuid, aAddress, aRunnable);
+}
+
+void
+BluetoothServiceBluedroid::GattServerDisconnectPeripheralInternal(
+  const nsAString& aAppUuid, const nsAString& aAddress,
+  BluetoothReplyRunnable* aRunnable)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable);
+
+  BluetoothGattManager* gatt = BluetoothGattManager::Get();
+  ENSURE_GATT_MGR_IS_READY_VOID(gatt, aRunnable);
+
+  gatt->DisconnectPeripheral(aAppUuid, aAddress, aRunnable);
+}
+
+void
+BluetoothServiceBluedroid::UnregisterGattServerInternal(
+  int aServerIf, BluetoothReplyRunnable* aRunnable)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  ENSURE_BLUETOOTH_IS_READY_VOID(aRunnable);
+
+  BluetoothGattManager* gatt = BluetoothGattManager::Get();
+  ENSURE_GATT_MGR_IS_READY_VOID(gatt, aRunnable);
+
+  gatt->UnregisterServer(aServerIf, aRunnable);
+}
+
 nsresult
 BluetoothServiceBluedroid::GetAdaptersInternal(
   BluetoothReplyRunnable* aRunnable)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   /**
    * Wrap BluetoothValue =
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.h
@@ -254,16 +254,32 @@ public:
   GattClientWriteDescriptorValueInternal(
     const nsAString& aAppUuid,
     const BluetoothGattServiceId& aServiceId,
     const BluetoothGattId& aCharacteristicId,
     const BluetoothGattId& aDescriptorId,
     const nsTArray<uint8_t>& aValue,
     BluetoothReplyRunnable* aRunnable) override;
 
+  virtual void
+  GattServerConnectPeripheralInternal(
+    const nsAString& aAppUuid,
+    const nsAString& aAddress,
+    BluetoothReplyRunnable* aRunnable) override;
+
+  virtual void
+  GattServerDisconnectPeripheralInternal(
+    const nsAString& aAppUuid,
+    const nsAString& aAddress,
+    BluetoothReplyRunnable* aRunnable) override;
+
+  virtual void
+  UnregisterGattServerInternal(int aServerIf,
+                               BluetoothReplyRunnable* aRunnable) override;
+
   //
   // Bluetooth notifications
   //
 
   virtual void AdapterStateChangedNotification(bool aState) override;
   virtual void AdapterPropertiesNotification(
     BluetoothStatus aStatus, int aNumProperties,
     const BluetoothProperty* aProperties) override;
--- a/dom/bluetooth/bluetooth2/BluetoothDiscoveryHandle.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothDiscoveryHandle.cpp
@@ -18,17 +18,16 @@ USING_BLUETOOTH_NAMESPACE
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothDiscoveryHandle)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(BluetoothDiscoveryHandle, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(BluetoothDiscoveryHandle, DOMEventTargetHelper)
 
 BluetoothDiscoveryHandle::BluetoothDiscoveryHandle(nsPIDOMWindow* aWindow)
   : DOMEventTargetHelper(aWindow)
-  , mLeScanUuid(EmptyString())
 {
   MOZ_ASSERT(aWindow);
 }
 
 BluetoothDiscoveryHandle::BluetoothDiscoveryHandle(
   nsPIDOMWindow* aWindow,
   const nsTArray<nsString>& aServiceUuids,
   const nsAString& aLeScanUuid)
--- a/dom/bluetooth/bluetooth2/BluetoothGatt.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothGatt.cpp
@@ -46,17 +46,16 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(BluetoothGatt, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(BluetoothGatt, DOMEventTargetHelper)
 
 BluetoothGatt::BluetoothGatt(nsPIDOMWindow* aWindow,
                              const nsAString& aDeviceAddr)
   : DOMEventTargetHelper(aWindow)
-  , mAppUuid(EmptyString())
   , mClientIf(0)
   , mConnectionState(BluetoothConnectionState::Disconnected)
   , mDeviceAddr(aDeviceAddr)
   , mDiscoveringServices(false)
 {
   MOZ_ASSERT(aWindow);
   MOZ_ASSERT(!mDeviceAddr.IsEmpty());
 }
--- a/dom/bluetooth/bluetooth2/BluetoothGattServer.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothGattServer.cpp
@@ -1,50 +1,173 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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 "BluetoothGattServer.h"
 
+#include "BluetoothReplyRunnable.h"
+#include "BluetoothService.h"
+#include "BluetoothUtils.h"
+#include "mozilla/dom/BluetoothStatusChangedEvent.h"
+#include "mozilla/dom/Promise.h"
+
 using namespace mozilla;
 using namespace mozilla::dom;
 
 USING_BLUETOOTH_NAMESPACE
 
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(BluetoothGattServer,
-                                      mOwner)
+NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothGattServer)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothGattServer,
+                                                DOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
 
-NS_IMPL_CYCLE_COLLECTING_ADDREF(BluetoothGattServer)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(BluetoothGattServer)
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(BluetoothGattServer)
-  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
-  NS_INTERFACE_MAP_ENTRY(nsISupports)
-NS_INTERFACE_MAP_END
+  /**
+   * Unregister the bluetooth signal handler after unlinked.
+   *
+   * This is needed to avoid ending up with exposing a deleted object to JS or
+   * accessing deleted objects while receiving signals from parent process
+   * after unlinked. Please see Bug 1138267 for detail informations.
+   */
+  UnregisterBluetoothSignalHandler(tmp->mAppUuid, tmp);
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothGattServer,
+                                                  DOMEventTargetHelper)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothGattServer)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+NS_IMPL_ADDREF_INHERITED(BluetoothGattServer, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(BluetoothGattServer, DOMEventTargetHelper)
 
 BluetoothGattServer::BluetoothGattServer(nsPIDOMWindow* aOwner)
   : mOwner(aOwner)
+  , mServerIf(0)
   , mValid(true)
-{
-}
+{ }
 
 BluetoothGattServer::~BluetoothGattServer()
 {
   Invalidate();
 }
 
+void
+BluetoothGattServer::Notify(const BluetoothSignal& aData)
+{
+  BT_LOGD("[GattServer] %s", NS_ConvertUTF16toUTF8(aData.name()).get());
+  NS_ENSURE_TRUE_VOID(mSignalRegistered);
+
+  BluetoothValue v = aData.value();
+  if (aData.name().EqualsLiteral("ServerRegistered")) {
+    MOZ_ASSERT(v.type() == BluetoothValue::Tuint32_t);
+    mServerIf = v.get_uint32_t();
+  } else if (aData.name().EqualsLiteral("ServerUnregistered")) {
+    mServerIf = 0;
+  } else if (aData.name().EqualsLiteral(GATT_CONNECTION_STATE_CHANGED_ID)) {
+    MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
+    const InfallibleTArray<BluetoothNamedValue>& arr =
+      v.get_ArrayOfBluetoothNamedValue();
+
+    MOZ_ASSERT(arr.Length() == 2 &&
+               arr[0].value().type() == BluetoothValue::Tbool &&
+               arr[1].value().type() == BluetoothValue::TnsString);
+
+    BluetoothStatusChangedEventInit init;
+    init.mStatus = arr[0].value().get_bool();
+    init.mAddress = arr[1].value().get_nsString();
+
+    nsRefPtr<BluetoothStatusChangedEvent> event =
+      BluetoothStatusChangedEvent::Constructor(
+        this, NS_LITERAL_STRING(GATT_CONNECTION_STATE_CHANGED_ID), init);
+
+    DispatchTrustedEvent(event);
+  } else {
+    BT_WARNING("Not handling GATT signal: %s",
+               NS_ConvertUTF16toUTF8(aData.name()).get());
+  }
+}
+
 JSObject*
 BluetoothGattServer::WrapObject(JSContext* aContext,
                                 JS::Handle<JSObject*> aGivenProto)
 {
   return BluetoothGattServerBinding::Wrap(aContext, this, aGivenProto);
 }
 
 void
+BluetoothGattServer::DisconnectFromOwner()
+{
+  DOMEventTargetHelper::DisconnectFromOwner();
+  Invalidate();
+}
+
+void
 BluetoothGattServer::Invalidate()
 {
   mValid = false;
 
-  /* TODO: add tear down stuff here */
+  BluetoothService* bs = BluetoothService::Get();
+  NS_ENSURE_TRUE_VOID(bs);
+
+  if (mServerIf > 0) {
+    bs->UnregisterGattServerInternal(mServerIf, nullptr);
+  }
+
+  UnregisterBluetoothSignalHandler(mAppUuid, this);
+}
+
+already_AddRefed<Promise>
+BluetoothGattServer::Connect(const nsAString& aAddress, ErrorResult& aRv)
+{
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
+  if (!global) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<Promise> promise = Promise::Create(global, aRv);
+  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
+
+  BT_ENSURE_TRUE_REJECT(mValid, promise, NS_ERROR_NOT_AVAILABLE);
+  BluetoothService* bs = BluetoothService::Get();
+  BT_ENSURE_TRUE_REJECT(bs, promise, NS_ERROR_NOT_AVAILABLE);
 
-  return;
-}
\ No newline at end of file
+  if (mAppUuid.IsEmpty()) {
+    GenerateUuid(mAppUuid);
+    BT_ENSURE_TRUE_REJECT(!mAppUuid.IsEmpty(),
+                          promise,
+                          NS_ERROR_DOM_OPERATION_ERR);
+    RegisterBluetoothSignalHandler(mAppUuid, this);
+  }
+
+  bs->GattServerConnectPeripheralInternal(
+    mAppUuid, aAddress, new BluetoothVoidReplyRunnable(nullptr, promise));
+
+  return promise.forget();
+}
+
+already_AddRefed<Promise>
+BluetoothGattServer::Disconnect(const nsAString& aAddress, ErrorResult& aRv)
+{
+  nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
+  if (!global) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<Promise> promise = Promise::Create(global, aRv);
+  NS_ENSURE_TRUE(!aRv.Failed(), nullptr);
+
+  BT_ENSURE_TRUE_REJECT(mValid, promise, NS_ERROR_NOT_AVAILABLE);
+  BluetoothService* bs = BluetoothService::Get();
+  BT_ENSURE_TRUE_REJECT(bs, promise, NS_ERROR_NOT_AVAILABLE);
+
+  bs->GattServerDisconnectPeripheralInternal(
+    mAppUuid, aAddress, new BluetoothVoidReplyRunnable(nullptr, promise));
+
+  return promise.forget();
+}
--- a/dom/bluetooth/bluetooth2/BluetoothGattServer.h
+++ b/dom/bluetooth/bluetooth2/BluetoothGattServer.h
@@ -2,68 +2,96 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* 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/. */
 
 #ifndef mozilla_dom_bluetooth_BluetoothGattServer_h
 #define mozilla_dom_bluetooth_BluetoothGattServer_h
 
+#include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/BluetoothGattServerBinding.h"
 #include "mozilla/dom/bluetooth/BluetoothCommon.h"
 #include "nsCOMPtr.h"
 #include "nsPIDOMWindow.h"
-#include "nsWrapperCache.h"
+
+namespace mozilla {
+namespace dom {
+class Promise;
+}
+}
 
 BEGIN_BLUETOOTH_NAMESPACE
 
-class BluetoothGattServer final : public nsISupports
-                                , public nsWrapperCache
+class BluetoothSignal;
+
+class BluetoothGattServer final : public DOMEventTargetHelper
+                                , public BluetoothSignalObserver
 {
 public:
-  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
-  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(BluetoothGattServer)
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothGattServer,
+                                           DOMEventTargetHelper)
 
   /****************************************************************************
    * Attribute Getters
    ***************************************************************************/
 
   /****************************************************************************
    * Event Handlers
    ***************************************************************************/
+  IMPL_EVENT_HANDLER(connectionstatechanged);
 
   /****************************************************************************
    * Methods (Web API Implementation)
    ***************************************************************************/
+  already_AddRefed<Promise> Connect(
+    const nsAString& aAddress, ErrorResult& aRv);
+  already_AddRefed<Promise> Disconnect(
+    const nsAString& aAddress, ErrorResult& aRv);
 
   /****************************************************************************
    * Others
    ***************************************************************************/
+  void Notify(const BluetoothSignal& aData); // BluetoothSignalObserver
+
   nsPIDOMWindow* GetParentObject() const
   {
      return mOwner;
   }
 
   virtual JSObject* WrapObject(JSContext* aCx,
                                JS::Handle<JSObject*> aGivenProto) override;
 
+  virtual void DisconnectFromOwner() override;
   BluetoothGattServer(nsPIDOMWindow* aOwner);
 
   /* Invalidate the GATT server.
    * If the BluetoothAdapter turns off, existing BluetoothGattServer instances
    * should stop working till the end of life.
    */
   void Invalidate();
 
 private:
   ~BluetoothGattServer();
 
   /****************************************************************************
    * Variables
    ***************************************************************************/
   nsCOMPtr<nsPIDOMWindow> mOwner;
 
+  /**
+   * Random generated UUID of this GATT client.
+   */
+  nsString mAppUuid;
+
+  /**
+   * Id of the GATT server interface given by bluetooth stack.
+   * 0 if the interface is not registered yet, nonzero otherwise.
+   */
+  int mServerIf;
+
   bool mValid;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif // mozilla_dom_bluetooth_BluetoothGattServer_h
--- a/dom/bluetooth/bluetooth2/BluetoothService.h
+++ b/dom/bluetooth/bluetooth2/BluetoothService.h
@@ -453,16 +453,35 @@ public:
   GattClientWriteDescriptorValueInternal(
     const nsAString& aAppUuid,
     const BluetoothGattServiceId& aServiceId,
     const BluetoothGattId& aCharacteristicId,
     const BluetoothGattId& aDescriptorId,
     const nsTArray<uint8_t>& aValue,
     BluetoothReplyRunnable* aRunnable) = 0;
 
+  virtual void
+  GattServerConnectPeripheralInternal(
+    const nsAString& aAppUuid,
+    const nsAString& aAddress,
+    BluetoothReplyRunnable* aRunnable) = 0;
+
+  virtual void
+  GattServerDisconnectPeripheralInternal(
+    const nsAString& aAppUuid,
+    const nsAString& aAddress,
+    BluetoothReplyRunnable* aRunnable) = 0;
+
+  /**
+   * Unregister a GATT server. (platform specific implementation)
+   */
+  virtual void
+  UnregisterGattServerInternal(int aServerIf,
+                               BluetoothReplyRunnable* aRunnable) = 0;
+
   bool
   IsEnabled() const
   {
     return mEnabled;
   }
 
   bool
   IsToggling() const;
--- a/dom/bluetooth/bluetooth2/ipc/BluetoothParent.cpp
+++ b/dom/bluetooth/bluetooth2/ipc/BluetoothParent.cpp
@@ -281,16 +281,24 @@ BluetoothParent::RecvPBluetoothRequestCo
       return actor->DoRequest(
         aRequest.get_GattClientWriteCharacteristicValueRequest());
     case Request::TGattClientReadDescriptorValueRequest:
       return actor->DoRequest(
         aRequest.get_GattClientReadDescriptorValueRequest());
     case Request::TGattClientWriteDescriptorValueRequest:
       return actor->DoRequest(
         aRequest.get_GattClientWriteDescriptorValueRequest());
+    case Request::TGattServerConnectPeripheralRequest:
+      return actor->DoRequest(
+        aRequest.get_GattServerConnectPeripheralRequest());
+    case Request::TGattServerDisconnectPeripheralRequest:
+      return actor->DoRequest(
+        aRequest.get_GattServerDisconnectPeripheralRequest());
+    case Request::TUnregisterGattServerRequest:
+      return actor->DoRequest(aRequest.get_UnregisterGattServerRequest());
     default:
       MOZ_CRASH("Unknown type!");
   }
 
   MOZ_CRASH("Should never get here!");
 }
 
 PBluetoothRequestParent*
@@ -924,8 +932,50 @@ BluetoothRequestParent::DoRequest(
                                                    aRequest.serviceId(),
                                                    aRequest.charId(),
                                                    aRequest.descId(),
                                                    aRequest.value(),
                                                    mReplyRunnable.get());
 
   return true;
 }
+
+bool
+BluetoothRequestParent::DoRequest(
+  const GattServerConnectPeripheralRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType ==
+             Request::TGattServerConnectPeripheralRequest);
+
+  mService->GattServerConnectPeripheralInternal(aRequest.appUuid(),
+                                                aRequest.address(),
+                                                mReplyRunnable.get());
+
+  return true;
+}
+
+bool
+BluetoothRequestParent::DoRequest(
+  const GattServerDisconnectPeripheralRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType ==
+             Request::TGattServerDisconnectPeripheralRequest);
+
+  mService->GattServerDisconnectPeripheralInternal(aRequest.appUuid(),
+                                                   aRequest.address(),
+                                                   mReplyRunnable.get());
+
+  return true;
+}
+
+bool
+BluetoothRequestParent::DoRequest(const UnregisterGattServerRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  MOZ_ASSERT(mRequestType == Request::TUnregisterGattServerRequest);
+
+  mService->UnregisterGattServerInternal(aRequest.serverIf(),
+                                         mReplyRunnable.get());
+
+  return true;
+}
--- a/dom/bluetooth/bluetooth2/ipc/BluetoothParent.h
+++ b/dom/bluetooth/bluetooth2/ipc/BluetoothParent.h
@@ -256,13 +256,22 @@ protected:
   bool
   DoRequest(const GattClientWriteCharacteristicValueRequest& aRequest);
 
   bool
   DoRequest(const GattClientReadDescriptorValueRequest& aRequest);
 
   bool
   DoRequest(const GattClientWriteDescriptorValueRequest& aRequest);
+
+  bool
+  DoRequest(const GattServerConnectPeripheralRequest& aRequest);
+
+  bool
+  DoRequest(const GattServerDisconnectPeripheralRequest& aRequest);
+
+  bool
+  DoRequest(const UnregisterGattServerRequest& aRequest);
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif // mozilla_dom_bluetooth_ipc_BluetoothParent_h
--- a/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.cpp
+++ b/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.cpp
@@ -533,16 +533,45 @@ BluetoothServiceChildProcess::GattClient
   SendRequest(aRunnable,
     GattClientWriteDescriptorValueRequest(nsString(aAppUuid),
                                           aServiceId,
                                           aCharacteristicId,
                                           aDescriptorId,
                                           aValue));
 }
 
+void
+BluetoothServiceChildProcess::GattServerConnectPeripheralInternal(
+  const nsAString& aAppUuid,
+  const nsAString& aAddress,
+  BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable,
+    GattServerConnectPeripheralRequest(nsString(aAppUuid),
+                                       nsString(aAddress)));
+}
+
+void
+BluetoothServiceChildProcess::GattServerDisconnectPeripheralInternal(
+  const nsAString& aAppUuid,
+  const nsAString& aAddress,
+  BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable,
+    GattServerDisconnectPeripheralRequest(nsString(aAppUuid),
+                                          nsString(aAddress)));
+}
+
+void
+BluetoothServiceChildProcess::UnregisterGattServerInternal(
+  int aServerIf, BluetoothReplyRunnable* aRunnable)
+{
+  SendRequest(aRunnable, UnregisterGattServerRequest(aServerIf));
+}
+
 nsresult
 BluetoothServiceChildProcess::HandleStartup()
 {
   // Don't need to do anything here for startup since our Create function takes
   // care of the actor machinery.
   return NS_OK;
 }
 
--- a/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.h
+++ b/dom/bluetooth/bluetooth2/ipc/BluetoothServiceChildProcess.h
@@ -262,16 +262,32 @@ public:
   GattClientWriteDescriptorValueInternal(
     const nsAString& aAppUuid,
     const BluetoothGattServiceId& aServiceId,
     const BluetoothGattId& aCharacteristicId,
     const BluetoothGattId& aDescriptorId,
     const nsTArray<uint8_t>& aValue,
     BluetoothReplyRunnable* aRunnable);
 
+  virtual void
+  GattServerConnectPeripheralInternal(
+    const nsAString& aAppUuid,
+    const nsAString& aAddress,
+    BluetoothReplyRunnable* aRunnable);
+
+  virtual void
+  GattServerDisconnectPeripheralInternal(
+    const nsAString& aAppUuid,
+    const nsAString& aAddress,
+    BluetoothReplyRunnable* aRunnable);
+
+  virtual void
+  UnregisterGattServerInternal(int aServerIf,
+                               BluetoothReplyRunnable* aRunnable) override;
+
 protected:
   BluetoothServiceChildProcess();
   virtual ~BluetoothServiceChildProcess();
 
   void
   NoteDeadActor();
 
   void
--- a/dom/bluetooth/bluetooth2/ipc/PBluetooth.ipdl
+++ b/dom/bluetooth/bluetooth2/ipc/PBluetooth.ipdl
@@ -270,16 +270,33 @@ struct GattClientWriteDescriptorValueReq
 {
   nsString appUuid;
   BluetoothGattServiceId serviceId;
   BluetoothGattId charId;
   BluetoothGattId descId;
   uint8_t[] value;
 };
 
+struct GattServerConnectPeripheralRequest
+{
+  nsString appUuid;
+  nsString address;
+};
+
+struct GattServerDisconnectPeripheralRequest
+{
+  nsString appUuid;
+  nsString address;
+};
+
+struct UnregisterGattServerRequest
+{
+  int serverIf;
+};
+
 union Request
 {
   GetAdaptersRequest;
   StartBluetoothRequest;
   StopBluetoothRequest;
   SetPropertyRequest;
   GetPropertyRequest;
   StartDiscoveryRequest;
@@ -317,16 +334,19 @@ union Request
   GattClientStartNotificationsRequest;
   GattClientStopNotificationsRequest;
   UnregisterGattClientRequest;
   GattClientReadRemoteRssiRequest;
   GattClientReadCharacteristicValueRequest;
   GattClientWriteCharacteristicValueRequest;
   GattClientReadDescriptorValueRequest;
   GattClientWriteDescriptorValueRequest;
+  GattServerConnectPeripheralRequest;
+  GattServerDisconnectPeripheralRequest;
+  UnregisterGattServerRequest;
 };
 
 protocol PBluetooth
 {
   manager PContent;
   manages PBluetoothRequest;
 
   /**
--- a/dom/bluetooth/bluez/BluetoothDBusService.cpp
+++ b/dom/bluetooth/bluez/BluetoothDBusService.cpp
@@ -4373,8 +4373,28 @@ BluetoothDBusService::GattClientWriteDes
   const nsAString& aAppUuid,
   const BluetoothGattServiceId& aServiceId,
   const BluetoothGattId& aCharacteristicId,
   const BluetoothGattId& aDescriptorId,
   const nsTArray<uint8_t>& aValue,
   BluetoothReplyRunnable* aRunnable)
 {
 }
+
+void
+BluetoothDBusService::GattServerConnectPeripheralInternal(
+  const nsAString& aAppUuid, const nsAString& aAddress,
+  BluetoothReplyRunnable* aRunnable)
+{
+}
+
+void
+BluetoothDBusService::GattServerDisconnectPeripheralInternal(
+  const nsAString& aAppUuid, const nsAString& aAddress,
+  BluetoothReplyRunnable* aRunnable)
+{
+}
+
+void
+BluetoothDBusService::UnregisterGattServerInternal(
+  int aServerIf, BluetoothReplyRunnable* aRunnable)
+{
+}
--- a/dom/bluetooth/bluez/BluetoothDBusService.h
+++ b/dom/bluetooth/bluez/BluetoothDBusService.h
@@ -269,16 +269,32 @@ public:
   GattClientWriteDescriptorValueInternal(
     const nsAString& aAppUuid,
     const BluetoothGattServiceId& aServiceId,
     const BluetoothGattId& aCharacteristicId,
     const BluetoothGattId& aDescriptorId,
     const nsTArray<uint8_t>& aValue,
     BluetoothReplyRunnable* aRunnable) override;
 
+  virtual void
+  GattServerConnectPeripheralInternal(
+    const nsAString& aAppUuid,
+    const nsAString& aAddress,
+    BluetoothReplyRunnable* aRunnable) override;
+
+  virtual void
+  GattServerDisconnectPeripheralInternal(
+    const nsAString& aAppUuid,
+    const nsAString& aAddress,
+    BluetoothReplyRunnable* aRunnable) override;
+
+  virtual void
+  UnregisterGattServerInternal(int aServerIf,
+                               BluetoothReplyRunnable* aRunnable) override;
+
 private:
   nsresult SendGetPropertyMessage(const nsAString& aPath,
                                   const char* aInterface,
                                   void (*aCB)(DBusMessage *, void *),
                                   BluetoothReplyRunnable* aRunnable);
 
   nsresult SendDiscoveryMessage(const char* aMessageName,
                                 BluetoothReplyRunnable* aRunnable);
--- a/dom/camera/CameraControlImpl.cpp
+++ b/dom/camera/CameraControlImpl.cpp
@@ -1,16 +1,17 @@
 /* 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 "CameraControlImpl.h"
 #include "base/basictypes.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/unused.h"
+#include "nsPrintfCString.h"
 #include "nsIWeakReferenceUtils.h"
 #include "CameraCommon.h"
 #include "nsGlobalWindow.h"
 #include "DeviceStorageFileDescriptor.h"
 #include "CameraControlListener.h"
 
 using namespace mozilla;
 
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -134,23 +134,29 @@ nsGonkCameraControl::StartInternal(const
    * up-front as possible without waiting for blocking Camera Thread calls
    * to complete.
    */
   nsresult rv = Initialize();
   switch (rv) {
     case NS_ERROR_ALREADY_INITIALIZED:
     case NS_OK:
       break;
-    
+
     default:
       return rv;
   }
 
   if (aInitialConfig) {
-    rv = SetConfigurationInternal(*aInitialConfig);
+    Configuration config;
+    rv = ValidateConfiguration(*aInitialConfig, config);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    rv = SetConfigurationInternal(config);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       // The initial configuration failed, close up the hardware
       StopInternal();
       return rv;
     }
   }
 
   OnHardwareStateChange(CameraControlListener::kHardwareOpen, NS_OK);
@@ -178,16 +184,18 @@ nsGonkCameraControl::Initialize()
   mCameraHw = GonkCameraHardware::Connect(this, mCameraId);
   if (!mCameraHw.get()) {
     DOM_CAMERA_LOGE("Failed to connect to camera %d (this=%p)\n", mCameraId, this);
     return NS_ERROR_NOT_INITIALIZED;
   }
 
   DOM_CAMERA_LOGI("Initializing camera %d (this=%p, mCameraHw=%p)\n", mCameraId, this, mCameraHw.get());
   mCurrentConfiguration.mRecorderProfile.Truncate();
+  mRequestedPreviewSize.width = UINT32_MAX;
+  mRequestedPreviewSize.height = UINT32_MAX;
 
   // Initialize our camera configuration database.
   mCameraHw->PullParameters(mParams);
 
   // Set preferred preview frame format.
   mParams.Set(CAMERA_PARAM_PREVIEWFORMAT, NS_LITERAL_STRING("yuv420sp"));
   // Turn off any normal pictures returned by the HDR scene mode
   mParams.Set(CAMERA_PARAM_SCENEMODE_HDR_RETURNNORMALPICTURE, false);
@@ -273,17 +281,17 @@ nsGonkCameraControl::Initialize()
         }
       }
     }
 
     mParams.Get(CAMERA_PARAM_METERINGMODE, mode);
     DOM_CAMERA_LOGI(" - metering mode:                 '%s'\n",
       NS_ConvertUTF16toUTF8(mode).get());
   }
-      
+
   return NS_OK;
 }
 
 nsGonkCameraControl::~nsGonkCameraControl()
 {
   DOM_CAMERA_LOGT("%s:%d : this=%p, mCameraHw = %p\n", __func__, __LINE__, this, mCameraHw.get());
 
   StopImpl();
@@ -316,102 +324,116 @@ nsGonkCameraControl::ValidateConfigurati
 
   RecorderProfile* profile;
   if (!mRecorderProfiles.Get(profileName, &profile)) {
     DOM_CAMERA_LOGE("Recorder profile '%s' is not supported\n",
       NS_ConvertUTF16toUTF8(aConfig.mRecorderProfile).get());
     return NS_ERROR_INVALID_ARG;
   }
 
+  if (mCurrentConfiguration.mMode == aConfig.mMode &&
+      mRequestedPreviewSize.width == aConfig.mPreviewSize.width &&
+      mRequestedPreviewSize.height == aConfig.mPreviewSize.height &&
+      mCurrentConfiguration.mRecorderProfile.Equals(profile->GetName()))
+  {
+    DOM_CAMERA_LOGI("Camera configuration is unchanged\n");
+    return NS_ERROR_ALREADY_INITIALIZED;
+  }
+
   aValidatedConfig.mMode = aConfig.mMode;
   aValidatedConfig.mPreviewSize = aConfig.mPreviewSize;
   aValidatedConfig.mRecorderProfile = profile->GetName();
+  mRequestedPreviewSize = aConfig.mPreviewSize;
   return NS_OK;
 }
 
 nsresult
 nsGonkCameraControl::SetConfigurationInternal(const Configuration& aConfig)
 {
   DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
 
-  // Ensure sanity of all provided parameters and determine defaults if
-  // none are provided when given a new configuration
-  Configuration config;
-  nsresult rv = ValidateConfiguration(aConfig, config);
+  ICameraControlParameterSetAutoEnter set(this);
+
+  nsresult rv;
+  switch (aConfig.mMode) {
+    case kPictureMode:
+      rv = SetPictureConfiguration(aConfig);
+      break;
+
+    case kVideoMode:
+      rv = SetVideoConfiguration(aConfig);
+      break;
+
+    default:
+      MOZ_ASSERT_UNREACHABLE("Unanticipated camera mode in SetConfigurationInternal()");
+      rv = NS_ERROR_FAILURE;
+      break;
+  }
+
+  DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
   if (NS_WARN_IF(NS_FAILED(rv))) {
+    mRequestedPreviewSize.width = UINT32_MAX;
+    mRequestedPreviewSize.height = UINT32_MAX;
     return rv;
   }
 
-  {
-    ICameraControlParameterSetAutoEnter set(this);
-
-    switch (config.mMode) {
-      case kPictureMode:
-        rv = SetPictureConfiguration(config);
-        break;
+  rv = Set(CAMERA_PARAM_RECORDINGHINT, aConfig.mMode == kVideoMode);
+  if (NS_FAILED(rv)) {
+    DOM_CAMERA_LOGE("Failed to set recording hint (0x%x)\n", rv);
+  }
 
-      case kVideoMode:
-        rv = SetVideoConfiguration(config);
-        break;
-
-      default:
-        MOZ_ASSERT_UNREACHABLE("Unanticipated camera mode in SetConfigurationInternal()");
-        rv = NS_ERROR_FAILURE;
-        break;
-    }
+  mCurrentConfiguration.mMode = aConfig.mMode;
+  mCurrentConfiguration.mRecorderProfile = aConfig.mRecorderProfile;
 
-    DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    rv = Set(CAMERA_PARAM_RECORDINGHINT, config.mMode == kVideoMode);
-    if (NS_FAILED(rv)) {
-      DOM_CAMERA_LOGE("Failed to set recording hint (0x%x)\n", rv);
-    }
-
-    mCurrentConfiguration.mMode = config.mMode;
-    mCurrentConfiguration.mRecorderProfile = config.mRecorderProfile;
-    
-    if (config.mMode == kPictureMode) {
-      mCurrentConfiguration.mPictureSize = config.mPictureSize;
-    } else /* if config.mMode == kVideoMode */ {
-      // The following is best-effort; we don't currently support taking
-      // pictures while in video mode, but we should at least return
-      // sane values to OnConfigurationChange() handlers...
-      SetPictureSizeImpl(config.mPictureSize);
-    }
+  if (aConfig.mMode == kPictureMode) {
+    mCurrentConfiguration.mPictureSize = aConfig.mPictureSize;
+  } else /* if config.mMode == kVideoMode */ {
+    // The following is best-effort; we don't currently support taking
+    // pictures while in video mode, but we should at least return
+    // sane values to OnConfigurationChange() handlers...
+    SetPictureSizeImpl(aConfig.mPictureSize);
   }
   return NS_OK;
 }
 
 nsresult
 nsGonkCameraControl::SetConfigurationImpl(const Configuration& aConfig)
 {
   DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
   MOZ_ASSERT(NS_GetCurrentThread() == mCameraThread);
 
   if (aConfig.mMode == kUnspecifiedMode) {
     DOM_CAMERA_LOGW("Can't set camera mode to 'unspecified', ignoring\n");
     return NS_ERROR_INVALID_ARG;
   }
 
+  Configuration config;
+  nsresult rv = ValidateConfiguration(aConfig, config);
+  if (rv == NS_ERROR_ALREADY_INITIALIZED) {
+    // Configuration did not change, so no need to stop/start the preview
+    // or push parameters to the camera hardware
+    OnConfigurationChange();
+    return NS_OK;
+  } else if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
   // Stop any currently running preview
-  nsresult rv = PausePreview();
+  rv = PausePreview();
   if (NS_FAILED(rv)) {
     DOM_CAMERA_LOGW("PausePreview() in SetConfigurationImpl() failed (0x%x)\n", rv);
     if (rv == NS_ERROR_NOT_INITIALIZED) {
       // If there no hardware available, nothing else we try will work,
       // so bail out here.
       return rv;
     }
   }
 
   DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
-  rv = SetConfigurationInternal(aConfig);
+  rv = SetConfigurationInternal(config);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     StopPreviewImpl();
     return rv;
   }
 
   // Restart the preview
   DOM_CAMERA_LOGT("%s:%d\n", __func__, __LINE__);
   rv = StartPreviewInternal();
--- a/dom/camera/GonkCameraControl.h
+++ b/dom/camera/GonkCameraControl.h
@@ -174,16 +174,17 @@ protected:
   int32_t RationalizeRotation(int32_t aRotation);
 
   uint32_t                  mCameraId;
 
   android::sp<android::GonkCameraHardware> mCameraHw;
 
   Size                      mLastThumbnailSize;
   Size                      mLastRecorderSize;
+  Size                      mRequestedPreviewSize;
   uint32_t                  mPreviewFps;
   bool                      mResumePreviewAfterTakingPicture;
   bool                      mFlashSupported;
   bool                      mLuminanceSupported;
   bool                      mAutoFlashModeOverridden;
   bool                      mSeparateVideoAndPreviewSizesSupported;
   Atomic<uint32_t>          mDeferConfigUpdate;
   GonkCameraParameters      mParams;
--- a/dom/system/gonk/nsVolume.cpp
+++ b/dom/system/gonk/nsVolume.cpp
@@ -61,16 +61,32 @@ nsVolume::nsVolume(const Volume* aVolume
     mIsSharing(aVolume->IsSharing()),
     mIsFormatting(aVolume->IsFormatting()),
     mIsUnmounting(aVolume->IsUnmounting()),
     mIsRemovable(aVolume->IsRemovable()),
     mIsHotSwappable(aVolume->IsHotSwappable())
 {
 }
 
+nsVolume::nsVolume(const nsVolume* aVolume)
+  : mName(aVolume->mName),
+    mMountPoint(aVolume->mMountPoint),
+    mState(aVolume->mState),
+    mMountGeneration(aVolume->mMountGeneration),
+    mMountLocked(aVolume->mMountLocked),
+    mIsFake(aVolume->mIsFake),
+    mIsMediaPresent(aVolume->mIsMediaPresent),
+    mIsSharing(aVolume->mIsSharing),
+    mIsFormatting(aVolume->mIsFormatting),
+    mIsUnmounting(aVolume->mIsUnmounting),
+    mIsRemovable(aVolume->mIsRemovable),
+    mIsHotSwappable(aVolume->mIsHotSwappable)
+{
+}
+
 void nsVolume::Dump(const char* aLabel) const
 {
   LOG("%s: Volume: %s is %s and %s @ %s gen %d locked %d",
       aLabel,
       NameStr().get(),
       StateStr(),
       IsMediaPresent() ? "inserted" : "missing",
       MountPointStr().get(),
@@ -328,50 +344,38 @@ nsVolume::LogState() const
         (int)IsFormatting(), (int)IsUnmounting(),
         (int)IsRemovable(), (int)IsHotSwappable());
     return;
   }
 
   LOG("nsVolume: %s state %s", NameStr().get(), StateStr());
 }
 
-void nsVolume::Set(nsIVolume* aVolume)
+void nsVolume::UpdateMountLock(nsVolume* aOldVolume)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  aVolume->GetName(mName);
-  aVolume->GetMountPoint(mMountPoint);
-  aVolume->GetState(&mState);
-  aVolume->GetIsFake(&mIsFake);
-  aVolume->GetIsMediaPresent(&mIsMediaPresent);
-  aVolume->GetIsSharing(&mIsSharing);
-  aVolume->GetIsFormatting(&mIsFormatting);
-  aVolume->GetIsUnmounting(&mIsUnmounting);
-  aVolume->GetIsRemovable(&mIsRemovable);
-  aVolume->GetIsHotSwappable(&mIsHotSwappable);
-
-  int32_t volMountGeneration;
-  aVolume->GetMountGeneration(&volMountGeneration);
-
+  bool oldMountLocked = aOldVolume ? aOldVolume->mMountLocked : false;
   if (mState != nsIVolume::STATE_MOUNTED) {
     // Since we're not in the mounted state, we need to
     // forgot whatever mount generation we may have had.
     mMountGeneration = -1;
-    return;
-  }
-  if (mMountGeneration == volMountGeneration) {
-    // No change in mount generation, nothing else to do
+    mMountLocked = oldMountLocked;
     return;
   }
 
-  mMountGeneration = volMountGeneration;
+  int32_t oldMountGeneration = aOldVolume ? aOldVolume->mMountGeneration : -1;
+  if (mMountGeneration == oldMountGeneration) {
+    // No change in mount generation, nothing else to do
+    mMountLocked = oldMountLocked;
+    return;
+  }
 
   if (!XRE_IsParentProcess()) {
     // Child processes just track the state, not maintain it.
-    aVolume->GetIsMountLocked(&mMountLocked);
     return;
   }
 
   // Notify the Volume on IOThread whether the volume is locked or not.
   nsCOMPtr<nsIPowerManagerService> pmService =
     do_GetService(POWERMANAGERSERVICE_CONTRACTID);
   if (!pmService) {
     return;
--- a/dom/system/gonk/nsVolume.h
+++ b/dom/system/gonk/nsVolume.h
@@ -19,16 +19,19 @@ class nsVolume : public nsIVolume
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIVOLUME
 
   // This constructor is used by the UpdateVolumeRunnable constructor
   nsVolume(const Volume* aVolume);
 
+  // This constructor is used by nsVolumeService::SetFakeVolumeState
+  nsVolume(const nsVolume* aVolume);
+
   // This constructor is used by ContentChild::RecvFileSystemUpdate which is
   // used to update the volume cache maintained in the child process.
   nsVolume(const nsAString& aName, const nsAString& aMountPoint,
            const int32_t& aState, const int32_t& aMountGeneration,
            const bool& aIsMediaPresent, const bool& aIsSharing,
            const bool& aIsFormatting, const bool& aIsFake,
            const bool& aIsUnmounting, const bool& aIsRemovable,
            const bool& aIsHotSwappable)
@@ -42,35 +45,18 @@ public:
       mIsSharing(aIsSharing),
       mIsFormatting(aIsFormatting),
       mIsUnmounting(aIsUnmounting),
       mIsRemovable(aIsRemovable),
       mIsHotSwappable(aIsHotSwappable)
   {
   }
 
-  // This constructor is used by nsVolumeService::FindAddVolumeByName, and
-  // will be followed shortly by a Set call.
-  nsVolume(const nsAString& aName)
-    : mName(aName),
-      mState(STATE_INIT),
-      mMountGeneration(-1),
-      mMountLocked(true),  // Needs to agree with Volume::Volume
-      mIsFake(false),
-      mIsMediaPresent(false),
-      mIsSharing(false),
-      mIsFormatting(false),
-      mIsUnmounting(false),
-      mIsRemovable(false),
-      mIsHotSwappable(false)
-  {
-  }
-
   bool Equals(nsIVolume* aVolume);
-  void Set(nsIVolume* aVolume);
+  void UpdateMountLock(nsVolume* aOldVolume);
 
   void LogState() const;
 
   const nsString& Name() const        { return mName; }
   nsCString NameStr() const           { return NS_LossyConvertUTF16toASCII(mName); }
 
   void Dump(const char* aLabel) const;
 
--- a/dom/system/gonk/nsVolumeService.cpp
+++ b/dom/system/gonk/nsVolumeService.cpp
@@ -363,81 +363,64 @@ nsVolumeService::FindVolumeByMountLockNa
     if (mountLockName.Equals(aMountLockName)) {
       return vol.forget();
     }
   }
   return nullptr;
 }
 
 already_AddRefed<nsVolume>
-nsVolumeService::FindVolumeByName(const nsAString& aName)
+nsVolumeService::FindVolumeByName(const nsAString& aName, nsVolume::Array::index_type* aIndex)
 {
   mArrayMonitor.AssertCurrentThreadOwns();
 
   nsVolume::Array::size_type numVolumes = mVolumeArray.Length();
   nsVolume::Array::index_type volIndex;
   for (volIndex = 0; volIndex < numVolumes; volIndex++) {
     nsRefPtr<nsVolume> vol = mVolumeArray[volIndex];
     if (vol->Name().Equals(aName)) {
+      if (aIndex) {
+        *aIndex = volIndex;
+      }
       return vol.forget();
     }
   }
   return nullptr;
 }
 
-//static
-already_AddRefed<nsVolume>
-nsVolumeService::CreateOrFindVolumeByName(const nsAString& aName, bool aIsFake /*= false*/)
-{
-  MonitorAutoLock autoLock(mArrayMonitor);
-
-  nsRefPtr<nsVolume> vol;
-  vol = FindVolumeByName(aName);
-  if (vol) {
-    return vol.forget();
-  }
-  // Volume not found - add a new one
-  vol = new nsVolume(aName);
-  vol->SetIsFake(aIsFake);
-  mVolumeArray.AppendElement(vol);
-  return vol.forget();
-}
-
 void
-nsVolumeService::UpdateVolume(nsIVolume* aVolume, bool aNotifyObservers)
+nsVolumeService::UpdateVolume(nsVolume* aVolume, bool aNotifyObservers)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  nsString volName;
-  aVolume->GetName(volName);
-  bool aIsFake;
-  aVolume->GetIsFake(&aIsFake);
-  nsRefPtr<nsVolume> vol = CreateOrFindVolumeByName(volName, aIsFake);
-  if (vol->Equals(aVolume)) {
-    // Nothing has really changed. Don't bother telling anybody.
-    return;
+  {
+    MonitorAutoLock autoLock(mArrayMonitor);
+    nsVolume::Array::index_type volIndex;
+    nsRefPtr<nsVolume> vol = FindVolumeByName(aVolume->Name(), &volIndex);
+    if (!vol) {
+      mVolumeArray.AppendElement(aVolume);
+    } else if (vol->Equals(aVolume) || (!vol->IsFake() && aVolume->IsFake())) {
+      // Ignore if nothing changed or if a fake tries to override a real volume.
+      return;
+    } else {
+      mVolumeArray.ReplaceElementAt(volIndex, aVolume);
+    }
+    aVolume->UpdateMountLock(vol);
   }
 
-  if (!vol->IsFake() && aIsFake) {
-    // Prevent an incoming fake volume from overriding an existing real volume.
-    return;
-  }
-
-  vol->Set(aVolume);
-
   if (!aNotifyObservers) {
     return;
   }
 
   nsCOMPtr<nsIObserverService> obs = GetObserverService();
   if (!obs) {
     return;
   }
-  NS_ConvertUTF8toUTF16 stateStr(vol->StateStr());
-  obs->NotifyObservers(vol, NS_VOLUME_STATE_CHANGED, stateStr.get());
+  NS_ConvertUTF8toUTF16 stateStr(aVolume->StateStr());
+  obs->NotifyObservers(aVolume, NS_VOLUME_STATE_CHANGED, stateStr.get());
 }
 
 NS_IMETHODIMP
 nsVolumeService::CreateFakeVolume(const nsAString& name, const nsAString& path)
 {
   if (XRE_IsParentProcess()) {
     nsRefPtr<nsVolume> vol = new nsVolume(name, path, nsIVolume::STATE_INIT,
                                           -1    /* mountGeneration */,
@@ -466,21 +449,18 @@ nsVolumeService::SetFakeVolumeState(cons
     {
       MonitorAutoLock autoLock(mArrayMonitor);
       vol = FindVolumeByName(name);
     }
     if (!vol || !vol->IsFake()) {
       return NS_ERROR_NOT_AVAILABLE;
     }
 
-    // UpdateVolume expects the volume passed in to NOT be the
-    // same pointer as what CreateOrFindVolumeByName would return,
-    // which is why we allocate a temporary volume here.
-    nsRefPtr<nsVolume> volume = new nsVolume(name);
-    volume->Set(vol);
+    // Clone the existing volume so we can replace it
+    nsRefPtr<nsVolume> volume = new nsVolume(vol);
     volume->SetState(state);
     volume->LogState();
     UpdateVolume(volume.get());
     return NS_OK;
   }
 
   ContentChild::GetSingleton()->SendSetFakeVolumeState(nsString(name), state);
   return NS_OK;
@@ -497,25 +477,25 @@ nsVolumeService::RemoveFakeVolume(const 
 
   ContentChild::GetSingleton()->SendRemoveFakeVolume(nsString(name));
   return NS_OK;
 }
 
 void
 nsVolumeService::RemoveVolumeByName(const nsAString& aName)
 {
-  nsRefPtr<nsVolume> vol;
   {
     MonitorAutoLock autoLock(mArrayMonitor);
-    vol = FindVolumeByName(aName);
+    nsVolume::Array::index_type volIndex;
+    nsRefPtr<nsVolume> vol = FindVolumeByName(aName, &volIndex);
+    if (!vol) {
+      return;
+    }
+    mVolumeArray.RemoveElementAt(volIndex);
   }
-  if (!vol) {
-    return;
-  }
-  mVolumeArray.RemoveElement(vol);
 
   if (XRE_IsParentProcess()) {
     nsCOMPtr<nsIObserverService> obs = GetObserverService();
     if (!obs) {
       return;
     }
     obs->NotifyObservers(nullptr, NS_VOLUME_REMOVED, nsString(aName).get());
   }
--- a/dom/system/gonk/nsVolumeService.h
+++ b/dom/system/gonk/nsVolumeService.h
@@ -42,32 +42,33 @@ public:
 
   static already_AddRefed<nsVolumeService> GetSingleton();
   //static nsVolumeService* GetSingleton();
   static void Shutdown();
 
   void DumpNoLock(const char* aLabel);
 
   // To use this function, you have to create a new volume and pass it in.
-  void UpdateVolume(nsIVolume* aVolume, bool aNotifyObservers = true);
+  void UpdateVolume(nsVolume* aVolume, bool aNotifyObservers = true);
   void UpdateVolumeIOThread(const Volume* aVolume);
 
   void RecvVolumesFromParent(const nsTArray<dom::VolumeInfo>& aVolumes);
   void GetVolumesForIPC(nsTArray<dom::VolumeInfo>* aResult);
 
   void RemoveVolumeByName(const nsAString& aName);
 
 private:
   ~nsVolumeService();
 
   void CheckMountLock(const nsAString& aMountLockName,
                       const nsAString& aMountLockState);
   already_AddRefed<nsVolume> FindVolumeByMountLockName(const nsAString& aMountLockName);
-  already_AddRefed<nsVolume> FindVolumeByName(const nsAString& aName);
-  already_AddRefed<nsVolume> CreateOrFindVolumeByName(const nsAString& aName, bool aIsFake = false);
+
+  already_AddRefed<nsVolume> FindVolumeByName(const nsAString& aName,
+                                              nsVolume::Array::index_type* aIndex = nullptr);
 
   Monitor mArrayMonitor;
   nsVolume::Array mVolumeArray;
 
   static StaticRefPtr<nsVolumeService> sSingleton;
   bool mGotVolumesFromParent;
 };
 
--- a/dom/webidl/BluetoothGattServer.webidl
+++ b/dom/webidl/BluetoothGattServer.webidl
@@ -1,13 +1,23 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/.
  */
 
 [CheckAnyPermissions="bluetooth"]
-interface BluetoothGattServer
+interface BluetoothGattServer : EventTarget
 {
-  /* The implementation of BluetoothGattServer will come later.
-   * (see dependent bugs of bug 933358)
+  // Fired when a remote device has been connected/disconnected
+  attribute EventHandler  onconnectionstatechanged;
+
+  /**
+   * Connect/Disconnect to the remote BLE device with the target address.
+   *
+   * Promise will be rejected if the local GATT server is busy connecting or
+   * disconnecting to other devices.
    */
+  [NewObject]
+  Promise<void> connect(DOMString address);
+  [NewObject]
+  Promise<void> disconnect(DOMString address);
 };
--- a/dom/webidl/CameraControl.webidl
+++ b/dom/webidl/CameraControl.webidl
@@ -256,17 +256,17 @@ interface CameraControl : MediaStream
              'Resumed' if the recording is resumed after pausing
              'PosterCreated' if a poster was requested and created
              'PosterFailed' if a poster was requested and failed to create
              'FileSizeLimitReached' if stopped due to file size limit
              'VideoLengthLimitReached' if stopped due to a time limit
              'TrackCompleted' if audio or video track complete when stopping
              'TrackFailed' if audio or video track incomplete when stopping
              'MediaRecorderFailed' if failed due to local error
-             'MediaServerFailed' if failed due to media server
+             'MediaServerFailed' if failed due to media server */
   attribute EventHandler    onrecorderstatechange;
 
   /* the event dispatched when the viewfinder stops or starts,
      useful for synchronizing other UI elements.
 
      event type is CameraStateChangeEvent where:
          'newState' is the new preview state */
   attribute EventHandler    onpreviewstatechange;
--- a/testing/taskcluster/tasks/branches/try/job_flags.yml
+++ b/testing/taskcluster/tasks/branches/try/job_flags.yml
@@ -48,16 +48,18 @@ builds:
       opt:
         task: tasks/builds/b2g_emulator_x86_l_opt.yml
   emulator-x86-kk:
     platforms:
       - b2g
     types:
       opt:
         task: tasks/builds/b2g_emulator_x86_kk_opt.yml
+      debug:
+        task: tasks/builds/b2g_emulator_x86_kk_debug.yml
   emulator-jb:
     platforms:
       - b2g
     types:
       opt:
         task: tasks/builds/b2g_emulator_jb_opt.yml
       debug:
         task: tasks/builds/b2g_emulator_jb_debug.yml
@@ -192,20 +194,24 @@ post-build:
 
 tests:
   cppunit:
     allowed_build_tasks:
       tasks/builds/b2g_emulator_ics_opt.yml:
         task: tasks/tests/b2g_emulator_cpp_unit.yml
       tasks/builds/b2g_emulator_ics_debug.yml:
         task: tasks/tests/b2g_emulator_cpp_unit.yml
+      tasks/builds/b2g_emulator_x86_kk_opt.yml:
+        task: tasks/tests/b2g_emulator_cpp_unit.yml
   crashtest:
     allowed_build_tasks:
       tasks/builds/b2g_emulator_ics_opt.yml:
         task: tasks/tests/b2g_emulator_crashtest.yml
+      tasks/builds/b2g_emulator_x86_kk_opt.yml:
+        task: tasks/tests/b2g_emulator_crashtest.yml
   gaia-build:
     allowed_build_tasks:
       tasks/builds/b2g_desktop_opt.yml:
         task: tasks/tests/b2g_build_test.yml
       tasks/builds/mulet_linux.yml:
         task: tasks/tests/mulet_build_test.yml
   gaia-build-unit:
     allowed_build_tasks:
@@ -246,22 +252,26 @@ tests:
   gaia-unit:
     allowed_build_tasks:
       tasks/builds/b2g_desktop_opt.yml:
         task: tasks/tests/b2g_gaia_unit.yml
   marionette:
     allowed_build_tasks:
       tasks/builds/b2g_emulator_kk_opt.yml:
         task: tasks/tests/b2g_emulator_marionette.yml
+      tasks/builds/b2g_emulator_x86_kk_opt.yml:
+        task: tasks/tests/b2g_emulator_marionette.yml
       tasks/builds/b2g_emulator_ics_opt.yml:
         task: tasks/tests/b2g_emulator_marionette.yml
   marionette-webapi:
     allowed_build_tasks:
       tasks/builds/b2g_emulator_kk_opt.yml:
         task: tasks/tests/b2g_emulator_marionette_webapi.yml
+      tasks/builds/b2g_emulator_x86_kk_opt.yml:
+        task: tasks/tests/b2g_emulator_marionette_webapi.yml
       tasks/builds/b2g_emulator_ics_opt.yml:
         task: tasks/tests/b2g_emulator_marionette_webapi.yml
   mochitest:
     allowed_build_tasks:
       tasks/builds/b2g_emulator_kk_debug.yml:
         task: tasks/tests/b2g_emulator_mochitest.yml
       tasks/builds/b2g_emulator_kk_opt.yml:
         task: tasks/tests/b2g_emulator_mochitest.yml
@@ -292,16 +302,16 @@ tests:
       tasks/builds/b2g_emulator_ics_opt.yml:
         task: tasks/tests/b2g_emulator_reftest.yml
   reftest-sanity-oop:
     allowed_build_tasks:
       tasks/builds/b2g_desktop_opt.yml:
         task: tasks/tests/b2g_reftests_sanity_oop.yml
   xpcshell:
     allowed_build_tasks:
-      tasks/builds/b2g_emulator_x86_kk_opt.yml:
+      tasks/builds/b2g_emulator_kk_opt.yml:
         task: tasks/tests/b2g_emulator_xpcshell_chunked.yml
-      tasks/builds/b2g_emulator_kk_opt.yml:
+      tasks/builds/b2g_emulator_x86_kk_opt.yml:
         task: tasks/tests/b2g_emulator_xpcshell_chunked.yml
       tasks/builds/b2g_emulator_ics_opt.yml:
         task: tasks/tests/b2g_emulator_xpcshell_chunked.yml
       tasks/builds/b2g_emulator_ics_debug.yml:
         task: tasks/tests/b2g_emulator_xpcshell_chunked.yml
new file mode 100644
--- /dev/null
+++ b/testing/taskcluster/tasks/builds/b2g_emulator_x86_kk_debug.yml
@@ -0,0 +1,30 @@
+$inherits:
+  from: 'tasks/builds/b2g_emulator_x86_base.yml'
+  variables:
+    build_name: 'emulator-x86-kk'
+    build_type: 'debug'
+task:
+  workerType: emulator-x86-kk
+  scopes:
+    - 'docker-worker:cache:workspace-emulator-kk-x86-debug'
+  metadata:
+    name: '[TC] B2G KK X86 Emulator (Debug)'
+
+  extra:
+    treeherderEnv:
+      - production
+      - staging
+    treeherder:
+      # Disable "TC" prefix...
+      groupSymbol: "?"
+      collection:
+        debug: true
+      machine:
+        platform: b2g-emu-x86-kk
+
+  payload:
+    cache:
+      workspace-emulator-kk-x86-debug: /home/worker/workspace
+    env:
+      TARGET: 'emulator-x86-kk'
+      B2G_DEBUG: 1
--- a/testing/taskcluster/tasks/builds/b2g_emulator_x86_kk_opt.yml
+++ b/testing/taskcluster/tasks/builds/b2g_emulator_x86_kk_opt.yml
@@ -7,16 +7,17 @@ task:
   workerType: emulator-x86-kk
   scopes:
     - 'docker-worker:cache:workspace-emulator-kk-x86-opt'
   metadata:
     name: '[TC] B2G KK X86 Emulator (Opt)'
 
   extra:
     treeherderEnv:
+      - production
       - staging
     treeherder:
       # Disable "TC" prefix...
       groupSymbol: "?"
       machine:
         platform: b2g-emu-x86-kk
 
   payload: