Merge m-c to m-i
authorPhil Ringnalda <philringnalda@gmail.com>
Sun, 09 Aug 2015 16:39:03 -0700
changeset 257038 c22589ab4e46415721619ee6b9cbe65bb4c72265
parent 257037 b41dbdb8e871cf8528571a16272b05fc6449bc82 (current diff)
parent 257018 0e269a1f1beb284a630f1a8ca92c05254333f6f1 (diff)
child 257039 2e4b173197e25cd1c6bb41a48c90ce84d4071af4
push idunknown
push userunknown
push dateunknown
milestone42.0a1
Merge m-c to m-i
browser/components/extensions/bootstrap.js
browser/components/extensions/prepare.py
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -10,25 +10,25 @@
   <!--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="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="3e5271663e7ef26290c29a45d2e42c0d3c20fe04"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
   <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="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <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="735805df70bc64af1e5b709133afb76499a92ee1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
   <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,25 +10,25 @@
   <!--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="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="3e5271663e7ef26290c29a45d2e42c0d3c20fe04"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
   <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="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <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="735805df70bc64af1e5b709133afb76499a92ee1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
   <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
--- 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="3e5271663e7ef26290c29a45d2e42c0d3c20fe04"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
   <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="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <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,20 +12,20 @@
   <!--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="3e5271663e7ef26290c29a45d2e42c0d3c20fe04"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="735805df70bc64af1e5b709133afb76499a92ee1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--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="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="3e5271663e7ef26290c29a45d2e42c0d3c20fe04"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
   <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="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <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="735805df70bc64af1e5b709133afb76499a92ee1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
   <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -10,25 +10,25 @@
   <!--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="3e5271663e7ef26290c29a45d2e42c0d3c20fe04"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
   <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="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <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="735805df70bc64af1e5b709133afb76499a92ee1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
   <!-- Stock Android things -->
   <project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" revision="8af5ff6f5dced9eb5a8127459df6c75d24342204"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" revision="30915518fa7ea07166efedc191a4f40aef516fe7"/>
   <project groups="pdk,linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6" revision="96eee58e3389fb05a835310d6a06a6ba4486097a"/>
   <project groups="pdk,linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" revision="7c8a46698171aa2e0be09edb43d15a6acf832770"/>
   <project groups="pdk,linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8" path="prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8" revision="24b2038be8a636fd4a5d21f0abae1e466b07bcf7"/>
--- 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="3e5271663e7ef26290c29a45d2e42c0d3c20fe04"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
   <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="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--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="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="3e5271663e7ef26290c29a45d2e42c0d3c20fe04"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
   <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="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <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="735805df70bc64af1e5b709133afb76499a92ee1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
   <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "3e5271663e7ef26290c29a45d2e42c0d3c20fe04", 
+        "git_revision": "09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "7051317f9ab92e5226b585127aa6b69f030bf759", 
+    "revision": "27c4198462ca807ccff1e51229a77830930eb182", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,20 +12,20 @@
   <!--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="3e5271663e7ef26290c29a45d2e42c0d3c20fe04"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="62cfa11ae7d77f6330de019a5aa79607e35be7d1"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="657894b4a1dc0a926117f4812e0940229f9f676f"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="735805df70bc64af1e5b709133afb76499a92ee1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
   <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"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -10,25 +10,25 @@
   <!--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="3e5271663e7ef26290c29a45d2e42c0d3c20fe04"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="09dea2d5ff21cdb56da35fe4aa5bf4c90cf1da7f"/>
   <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="657894b4a1dc0a926117f4812e0940229f9f676f"/>
   <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="735805df70bc64af1e5b709133afb76499a92ee1"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1eb9029d752b12c3bacb6399bd78c2c63dfdda3c"/>
   <!-- Stock Android things -->
   <project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" revision="8af5ff6f5dced9eb5a8127459df6c75d24342204"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" revision="30915518fa7ea07166efedc191a4f40aef516fe7"/>
   <project groups="pdk,linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6" revision="96eee58e3389fb05a835310d6a06a6ba4486097a"/>
   <project groups="pdk,linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" revision="7c8a46698171aa2e0be09edb43d15a6acf832770"/>
   <project groups="pdk,linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8" path="prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8" revision="24b2038be8a636fd4a5d21f0abae1e466b07bcf7"/>
--- a/browser/base/content/test/general/browser_datachoices_notification.js
+++ b/browser/base/content/test/general/browser_datachoices_notification.js
@@ -19,16 +19,29 @@ const PREF_BRANCH = "datareporting.polic
 const PREF_DRS_ENABLED = "datareporting.healthreport.service.enabled";
 const PREF_BYPASS_NOTIFICATION = PREF_BRANCH + "dataSubmissionPolicyBypassNotification";
 const PREF_CURRENT_POLICY_VERSION = PREF_BRANCH + "currentPolicyVersion";
 const PREF_ACCEPTED_POLICY_VERSION = PREF_BRANCH + "dataSubmissionPolicyAcceptedVersion";
 const PREF_ACCEPTED_POLICY_DATE = PREF_BRANCH + "dataSubmissionPolicyNotifiedTime";
 
 const TEST_POLICY_VERSION = 37;
 
+function fakeShowPolicyTimeout(set, clear) {
+  let reportingPolicy =
+    Cu.import("resource://gre/modules/TelemetryReportingPolicy.jsm", {}).Policy;
+  reportingPolicy.setShowInfobarTimeout = set;
+  reportingPolicy.clearShowInfobarTimeout = clear;
+}
+
+function sendSessionRestoredNotification() {
+  let reportingPolicyImpl =
+    Cu.import("resource://gre/modules/TelemetryReportingPolicy.jsm", {}).TelemetryReportingPolicyImpl;
+  reportingPolicyImpl.observe(null, "sessionstore-windows-restored", null);
+}
+
 /**
  * Wait for a tick.
  */
 function promiseNextTick() {
   return new Promise(resolve => executeSoon(resolve));
 }
 
 /**
@@ -51,16 +64,31 @@ function promiseWaitForAlertActive(aNoti
  * @return {Promise} Resolved when the notification is closed.
  */
 function promiseWaitForNotificationClose(aNotification) {
   let deferred = PromiseUtils.defer();
   waitForNotificationClose(aNotification, deferred.resolve);
   return deferred.promise;
 }
 
+function triggerInfoBar(expectedTimeoutMs) {
+  let showInfobarCallback = null;
+  let timeoutMs = null;
+  fakeShowPolicyTimeout((callback, timeout) => {
+    showInfobarCallback = callback;
+    timeoutMs = timeout;
+  }, () => {});
+  sendSessionRestoredNotification();
+  Assert.ok(!!showInfobarCallback, "Must have a timer callback.");
+  if (expectedTimeoutMs !== undefined) {
+    Assert.equal(timeoutMs, expectedTimeoutMs, "Timeout should match");
+  }
+  showInfobarCallback();
+}
+
 let checkInfobarButton = Task.async(function* (aNotification) {
   // Check that the button on the data choices infobar does the right thing.
   let buttons = aNotification.getElementsByTagName("button");
   Assert.equal(buttons.length, 1, "There is 1 button in the data reporting notification.");
   let button = buttons[0];
 
   // Add an observer to ensure the "advanced" pane opened (but don't bother
   // closing it - we close the entire window when done.)
@@ -125,21 +153,21 @@ add_task(function* test_single_window(){
   Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_VERSION, 0), 0,
                "No version should be set on init.");
   Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_DATE, 0), 0,
                "No date should be set on init.");
   Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(),
             "User not notified about datareporting policy.");
 
   let alertShownPromise = promiseWaitForAlertActive(notificationBox);
-  // This should be false and trigger the Infobar.
   Assert.ok(!TelemetryReportingPolicy.canUpload(),
-            "User should not be allowed to upload and the infobar should be triggered.");
+            "User should not be allowed to upload.");
 
   // Wait for the infobar to be displayed.
+  triggerInfoBar(10 * 1000);
   yield alertShownPromise;
 
   Assert.equal(notificationBox.allNotifications.length, 1, "Notification Displayed.");
   Assert.ok(TelemetryReportingPolicy.canUpload(), "User should be allowed to upload now.");
 
   yield promiseNextTick();
   let promiseClosed = promiseWaitForNotificationClose(notificationBox.currentNotification);
   yield checkInfobarButton(notificationBox.currentNotification);
@@ -180,20 +208,21 @@ add_task(function* test_multiple_windows
   Assert.equal(Preferences.get(PREF_ACCEPTED_POLICY_DATE, 0), 0, "No date should be set on init.");
   Assert.ok(!TelemetryReportingPolicy.testIsUserNotified(), "User not notified about datareporting policy.");
 
   let showAlertPromises = [
     promiseWaitForAlertActive(notificationBoxes[0]),
     promiseWaitForAlertActive(notificationBoxes[1])
   ];
 
-  // This should be false and trigger the Infobar.
   Assert.ok(!TelemetryReportingPolicy.canUpload(),
-            "User should not be allowed to upload and the infobar should be triggered.");
+            "User should not be allowed to upload.");
 
+  // Wait for the infobars.
+  triggerInfoBar(10 * 1000);
   yield Promise.all(showAlertPromises);
 
   // Both notification were displayed. Close one and check that both gets closed.
   let closeAlertPromises = [
     promiseWaitForNotificationClose(notificationBoxes[0].currentNotification),
     promiseWaitForNotificationClose(notificationBoxes[1].currentNotification)
   ];
   notificationBoxes[0].currentNotification.close();
--- a/browser/base/content/test/general/browser_urlbarSearchSuggestionsNotification.js
+++ b/browser/base/content/test/general/browser_urlbarSearchSuggestionsNotification.js
@@ -1,19 +1,22 @@
 const SUGGEST_ALL_PREF = "browser.search.suggest.enabled";
 const SUGGEST_URLBAR_PREF = "browser.urlbar.suggest.searches";
 const CHOICE_PREF = "browser.urlbar.userMadeSearchSuggestionsChoice";
 const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
 
 // Must run first.
 add_task(function* prepare() {
+  // The test makes only sense if unified complete is enabled.
+  Services.prefs.setBoolPref("browser.urlbar.unifiedcomplete", true);
   let engine = yield promiseNewSearchEngine(TEST_ENGINE_BASENAME);
   let oldCurrentEngine = Services.search.currentEngine;
   Services.search.currentEngine = engine;
   registerCleanupFunction(function () {
+    Services.prefs.clearUserPref("browser.urlbar.unifiedcomplete");
     Services.search.currentEngine = oldCurrentEngine;
     Services.prefs.clearUserPref(SUGGEST_ALL_PREF);
     Services.prefs.clearUserPref(SUGGEST_URLBAR_PREF);
 
     // Disable the notification for future tests so it doesn't interfere with
     // them.  clearUserPref() won't work because by default the pref is false.
     Services.prefs.setBoolPref(CHOICE_PREF, true);
 
deleted file mode 100644
--- a/browser/components/extensions/prepare.py
+++ /dev/null
@@ -1,83 +0,0 @@
-#!/usr/bin/env python
-# 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/.
-
-import argparse
-import json
-import uuid
-import sys
-import os.path
-
-parser = argparse.ArgumentParser(description='Create install.rdf from manifest.json')
-parser.add_argument('--locale')
-parser.add_argument('--profile')
-parser.add_argument('--uuid')
-parser.add_argument('dir')
-args = parser.parse_args()
-
-manifestFile = os.path.join(args.dir, 'manifest.json')
-manifest = json.load(open(manifestFile))
-
-locale = args.locale
-if not locale:
-    locale = manifest.get('default_locale', 'en-US')
-
-def process_locale(s):
-    if s.startswith('__MSG_') and s.endswith('__'):
-        tag = s[6:-2]
-        path = os.path.join(args.dir, '_locales', locale, 'messages.json')
-        data = json.load(open(path))
-        return data[tag]['message']
-    else:
-        return s
-
-id = args.uuid
-if not id:
-    id = '{' + str(uuid.uuid4()) + '}'
-
-name = process_locale(manifest['name'])
-desc = process_locale(manifest['description'])
-version = manifest['version']
-
-installFile = open(os.path.join(args.dir, 'install.rdf'), 'w')
-print >>installFile, '<?xml version="1.0"?>'
-print >>installFile, '<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"'
-print >>installFile, '     xmlns:em="http://www.mozilla.org/2004/em-rdf#">'
-print >>installFile
-print >>installFile, '  <Description about="urn:mozilla:install-manifest">'
-print >>installFile, '    <em:id>{}</em:id>'.format(id)
-print >>installFile, '    <em:type>2</em:type>'
-print >>installFile, '    <em:name>{}</em:name>'.format(name)
-print >>installFile, '    <em:description>{}</em:description>'.format(desc)
-print >>installFile, '    <em:version>{}</em:version>'.format(version)
-print >>installFile, '    <em:bootstrap>true</em:bootstrap>'
-
-print >>installFile, '    <em:targetApplication>'
-print >>installFile, '      <Description>'
-print >>installFile, '        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>'
-print >>installFile, '        <em:minVersion>4.0</em:minVersion>'
-print >>installFile, '        <em:maxVersion>50.0</em:maxVersion>'
-print >>installFile, '      </Description>'
-print >>installFile, '    </em:targetApplication>'
-
-print >>installFile, '  </Description>'
-print >>installFile, '</RDF>'
-installFile.close()
-
-bootstrapPath = os.path.join(os.path.dirname(sys.argv[0]), 'bootstrap.js')
-data = open(bootstrapPath).read()
-boot = open(os.path.join(args.dir, 'bootstrap.js'), 'w')
-boot.write(data)
-boot.close()
-
-if args.profile:
-    os.system('mkdir -p {}/extensions'.format(args.profile))
-    output = open(args.profile + '/extensions/' + id, 'w')
-    print >>output, os.path.realpath(args.dir)
-    output.close()
-else:
-    dir = os.path.realpath(args.dir)
-    if dir[-1] == os.sep:
-        dir = dir[:-1]
-    os.system('cd "{}"; zip ../"{}".xpi -r *'.format(args.dir, os.path.basename(dir)))
--- a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js
+++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.js
@@ -55,28 +55,16 @@ document.addEventListener("DOMContentLoa
                         .getService(Ci.nsIURLFormatter).formatURLPref;
   document.getElementById("startTour").setAttribute("href",
                      formatURLPref("privacy.trackingprotection.introURL"));
   document.getElementById("learnMore").setAttribute("href",
                      formatURLPref("app.support.baseURL") + "private-browsing");
 
   // Update state that depends on preferences.
   prefObserver.observe();
-
-  // This check can be removed when Tracking Protection is always available.
-  let tpUIEnabled = false;
-  try {
-    tpUIEnabled = Services.prefs.getBoolPref("privacy.trackingprotection.ui.enabled");
-  } catch (ex) {
-    // The preference is not available.
-  }
-  if (!tpUIEnabled) {
-    document.getElementById("trackingProtectionSection")
-            .setAttribute("hidden", "true");
-  }
 }, false);
 
 function openPrivateWindow() {
   // Ask chrome to open a private window
   document.dispatchEvent(
     new CustomEvent("AboutPrivateBrowsingOpenWindow", {bubbles:true}));
 }
 
--- a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml
+++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.xhtml
@@ -37,51 +37,51 @@
            style="width: &aboutPrivateBrowsing.width;">
         <div class="sectionHeader">&aboutPrivateBrowsing.title;</div>
         <p>&aboutPrivateBrowsing.subtitle;</p>
         <div id="list-area">
           <div>
             <div class="list-header">&aboutPrivateBrowsing.info.forgotten;</div>
             <ul id="forgotten">
               <li>&aboutPrivateBrowsing.info.history;</li>
-              <li>&aboutPrivateBrowsing.info.search;</li>
+              <li>&aboutPrivateBrowsing.info.searches;</li>
               <li>&aboutPrivateBrowsing.info.cookies;</li>
               <li>&aboutPrivateBrowsing.info.temporaryFiles;</li>
             </ul>
           </div>
           <div>
             <div class="list-header">&aboutPrivateBrowsing.info.kept;</div>
             <ul id="kept">
               <li>&aboutPrivateBrowsing.info.downloads;</li>
               <li>&aboutPrivateBrowsing.info.bookmarks;</li>
             </ul>
           </div>
         </div>
-        <p>&aboutPrivateBrowsing.note;</p>
+        <p>&aboutPrivateBrowsing.note1;</p>
         <a id="learnMore" target="_blank">&aboutPrivateBrowsing.learnMore;</a>
       </div>
       <div id="trackingProtectionSection"
            style="width: &trackingProtection.width;">
         <div class="sectionHeader">&trackingProtection.title;
           <span id="tpEnabled"
                 style="width: &trackingProtection.state.width;"
                 class="showTpEnabled">&trackingProtection.state.enabled;</span>
           <span id="tpDisabled"
                 style="width: &trackingProtection.state.width;"
                 class="showTpDisabled">&trackingProtection.state.disabled;</span>
         </div>
         <p id="tpDiagram"/>
-        <p>&trackingProtection.description;</p>
+        <p>&trackingProtection.description1;</p>
         <!-- Use text links to implement plain styled buttons without an href. -->
         <label xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
                id="disableTrackingProtection"
                class="text-link showTpEnabled"
                value="&trackingProtection.disable;"/>
         <label xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
                id="enableTrackingProtection"
                class="text-link showTpDisabled"
                value="&trackingProtection.enable;"/>
         <p id="tpStartTour"
-           class="showTpEnabled"><a id="startTour">&trackingProtection.startTour;</a></p>
+           class="showTpEnabled"><a id="startTour">&trackingProtection.startTour1;</a></p>
       </div>
     </div>
   </body>
 </html>
--- a/browser/components/privatebrowsing/test/browser/browser.ini
+++ b/browser/components/privatebrowsing/test/browser/browser.ini
@@ -12,16 +12,17 @@ support-files =
   browser_privatebrowsing_protocolhandler_page.html
   browser_privatebrowsing_windowtitle_page.html
   head.js
   popup.html
   title.sjs
 
 [browser_privatebrowsing_DownloadLastDirWithCPS.js]
 [browser_privatebrowsing_about.js]
+tags = trackingprotection
 [browser_privatebrowsing_aboutHomeButtonAfterWindowClose.js]
 [browser_privatebrowsing_aboutSessionRestore.js]
 [browser_privatebrowsing_cache.js]
 [browser_privatebrowsing_certexceptionsui.js]
 [browser_privatebrowsing_concurrent.js]
 [browser_privatebrowsing_cookieacceptdialog.js]
 [browser_privatebrowsing_crh.js]
 [browser_privatebrowsing_downloadLastDir.js]
--- a/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about.js
+++ b/browser/components/privatebrowsing/test/browser/browser_privatebrowsing_about.js
@@ -41,24 +41,22 @@ function* testLinkOpensUrl({ win, tab, e
      `Clicking ${elementId} opened ${expectedUrl} in the same tab.`);
 }
 
 /**
  * Tests the links in "about:privatebrowsing".
  */
 add_task(function* test_links() {
   // Use full version and change the remote URLs to prevent network access.
-  Services.prefs.setBoolPref("privacy.trackingprotection.ui.enabled", true);
   Services.prefs.setCharPref("app.support.baseURL", "https://example.com/");
   Services.prefs.setCharPref("privacy.trackingprotection.introURL",
                              "https://example.com/tour");
   registerCleanupFunction(function () {
     Services.prefs.clearUserPref("privacy.trackingprotection.introURL");
     Services.prefs.clearUserPref("app.support.baseURL");
-    Services.prefs.clearUserPref("privacy.trackingprotection.ui.enabled");
   });
 
   let { win, tab } = yield openAboutPrivateBrowsing();
 
   yield testLinkOpensTab({ win, tab,
     elementId: "learnMore",
     expectedUrl: "https://example.com/private-browsing",
   });
@@ -72,22 +70,20 @@ add_task(function* test_links() {
 });
 
 /**
  * Tests the action to disable and re-enable Tracking Protection in
  * "about:privatebrowsing".
  */
 add_task(function* test_toggleTrackingProtection() {
   // Use tour version but disable Tracking Protection.
-  Services.prefs.setBoolPref("privacy.trackingprotection.ui.enabled", true);
   Services.prefs.setBoolPref("privacy.trackingprotection.pbmode.enabled",
                              true);
   registerCleanupFunction(function () {
     Services.prefs.clearUserPref("privacy.trackingprotection.pbmode.enabled");
-    Services.prefs.clearUserPref("privacy.trackingprotection.ui.enabled");
   });
 
   let { win, tab } = yield openAboutPrivateBrowsing();
 
   // Set up the observer for the preference change before triggering the action.
   let prefBranch =
       Services.prefs.getBranch("privacy.trackingprotection.pbmode.");
   let waitForPrefChanged = () => new Promise(resolve => {
--- a/browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd
+++ b/browser/locales/en-US/chrome/browser/aboutPrivateBrowsing.dtd
@@ -7,45 +7,51 @@
 <!ENTITY privatebrowsingpage.openPrivateWindow.accesskey "P">
 
 <!ENTITY privateBrowsing.title                 "Private Browsing">
 
 <!-- LOCALIZATION NOTE (aboutPrivateBrowsing.width):
      Width of the Private Browsing section.
      -->
 <!ENTITY aboutPrivateBrowsing.width            "25em">
+
+<!-- LOCALIZATION NOTE (aboutPrivateBrowsing.subtitle,
+     aboutPrivateBrowsing.info.forgotten, aboutPrivateBrowsing.info.kept):
+     These strings will be replaced by aboutPrivateBrowsing.forgotten and
+     aboutPrivateBrowsing.kept when the new visual design lands (bug 1192625).
+     -->
 <!ENTITY aboutPrivateBrowsing.title            "You're browsing privately">
 <!ENTITY aboutPrivateBrowsing.subtitle         "In this window, &brandShortName; will not remember any history.">
 
 <!ENTITY aboutPrivateBrowsing.forgotten        "In this window, &brandShortName; will not remember:">
 <!ENTITY aboutPrivateBrowsing.info.forgotten   "Forgotten">
 <!ENTITY aboutPrivateBrowsing.info.history     "History">
-<!ENTITY aboutPrivateBrowsing.info.search      "Searches">
+<!ENTITY aboutPrivateBrowsing.info.searches    "Searches">
 <!ENTITY aboutPrivateBrowsing.info.cookies     "Cookies">
 <!ENTITY aboutPrivateBrowsing.info.temporaryFiles "Temporary Files">
 
 <!ENTITY aboutPrivateBrowsing.kept             "&brandShortName; will keep:">
 <!ENTITY aboutPrivateBrowsing.info.kept        "Kept">
 <!ENTITY aboutPrivateBrowsing.info.downloads   "Downloads">
 <!ENTITY aboutPrivateBrowsing.info.bookmarks   "Bookmarks">
 
-<!ENTITY aboutPrivateBrowsing.note             "Please note that your employer or Internet service provider can still track the pages you visit.">
+<!ENTITY aboutPrivateBrowsing.note1            "Please note that your employer or Internet service provider can still track the pages you visit.">
 <!ENTITY aboutPrivateBrowsing.learnMore        "Learn More.">
 
 <!-- LOCALIZATION NOTE (trackingProtection.width):
      Width of the Tracking Protection section. This should be enough to
      accommodate the title as well as the enabled or disabled indicator.
      -->
 <!ENTITY trackingProtection.width              "22em">
 <!ENTITY trackingProtection.title              "Tracking Protection">
 
 <!-- LOCALIZATION NOTE (trackingProtection.state.width):
      Width of the element representing the enabled or disabled indicator.
      -->
 <!ENTITY trackingProtection.state.width        "6ch">
 <!ENTITY trackingProtection.state.enabled      "ON">
 <!ENTITY trackingProtection.state.disabled     "OFF">
 
-<!ENTITY trackingProtection.description        "Private Windows now block parts of the page that may track your browsing activity.">
+<!ENTITY trackingProtection.description1       "Private Windows now block parts of the page that may track your browsing activity.">
 
 <!ENTITY trackingProtection.disable            "Turn Tracking Protection Off">
 <!ENTITY trackingProtection.enable             "Turn Tracking Protection On">
-<!ENTITY trackingProtection.startTour          "See how this works">
+<!ENTITY trackingProtection.startTour1         "See how this works">
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -82,17 +82,18 @@
   min-height: 0.1px;
   max-height: 0;
   transition: min-height 170ms ease-out, max-height 170ms ease-out, visibility 170ms linear;
 }
 
 #TabsToolbar:not([collapsed="true"]) + #nav-bar {
   border-top: 1px solid hsla(0,0%,0%,.3) !important;
   background-clip: padding-box;
-  margin-top: -1px; /* Move up into the TabsToolbar for the inner highlight at the top of the nav-bar */
+  /* Move up into the TabsToolbar for the inner highlight at the top of the nav-bar */
+  margin-top: calc(-1 * var(--navbar-tab-toolbar-highlight-overlap));
   /* Position the toolbar above the bottom of background tabs */
   position: relative;
   z-index: 1;
 }
 
 #nav-bar {
   background-image: linear-gradient(@toolbarHighlight@, transparent);
   box-shadow: 0 1px 0 @toolbarHighlight@ inset;
@@ -1563,17 +1564,17 @@ richlistitem[type~="action"][actiontype=
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down[notifybgtab] {
   background-color: Highlight;
   transition: none;
 }
 
 #TabsToolbar .toolbarbutton-1 {
-  margin-bottom: var(--tab-toolbar-navbar-overlap);
+  margin-bottom: var(--navbar-tab-toolbar-highlight-overlap);
 }
 
 #alltabs-button {
   list-style-image: url("chrome://browser/skin/tabbrowser/alltabs.png");
 }
 
 #TabsToolbar[brighttext] > #alltabs-button,
 #TabsToolbar[brighttext] > toolbarpaletteitem > #alltabs-button {
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -202,29 +202,29 @@ toolbarseparator {
 
 /* Draw the bottom border of the tabs toolbar when it's not using
    -moz-appearance: toolbar. */
 #main-window:-moz-any([sizemode="fullscreen"],[customize-entered]) #TabsToolbar:not([collapsed="true"]) + #nav-bar,
 #main-window:not([tabsintitlebar]) #TabsToolbar:not([collapsed="true"]) + #nav-bar,
 #TabsToolbar:not([collapsed="true"]) + #nav-bar:-moz-lwtheme {
   border-top: 1px solid hsla(0,0%,0%,.3);
   background-clip: padding-box;
-  margin-top: calc(-1 * var(--tab-toolbar-navbar-overlap));
+  margin-top: calc(-1 * var(--navbar-tab-toolbar-highlight-overlap));
   /* Position the toolbar above the bottom of background tabs */
   position: relative;
   z-index: 1;
 }
 
 /* Always draw a border on Yosemite to ensure the border is well-defined there
  * (the default border is too light). */
 @media (-moz-mac-yosemite-theme) {
   #main-window[tabsintitlebar] #TabsToolbar:not([collapsed="true"]) + #nav-bar:not(:-moz-lwtheme) {
     border-top: 1px solid hsla(0,0%,0%,.2);
     background-clip: padding-box;
-    margin-top: calc(-1 * var(--tab-toolbar-navbar-overlap));
+    margin-top: calc(-1 * var(--navbar-tab-toolbar-highlight-overlap));
     /* Position the toolbar above the bottom of background tabs */
     position: relative;
     z-index: 1;
   }
 }
 
 #nav-bar-customization-target {
   padding: 4px;
@@ -2842,17 +2842,17 @@ toolbarbutton.chevron > .toolbarbutton-m
 }
 
 #TabsToolbar .toolbarbutton-1:not([type="menu-button"]),
 #TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   padding: 0 1px;
 }
 
 #TabsToolbar .toolbarbutton-1 {
-  margin-bottom: var(--tab-toolbar-navbar-overlap);
+  margin-bottom: var(--navbar-tab-toolbar-highlight-overlap);
 }
 
 #TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker {
   padding-left: 4px;
   padding-right: 4px;
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled]):hover,
--- a/browser/themes/shared/devedition.inc.css
+++ b/browser/themes/shared/devedition.inc.css
@@ -3,16 +3,17 @@
 % file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 /* devedition.css is loaded in browser.xul after browser.css when it is
    preffed on.  The bulk of the styling is here in the shared file, but
    there are overrides for each platform in their devedition.css files. */
 
 :root {
   --tab-toolbar-navbar-overlap: 0px;
+  --navbar-tab-toolbar-highlight-overlap: 0px;
   --space-above-tabbar: 0px;
   --toolbarbutton-text-shadow: none;
   --backbutton-urlbar-overlap: 0px;
 }
 
 :root[devtoolstheme="dark"] {
   /* Chrome */
   --chrome-background-color: #1C2126;
@@ -305,21 +306,16 @@ searchbar:not([oneoffui]) .search-go-but
 }
 
 .tabbrowser-arrowscrollbox > .scrollbutton-down,
 .tabbrowser-arrowscrollbox > .scrollbutton-up {
   background-color: var(--tab-background-color);
   border-color: transparent;
 }
 
-.tabbrowser-arrowscrollbox > .arrowscrollbox-overflow-start-indicator:not([collapsed]),
-.tabbrowser-arrowscrollbox > .arrowscrollbox-overflow-end-indicator:not([collapsed]) {
-  margin-bottom: 0;
-}
-
 .tabbrowser-tab {
   /* We normally rely on other tab elements for pointer events, but this
      theme hides those so we need it set here instead */
   pointer-events: auto;
 }
 
 .tabbrowser-tab[pinned][titlechanged]:not([visuallyselected="true"]) > .tab-stack > .tab-content {
   background-image: var(--pinned-tab-glow);
--- a/browser/themes/shared/tabs.inc.css
+++ b/browser/themes/shared/tabs.inc.css
@@ -1,16 +1,17 @@
 %if 0
 /* 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/. */
 %endif
 
 :root {
   --tab-toolbar-navbar-overlap: 1px;
+  --navbar-tab-toolbar-highlight-overlap: 1px;
   --tab-min-height: 31px;
 }
 #TabsToolbar {
   --tab-separator-image: url(chrome://browser/skin/tabbrowser/tab-separator.png);
   --tab-separator-size: 3px 100%;
   --tab-separator-opacity: 1;
   --tab-stroke-background-size: auto 100%;
 }
@@ -258,17 +259,17 @@
 }
 
 /* Tab Overflow */
 .tabbrowser-arrowscrollbox > .arrowscrollbox-overflow-start-indicator:not([collapsed]),
 .tabbrowser-arrowscrollbox > .arrowscrollbox-overflow-end-indicator:not([collapsed]) {
   background-image: url(chrome://browser/skin/tabbrowser/tab-overflow-indicator.png);
   background-size: 100% 100%;
   width: 14px;
-  margin-bottom: var(--tab-toolbar-navbar-overlap);
+  margin-bottom: var(--navbar-tab-toolbar-highlight-overlap);
   pointer-events: none;
   position: relative;
   z-index: 3; /* the selected tab's z-index + 1 */
 }
 
 .tabbrowser-arrowscrollbox > .arrowscrollbox-overflow-start-indicator:-moz-locale-dir(rtl),
 .tabbrowser-arrowscrollbox > .arrowscrollbox-overflow-end-indicator:-moz-locale-dir(ltr) {
   transform: scaleX(-1);
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -303,17 +303,18 @@
         rgb(207, 214, 188) 0, rgb(207, 214, 188) 1px,
         rgb(224, 226, 200) 1px, rgb(224, 226, 200) 2px,
         rgb(214, 216, 190) 2px, rgb(214, 216, 190) 3px,
         transparent 3px);
   }
 }
 
 #TabsToolbar:not([collapsed="true"]) + #nav-bar {
-  margin-top: -1px; /* Move up into the TabsToolbar for the inner highlight at the top of the nav-bar */
+  /* Move up into the TabsToolbar for the inner highlight at the top of the nav-bar */
+  margin-top: calc(-1 * var(--navbar-tab-toolbar-highlight-overlap));
   /* Position the toolbar above the bottom of background tabs */
   position: relative;
   z-index: 1;
 }
 
 #nav-bar {
   background-clip: padding-box;
   background-image: linear-gradient(@toolbarHighlight@, transparent);
@@ -923,17 +924,17 @@ toolbarbutton[constrain-size="true"][cui
 .tabbrowser-arrowscrollbox > .scrollbutton-up,
 .tabbrowser-arrowscrollbox > .scrollbutton-down {
   -moz-appearance: none;
   border-style: none;
   padding: 0 3px;
 }
 
 #TabsToolbar .toolbarbutton-1 {
-  margin-bottom: var(--tab-toolbar-navbar-overlap);
+  margin-bottom: var(--navbar-tab-toolbar-highlight-overlap);
 }
 
 #TabsToolbar .toolbarbutton-1:not([disabled=true]):hover,
 #TabsToolbar .toolbarbutton-1[open],
 #TabsToolbar .toolbarbutton-1 > .toolbarbutton-menubutton-button:not([disabled=true]):hover,
 .tabbrowser-arrowscrollbox > .scrollbutton-up:not([disabled=true]):hover,
 .tabbrowser-arrowscrollbox > .scrollbutton-down:not([disabled=true]):hover {
   background-image: linear-gradient(transparent, rgba(255,255,255,.5)),
--- a/dom/push/PushService.jsm
+++ b/dom/push/PushService.jsm
@@ -1,17 +1,17 @@
 /* jshint moz: true, esnext: true */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // Don't modify this, instead set dom.push.debug.
-let gDebuggingEnabled = true;
+let gDebuggingEnabled = false;
 
 function debug(s) {
   if (gDebuggingEnabled) {
     dump("-*- PushService.jsm: " + s + "\n");
   }
 }
 
 const Cc = Components.classes;
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -208,16 +208,19 @@ class RefTest(object):
 
         # Ensure that telemetry is disabled, so we don't connect to the telemetry
         # server in the middle of the tests.
         prefs['toolkit.telemetry.enabled'] = False
         prefs['toolkit.telemetry.unified'] = False
         # Likewise for safebrowsing.
         prefs['browser.safebrowsing.enabled'] = False
         prefs['browser.safebrowsing.malware.enabled'] = False
+        # Likewise for tracking protection.
+        prefs['privacy.trackingprotection.enabled'] = False
+        prefs['privacy.trackingprotection.pbmode.enabled'] = False
         # And for snippets.
         prefs['browser.snippets.enabled'] = False
         prefs['browser.snippets.syncPromo.enabled'] = False
         prefs['browser.snippets.firstrunHomepage.enabled'] = False
         # And for useragent updates.
         prefs['general.useragent.updates.enabled'] = False
         # And for webapp updates.  Yes, it is supposed to be an integer.
         prefs['browser.webapps.checkForUpdates'] = 0
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -3964,11 +3964,14 @@ public class BrowserApp extends GeckoApp
     }
 
     @Override
     protected StartupAction getStartupAction(final String passedURL) {
         final boolean inGuestMode = GeckoProfile.get(this).inGuestMode();
         if (inGuestMode) {
             return StartupAction.GUEST;
         }
+        if (RestrictedProfiles.isRestrictedProfile(this)) {
+            return StartupAction.RESTRICTED;
+        }
         return (passedURL == null ? StartupAction.NORMAL : StartupAction.URL);
     }
 }
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -132,17 +132,18 @@ public abstract class GeckoApp
     private static final String LOGTAG = "GeckoApp";
     private static final int ONE_DAY_MS = 1000*60*60*24;
 
     public static enum StartupAction {
         NORMAL,     /* normal application start */
         URL,        /* launched with a passed URL */
         PREFETCH,   /* launched with a passed URL that we prefetch */
         WEBAPP,     /* launched as a webapp runtime */
-        GUEST       /* launched in guest browsing */
+        GUEST,      /* launched in guest browsing */
+        RESTRICTED  /* launched with restricted profile */
     }
 
     public static final String ACTION_ALERT_CALLBACK       = "org.mozilla.gecko.ACTION_ALERT_CALLBACK";
     public static final String ACTION_HOMESCREEN_SHORTCUT  = "org.mozilla.gecko.BOOKMARK";
     public static final String ACTION_DEBUG                = "org.mozilla.gecko.DEBUG";
     public static final String ACTION_LAUNCH_SETTINGS      = "org.mozilla.gecko.SETTINGS";
     public static final String ACTION_LOAD                 = "org.mozilla.gecko.LOAD";
     public static final String ACTION_INIT_PW              = "org.mozilla.gecko.INIT_PW";
--- a/mobile/android/base/home/HomeConfigPrefsBackend.java
+++ b/mobile/android/base/home/HomeConfigPrefsBackend.java
@@ -69,34 +69,25 @@ class HomeConfigPrefsBackend implements 
 
     private State loadDefaultConfig() {
         final ArrayList<PanelConfig> panelConfigs = new ArrayList<PanelConfig>();
 
         panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.TOP_SITES,
                                                   EnumSet.of(PanelConfig.Flags.DEFAULT_PANEL)));
 
         panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.BOOKMARKS));
-        panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.READING_LIST));
-
-        final PanelConfig historyEntry = createBuiltinPanelConfig(mContext, PanelType.HISTORY);
-        final PanelConfig recentTabsEntry = createBuiltinPanelConfig(mContext, PanelType.RECENT_TABS);
+        panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.HISTORY));
 
-        // We disable Synced Tabs for guest mode profiles.
-        final PanelConfig remoteTabsEntry;
+        // We disable Synced Tabs for guest mode / restricted profiles.
         if (RestrictedProfiles.isAllowed(mContext, Restriction.DISALLOW_MODIFY_ACCOUNTS)) {
-            remoteTabsEntry = createBuiltinPanelConfig(mContext, PanelType.REMOTE_TABS);
-        } else {
-            remoteTabsEntry = null;
+            panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.REMOTE_TABS));
         }
 
-        panelConfigs.add(historyEntry);
-        panelConfigs.add(recentTabsEntry);
-        if (remoteTabsEntry != null) {
-            panelConfigs.add(remoteTabsEntry);
-        }
+        panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.RECENT_TABS));
+        panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.READING_LIST));
 
         return new State(panelConfigs, true);
     }
 
     /**
      * Iterate through the panels to check if they are all disabled.
      */
     private static boolean allPanelsAreDisabled(JSONArray jsonPanels) throws JSONException {
--- a/mobile/android/tests/browser/robocop/components/AboutHomeComponent.java
+++ b/mobile/android/tests/browser/robocop/components/AboutHomeComponent.java
@@ -29,20 +29,20 @@ import com.jayway.android.robotium.solo.
  * A class representing any interactions that take place on the Awesomescreen.
  */
 public class AboutHomeComponent extends BaseComponent {
     private static final String LOGTAG = AboutHomeComponent.class.getSimpleName();
 
     private static final List<PanelType> PANEL_ORDERING = Arrays.asList(
             PanelType.TOP_SITES,
             PanelType.BOOKMARKS,
-            PanelType.READING_LIST,
             PanelType.HISTORY,
+            PanelType.REMOTE_TABS,
             PanelType.RECENT_TABS,
-            PanelType.REMOTE_TABS
+            PanelType.READING_LIST
     );
 
     // The percentage of the panel to swipe between 0 and 1. This value was set through
     // testing: 0.55f was tested on try and fails on armv6 devices.
     private static final float SWIPE_PERCENTAGE = 0.70f;
 
     public AboutHomeComponent(final UITestContext testContext) {
         super(testContext);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -1082,17 +1082,17 @@ pref("content.sink.pending_event_mode", 
 //   2 = openAbused
 pref("privacy.popups.disable_from_plugins", 2);
 
 // send "do not track" HTTP header, disabled by default
 pref("privacy.donottrackheader.enabled",    false);
 // Enforce tracking protection in all modes
 pref("privacy.trackingprotection.enabled",  false);
 // Enforce tracking protection in Private Browsing mode
-pref("privacy.trackingprotection.pbmode.enabled",  false);
+pref("privacy.trackingprotection.pbmode.enabled",  true);
 
 pref("dom.event.contextmenu.enabled",       true);
 pref("dom.event.clipboardevents.enabled",   true);
 #if defined(XP_WIN) && !defined(RELEASE_BUILD)
 pref("dom.event.highrestimestamp.enabled",  true);
 #else
 pref("dom.event.highrestimestamp.enabled",  false);
 #endif
--- a/testing/talos/talos.json
+++ b/testing/talos/talos.json
@@ -1,16 +1,16 @@
 {
     "talos.zip": {
         "url": "http://talos-bundles.pvt.build.mozilla.org/zips/talos.a6052c33d420.zip",
         "path": ""
     },
     "global": {
         "talos_repo": "https://hg.mozilla.org/build/talos",
-        "talos_revision": "d44548b8feb9"
+        "talos_revision": "c7446ecc3bfb"
     },
     "extra_options": {
         "android": [ "--apkPath=%(apk_path)s" ]
     },
     "suites": {
         "chromez": {
             "tests": ["tresize", "tcanvasmark"]
         },
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -136,16 +136,20 @@ let Management = {
     this.emitter.on(hook, callback);
   },
 
   // Ask to run all the callbacks that are registered for a given hook.
   emit(hook, ...args) {
     this.lazyInit();
     this.emitter.emit(hook, ...args);
   },
+
+  off(hook, callback) {
+    this.emitter.off(hook, callback);
+  }
 };
 
 // A MessageBroker that's used to send and receive messages for
 // extension pages (which run in the chrome process).
 let globalBroker = new MessageBroker([Services.mm, Services.ppmm]);
 
 // An extension page is an execution context for any extension content
 // that runs in the chrome process. It's used for background pages
@@ -524,23 +528,23 @@ Extension.prototype = {
     this.onShutdown.add(obj);
   },
 
   forgetOnClose(obj) {
     this.onShutdown.delete(obj);
   },
 
   startup() {
-    GlobalManager.init(this);
-
     return Promise.all([this.readManifest(), this.readLocaleMessages()]).then(([manifest, messages]) => {
       if (this.hasShutdown) {
         return;
       }
 
+      GlobalManager.init(this);
+
       this.manifest = manifest;
       this.localeMessages = messages;
 
       Management.emit("startup", this);
 
       this.runManifest(manifest);
     }).catch(e => {
       dump(`Extension error: ${e} ${e.fileName}:${e.lineNumber}\n`);
--- a/toolkit/components/telemetry/TelemetryReportingPolicy.jsm
+++ b/toolkit/components/telemetry/TelemetryReportingPolicy.jsm
@@ -332,57 +332,57 @@ let TelemetryReportingPolicyImpl = {
    */
   canUpload: function() {
     // If data submission is disabled, there's no point in showing the infobar. Just
     // forbid to upload.
     if (!this.dataSubmissionEnabled) {
       return false;
     }
 
-    // Make sure the user is notified of the current policy. If he isn't, don't try
-    // to upload anything.
-    if (!this._ensureUserNotified()) {
-      return false;
-    }
-
-    // Submission is enabled and user is notified: upload is allowed.
-    return true;
+    // Submission is enabled. We enable upload if user is notified or we need to bypass
+    // the policy.
+    const bypassNotification = Preferences.get(PREF_BYPASS_NOTIFICATION, false);
+    return this.isUserNotifiedOfCurrentPolicy || bypassNotification;
   },
 
   /**
    * Migrate the data policy preferences, if needed.
    */
   _migratePreferences: function() {
     // Current prefs are mostly the same than the old ones, except for some deprecated ones.
     for (let pref of DEPRECATED_FHR_PREFS) {
       Preferences.reset(pref);
     }
   },
 
   /**
-   * Make sure the user is notified about the policy before allowing upload.
-   * @return {Boolean} True if the user was notified, false otherwise.
+   * Show the data choices infobar if the user wasn't already notified and data submission
+   * is enabled.
    */
-  _ensureUserNotified: function() {
-    const BYPASS_NOTIFICATION = Preferences.get(PREF_BYPASS_NOTIFICATION, false);
-    if (this.isUserNotifiedOfCurrentPolicy || BYPASS_NOTIFICATION) {
-      return true;
+  _showInfobar: function() {
+    if (!this.dataSubmissionEnabled) {
+      this._log.trace("_showInfobar - Data submission disabled by the policy.");
+      return;
     }
 
-    this._log.trace("ensureUserNotified - User not notified, notifying now.");
-    if (this._notificationInProgress) {
-      this._log.trace("ensureUserNotified - User not notified, notification in progress.");
-      return false;
+    const bypassNotification = Preferences.get(PREF_BYPASS_NOTIFICATION, false);
+    if (this.isUserNotifiedOfCurrentPolicy || bypassNotification) {
+      this._log.trace("_showInfobar - User already notified or bypassing the policy.");
+      return;
     }
 
+    if (this._notificationInProgress) {
+      this._log.trace("_showInfobar - User not notified, notification already in progress.");
+      return;
+    }
+
+    this._log.trace("_showInfobar - User not notified, notifying now.");
     this._notificationInProgress = true;
     let request = new NotifyPolicyRequest(this._log);
     Observers.notify("datareporting:notify-data-policy:request", request);
-
-    return false;
   },
 
   /**
    * Called when the user is notified with the infobar.
    */
   _infobarShownCallback: function() {
     this._log.trace("_infobarShownCallback");
     this._recordNotificationData();
@@ -407,13 +407,13 @@ let TelemetryReportingPolicyImpl = {
     }
 
     const isFirstRun = Preferences.get(PREF_FIRST_RUN, true);
     const delay =
       isFirstRun ? NOTIFICATION_DELAY_FIRST_RUN_MSEC: NOTIFICATION_DELAY_NEXT_RUNS_MSEC;
 
     this._startupNotificationTimerId = Policy.setShowInfobarTimeout(
         // Calling |canUpload| eventually shows the infobar, if needed.
-        () => this.canUpload(), delay);
+        () => this._showInfobar(), delay);
     // We performed at least a run, flip the firstRun preference.
     Preferences.set(PREF_FIRST_RUN, false);
   },
 };
--- a/toolkit/components/telemetry/TelemetrySend.jsm
+++ b/toolkit/components/telemetry/TelemetrySend.jsm
@@ -108,16 +108,30 @@ function isV4PingFormat(aPing) {
  * Check if the provided ping is a deletion ping.
  * @param {Object} aPing The ping to check.
  * @return {Boolean} True if the ping is a deletion ping, false otherwise.
  */
 function isDeletionPing(aPing) {
   return isV4PingFormat(aPing) && (aPing.type == PING_TYPE_DELETION);
 }
 
+/**
+ * Save the provided ping as a pending ping. If it's a deletion ping, save it
+ * to a special location.
+ * @param {Object} aPing The ping to save.
+ * @return {Promise} A promise resolved when the ping is saved.
+ */
+function savePing(aPing) {
+  if (isDeletionPing(aPing)) {
+    return TelemetryStorage.saveDeletionPing(aPing);
+  } else {
+    return TelemetryStorage.savePendingPing(aPing);
+  }
+}
+
 function tomorrow(date) {
   let d = new Date(date);
   d.setDate(d.getDate() + 1);
   return d;
 }
 
 /**
  * @return {String} This returns a string with the gzip compressed data.
@@ -668,17 +682,17 @@ let TelemetrySendImpl = {
       this._log.trace("submitPing - Telemetry is not allowed to send pings.");
       return Promise.resolve();
     }
 
     if (!this.canSendNow) {
       // Sending is disabled or throttled, add this to the persisted pending pings.
       this._log.trace("submitPing - can't send ping now, persisting to disk - " +
                       "canSendNow: " + this.canSendNow);
-      return TelemetryStorage.savePendingPing(ping);
+      return savePing(ping);
     }
 
     // Let the scheduler trigger sending pings if possible.
     // As a safety mechanism, this resets any currently active throttling.
     this._log.trace("submitPing - can send pings, trying to send now");
     this._currentPings.set(ping.id, ping);
     SendScheduler.triggerSendingPings(true);
     return Promise.resolve();
@@ -711,21 +725,17 @@ let TelemetrySendImpl = {
     for (let current of currentPings) {
       let ping = current;
       let p = Task.spawn(function*() {
         try {
           yield this._doPing(ping, ping.id, false);
         } catch (ex) {
           this._log.info("sendPings - ping " + ping.id + " not sent, saving to disk", ex);
           // Deletion pings must be saved to a special location.
-          if (isDeletionPing(ping)) {
-            yield TelemetryStorage.saveDeletionPing(ping);
-          } else {
-            yield TelemetryStorage.savePendingPing(ping);
-          }
+          yield savePing(ping);
         } finally {
           this._currentPings.delete(ping.id);
         }
       }.bind(this));
 
       this._trackPendingPingTask(p);
       pingSends.push(p);
     }
@@ -1017,17 +1027,17 @@ let TelemetrySendImpl = {
     })];
     p.push(SendScheduler.waitOnSendTask());
     return Promise.all(p);
   },
 
   _persistCurrentPings: Task.async(function*() {
     for (let [id, ping] of this._currentPings) {
       try {
-        yield TelemetryStorage.savePendingPing(ping);
+        yield savePing(ping);
         this._log.trace("_persistCurrentPings - saved ping " + id);
       } catch (ex) {
         this._log.error("_persistCurrentPings - failed to save ping " + id, ex);
       } finally {
         this._currentPings.delete(id);
       }
     }
   }),
--- a/toolkit/devtools/server/tests/mochitest/chrome.ini
+++ b/toolkit/devtools/server/tests/mochitest/chrome.ini
@@ -42,16 +42,18 @@ skip-if = buildapp == 'mulet'
 [test_framerate_02.html]
 skip-if = buildapp == 'mulet'
 [test_framerate_03.html]
 skip-if = buildapp == 'mulet'
 [test_framerate_04.html]
 skip-if = buildapp == 'mulet'
 [test_framerate_05.html]
 skip-if = buildapp == 'mulet'
+[test_framerate_06.html]
+skip-if = buildapp == 'mulet'
 [test_getProcess.html]
 skip-if = buildapp == 'mulet'
 [test_inspector-anonymous.html]
 [test_inspector-changeattrs.html]
 [test_inspector-changevalue.html]
 [test_inspector-dead-nodes.html]
 [test_inspector_getImageData.html]
 skip-if = buildapp == 'mulet'
new file mode 100644
--- /dev/null
+++ b/toolkit/devtools/server/tests/mochitest/test_framerate_06.html
@@ -0,0 +1,82 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Bug 1171489 - Tests if the framerate actor does not record timestamps from multiple frames. 
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Framerate actor test</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="application/javascript;version=1.8" src="inspector-helpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script>
+
+window.onload = function() {
+  SimpleTest.waitForExplicitFinish();
+  var {FramerateFront} = require("devtools/server/actors/framerate");
+  var {TargetFactory} = require("devtools/framework/target");
+
+  var url = document.getElementById("testContent").href;
+  attachURL(url, onTab);
+
+  function onTab(_, client, form, contentDoc) {
+    var contentWin = contentDoc.defaultView;
+    var chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
+    var selectedTab = chromeWin.gBrowser.selectedTab;
+
+    var target = TargetFactory.forTab(selectedTab);
+    var front = FramerateFront(client, form);
+
+    front.startRecording().then(() => {
+      window.setTimeout(() => {
+        // Wait for the iframe to be loaded again
+        window.addEventListener("message", function loaded (event) {
+          if (event.data === "ready") {
+            window.removeEventListener("message", loaded);
+            window.setTimeout(() => {
+              front.stopRecording().then(ticks => {
+                onRecordingStopped(client, ticks);
+              });
+            }, 1000);
+          }
+        });
+        contentWin.location.reload();
+      }, 1000);
+    });
+  }
+
+  function onRecordingStopped(client, ticks) {
+    var diffs = [];
+
+    info(`Got ${ticks.length} ticks.`);
+
+    for (var i = 1; i < ticks.length; i++) {
+      var prev = ticks[i - 1];
+      var curr = ticks[i];
+      diffs.push(curr - prev);
+      info(curr + " - " + (curr - prev));
+    }
+
+    // 1000 / 60 => 16.666... so we shouldn't get more than diffs of 16.66.. but
+    // when we get ticks from other frames they're usually at diffs of < 1. Sometimes
+    // ticks can still be less than 16ms even on one frame (usually following a very slow
+    // frame), so use a low number (2) to be our threshold
+    var THRESHOLD = 2;
+    ok(ticks.length >= 60, "we should have 2 seconds worth of ticks, atleast 60 ticks");
+    var belowThreshold = diffs.filter(v => v <= THRESHOLD);
+    ok(belowThreshold.length <= 10, "we should have very few frames less than the threshold");
+
+    client.close(() => {
+      DebuggerServer.destroy();
+      SimpleTest.finish()
+    });
+  }
+}
+</script>
+</pre>
+<a id="testContent" target="_blank" href="inspector-traversal-data.html">Test Document</a>
+</body>
+</html>
--- a/toolkit/devtools/shared/framerate.js
+++ b/toolkit/devtools/shared/framerate.js
@@ -87,12 +87,13 @@ let Framerate = exports.Framerate = Clas
     this._ticks.push(this.tabActor.docShell.now() - this._startTime);
   },
 
   /**
    * When the content window for the tab actor is created.
    */
   _onGlobalCreated: function (win) {
     if (this._recording) {
+      this._contentWin.cancelAnimationFrame(this._rafID);
       this._rafID = this._contentWin.requestAnimationFrame(this._onRefreshDriverTick);
     }
   }
 });
--- a/toolkit/locales/en-US/chrome/passwordmgr/passwordManager.dtd
+++ b/toolkit/locales/en-US/chrome/passwordmgr/passwordManager.dtd
@@ -17,16 +17,19 @@
 <!ENTITY      treehead.timePasswordChanged.label "Last Changed">
 <!ENTITY      treehead.timesUsed.label           "Times Used">
 
 <!ENTITY      remove.label                    "Remove">
 <!ENTITY      remove.accesskey                "R">
 <!ENTITY      removeall.label                 "Remove All">
 <!ENTITY      removeall.accesskey             "A">
 
+<!ENTITY      addLogin.label                  "Add Login">
+<!ENTITY      addLogin.accesskey              "L">
+
 <!ENTITY      import.label                    "Import…">
 <!ENTITY      import.accesskey                "I">
 
 <!ENTITY      filter.label                    "Search:">
 <!ENTITY      filter.accesskey                "S">
 
 <!ENTITY      windowClose.key                 "w">
 <!ENTITY      focusSearch1.key                "f">
--- a/toolkit/locales/en-US/chrome/passwordmgr/passwordmgr.properties
+++ b/toolkit/locales/en-US/chrome/passwordmgr/passwordmgr.properties
@@ -49,17 +49,21 @@ notifyBarDontChangeButtonAccessKey = D
 userSelectText = Please confirm which user you are changing the password for
 hidePasswords=Hide Passwords
 hidePasswordsAccessKey=P
 showPasswords=Show Passwords
 showPasswordsAccessKey=P
 noMasterPasswordPrompt=Are you sure you wish to show your passwords?
 removeAllPasswordsPrompt=Are you sure you wish to remove all passwords?
 removeAllPasswordsTitle=Remove all passwords
+removeLoginPrompt=Are you sure you wish to remove this login?
+removeLoginTitle=Remove login
 loginsSpielAll=Passwords for the following sites are stored on your computer:
 loginsSpielFiltered=The following passwords match your search:
 # LOCALIZATION NOTE (loginHostAge):
 # This is used to show the context menu login items with their age.
 # 1st string is the username for the login, 2nd is the login's age.
 loginHostAge=%1$S (%2$S)
 # LOCALIZATION NOTE (noUsername):
 # String is used on the context menu when a login doesn't have a username.
 noUsername=No username
+duplicateLoginTitle=Login already exists
+duplicateLogin=A duplicate login already exists.
rename from browser/components/extensions/bootstrap.js
rename to toolkit/mozapps/extensions/internal/WebExtensionBootstrap.js
--- a/browser/components/extensions/bootstrap.js
+++ b/toolkit/mozapps/extensions/internal/WebExtensionBootstrap.js
@@ -3,18 +3,26 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 Components.utils.import("resource://gre/modules/Extension.jsm");
 
 let extension;
 
+function install(data, reason)
+{
+}
+
 function startup(data, reason)
 {
   extension = new Extension(data);
   extension.startup();
 }
 
 function shutdown(data, reason)
 {
   extension.shutdown();
 }
+
+function uninstall(data, reason)
+{
+}
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -116,17 +116,18 @@ const URI_EXTENSION_STRINGS           = 
 const STRING_TYPE_NAME                = "type.%ID%.name";
 
 const DIR_EXTENSIONS                  = "extensions";
 const DIR_STAGE                       = "staged";
 const DIR_TRASH                       = "trash";
 
 const FILE_DATABASE                   = "extensions.json";
 const FILE_OLD_CACHE                  = "extensions.cache";
-const FILE_INSTALL_MANIFEST           = "install.rdf";
+const FILE_RDF_MANIFEST               = "install.rdf";
+const FILE_WEB_MANIFEST               = "manifest.json";
 const FILE_XPI_ADDONS_LIST            = "extensions.ini";
 
 const KEY_PROFILEDIR                  = "ProfD";
 const KEY_APPDIR                      = "XCurProcD";
 const KEY_TEMPDIR                     = "TmpD";
 const KEY_APP_DISTRIBUTION            = "XREAppDist";
 
 const KEY_APP_PROFILE                 = "app-profile";
@@ -197,23 +198,31 @@ const TYPES = {
   extension: 2,
   theme: 4,
   locale: 8,
   multipackage: 32,
   dictionary: 64,
   experiment: 128,
 };
 
+// Some add-on types that we track internally are presented as other types
+// externally
+const TYPE_ALIASES = {
+  "webextension": "extension",
+};
+
 const RESTARTLESS_TYPES = new Set([
+  "webextension",
   "dictionary",
   "experiment",
   "locale",
 ]);
 
 const SIGNED_TYPES = new Set([
+  "webextension",
   "extension",
   "experiment",
 ]);
 
 // Whether add-on signing is required.
 function mustSign(aType) {
   if (!SIGNED_TYPES.has(aType))
     return false;
@@ -637,16 +646,75 @@ function createAddonDetails(id, aAddon) 
     id: id || aAddon.id,
     type: aAddon.type,
     version: aAddon.version,
     multiprocessCompatible: aAddon.multiprocessCompatible
   };
 }
 
 /**
+ * Converts an internal add-on type to the type presented through the API.
+ *
+ * @param  aType
+ *         The internal add-on type
+ * @return an external add-on type
+ */
+function getExternalType(aType) {
+  if (aType in TYPE_ALIASES)
+    return TYPE_ALIASES[aType];
+  return aType;
+}
+
+function getManifestFileForDir(aDir) {
+  let file = aDir.clone();
+  file.append(FILE_WEB_MANIFEST);
+  if (file.exists() && file.isFile())
+    return file;
+  file.leafName = FILE_RDF_MANIFEST;
+  if (file.exists() && file.isFile())
+    return file;
+  return null;
+}
+
+function getManifestEntryForZipReader(aZipReader) {
+  if (aZipReader.hasEntry(FILE_WEB_MANIFEST))
+    return FILE_WEB_MANIFEST;
+  if (aZipReader.hasEntry(FILE_RDF_MANIFEST))
+    return FILE_RDF_MANIFEST;
+  return null;
+}
+
+/**
+ * Converts a list of API types to a list of API types and any aliases for those
+ * types.
+ *
+ * @param  aTypes
+ *         An array of types or null for all types
+ * @return an array of types or null for all types
+ */
+function getAllAliasesForTypes(aTypes) {
+  if (!aTypes)
+    return null;
+
+  // Build a set of all requested types and their aliases
+  let typeset = new Set(aTypes);
+
+  for (let alias of Object.keys(TYPE_ALIASES)) {
+    // Ignore any requested internal types
+    typeset.delete(alias);
+
+    // Add any alias for the internal type
+    if (typeset.has(TYPE_ALIASES[alias]))
+      typeset.add(alias);
+  }
+
+  return [...typeset];
+}
+
+/**
  * Converts an RDF literal, resource or integer into a string.
  *
  * @param  aLiteral
  *         The RDF object to convert
  * @return a string if the object could be converted or null
  */
 function getRDFValue(aLiteral) {
   if (aLiteral instanceof Ci.nsIRDFLiteral)
@@ -669,16 +737,106 @@ function getRDFValue(aLiteral) {
  *         The property to read
  * @return a string if the property existed or null
  */
 function getRDFProperty(aDs, aResource, aProperty) {
   return getRDFValue(aDs.GetTarget(aResource, EM_R(aProperty), true));
 }
 
 /**
+ * Reads an AddonInternal object from a manifest stream.
+ *
+ * @param  aStream
+ *         An open stream to read the manifest from
+ * @return an AddonInternal object
+ * @throws if the install manifest in the stream is corrupt or could not
+ *         be read
+ */
+function loadManifestFromWebManifest(aStream) {
+  let decoder = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
+  let manifest = decoder.decodeFromStream(aStream, aStream.available());
+
+  function findProp(obj, current, properties) {
+    if (properties.length == 0)
+      return obj;
+
+    let field = properties[0];
+    current += "." + field;
+    if (!obj || !(field in obj)) {
+      throw new Error("Manifest file was missing required property " + current.substring(1));
+    }
+
+    return findProp(obj[field], current, properties.slice(1));
+  }
+
+  function getProp(path) {
+    return findProp(manifest, "", path.split("."));
+  }
+
+  function getOptionalProp(path, defValue = null) {
+    try {
+      return findProp(manifest, "", path.split("."));
+    }
+    catch (e) {
+      return defValue;
+    }
+  }
+
+  let mVersion = getProp("manifest_version");
+  if (mVersion != 2) {
+    throw new Error("Expected manifest_version to be 2 but was " + mVersion);
+  }
+
+  let addon = new AddonInternal();
+  addon.id = getProp("applications.gecko.id");
+  if (!gIDTest.test(addon.id))
+    throw new Error("Illegal add-on ID " + addon.id);
+  addon.version = getProp("version");
+  addon.type = "webextension";
+  addon.unpack = false;
+  addon.strictCompatibility = true;
+  addon.bootstrap = true;
+  addon.hasBinaryComponents = false;
+  addon.multiprocessCompatible = true;
+  addon.internalName = null;
+  addon.updateURL = null;
+  addon.updateKey = null;
+  addon.optionsURL = null;
+  addon.optionsType = null;
+  addon.aboutURL = null;
+  addon.iconURL = null;
+  addon.icon64URL = null;
+  addon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DEFAULT;
+
+  addon.defaultLocale = {
+    name: getProp("name"),
+    description: getOptionalProp("description"),
+    creator: null,
+    homepageURL: null,
+
+    developers: null,
+    translators: null,
+    contributors: null,
+  }
+
+  addon.targetApplications = [{
+    id: TOOLKIT_ID,
+    minVersion: "42a1",
+    maxVersion: "*",
+  }];
+
+  addon.locales = [];
+  addon.targetPlatforms = [];
+  addon.userDisabled = false;
+  addon.softDisabled = addon.blocklistState == Blocklist.STATE_SOFTBLOCKED;
+
+  return addon;
+}
+
+/**
  * Reads an AddonInternal object from an RDF stream.
  *
  * @param  aUri
  *         The URI that the manifest is being read from
  * @param  aStream
  *         An open stream to read the RDF from
  * @return an AddonInternal object
  * @throws if the install manifest in the RDF stream is corrupt or could not
@@ -929,48 +1087,49 @@ function loadManifestFromRDF(aUri, aStre
     addon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DISABLE;
     addon.updateURL = null;
     addon.updateKey = null;
 
     addon.targetApplications = [];
     addon.targetPlatforms = [];
   }
 
+  return addon;
+}
+
+function defineSyncGUID(aAddon) {
   // Load the storage service before NSS (nsIRandomGenerator),
   // to avoid a SQLite initialization error (bug 717904).
   let storage = Services.storage;
 
   // Define .syncGUID as a lazy property which is also settable
-  Object.defineProperty(addon, "syncGUID", {
+  Object.defineProperty(aAddon, "syncGUID", {
     get: () => {
-
       // Generate random GUID used for Sync.
       // This was lifted from util.js:makeGUID() from services-sync.
       let rng = Cc["@mozilla.org/security/random-generator;1"].
         createInstance(Ci.nsIRandomGenerator);
       let bytes = rng.generateRandomBytes(9);
       let byte_string = [String.fromCharCode(byte) for each (byte in bytes)]
                         .join("");
       // Base64 encode
       let guid = btoa(byte_string).replace(/\+/g, '-')
         .replace(/\//g, '_');
 
-      delete addon.syncGUID;
-      addon.syncGUID = guid;
+      delete aAddon.syncGUID;
+      aAddon.syncGUID = guid;
       return guid;
     },
     set: (val) => {
-      delete addon.syncGUID;
-      addon.syncGUID = val;
+      delete aAddon.syncGUID;
+      aAddon.syncGUID = val;
     },
     configurable: true,
     enumerable: true,
   });
-
-  return addon;
 }
 
 /**
  * Loads an AddonInternal object from an add-on extracted in a directory.
  *
  * @param  aDir
  *         The nsIFile directory holding the add-on
  * @return an AddonInternal object
@@ -988,43 +1147,52 @@ let loadManifestFromDir = Task.async(fun
     let entries = aFile.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
     let entry;
     while ((entry = entries.nextFile))
       size += getFileSize(entry);
     entries.close();
     return size;
   }
 
-  let file = aDir.clone();
-  file.append(FILE_INSTALL_MANIFEST);
-  if (!file.exists() || !file.isFile())
+  function loadFromRDF(aFile, aStream) {
+    let addon = loadManifestFromRDF(Services.io.newFileURI(aFile), aStream);
+
+    let file = aDir.clone();
+    file.append("chrome.manifest");
+    let chromeManifest = ChromeManifestParser.parseSync(Services.io.newFileURI(file));
+    addon.hasBinaryComponents = ChromeManifestParser.hasType(chromeManifest,
+                                                             "binary-component");
+    return addon;
+  }
+
+  let file = getManifestFileForDir(aDir);
+  if (!file) {
     throw new Error("Directory " + aDir.path + " does not contain a valid " +
                     "install manifest");
+  }
 
   let fis = Cc["@mozilla.org/network/file-input-stream;1"].
             createInstance(Ci.nsIFileInputStream);
   fis.init(file, -1, -1, false);
   let bis = Cc["@mozilla.org/network/buffered-input-stream;1"].
             createInstance(Ci.nsIBufferedInputStream);
   bis.init(fis, 4096);
 
   try {
-    let addon = loadManifestFromRDF(Services.io.newFileURI(file), bis);
+    let addon = file.leafName == FILE_WEB_MANIFEST ?
+                loadManifestFromWebManifest(bis) :
+                loadFromRDF(file, bis);
+
     addon._sourceBundle = aDir.clone();
     addon.size = getFileSize(aDir);
-
-    file = aDir.clone();
-    file.append("chrome.manifest");
-    let chromeManifest = ChromeManifestParser.parseSync(Services.io.newFileURI(file));
-    addon.hasBinaryComponents = ChromeManifestParser.hasType(chromeManifest,
-                                                             "binary-component");
-
     addon.signedState = yield verifyDirSignedState(aDir, addon);
-
     addon.appDisabled = !isUsableAddon(addon);
+
+    defineSyncGUID(addon);
+
     return addon;
   }
   finally {
     bis.close();
     fis.close();
   }
 });
 
@@ -1032,44 +1200,61 @@ let loadManifestFromDir = Task.async(fun
  * Loads an AddonInternal object from an nsIZipReader for an add-on.
  *
  * @param  aZipReader
  *         An open nsIZipReader for the add-on's files
  * @return an AddonInternal object
  * @throws if the XPI file does not contain a valid install manifest
  */
 let loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(aZipReader) {
-  let zis = aZipReader.getInputStream(FILE_INSTALL_MANIFEST);
-  let bis = Cc["@mozilla.org/network/buffered-input-stream;1"].
-            createInstance(Ci.nsIBufferedInputStream);
-  bis.init(zis, 4096);
-
-  try {
-    let uri = buildJarURI(aZipReader.file, FILE_INSTALL_MANIFEST);
-    let addon = loadManifestFromRDF(uri, bis);
-    addon._sourceBundle = aZipReader.file;
-
-    addon.size = 0;
-    let entries = aZipReader.findEntries(null);
-    while (entries.hasMore())
-      addon.size += aZipReader.getEntry(entries.getNext()).realSize;
+  function loadFromRDF(aStream) {
+    let uri = buildJarURI(aZipReader.file, FILE_RDF_MANIFEST);
+    let addon = loadManifestFromRDF(uri, aStream);
 
     // Binary components can only be loaded from unpacked addons.
     if (addon.unpack) {
       uri = buildJarURI(aZipReader.file, "chrome.manifest");
       let chromeManifest = ChromeManifestParser.parseSync(uri);
       addon.hasBinaryComponents = ChromeManifestParser.hasType(chromeManifest,
                                                                "binary-component");
     } else {
       addon.hasBinaryComponents = false;
     }
 
+    return addon;
+  }
+
+  let entry = getManifestEntryForZipReader(aZipReader);
+  if (!entry) {
+    throw new Error("File " + aZipReader.file.path + " does not contain a valid " +
+                    "install manifest");
+  }
+
+  let zis = aZipReader.getInputStream(entry);
+  let bis = Cc["@mozilla.org/network/buffered-input-stream;1"].
+            createInstance(Ci.nsIBufferedInputStream);
+  bis.init(zis, 4096);
+
+  try {
+    let addon = entry == FILE_WEB_MANIFEST ?
+                loadManifestFromWebManifest(bis) :
+                loadFromRDF(bis);
+
+    addon._sourceBundle = aZipReader.file;
+
+    addon.size = 0;
+    let entries = aZipReader.findEntries(null);
+    while (entries.hasMore())
+      addon.size += aZipReader.getEntry(entries.getNext()).realSize;
+
     addon.signedState = yield verifyZipSignedState(aZipReader.file, addon);
-
     addon.appDisabled = !isUsableAddon(addon);
+
+    defineSyncGUID(addon);
+
     return addon;
   }
   finally {
     bis.close();
     zis.close();
   }
 });
 
@@ -1635,25 +1820,22 @@ XPIState.prototype = {
       let [modFile, modTime, items] = recursiveLastModifiedTime(aFile);
       XPIProvider._mostRecentlyModifiedFile[aId] = modFile;
       XPIProvider.setTelemetry(aId, "scan_items", items);
       if (modTime != this.scanTime) {
         this.scanTime = modTime;
         changed = true;
       }
     }
-    // if the add-on is disabled, modified time is the install.rdf time, if any.
-    // If {path}/install.rdf doesn't exist, we assume this is a packed .xpi and use
+    // if the add-on is disabled, modified time is the install manifest time, if
+    // any. If no manifest exists, we assume this is a packed .xpi and use
     // the time stamp of {path}
     try {
-      // Get the install.rdf update time, if any.
-      // XXX This will eventually also need to check for package.json or whatever
-      // the new manifest is named.
-      let maniFile = aFile.clone();
-      maniFile.append(FILE_INSTALL_MANIFEST);
+      // Get the install manifest update time, if any.
+      let maniFile = getManifestFileForDir(aFile);
       if (!(aId in XPIProvider._mostRecentlyModifiedFile)) {
         XPIProvider._mostRecentlyModifiedFile[aId] = maniFile.leafName;
       }
       let maniTime = maniFile.lastModifiedTime;
       if (maniTime != this.manifestTime) {
         this.manifestTime = maniTime;
         changed = true;
       }
@@ -2655,22 +2837,21 @@ this.XPIProvider = {
           seenFiles.push(stageDirEntry.leafName);
           continue;
         }
 
         changed = true;
 
         if (isDir) {
           // Check if the directory contains an install manifest.
-          let manifest = stageDirEntry.clone();
-          manifest.append(FILE_INSTALL_MANIFEST);
+          let manifest = getManifestFileForDir(stageDirEntry);
 
           // If the install manifest doesn't exist uninstall this add-on in this
           // install location.
-          if (!manifest.exists()) {
+          if (!manifest) {
             logger.debug("Processing uninstall of " + id + " in " + aLocation.name);
             try {
               aLocation.uninstallAddon(id);
               seenFiles.push(stageDirEntry.leafName);
             }
             catch (e) {
               logger.error("Failed to uninstall add-on " + id + " in " + aLocation.name, e);
             }
@@ -3954,17 +4135,19 @@ this.XPIProvider = {
    * Called to get Addons of a particular type.
    *
    * @param  aTypes
    *         An array of types to fetch. Can be null to get all types.
    * @param  aCallback
    *         A callback to pass an array of Addons to
    */
   getAddonsByTypes: function XPI_getAddonsByTypes(aTypes, aCallback) {
-    XPIDatabase.getVisibleAddons(aTypes, function getAddonsByTypes_getVisibleAddons(aAddons) {
+    let typesToGet = getAllAliasesForTypes(aTypes);
+
+    XPIDatabase.getVisibleAddons(typesToGet, function getAddonsByTypes_getVisibleAddons(aAddons) {
       aCallback([createWrapper(a) for each (a in aAddons)]);
     });
   },
 
   /**
    * Obtain an Addon having the specified Sync GUID.
    *
    * @param  aGUID
@@ -3983,17 +4166,19 @@ this.XPIProvider = {
    *
    * @param  aTypes
    *         An array of types to fetch. Can be null to get all types
    * @param  aCallback
    *         A callback to pass an array of Addons to
    */
   getAddonsWithOperationsByTypes:
   function XPI_getAddonsWithOperationsByTypes(aTypes, aCallback) {
-    XPIDatabase.getVisibleAddonsWithPendingOperations(aTypes,
+    let typesToGet = getAllAliasesForTypes(aTypes);
+
+    XPIDatabase.getVisibleAddonsWithPendingOperations(typesToGet,
       function getAddonsWithOpsByTypes_getVisibleAddonsWithPendingOps(aAddons) {
       let results = [createWrapper(a) for each (a in aAddons)];
       XPIProvider.installs.forEach(function(aInstall) {
         if (aInstall.state == AddonManager.STATE_INSTALLED &&
             !(aInstall.addon.inDatabase))
           results.push(createWrapper(aInstall.addon));
       });
       aCallback(results);
@@ -4007,17 +4192,17 @@ this.XPIProvider = {
    * @param  aTypes
    *         An array of types or null to get all types
    * @param  aCallback
    *         A callback to pass the array of AddonInstalls to
    */
   getInstallsByTypes: function XPI_getInstallsByTypes(aTypes, aCallback) {
     let results = [];
     this.installs.forEach(function(aInstall) {
-      if (!aTypes || aTypes.indexOf(aInstall.type) >= 0)
+      if (!aTypes || aTypes.indexOf(getExternalType(aInstall.type)) >= 0)
         results.push(aInstall.wrapper);
     });
     aCallback(results);
   },
 
   /**
    * Synchronously map a URI to the corresponding Addon ID.
    *
@@ -4446,16 +4631,18 @@ this.XPIProvider = {
                                     metadata: { addonID: aId } });
       logger.error("Attempted to load bootstrap scope from missing directory " + aFile.path);
       return;
     }
 
     let uri = getURIForResourceInFile(aFile, "bootstrap.js").spec;
     if (aType == "dictionary")
       uri = "resource://gre/modules/addons/SpellCheckDictionaryBootstrap.js"
+    else if (aType == "webextension")
+      uri = "resource://gre/modules/addons/WebExtensionBootstrap.js"
 
     this.bootstrapScopes[aId] =
       new Cu.Sandbox(principal, { sandboxName: uri,
                                   wantGlobalProperties: ["indexedDB"],
                                   addonId: aId,
                                   metadata: { addonID: aId, URI: uri } });
 
     let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
@@ -6150,21 +6337,23 @@ AddonInstall.createUpdate = function AI_
  */
 function AddonInstallWrapper(aInstall) {
 #ifdef MOZ_EM_DEBUG
   this.__defineGetter__("__AddonInstallInternal__", function AIW_debugGetter() {
     return aInstall;
   });
 #endif
 
-  ["name", "type", "version", "icons", "releaseNotesURI", "file", "state", "error",
+  ["name", "version", "icons", "releaseNotesURI", "file", "state", "error",
    "progress", "maxProgress", "certificate", "certName"].forEach(function(aProp) {
     this.__defineGetter__(aProp, function AIW_propertyGetter() aInstall[aProp]);
   }, this);
 
+  this.__defineGetter__("type", () => getExternalType(aInstall.type));
+
   this.__defineGetter__("iconURL", function AIW_iconURL() aInstall.icons[32]);
 
   this.__defineGetter__("existingAddon", function AIW_existingAddonGetter() {
     return createWrapper(aInstall.existingAddon);
   });
   this.__defineGetter__("addon", function AIW_addonGetter() createWrapper(aInstall.addon));
   this.__defineGetter__("sourceURI", function AIW_sourceURIGetter() aInstall.sourceURI);
 
@@ -6737,24 +6926,26 @@ function AddonWrapper(aAddon) {
     if (repositoryAddon && (aProp in repositoryAddon) &&
         (objValue === undefined || objValue === null)) {
       return [repositoryAddon[aProp], true];
     }
 
     return [objValue, false];
   }
 
-  ["id", "syncGUID", "version", "type", "isCompatible", "isPlatformCompatible",
+  ["id", "syncGUID", "version", "isCompatible", "isPlatformCompatible",
    "providesUpdatesSecurely", "blocklistState", "blocklistURL", "appDisabled",
    "softDisabled", "skinnable", "size", "foreignInstall", "hasBinaryComponents",
    "strictCompatibility", "compatibilityOverrides", "updateURL",
    "getDataDirectory", "multiprocessCompatible", "signedState"].forEach(function(aProp) {
      this.__defineGetter__(aProp, function AddonWrapper_propertyGetter() aAddon[aProp]);
   }, this);
 
+  this.__defineGetter__("type", () => getExternalType(aAddon.type));
+
   ["fullDescription", "developerComments", "eula", "supportURL",
    "contributionURL", "contributionAmount", "averageRating", "reviewCount",
    "reviewURL", "totalDownloads", "weeklyDownloads", "dailyUsers",
    "repositoryStatus"].forEach(function(aProp) {
     this.__defineGetter__(aProp, function AddonWrapper_repoPropertyGetter() {
       if (aAddon._repositoryAddon)
         return aAddon._repositoryAddon[aProp];
 
--- a/toolkit/mozapps/extensions/internal/moz.build
+++ b/toolkit/mozapps/extensions/internal/moz.build
@@ -8,16 +8,17 @@ EXTRA_JS_MODULES.addons += [
     'AddonLogging.jsm',
     'AddonRepository.jsm',
     'AddonRepository_SQLiteMigrator.jsm',
     'AddonUpdateChecker.jsm',
     'Content.js',
     'GMPProvider.jsm',
     'LightweightThemeImageOptimizer.jsm',
     'SpellCheckDictionaryBootstrap.js',
+    'WebExtensionBootstrap.js',
 ]
 
 # Don't ship unused providers on Android
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
     EXTRA_JS_MODULES.addons += [
         'PluginProvider.jsm',
     ]
 
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/webextension_1/manifest.json
@@ -0,0 +1,10 @@
+{
+  "name": "Web Extension Name",
+  "version": "1.0",
+  "manifest_version": 2,
+  "applications": {
+    "gecko": {
+      "id": "webextension1@tests.mozilla.org"
+    }
+  }
+}
--- a/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/head_addons.js
@@ -765,16 +765,72 @@ function writeInstallRDFToDir(aData, aDi
 function writeInstallRDFForExtension(aData, aDir, aId, aExtraFile) {
   if (TEST_UNPACKED) {
     return writeInstallRDFToDir(aData, aDir, aId, aExtraFile);
   }
   return writeInstallRDFToXPI(aData, aDir, aId, aExtraFile);
 }
 
 /**
+ * Writes a manifest.json manifest into an extension using the properties passed
+ * in a JS object.
+ *
+ * @param   aManifest
+ *          The data to write
+ * @param   aDir
+ *          The install directory to add the extension to
+ * @param   aId
+ *          An optional string to override the default installation aId
+ * @return  A file pointing to where the extension was installed
+ */
+function writeWebManifestForExtension(aData, aDir, aId = undefined) {
+  if (!aId)
+    aId = aData.applications.gecko.id;
+
+  if (TEST_UNPACKED) {
+    let dir = aDir.clone();
+    dir.append(aId);
+    if (!dir.exists())
+      dir.create(AM_Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
+
+    let file = dir.clone();
+    file.append("manifest.json");
+    if (file.exists())
+      file.remove(true);
+
+    let data = JSON.stringify(aData);
+    let fos = AM_Cc["@mozilla.org/network/file-output-stream;1"].
+              createInstance(AM_Ci.nsIFileOutputStream);
+    fos.init(file,
+             FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE,
+             FileUtils.PERMS_FILE, 0);
+    fos.write(data, data.length);
+    fos.close();
+
+    return dir;
+  }
+  else {
+    let file = aDir.clone();
+    file.append(aId + ".xpi");
+
+    let stream = AM_Cc["@mozilla.org/io/string-input-stream;1"].
+                 createInstance(AM_Ci.nsIStringInputStream);
+    stream.setData(JSON.stringify(aData), -1);
+    let zipW = AM_Cc["@mozilla.org/zipwriter;1"].
+               createInstance(AM_Ci.nsIZipWriter);
+    zipW.open(file, FileUtils.MODE_WRONLY | FileUtils.MODE_CREATE | FileUtils.MODE_TRUNCATE);
+    zipW.addEntryStream("manifest.json", 0, AM_Ci.nsIZipWriter.COMPRESSION_NONE,
+                        stream, false);
+    zipW.close();
+
+    return file;
+  }
+}
+
+/**
  * Writes an install.rdf manifest into a packed extension using the properties passed
  * in a JS object. The objects should contain a property for each property to
  * appear in the RDF. The object may contain an array of objects with id,
  * minVersion and maxVersion in the targetApplications property to give target
  * application compatibility.
  *
  * @param   aData
  *          The object holding data about the add-on
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js
@@ -0,0 +1,189 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+const ID = "webextension1@tests.mozilla.org";
+
+const profileDir = gProfD.clone();
+profileDir.append("extensions");
+
+createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "42");
+startupManager();
+
+const { GlobalManager, Management } = Components.utils.import("resource://gre/modules/Extension.jsm", {});
+
+function promiseAddonStartup() {
+  return new Promise(resolve => {
+    let listener = (extension) => {
+      Management.off("startup", listener);
+      resolve(extension);
+    }
+
+    Management.on("startup", listener);
+  });
+}
+
+add_task(function*() {
+  do_check_eq(GlobalManager.count, 0);
+  do_check_false(GlobalManager.extensionMap.has(ID));
+
+  yield Promise.all([
+    promiseInstallAllFiles([do_get_addon("webextension_1")], true),
+    promiseAddonStartup()
+  ]);
+
+  do_check_eq(GlobalManager.count, 1);
+  do_check_true(GlobalManager.extensionMap.has(ID));
+
+  let addon = yield promiseAddonByID(ID);
+  do_check_neq(addon, null);
+  do_check_eq(addon.version, "1.0");
+  do_check_eq(addon.name, "Web Extension Name");
+  do_check_true(addon.isCompatible);
+  do_check_false(addon.appDisabled);
+  do_check_true(addon.isActive);
+  do_check_eq(addon.type, "extension");
+  do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_MISSING);
+
+  // Should persist through a restart
+  yield promiseShutdownManager();
+
+  do_check_eq(GlobalManager.count, 0);
+  do_check_false(GlobalManager.extensionMap.has(ID));
+
+  startupManager();
+  yield promiseAddonStartup();
+
+  do_check_eq(GlobalManager.count, 1);
+  do_check_true(GlobalManager.extensionMap.has(ID));
+
+  addon = yield promiseAddonByID(ID);
+  do_check_neq(addon, null);
+  do_check_eq(addon.version, "1.0");
+  do_check_eq(addon.name, "Web Extension Name");
+  do_check_true(addon.isCompatible);
+  do_check_false(addon.appDisabled);
+  do_check_true(addon.isActive);
+  do_check_eq(addon.type, "extension");
+  do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_MISSING);
+
+  let file = getFileForAddon(profileDir, ID);
+  do_check_true(file.exists());
+
+  addon.userDisabled = true;
+
+  do_check_eq(GlobalManager.count, 0);
+  do_check_false(GlobalManager.extensionMap.has(ID));
+
+  addon.userDisabled = false;
+  yield promiseAddonStartup();
+
+  do_check_eq(GlobalManager.count, 1);
+  do_check_true(GlobalManager.extensionMap.has(ID));
+
+  addon.uninstall();
+
+  do_check_eq(GlobalManager.count, 0);
+  do_check_false(GlobalManager.extensionMap.has(ID));
+
+  yield promiseShutdownManager();
+});
+
+// Writing the manifest direct to the profile should work
+add_task(function*() {
+  writeWebManifestForExtension({
+    name: "Web Extension Name",
+    version: "1.0",
+    manifest_version: 2,
+    applications: {
+      gecko: {
+        id: ID
+      }
+    }
+  }, profileDir);
+
+  startupManager();
+
+  let addon = yield promiseAddonByID(ID);
+  do_check_neq(addon, null);
+  do_check_eq(addon.version, "1.0");
+  do_check_eq(addon.name, "Web Extension Name");
+  do_check_true(addon.isCompatible);
+  do_check_false(addon.appDisabled);
+  do_check_true(addon.isActive);
+  do_check_eq(addon.type, "extension");
+  do_check_eq(addon.signedState, AddonManager.SIGNEDSTATE_MISSING);
+
+  let file = getFileForAddon(profileDir, ID);
+  do_check_true(file.exists());
+
+  addon.uninstall();
+
+  yield promiseRestartManager();
+});
+
+// Missing ID should cause a failure
+add_task(function*() {
+  writeWebManifestForExtension({
+    name: "Web Extension Name",
+    version: "1.0",
+    manifest_version: 2,
+  }, profileDir, ID);
+
+  yield promiseRestartManager();
+
+  let addon = yield promiseAddonByID(ID);
+  do_check_eq(addon, null);
+
+  let file = getFileForAddon(profileDir, ID);
+  do_check_false(file.exists());
+
+  yield promiseRestartManager();
+});
+
+// Missing version should cause a failure
+add_task(function*() {
+  writeWebManifestForExtension({
+    name: "Web Extension Name",
+    manifest_version: 2,
+    applications: {
+      gecko: {
+        id: ID
+      }
+    }
+  }, profileDir);
+
+  yield promiseRestartManager();
+
+  let addon = yield promiseAddonByID(ID);
+  do_check_eq(addon, null);
+
+  let file = getFileForAddon(profileDir, ID);
+  do_check_false(file.exists());
+
+  yield promiseRestartManager();
+});
+
+// Incorrect manifest version should cause a failure
+add_task(function*() {
+  writeWebManifestForExtension({
+    name: "Web Extension Name",
+    version: "1.0",
+    manifest_version: 1,
+    applications: {
+      gecko: {
+        id: ID
+      }
+    }
+  }, profileDir);
+
+  yield promiseRestartManager();
+
+  let addon = yield promiseAddonByID(ID);
+  do_check_eq(addon, null);
+
+  let file = getFileForAddon(profileDir, ID);
+  do_check_false(file.exists());
+
+  yield promiseRestartManager();
+});
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell-shared.ini
@@ -280,9 +280,10 @@ skip-if = os == "android"
 run-sequentially = Uses global XCurProcD dir.
 [test_upgrade_strictcompat.js]
 # Bug 676992: test consistently hangs on Android
 skip-if = os == "android"
 run-sequentially = Uses global XCurProcD dir.
 [test_overrideblocklist.js]
 run-sequentially = Uses global XCurProcD dir.
 [test_sourceURI.js]
+[test_webextension.js]
 [test_bootstrap_globals.js]
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
@@ -21,9 +21,10 @@ skip-if = appname != "firefox"
 [test_provider_markSafe.js]
 [test_provider_shutdown.js]
 [test_provider_unsafe_access_shutdown.js]
 [test_provider_unsafe_access_startup.js]
 [test_shutdown.js]
 [test_XPIcancel.js]
 [test_XPIStates.js]
 
+
 [include:xpcshell-shared.ini]