Merge b2ginbound to central, a=merge
authorWes Kocher <wkocher@mozilla.com>
Tue, 27 Oct 2015 14:12:08 -0700
changeset 269799 2b333a1d94e805a59c619ee41a6dec7fdcce505d
parent 269755 4e164269cf888c03a18d1c4ea057bca68fb0ed32 (current diff)
parent 269798 2c4b2deaf1e8b715a5f7849dfac8b0d023b96e63 (diff)
child 269802 c3fc4f7a7ae150c51072018112ca5404b2b76e28
child 269825 2d1015be72b5fcc0fc02981cad06d9aba591f5a0
child 269874 c6fa796af5487f5fafdef19f0b436102439d80d6
push id29590
push userkwierso@gmail.com
push dateTue, 27 Oct 2015 21:12:14 +0000
treeherdermozilla-central@2b333a1d94e8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone44.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge b2ginbound to central, a=merge
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -674,17 +674,17 @@ pref("javascript.options.mem.gc_allocati
 pref("javascript.options.mem.gc_decommit_threshold_mb", 1);
 pref("javascript.options.mem.gc_min_empty_chunk_count", 1);
 pref("javascript.options.mem.gc_max_empty_chunk_count", 2);
 
 // Show/Hide scrollbars when active/inactive
 pref("ui.showHideScrollbars", 1);
 pref("ui.useOverlayScrollbars", 1);
 pref("ui.scrollbarFadeBeginDelay", 450);
-pref("ui.scrollbarFadeDuration", 200);
+pref("ui.scrollbarFadeDuration", 0);
 
 // Scrollbar position follows the document `dir` attribute
 pref("layout.scrollbar.side", 1);
 
 // CSS Scroll Snapping
 pref("layout.css.scroll-snap.enabled", true);
 
 // Enable the ProcessPriorityManager, and give processes with no visible
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -398,27 +398,24 @@ var shell = {
                                .QueryInterface(Ci.nsIInterfaceRequestor)
                                .getInterface(Ci.nsIWebNavigation);
     webNav.sessionHistory = Cc["@mozilla.org/browser/shistory;1"].createInstance(Ci.nsISHistory);
 
 #ifdef MOZ_GRAPHENE
     webNav.QueryInterface(Ci.nsIDocShell).windowDraggingAllowed = true;
 #endif
 
-    this.allowedAudioChannels = new Map();
     let audioChannels = systemAppFrame.allowedAudioChannels;
     audioChannels && audioChannels.forEach(function(audioChannel) {
-      this.allowedAudioChannels.set(audioChannel.name, audioChannel);
-      audioChannel.addEventListener('activestatechanged', this);
       // Set all audio channels as unmuted by default
       // because some audio in System app will be played
       // before AudioChannelService[1] is Gaia is loaded.
       // [1]: https://github.com/mozilla-b2g/gaia/blob/master/apps/system/js/audio_channel_service.js
       audioChannel.setMuted(false);
-    }.bind(this));
+    });
 
     // On firefox mulet, shell.html is loaded in a tab
     // and we have to listen on the chrome event handler
     // to catch key events
     let chromeEventHandler = window.QueryInterface(Ci.nsIInterfaceRequestor)
                                    .getInterface(Ci.nsIWebNavigation)
                                    .QueryInterface(Ci.nsIDocShell)
                                    .chromeEventHandler || window;
@@ -678,28 +675,16 @@ var shell = {
         // the critical launch path of the app.
         SystemAppProxy._sendCustomEvent('mozChromeEvent', {
           type: 'system-first-paint'
         }, /* noPending */ true);
         break;
       case 'unload':
         this.stop();
         break;
-      case 'activestatechanged':
-        var channel = evt.target;
-        // TODO: We should get the `isActive` state from evt.isActive.
-        // Then we don't need to do `channel.isActive()` here.
-        channel.isActive().onsuccess = function(evt) {
-          SystemAppProxy._sendCustomEvent('mozSystemWindowChromeEvent', {
-            type: 'system-audiochannel-state-changed',
-            name: channel.name,
-            isActive: evt.target.result
-          });
-        }.bind(this);
-        break;
     }
   },
 
   // Send an event to a specific window, document or element.
   sendEvent: function shell_sendEvent(target, type, details) {
     if (target === this.contentBrowser) {
       // We must ask SystemAppProxy to send the event in this case so
       // that event would be dispatched from frame.contentWindow instead of
@@ -899,21 +884,16 @@ var CustomEventManager = {
       case 'captive-portal-login-cancel':
         CaptivePortalLoginHelper.handleEvent(detail);
         break;
       case 'inputmethod-update-layouts':
       case 'inputregistry-add':
       case 'inputregistry-remove':
         KeyboardHelper.handleEvent(detail);
         break;
-      case 'system-audiochannel-list':
-      case 'system-audiochannel-mute':
-      case 'system-audiochannel-volume':
-        SystemAppMozBrowserHelper.handleEvent(detail);
-        break;
       case 'do-command':
         DoCommandHelper.handleEvent(detail.cmd);
         break;
       case 'copypaste-do-command':
         Services.obs.notifyObservers({ wrappedJSObject: shell.contentBrowser },
                                      'ask-children-to-execute-copypaste-command', detail.cmd);
         break;
       case 'add-permission':
@@ -1071,73 +1051,16 @@ var KeyboardHelper = {
       case 'inputregistry-remove':
         Keyboard.inputRegistryGlue.returnMessage(detail);
 
         break;
     }
   }
 };
 
-var SystemAppMozBrowserHelper = {
-  handleEvent: function systemAppMozBrowser_handleEvent(detail) {
-    let request;
-    let name;
-    switch (detail.type) {
-      case 'system-audiochannel-list':
-        let audioChannels = [];
-        shell.allowedAudioChannels.forEach(function(value, name) {
-          audioChannels.push(name);
-        });
-        SystemAppProxy._sendCustomEvent('mozSystemWindowChromeEvent', {
-          type: 'system-audiochannel-list',
-          audioChannels: audioChannels
-        });
-        break;
-      case 'system-audiochannel-mute':
-        name = detail.name;
-        let isMuted = detail.isMuted;
-        request = shell.allowedAudioChannels.get(name).setMuted(isMuted);
-        request.onsuccess = function() {
-          SystemAppProxy._sendCustomEvent('mozSystemWindowChromeEvent', {
-            type: 'system-audiochannel-mute-onsuccess',
-            name: name,
-            isMuted: isMuted
-          });
-        };
-        request.onerror = function() {
-          SystemAppProxy._sendCustomEvent('mozSystemWindowChromeEvent', {
-            type: 'system-audiochannel-mute-onerror',
-            name: name,
-            isMuted: isMuted
-          });
-        };
-        break;
-      case 'system-audiochannel-volume':
-        name = detail.name;
-        let volume = detail.volume;
-        request = shell.allowedAudioChannels.get(name).setVolume(volume);
-        request.onsuccess = function() {
-          sSystemAppProxy._sendCustomEvent('mozSystemWindowChromeEvent', {
-            type: 'system-audiochannel-volume-onsuccess',
-            name: name,
-            volume: volume
-          });
-        };
-        request.onerror = function() {
-          SystemAppProxy._sendCustomEvent('mozSystemWindowChromeEvent', {
-            type: 'system-audiochannel-volume-onerror',
-            name: name,
-            volume: volume
-          });
-        };
-        break;
-    }
-  }
-};
-
 // This is the backend for Gaia's screenshot feature.  Gaia requests a
 // screenshot by sending a mozContentEvent with detail.type set to
 // 'take-screenshot'.  Then we take a screenshot and send a
 // mozChromeEvent with detail.type set to 'take-screenshot-success'
 // and detail.file set to the an image/png blob
 window.addEventListener('ContentStart', function ss_onContentStart() {
   let content = shell.contentBrowser.contentWindow;
   content.addEventListener('mozContentEvent', function ss_onMozContentEvent(e) {
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -10,26 +10,26 @@
   <!--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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="b6ede3d0fdec5fc922e9ca3401e60db461bf705c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0c28789b9957913be975eb002a22323f93585d4c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- 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"/>
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,26 +10,26 @@
   <!--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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="b6ede3d0fdec5fc922e9ca3401e60db461bf705c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0c28789b9957913be975eb002a22323f93585d4c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- 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"/>
--- 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="b6ede3d0fdec5fc922e9ca3401e60db461bf705c"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c72c9278ddc2f442d193474993d36e7f2cfb08c4"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- Stock Android things -->
--- 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="b6ede3d0fdec5fc922e9ca3401e60db461bf705c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0c28789b9957913be975eb002a22323f93585d4c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- 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"/>
--- 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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="b6ede3d0fdec5fc922e9ca3401e60db461bf705c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0c28789b9957913be975eb002a22323f93585d4c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- 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"/>
--- 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="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="b6ede3d0fdec5fc922e9ca3401e60db461bf705c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0c28789b9957913be975eb002a22323f93585d4c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- 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"/>
--- 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="b6ede3d0fdec5fc922e9ca3401e60db461bf705c"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c72c9278ddc2f442d193474993d36e7f2cfb08c4"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- Stock Android things -->
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,26 +10,26 @@
   <!--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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="b6ede3d0fdec5fc922e9ca3401e60db461bf705c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0c28789b9957913be975eb002a22323f93585d4c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- 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"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "b6ede3d0fdec5fc922e9ca3401e60db461bf705c", 
+        "git_revision": "a26eadc5e1133d5112b6cbc10badbb7670a1090f", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "220b45ec153f267a2efc58275a30a665a4ec9e57", 
+    "revision": "a99ff14b3258f49f5902775a5e3b849f3455714a", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4-kk/sources.xml
+++ b/b2g/config/nexus-4-kk/sources.xml
@@ -10,26 +10,26 @@
   <!--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="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="b6ede3d0fdec5fc922e9ca3401e60db461bf705c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0c28789b9957913be975eb002a22323f93585d4c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- 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"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -13,20 +13,20 @@
   <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="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="b6ede3d0fdec5fc922e9ca3401e60db461bf705c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0c28789b9957913be975eb002a22323f93585d4c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- 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"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -10,26 +10,26 @@
   <!--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="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="b6ede3d0fdec5fc922e9ca3401e60db461bf705c"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="a26eadc5e1133d5112b6cbc10badbb7670a1090f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="956700d9754349b630a34551750ae6353614b6aa"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3b9a47b517d345b8d98bc7f787b9a6c2f51ca75d"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="5f931350fbc87c3df9db8b0ceb37734b8b471593"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="48d8c7c950745f1b166b42125e6f0d3293d71636"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="0c28789b9957913be975eb002a22323f93585d4c"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="1837d370a964a9719160c79155a07980f2ea4bdf"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- 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"/>
--- a/dom/apps/AppsUtils.jsm
+++ b/dom/apps/AppsUtils.jsm
@@ -125,16 +125,17 @@ function _setAppProperties(aObj, aApp) {
   aObj.storeId = aApp.storeId || "";
   aObj.storeVersion = aApp.storeVersion || 0;
   aObj.role = aApp.role || "";
   aObj.redirects = aApp.redirects;
   aObj.widgetPages = aApp.widgetPages || [];
   aObj.kind = aApp.kind;
   aObj.enabled = aApp.enabled !== undefined ? aApp.enabled : true;
   aObj.sideloaded = aApp.sideloaded;
+  aObj.extensionVersion = aApp.extensionVersion;
 #ifdef MOZ_B2GDROID
   aObj.android_packagename = aApp.android_packagename;
   aObj.android_classname = aApp.android_classname;
 #endif
 }
 
 this.AppsUtils = {
   // Clones a app, without the manifest.
--- a/dom/apps/UserCustomizations.jsm
+++ b/dom/apps/UserCustomizations.jsm
@@ -133,16 +133,20 @@ this.UserCustomizations = {
     if (aManifest.description) {
       result.description = aManifest.description;
     }
 
     if (aManifest.icons) {
       result.icons = aManifest.icons;
     }
 
+    if (aManifest.version) {
+      result.version = aManifest.version;
+    }
+
     // chrome extension manifests have a single 'author' property, that we
     // map to 'developer.name'.
     // Note that it has to match the one in the mini-manifest.
     if (aManifest.author) {
       result.developer = {
         name: aManifest.author
       }
     }
--- a/dom/apps/Webapps.jsm
+++ b/dom/apps/Webapps.jsm
@@ -3807,16 +3807,20 @@ this.DOMApplicationRegistry = {
           NetUtil.readInputStreamToString(istream, istream.available()) || ""));
 
     if (!hasWebappManifest) {
       // Validate the extension manifest, and convert it.
       if (!UserCustomizations.checkExtensionManifest(newManifest)) {
         throw "INVALID_MANIFEST";
       }
       newManifest = UserCustomizations.convertManifest(newManifest);
+      // Keep track of the add-on version, to use for blocklisting.
+      if (newManifest.version) {
+        aNewApp.extensionVersion = newManifest.version;
+      }
     }
 
     if (!AppsUtils.checkManifest(newManifest, aOldApp)) {
       throw "INVALID_MANIFEST";
     }
 
     // For app updates we don't forbid apps to rename themselves but
     // we still retain the old name of the app. In the future we
--- a/dom/apps/tests/test_app_addons.html
+++ b/dom/apps/tests/test_app_addons.html
@@ -74,20 +74,22 @@ let apps = [];
 
 function installApp(manifestURL, expectedError) {
   info("About to install app at " + manifestURL);
   let req = navigator.mozApps.installPackage(manifestURL);
   req.onsuccess = function() {
     apps.push(req.result);
     is(req.result.manifestURL, manifestURL, "app installed");
     if (req.result.installState == "installed") {
+      is(req.result.manifest.version, "1.0", "correct version");
       is(req.result.installState, "installed", "app downloaded");
       continueTest();
     } else {
       req.result.ondownloadapplied = function() {
+        is(req.result.manifest.version, "1.0", "correct version");
         is(req.result.installState, "installed", "app downloaded");
         continueTest();
       }
 
       req.result.ondownloaderror = function() {
         if (expectedError) {
           is(req.result.downloadError.name, "MANIFEST_MISMATCH");
         } else {
--- a/dom/apps/tests/test_third_party_homescreen.html
+++ b/dom/apps/tests/test_third_party_homescreen.html
@@ -159,21 +159,21 @@ function runTest() {
   request.onerror = cbError;
   request.onsuccess = continueTest;
   yield undefined;
 
   var app = request.result;
   ok(app, "App is non-null");
   is(app.manifestURL, gManifestURL, "App manifest url is correct.");
 
-  var context = {"manifestURL": app.manifestURL, "isInBrowserElement": false};
+  var context = {manifestURL: app.manifestURL};
 
-  SpecialPowers.pushPermissions([{"type": "homescreen-webapps-manage",
-                                  "allow": 1,
-                                  "context": context}], continueTest);
+  SpecialPowers.pushPermissions([{type: "homescreen-webapps-manage",
+                                  allow: 1,
+                                  context: context}], continueTest);
   yield undefined;
 
   // Launch the app.
   info("Running " + app.manifestURL);
   runApp(app, continueTest);
   yield undefined;
 
   // Uninstall the app to cleanup after ourself.
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1602,31 +1602,33 @@ already_AddRefed<Promise>
 Navigator::HasFeature(const nsAString& aName, ErrorResult& aRv)
 {
   nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
   RefPtr<Promise> p = Promise::Create(go, aRv);
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  // Hardcoded web-extensions feature which is b2g specific.
+  // Hardcoded extensions features which are b2g specific.
 #ifdef MOZ_B2G
-  if (aName.EqualsLiteral("web-extensions")) {
+  if (aName.EqualsLiteral("web-extensions") ||
+      aName.EqualsLiteral("late-customization")) {
     p->MaybeResolve(true);
     return p.forget();
   }
 #endif
 
   // Hardcoded manifest features. Some are still b2g specific.
   const char manifestFeatures[][64] = {
     "manifest.origin"
   , "manifest.redirects"
 #ifdef MOZ_B2G
   , "manifest.chrome.navigation"
   , "manifest.precompile"
+  , "manifest.role.homescreen"
 #endif
   };
 
   nsAutoCString feature = NS_ConvertUTF16toUTF8(aName);
   for (uint32_t i = 0; i < MOZ_ARRAY_LENGTH(manifestFeatures); i++) {
     if (feature.Equals(manifestFeatures[i])) {
       p->MaybeResolve(true);
       return p.forget();
--- a/dom/base/test/test_getFeature_with_perm.html
+++ b/dom/base/test/test_getFeature_with_perm.html
@@ -121,16 +121,17 @@ SpecialPowers.pushPermissions([
   ok('hasFeature' in navigator, "navigator.hasFeature should exist");
   // B2G specific manifest features.
   // Touching navigator before pushPermissions makes it fail.
   if (!navigator.userAgent.includes("Android") &&
         /Mobile|Tablet/.test(navigator.userAgent)) {
     info("Adding B2G specific tests");
     tests.push(createManifestTest("manifest.chrome.navigation"));
     tests.push(createManifestTest("manifest.precompile"));
+    tests.push(createManifestTest("manifest.role.homescreen"));
   }
   runNextTest();
   ok(true, "Test DONE");
 });
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
--- a/dom/base/test/test_hasFeature.html
+++ b/dom/base/test/test_hasFeature.html
@@ -60,21 +60,29 @@ function testAPIs() {
   });
 }
 
 function testExtensions() {
   if (!b2gOnly) {
     return Promise.resolve();
   }
 
-  return navigator.hasFeature("web-extensions").then(function(value) {
-    is(value, true, "Resolve the Promise with " + value + " for web-extensions");
-  }, function() {
-    ok(false, "The Promise should not be rejected");
+  var builtInFeatures = [
+    {feature: "web-extensions", value: true},
+    {feature: "late-customization", value: true}
+  ];
+
+  builtInFeatures.forEach(function(x) {
+    navigator.hasFeature(x.feature).then(function(value) {
+      is(value, x.value, "Resolve the Promise with " + value + " for feature: " + x.feature);
+    }).catch(function(ex) {
+      ok(false, "The Promise should not be rejected");
+    });
   });
+  return Promise.resolve();
 }
 
 SpecialPowers.pushPermissions([
   {type: "feature-detection", allow: true, context: document}
 ], function() {
   b2gOnly = (function() {
     var isAndroid = !!navigator.userAgent.includes("Android");
     var isMulet = pref("b2g.is_mulet");
--- a/dom/base/test/test_messagemanager_assertpermission.html
+++ b/dom/base/test/test_messagemanager_assertpermission.html
@@ -27,18 +27,18 @@ let gAppsService = SpecialPowers.Cc["@mo
                      .getService(SpecialPowers.Ci.nsIAppsService);
 
 function setUp() {
   SpecialPowers.addPermission("browser", true, window.document);
   SpecialPowers.addPermission("embed-apps", true, window.document);
 
   let appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
   SpecialPowers.addPermission("foobar", true, { url: APP_URL,
-                                                appId: appId,
-                                                isInBrowserElement: false });
+                                                originAttributes: { appId: appId }
+                                              });
   SpecialPowers.pushPrefEnv({"set":[['dom.mozBrowserFramesEnabled', true],
                                     ['dom.ipc.browser_frames.oop_by_default', true]]}, runNextTest);
 }
 
 /**
  * Load the example.org app in an <iframe mozbrowser mozapp>
  */
 function loadApp(callback) {
--- a/dom/base/test/test_messagemanager_targetchain.html
+++ b/dom/base/test/test_messagemanager_targetchain.html
@@ -98,25 +98,27 @@
         ok(false, "top document shouldn't receive test event from child");
       }, true);
       document.body.appendChild(iframe);
     }
 
     addEventListener("load", function() {
       var principal = SpecialPowers.wrap(document).nodePrincipal;
       SpecialPowers.pushPermissions([
-        { "type": "browser", "allow": 1, "context": { "url": principal.URI.spec,
-                                                      "appId": principal.appId,
-                                                      "isInBrowserElement": false }},
-        { "type": "browser", "allow": 1, "context": { "url": principal.URI.spec,
-                                                      "appId": principal.appId,
-                                                      "isInBrowserElement": true }}
+        { type: "browser", allow: 1, context: { url: principal.URI.spec,
+                                                originAttributes: {
+                                                  appId: principal.appId
+                                                }}},
+        { type: "browser", allow: 1, context: { url: principal.URI.spec,
+                                                originAttributes: {
+                                                  appId: principal.appId,
+                                                  inBrowser: true }}}
       ], () => {
         SpecialPowers.pushPrefEnv({
-          "set": [
+          set: [
             ["dom.mozBrowserFramesEnabled", true],
             ["dom.ipc.browser_frames.oop_by_default", false],
           ]
         }, runTests);
       });
     });
   </script>
 </body>
--- a/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothPbapManager.cpp
@@ -472,16 +472,21 @@ BluetoothPbapManager::NotifyPbapRequest(
     // ... PullvCardListing function uses relative paths. An empty name header
     // may be sent to retrieve the vCard Listing object of the current folder.
     name = name.IsEmpty() ? mCurrentPath
                           : mCurrentPath + NS_LITERAL_STRING("/") + name;
   } else if (type.EqualsLiteral("x-bt/vcard")) {
     reqId.AssignLiteral(PULL_VCARD_ENTRY_REQ_ID);
     tagCount = MOZ_ARRAY_LENGTH(sVCardEntryTags);
     tags = sVCardEntryTags;
+
+    // Convert relative path to absolute path if it's not using X-BT-UID.
+    if (name.Find(NS_LITERAL_STRING("X-BT-UID")) == kNotFound) {
+      name = mCurrentPath + NS_LITERAL_STRING("/") + name;
+    }
   } else {
     BT_LOGR("Unknown PBAP request type: %s",
             NS_ConvertUTF16toUTF8(type).get());
     return ObexResponseCode::BadRequest;
   }
 
   // Ensure bluetooth service is available
   BluetoothService* bs = BluetoothService::Get();
--- a/dom/browser-element/mochitest/browserElement_AllowEmbedAppsInNestedOOIframe.js
+++ b/dom/browser-element/mochitest/browserElement_AllowEmbedAppsInNestedOOIframe.js
@@ -17,22 +17,21 @@ function runTest() {
   iframe.setAttribute('mozbrowser', 'true');
   iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
     is(e.detail.message == 'app', true, e.detail.message);
     SimpleTest.finish();
   });
 
   document.body.appendChild(iframe);
 
-  var context = { 'url': 'http://example.org',
-                  'appId': SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
-                  'isInBrowserElement': true };
+  var context = {url: 'http://example.org',
+                 originAttributes: {inBrowser: true}};
   SpecialPowers.pushPermissions([
-    {'type': 'browser', 'allow': 1, 'context': context},
-    {'type': 'embed-apps', 'allow': 1, 'context': context}
+    {type: 'browser', allow: 1, context: context},
+    {type: 'embed-apps', allow: 1, context: context}
   ], function() {
     iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_AllowEmbedAppsInNestedOOIframe.html';
   });
 }
 
 addEventListener('testready', () => {
-  SpecialPowers.pushPrefEnv({"set": [["dom.ipc.tabs.nested.enabled", true]]}, runTest);
+  SpecialPowers.pushPrefEnv({set: [["dom.ipc.tabs.nested.enabled", true]]}, runTest);
 });
--- a/dom/browser-element/mochitest/browserElement_CopyPaste.js
+++ b/dom/browser-element/mochitest/browserElement_CopyPaste.js
@@ -338,18 +338,19 @@ function testCut2(e) {
     dispatchTest(e);
   });
 
   mm.loadFrameScript(getScriptForGetContent(), false);
 }
 
 // Give our origin permission to open browsers, and remove it when the test is complete.
 var principal = SpecialPowers.wrap(document).nodePrincipal;
-var context = { 'url': SpecialPowers.wrap(principal.URI).spec,
-                'appId': principal.appId,
-                'isInBrowserElement': true };
+var context = { url: SpecialPowers.wrap(principal.URI).spec,
+                originAttributes: {
+                  appId: principal.appId,
+                  inBrowser: true }};
 
 addEventListener('testready', function() {
   SpecialPowers.pushPermissions([
-    {'type': 'browser', 'allow': 1, 'context': context}
+    {type: 'browser', allow: 1, context: context}
   ], runTest);
 });
 
--- a/dom/browser-element/mochitest/browserElement_DisallowEmbedAppsInOOP.js
+++ b/dom/browser-element/mochitest/browserElement_DisallowEmbedAppsInOOP.js
@@ -23,20 +23,19 @@ function runTest() {
 
   iframe.addEventListener('mozbrowsershowmodalprompt', function(e) {
     is(e.detail.message == 'app', canEmbedApp, e.detail.message);
     SimpleTest.finish();
   });
 
   document.body.appendChild(iframe);
 
-  var context = { 'url': 'http://example.org',
-                  'appId': SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
-                  'isInBrowserElement': true };
+  var context = {url: 'http://example.org',
+                 originAttributes: {inBrowser: true}};
   SpecialPowers.pushPermissions([
-    {'type': 'browser', 'allow': 1, 'context': context},
-    {'type': 'embed-apps', 'allow': 1, 'context': context}
+    {type: 'browser', allow: 1, context: context},
+    {type: 'embed-apps', allow: 1, context: context}
   ], function() {
     iframe.src = 'http://example.org/tests/dom/browser-element/mochitest/file_browserElement_DisallowEmbedAppsInOOP.html';
   });
 }
 
 addEventListener('testready', runTest);
--- a/dom/browser-element/mochitest/browserElement_Proxy.js
+++ b/dom/browser-element/mochitest/browserElement_Proxy.js
@@ -9,26 +9,28 @@ browserElementTestHelpers.addPermission(
 
 function runTest() {
   let frameUrl = SimpleTest.getTestFileURL('/file_empty.html');
   SpecialPowers.pushPermissions([{
     type: 'browser:embedded-system-app',
     allow: true,
     context: {
       url: frameUrl,
-      appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
-      isInBrowserElement: true
+      originAttributes: {
+        inBrowser: true
+      }
     }
   },{
     type: 'browser',
     allow: true,
     context: {
       url: frameUrl,
-      appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
-      isInBrowserElement: true
+      originAttributes: {
+        inBrowser: true
+      }
     }
   }], createFrame);
 }
 
 var frame;
 var mm;
 
 function createFrame() {
--- a/dom/browser-element/mochitest/browserElement_SetInputMethodActive.js
+++ b/dom/browser-element/mochitest/browserElement_SetInputMethodActive.js
@@ -31,18 +31,17 @@ function runTest() {
   let imeUrl = location.protocol + '//' + location.host +
                path.substring(0, path.lastIndexOf('/')) +
                '/file_inputmethod.html';
   SpecialPowers.pushPermissions([{
     type: 'input',
     allow: true,
     context: {
       url: imeUrl,
-      appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
-      isInBrowserElement: true
+      originAttributes: {inBrowser: true}
     }
   }], SimpleTest.waitForFocus.bind(SimpleTest, createFrames));
 }
 
 var gFrames = [];
 var gInputFrame;
 
 function createFrames() {
--- a/dom/browser-element/mochitest/browserElement_SetVisibleFrames.js
+++ b/dom/browser-element/mochitest/browserElement_SetVisibleFrames.js
@@ -13,19 +13,21 @@
 SimpleTest.waitForExplicitFinish();
 browserElementTestHelpers.setEnabledPref(true);
 browserElementTestHelpers.addPermission();
 
 var iframe;
 
 function runTest() {
   var principal = SpecialPowers.wrap(document).nodePrincipal;
-  SpecialPowers.addPermission("browser", true, { url: SpecialPowers.wrap(principal.URI).spec,
-                                                 appId: principal.appId,
-                                                 isInBrowserElement: true });
+  SpecialPowers.addPermission("browser", true, {url: SpecialPowers.wrap(principal.URI).spec,
+                                                originAttributes: {
+                                                  appId: principal.appId,
+                                                  inBrowser: true
+                                                }});
 
   iframe = document.createElement('iframe');
   iframe.setAttribute('mozbrowser', 'true');
 
   // Our test involves three <iframe mozbrowser>'s, parent, child1, and child2.
   // child1 and child2 are contained inside parent.  child1 is visibile, and
   // child2 is not.
   //
@@ -70,20 +72,21 @@ function finish() {
   // We need to remove this listener because when this test finishes and the
   // iframe containing this document is navigated, we'll fire a
   // visibilitychange(false) event on all child iframes.  That's OK and
   // expected, but if we don't remove our listener, then we'll end up causing
   // the /next/ test to fail!
   iframe.removeEventListener('mozbrowsershowmodalprompt', checkMessage);
 
   var principal = SpecialPowers.wrap(document).nodePrincipal;
-  SpecialPowers.removePermission("browser", { url: SpecialPowers.wrap(principal.URI).spec,
-                                              appId: principal.appId,
-                                              isInBrowserElement: true });
-
+  SpecialPowers.removePermission("browser", {url: SpecialPowers.wrap(principal.URI).spec,
+                                             originAttributes: {
+                                               appId: principal.appId,
+                                               inBrowser: true
+                                             }});
   SimpleTest.finish();
 }
 
 var expectedMsg = null;
 var expectedMsgCallback = null;
 function expectMessage(msg, next) {
   expectedMsg = msg;
   expectedMsgCallback = next;
--- a/dom/browser-element/mochitest/browserElement_SetVisibleFrames2.js
+++ b/dom/browser-element/mochitest/browserElement_SetVisibleFrames2.js
@@ -7,19 +7,21 @@
 "use strict";
 
 SimpleTest.waitForExplicitFinish();
 browserElementTestHelpers.setEnabledPref(true);
 browserElementTestHelpers.addPermission();
 
 function runTest() {
   var principal = SpecialPowers.wrap(document).nodePrincipal;
-  SpecialPowers.addPermission("browser", true, { url: SpecialPowers.wrap(principal.URI).spec,
-                                                 appId: principal.appId,
-                                                 isInBrowserElement: true });
+  SpecialPowers.addPermission("browser", true, {url: SpecialPowers.wrap(principal.URI).spec,
+                                                originAttributes: {
+                                                  appId: principal.appId,
+                                                  inBrowser: true
+                                                }});
 
   var iframe = document.createElement('iframe');
   iframe.setAttribute('mozbrowser', 'true');
 
   // We need remote = false here until bug 761935 is fixed; see
   // SetVisibleFrames.js for an explanation.
   iframe.remote = false;
 
@@ -51,16 +53,18 @@ function runTest() {
     }
   });
 
   document.body.appendChild(iframe);
 }
 
 function finish() {
   var principal = SpecialPowers.wrap(document).nodePrincipal;
-  SpecialPowers.removePermission("browser", { url: SpecialPowers.wrap(principal.URI).spec,
-                                              appId: principal.appId,
-                                              isInBrowserElement: true });
+  SpecialPowers.removePermission("browser", {url: SpecialPowers.wrap(principal.URI).spec,
+                                             originAttributes: {
+                                               appId: principal.appId,
+                                               inBrowser: true
+                                             }});
 
   SimpleTest.finish();
 }
 
 addEventListener('testready', runTest);
--- a/dom/browser-element/mochitest/priority/test_ExpectingSystemMessage2.html
+++ b/dom/browser-element/mochitest/priority/test_ExpectingSystemMessage2.html
@@ -17,25 +17,29 @@ message gets priority BACKGROUND_PERCEIV
 SimpleTest.waitForExplicitFinish();
 browserElementTestHelpers.setEnabledPref(true);
 browserElementTestHelpers.addPermission();
 browserElementTestHelpers.enableProcessPriorityManager();
 SpecialPowers.addPermission("embed-apps", true, document);
 
 // Give our origin permission to open browsers, and remove it when the test is complete.
 var principal = SpecialPowers.wrap(document).nodePrincipal;
-SpecialPowers.addPermission("browser", true, { url: SpecialPowers.wrap(principal.URI).spec,
-                                               appId: principal.appId,
-                                               isInBrowserElement: true });
+SpecialPowers.addPermission("browser", true, {url: SpecialPowers.wrap(principal.URI).spec,
+                                              originAttributes: {
+                                                appId: principal.appId,
+                                                inBrowser: true
+                                              }});
 
 addEventListener('unload', function() {
   var principal = SpecialPowers.wrap(document).nodePrincipal;
-  SpecialPowers.removePermission("browser", { url: SpecialPowers.wrap(principal.URI).spec,
-                                              appId: principal.appId,
-                                              isInBrowserElement: true });
+  SpecialPowers.removePermission("browser", {url: SpecialPowers.wrap(principal.URI).spec,
+                                             originAttributes: {
+                                               appId: principal.appId,
+                                               inBrowser: true
+                                             }});
 });
 
 function runTest() {
   var iframe = document.createElement('iframe');
   iframe.setAttribute('mozbrowser', true);
   iframe.setAttribute('expecting-system-message', true);
   iframe.setAttribute('mozapp', 'http://example.org/manifest.webapp');
 
--- a/dom/browser-element/mochitest/priority/test_NestedFrames.html
+++ b/dom/browser-element/mochitest/priority/test_NestedFrames.html
@@ -16,25 +16,29 @@ Test changing the visibility of an <ifra
 
 SimpleTest.waitForExplicitFinish();
 browserElementTestHelpers.setEnabledPref(true);
 browserElementTestHelpers.addPermission();
 browserElementTestHelpers.enableProcessPriorityManager();
 
 // Give our origin permission to open browsers, and remove it when the test is complete.
 var principal = SpecialPowers.wrap(document).nodePrincipal;
-SpecialPowers.addPermission("browser", true, { url: SpecialPowers.wrap(principal.URI).spec,
-                                               appId: principal.appId,
-                                               isInBrowserElement: true });
+SpecialPowers.addPermission("browser", true, {url: SpecialPowers.wrap(principal.URI).spec,
+                                              originAttributes: {
+                                                appId: principal.appId,
+                                                inBrowser: true
+                                              }});
 
 addEventListener('unload', function() {
   var principal = SpecialPowers.wrap(document).nodePrincipal;
-  SpecialPowers.removePermission("browser", { url: SpecialPowers.wrap(principal.URI).spec,
-                                              appId: principal.appId,
-                                              isInBrowserElement: true });
+  SpecialPowers.removePermission("browser", {url: SpecialPowers.wrap(principal.URI).spec,
+                                             originAttributes: {
+                                               appId: principal.appId,
+                                               inBrowser: true
+                                             }});
 });
 
 function runTest() {
   // Set up the following hierarchy of frames:
   //
   //   <iframe mozbrowser remote=false src='file_NestedFramesOuter.html'>
   //     <iframe mozbrowser remote=true src='file_empty.html'>
   //
--- a/dom/cache/test/mochitest/driver.js
+++ b/dom/cache/test/mochitest/driver.js
@@ -30,26 +30,17 @@ function runTests(testFile, order) {
         resolve();
       });
     });
   }
 
   // adapted from dom/indexedDB/test/helpers.js
   function clearStorage() {
     return new Promise(function(resolve, reject) {
-      var principal = SpecialPowers.wrap(document).nodePrincipal;
-      var appId, inBrowser;
-      var nsIPrincipal = SpecialPowers.Components.interfaces.nsIPrincipal;
-      if (principal.appId != nsIPrincipal.UNKNOWN_APP_ID &&
-          principal.appId != nsIPrincipal.NO_APP_ID) {
-        appId = principal.appId;
-        inBrowser = principal.isInBrowserElement;
-      }
-      SpecialPowers.clearStorageForURI(document.documentURI, resolve, appId,
-                                       inBrowser);
+      SpecialPowers.clearStorageForDoc(SpecialPowers.wrap(document), resolve);
     });
   }
 
   function loadScript(script) {
     return new Promise(function(resolve, reject) {
       var s = document.createElement("script");
       s.src = script;
       s.onerror = reject;
--- a/dom/cache/test/mochitest/test_cache_orphaned_body.html
+++ b/dom/cache/test/mochitest/test_cache_orphaned_body.html
@@ -19,56 +19,29 @@ function setupTestIframe() {
       resolve();
     };
     document.body.appendChild(iframe);
   });
 }
 
 function clearStorage() {
   return new Promise(function(resolve, reject) {
-    var principal = SpecialPowers.wrap(document).nodePrincipal;
-    var appId, inBrowser;
-    var nsIPrincipal = SpecialPowers.Components.interfaces.nsIPrincipal;
-    if (principal.appId != nsIPrincipal.UNKNOWN_APP_ID &&
-        principal.appId != nsIPrincipal.NO_APP_ID) {
-      appId = principal.appId;
-      inBrowser = principal.isInBrowserElement;
-    }
-    SpecialPowers.clearStorageForURI(document.documentURI, resolve, appId,
-                                     inBrowser);
+    SpecialPowers.clearStorageForDoc(SpecialPowers.wrap(document), resolve);
   });
 }
 
 function storageUsage() {
   return new Promise(function(resolve, reject) {
-    var principal = SpecialPowers.wrap(document).nodePrincipal;
-    var appId, inBrowser;
-    var nsIPrincipal = SpecialPowers.Components.interfaces.nsIPrincipal;
-    if (principal.appId != nsIPrincipal.UNKNOWN_APP_ID &&
-        principal.appId != nsIPrincipal.NO_APP_ID) {
-      appId = principal.appId;
-      inBrowser = principal.isInBrowserElement;
-    }
-    SpecialPowers.getStorageUsageForURI(document.documentURI, resolve, appId,
-                                        inBrowser);
+    SpecialPowers.getStorageUsageForDoc(SpecialPowers.wrap(document), resolve);
   });
 }
 
 function resetStorage() {
   return new Promise(function(resolve, reject) {
-    var principal = SpecialPowers.wrap(document).nodePrincipal;
-    var appId, inBrowser;
-    var nsIPrincipal = SpecialPowers.Components.interfaces.nsIPrincipal;
-    if (principal.appId != nsIPrincipal.UNKNOWN_APP_ID &&
-        principal.appId != nsIPrincipal.NO_APP_ID) {
-      appId = principal.appId;
-      inBrowser = principal.isInBrowserElement;
-    }
-    SpecialPowers.resetStorageForURI(document.documentURI, resolve, appId,
-                                     inBrowser);
+    SpecialPowers.resetStorageForDoc(SpecialPowers.wrap(document), resolve);
   });
 }
 
 function gc() {
   return new Promise(function(resolve, reject) {
     SpecialPowers.exactGC(window, resolve);
   });
 }
--- a/dom/cache/test/mochitest/test_cache_orphaned_cache.html
+++ b/dom/cache/test/mochitest/test_cache_orphaned_cache.html
@@ -19,56 +19,29 @@ function setupTestIframe() {
       resolve();
     };
     document.body.appendChild(iframe);
   });
 }
 
 function clearStorage() {
   return new Promise(function(resolve, reject) {
-    var principal = SpecialPowers.wrap(document).nodePrincipal;
-    var appId, inBrowser;
-    var nsIPrincipal = SpecialPowers.Components.interfaces.nsIPrincipal;
-    if (principal.appId != nsIPrincipal.UNKNOWN_APP_ID &&
-        principal.appId != nsIPrincipal.NO_APP_ID) {
-      appId = principal.appId;
-      inBrowser = principal.isInBrowserElement;
-    }
-    SpecialPowers.clearStorageForURI(document.documentURI, resolve, appId,
-                                     inBrowser);
+    SpecialPowers.clearStorageForDoc(SpecialPowers.wrap(document), resolve);
   });
 }
 
 function storageUsage() {
   return new Promise(function(resolve, reject) {
-    var principal = SpecialPowers.wrap(document).nodePrincipal;
-    var appId, inBrowser;
-    var nsIPrincipal = SpecialPowers.Components.interfaces.nsIPrincipal;
-    if (principal.appId != nsIPrincipal.UNKNOWN_APP_ID &&
-        principal.appId != nsIPrincipal.NO_APP_ID) {
-      appId = principal.appId;
-      inBrowser = principal.isInBrowserElement;
-    }
-    SpecialPowers.getStorageUsageForURI(document.documentURI, resolve, appId,
-                                        inBrowser);
+    SpecialPowers.getStorageUsageForDoc(SpecialPowers.wrap(document), resolve);
   });
 }
 
 function resetStorage() {
   return new Promise(function(resolve, reject) {
-    var principal = SpecialPowers.wrap(document).nodePrincipal;
-    var appId, inBrowser;
-    var nsIPrincipal = SpecialPowers.Components.interfaces.nsIPrincipal;
-    if (principal.appId != nsIPrincipal.UNKNOWN_APP_ID &&
-        principal.appId != nsIPrincipal.NO_APP_ID) {
-      appId = principal.appId;
-      inBrowser = principal.isInBrowserElement;
-    }
-    SpecialPowers.resetStorageForURI(document.documentURI, resolve, appId,
-                                     inBrowser);
+    SpecialPowers.resetStorageForDoc(SpecialPowers.wrap(document), resolve);
   });
 }
 
 function gc() {
   return new Promise(function(resolve, reject) {
     SpecialPowers.exactGC(window, resolve);
   });
 }
--- a/dom/cache/test/mochitest/test_cache_restart.html
+++ b/dom/cache/test/mochitest/test_cache_restart.html
@@ -18,26 +18,17 @@ function setupTestIframe() {
       resolve();
     };
     document.body.appendChild(iframe);
   });
 }
 
 function resetStorage() {
   return new Promise(function(resolve, reject) {
-    var principal = SpecialPowers.wrap(document).nodePrincipal;
-    var appId, inBrowser;
-    var nsIPrincipal = SpecialPowers.Components.interfaces.nsIPrincipal;
-    if (principal.appId != nsIPrincipal.UNKNOWN_APP_ID &&
-        principal.appId != nsIPrincipal.NO_APP_ID) {
-      appId = principal.appId;
-      inBrowser = principal.isInBrowserElement;
-    }
-    SpecialPowers.resetStorageForURI(document.documentURI, resolve, appId,
-                                     inBrowser);
+    SpecialPowers.resetStorageForDoc(SpecialPowers.wrap(document), resolve);
   });
 }
 
 SimpleTest.waitForExplicitFinish();
 SpecialPowers.pushPrefEnv({
   "set": [["dom.caches.enabled", true],
           ["dom.caches.testing.enabled", true],
           ["dom.quotaManager.testing", true]],
--- a/dom/cache/test/mochitest/test_cache_shrink.html
+++ b/dom/cache/test/mochitest/test_cache_shrink.html
@@ -19,56 +19,29 @@ function setupTestIframe() {
       resolve();
     };
     document.body.appendChild(iframe);
   });
 }
 
 function clearStorage() {
   return new Promise(function(resolve, reject) {
-    var principal = SpecialPowers.wrap(document).nodePrincipal;
-    var appId, inBrowser;
-    var nsIPrincipal = SpecialPowers.Components.interfaces.nsIPrincipal;
-    if (principal.appId != nsIPrincipal.UNKNOWN_APP_ID &&
-        principal.appId != nsIPrincipal.NO_APP_ID) {
-      appId = principal.appId;
-      inBrowser = principal.isInBrowserElement;
-    }
-    SpecialPowers.clearStorageForURI(document.documentURI, resolve, appId,
-                                     inBrowser);
+    SpecialPowers.clearStorageForDoc(SpecialPowers.wrap(document), resolve);
   });
 }
 
 function storageUsage() {
   return new Promise(function(resolve, reject) {
-    var principal = SpecialPowers.wrap(document).nodePrincipal;
-    var appId, inBrowser;
-    var nsIPrincipal = SpecialPowers.Components.interfaces.nsIPrincipal;
-    if (principal.appId != nsIPrincipal.UNKNOWN_APP_ID &&
-        principal.appId != nsIPrincipal.NO_APP_ID) {
-      appId = principal.appId;
-      inBrowser = principal.isInBrowserElement;
-    }
-    SpecialPowers.getStorageUsageForURI(document.documentURI, resolve, appId,
-                                        inBrowser);
+    SpecialPowers.getStorageUsageForDoc(SpecialPowers.wrap(document), resolve);
   });
 }
 
 function resetStorage() {
   return new Promise(function(resolve, reject) {
-    var principal = SpecialPowers.wrap(document).nodePrincipal;
-    var appId, inBrowser;
-    var nsIPrincipal = SpecialPowers.Components.interfaces.nsIPrincipal;
-    if (principal.appId != nsIPrincipal.UNKNOWN_APP_ID &&
-        principal.appId != nsIPrincipal.NO_APP_ID) {
-      appId = principal.appId;
-      inBrowser = principal.isInBrowserElement;
-    }
-    SpecialPowers.resetStorageForURI(document.documentURI, resolve, appId,
-                                     inBrowser);
+    SpecialPowers.resetStorageForDoc(SpecialPowers.wrap(document), resolve);
   });
 }
 
 function gc() {
   return new Promise(function(resolve, reject) {
     SpecialPowers.exactGC(window, resolve);
   });
 }
--- a/dom/indexedDB/test/file.js
+++ b/dom/indexedDB/test/file.js
@@ -184,27 +184,17 @@ function verifyMutableFile(mutableFile1,
 
 function grabFileUsageAndContinueHandler(usage, fileUsage)
 {
   testGenerator.send(fileUsage);
 }
 
 function getUsage(usageHandler)
 {
-  let principal = SpecialPowers.wrap(document).nodePrincipal;
-  let appId, inBrowser;
-  if (principal.appId != Components.interfaces.nsIPrincipal.UNKNOWN_APP_ID &&
-      principal.appId != Components.interfaces.nsIPrincipal.NO_APP_ID) {
-    appId = principal.appId;
-    inBrowser = principal.isInBrowserElement;
-  }
-  SpecialPowers.getStorageUsageForURI(window.document.documentURI,
-                                      usageHandler,
-                                      appId,
-                                      inBrowser);
+  SpecialPowers.getStorageUsageForDoc(SpecialPowers.wrap(document), usageHandler);
 }
 
 function getFileId(file)
 {
   return utils.getFileId(file);
 }
 
 function getFilePath(file)
--- a/dom/indexedDB/test/helpers.js
+++ b/dom/indexedDB/test/helpers.js
@@ -29,24 +29,17 @@ function executeSoon(aFun)
   thread.dispatch({
     run: function() {
       aFun();
     }
   }, Components.interfaces.nsIThread.DISPATCH_NORMAL);
 }
 
 function clearAllDatabases(callback) {
-  let principal = SpecialPowers.wrap(document).nodePrincipal;
-  let appId, inBrowser;
-  if (principal.appId != Components.interfaces.nsIPrincipal.UNKNOWN_APP_ID &&
-      principal.appId != Components.interfaces.nsIPrincipal.NO_APP_ID) {
-    appId = principal.appId;
-    inBrowser = principal.isInBrowserElement;
-  }
-  SpecialPowers.clearStorageForURI(document.documentURI, callback, appId, inBrowser);
+  SpecialPowers.clearStorageForDoc(SpecialPowers.wrap(document), callback);
 }
 
 var testHarnessGenerator = testHarnessSteps();
 testHarnessGenerator.next();
 
 function testHarnessSteps() {
   function nextTestHarnessStep(val) {
     testHarnessGenerator.send(val);
--- a/dom/indexedDB/test/webapp_clearBrowserData.js
+++ b/dom/indexedDB/test/webapp_clearBrowserData.js
@@ -112,21 +112,19 @@ function start()
 {
   if (!SpecialPowers.isMainProcess()) {
     todo(false, "Test disabled in child processes, for now");
     SimpleTest.finish();
     return;
   }
 
   SpecialPowers.addPermission("browser", true, document);
-  SpecialPowers.addPermission("browser", true, { manifestURL: manifestURL,
-                                                 isInBrowserElement: false });
+  SpecialPowers.addPermission("browser", true, { manifestURL: manifestURL });
   SpecialPowers.addPermission("embed-apps", true, document);
-  SpecialPowers.addPermission("indexedDB", true, { manifestURL: manifestURL,
-                                                   isInBrowserElement: false });
+  SpecialPowers.addPermission("indexedDB", true, { manifestURL: manifestURL });
 
   SpecialPowers.setAllAppsLaunchable(true);
 
   window.addEventListener("unload", function cleanup(event) {
     if (event.target == document) {
       window.removeEventListener("unload", cleanup, false);
 
       SpecialPowers.removePermission("browser", location.href);
--- a/dom/inputmethod/mochitest/test_bug1043828.html
+++ b/dom/inputmethod/mochitest/test_bug1043828.html
@@ -86,18 +86,19 @@ function runTest() {
     // simulate two different keyboard apps
     let imeUrl = basePath + '/file_blank.html';
 
     SpecialPowers.pushPermissions([{
       type: 'input',
       allow: true,
       context: {
         url: imeUrl,
-        appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
-        isInBrowserElement: true
+        originAttributes: {
+          inBrowser: true
+        }
       }
     }], function() {
       keyboardA.src = imeUrl;
       keyboardB.src = imeUrl;
 
       var handler = {
         handleEvent: function(){
           keyboardB.removeEventListener('mozbrowserloadend', this);
--- a/dom/inputmethod/mochitest/test_bug944397.html
+++ b/dom/inputmethod/mochitest/test_bug944397.html
@@ -73,18 +73,19 @@ function runTest() {
     // STEP 2b: Grant input privileges to the keyboard iframe
     let imeUrl = basePath + '/file_inputmethod.html#data';
 
     SpecialPowers.pushPermissions([{
       type: 'input',
       allow: true,
       context: {
         url: imeUrl,
-        appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
-        isInBrowserElement: true
+        originAttributes: {
+          inBrowser: true
+        }
       }
     }], function() {
       // STEP 2c: Tell Gecko to use this iframe as its keyboard app
       let req = keyboard.setInputMethodActive(true);
 
       req.onsuccess = function() {
         ok(true, 'setInputMethodActive succeeded.');
       };
--- a/dom/inputmethod/mochitest/test_focus_blur_manage_events.html
+++ b/dom/inputmethod/mochitest/test_focus_blur_manage_events.html
@@ -136,18 +136,19 @@ function setupInputAppFrame() {
     inputAppFrame.src = imeUrl;
     document.body.appendChild(inputAppFrame);
 
     SpecialPowers.pushPermissions([{
       type: 'input',
       allow: true,
       context: {
         url: imeUrl,
-        appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
-        isInBrowserElement: true
+        originAttributes: {
+          inBrowser: true
+        }
       }
     }], function() {
       let mm = SpecialPowers.getBrowserFrameMessageManager(inputAppFrame);
       inputAppFrame.addEventListener('mozbrowserloadend', function() {
         mm.addMessageListener('text:appEvent', function(msg) {
           ok(false, 'Input app should not receive ' + msg.data.type + ' event.');
         });
         mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
--- a/dom/inputmethod/mochitest/test_input_registry_events.html
+++ b/dom/inputmethod/mochitest/test_input_registry_events.html
@@ -65,18 +65,19 @@ function setupInputAppFrame() {
     inputAppFrame.src = imeUrl;
     document.body.appendChild(inputAppFrame);
 
     SpecialPowers.pushPermissions([{
       type: 'input',
       allow: true,
       context: {
         url: imeUrl,
-        appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
-        isInBrowserElement: true
+        originAttributes: {
+          inBrowser: true
+        }
       }
     }], function() {
       let mm = appFrameMM =
         SpecialPowers.getBrowserFrameMessageManager(inputAppFrame);
 
       inputAppFrame.addEventListener('mozbrowserloadend', function() {
         mm.addMessageListener('test:appEvent', function(msg) {
           ok(false, 'Input app should not receive ' + msg.data.type + ' event.');
--- a/dom/inputmethod/mochitest/test_simple_manage_events.html
+++ b/dom/inputmethod/mochitest/test_simple_manage_events.html
@@ -98,18 +98,19 @@ function setupInputAppFrame() {
     inputAppFrame.src = imeUrl;
     document.body.appendChild(inputAppFrame);
 
     SpecialPowers.pushPermissions([{
       type: 'input',
       allow: true,
       context: {
         url: imeUrl,
-        appId: SpecialPowers.Ci.nsIScriptSecurityManager.NO_APP_ID,
-        isInBrowserElement: true
+        originAttributes: {
+          inBrowser: true
+        }
       }
     }], function() {
       let mm = appFrameMM =
         SpecialPowers.getBrowserFrameMessageManager(inputAppFrame);
 
       inputAppFrame.addEventListener('mozbrowserloadend', function() {
         mm.addMessageListener('test:appEvent', function(msg) {
           ok(false, 'Input app should not receive ' + msg.data.type + ' event.');
--- a/dom/ipc/tests/test_permission_for_nested_oop_app.html
+++ b/dom/ipc/tests/test_permission_for_nested_oop_app.html
@@ -28,18 +28,17 @@ var tests = [
 
   // Install the app
   installApp,
 
   // Allow permission for embedApp to open mozbrowser and mozapp
   function() {
     var appId = gAppsService.getAppLocalIdByManifestURL(embedAppHostedManifestURL);
     var context = { url: embedApp.origin,
-                    appId: appId,
-                    isInBrowserElement: false };
+                    originAttributes: { appId: appId } };
     setupOpenAppPermission(context, runTests);
   },
 
   // +-------------------------------------------+
   // | Test 3: Open a test-target-app on 3rd     |
   // |         level child-process then close it |
   // +-------------------------------------------+
   //
--- a/dom/ipc/tests/test_permission_for_two_oop_apps.html
+++ b/dom/ipc/tests/test_permission_for_two_oop_apps.html
@@ -28,18 +28,17 @@ var tests = [
 
   // Install the app
   installApp,
 
   // Allow permission for embedApp to open mozbrowser and mozapp
   function() {
     var appId = gAppsService.getAppLocalIdByManifestURL(embedAppHostedManifestURL);
     var context = { url: embedApp.origin,
-                    appId: appId,
-                    isInBrowserElement: false };
+                    originAttributes: { appId: appId } };
     setupOpenAppPermission(context, runTests);
   },
 
   // +---------------------------------------------------------+
   // | Test 4: Open two test-target-app on 2nd and 3rd level   |
   // |         child-processes then close the one on 3rd level |
   // +---------------------------------------------------------+
   //
--- a/dom/ipc/tests/test_permission_helper.js
+++ b/dom/ipc/tests/test_permission_helper.js
@@ -48,18 +48,17 @@ function runTests() {
 
 function test1() {
   allocateAppFrame(APP_IFRAME_ID, DOM_PARENT, APP_URL, APP_MANIFEST);
 
   var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
 
   if (!SpecialPowers.hasPermission( PERMISSION_TYPE,
                                     { url: APP_URL,
-                                      appId: appId,
-                                      isInBrowserElement: false })) {
+                                      originAttributes: { appId: appId }})) {
     errorHandler('[test 1] App should have permission: ' + PERMISSION_TYPE);
   }
 
   removeAppFrame(APP_IFRAME_ID);
 
   // We expect there is no permission for the test-target-app
   // after removing the in-process iframe embedding this app
   runNextIfAppHasPermission(1, false, APP_URL, APP_MANIFEST);
@@ -77,18 +76,17 @@ function test2() {
   afterContentShutdown(1, afterShutdown);
 
   allocateAppFrame(APP_IFRAME_ID, DOM_PARENT, APP_URL, APP_MANIFEST, true);
 
   var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
 
   if (!SpecialPowers.hasPermission( PERMISSION_TYPE,
                                     { url: APP_URL,
-                                      appId: appId,
-                                      isInBrowserElement: false })) {
+                                      originAttributes: { appId: appId }})) {
     errorHandler('[test 2] App should have permission: ' + PERMISSION_TYPE);
   }
 
   removeAppFrame(APP_IFRAME_ID);
 }
 
 function test3() {
   var afterGrandchildShutdown = function () {
@@ -106,18 +104,17 @@ function test3() {
                    embedApp.manifest.launch_path,
                    embedApp.manifestURL,
                    true);
 
   var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
 
   if (!SpecialPowers.hasPermission(PERMISSION_TYPE,
                                    { url: APP_URL,
-                                     appId: appId,
-                                     isInBrowserElement: false })) {
+                                     originAttributes: { appId: appId }})) {
     errorHandler('[test 3] App should have permission: ' + PERMISSION_TYPE);
   }
 }
 
 function test4() {
   var afterGrandchildShutdown = function () {
     // We expect there is still a permission for the test-target-app
     // after killing test-target-app on 3rd-level process
@@ -143,18 +140,17 @@ function test4() {
                    APP_URL,
                    APP_MANIFEST,
                    true);
 
   var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
 
   if (!SpecialPowers.hasPermission(PERMISSION_TYPE,
                                    { url: APP_URL,
-                                     appId: appId,
-                                     isInBrowserElement: false })) {
+                                     originAttributes: { appId: appId }})) {
     errorHandler('[test 4] App should have permission: ' + PERMISSION_TYPE);
   }
 }
 
 function test5() {
   var afterShutdown = function () {
     // We expect there is no permission for the test-target-app
     // after crashing its parent-process
@@ -169,18 +165,17 @@ function test5() {
                    embedApp.manifest.launch_path + '#' + encodeURIComponent('crash'),
                    embedApp.manifestURL,
                    true);
 
   var appId = gAppsService.getAppLocalIdByManifestURL(APP_MANIFEST);
 
   if (!SpecialPowers.hasPermission( PERMISSION_TYPE,
                                     { url: APP_URL,
-                                      appId: appId,
-                                      isInBrowserElement: false })) {
+                                      originAttributes: { appId: appId }})) {
     errorHandler('[test 5] App should have permission: ' + PERMISSION_TYPE);
   }
 
   // Crash the child-process on 2nd level after
   // the grandchild process on 3rd is allocated
   var handler = {'crash': function() {
       gScript.sendAsyncMessage("crashreporter-status", {});
 
@@ -285,31 +280,29 @@ function addPermissionToApp(appURL, mani
 
   // Add app's permission asynchronously
   SpecialPowers.pushPermissions([
       { "type":PERMISSION_TYPE,
         "allow": 1,
         "expireType":permManager.EXPIRE_SESSION,
         "expireTime":now + SESSION_PERSIST_MINUTES*60*1000,
         "context": { url: appURL,
-                     appId: appId,
-                     isInBrowserElement:false }
+                     originAttributes: { appId: appId } }
       }
     ], function() {
       runTests();
     });
 }
 
 function runNextIfAppHasPermission(round, expect, appURL, manifestURL) {
   var appId = gAppsService.getAppLocalIdByManifestURL(manifestURL);
 
   var hasPerm = SpecialPowers.hasPermission(PERMISSION_TYPE,
                                             { url: appURL,
-                                              appId: appId,
-                                              isInBrowserElement: false });
+                                              originAttributes: { appId: appId }});
   var result = (expect==hasPerm);
   if (result) {
     runTests();
   } else {
     errorHandler( '[test ' + round + '] App should ' + ((expect)? '':'NOT ') +
                   'have permission: ' + PERMISSION_TYPE);
   }
 }
--- a/dom/ipc/tests/test_permission_when_oop_app_crashes.html
+++ b/dom/ipc/tests/test_permission_when_oop_app_crashes.html
@@ -28,18 +28,17 @@ var tests = [
 
   // Install the app
   installApp,
 
   // Allow permission for embedApp to open mozbrowser and mozapp
   function() {
     var appId = gAppsService.getAppLocalIdByManifestURL(embedAppHostedManifestURL);
     var context = { url: embedApp.origin,
-                    appId: appId,
-                    isInBrowserElement: false };
+                    originAttributes: { appId: appId } };
     setupOpenAppPermission(context, runTests);
   },
 
   // +-----------------------------------------------+
   // | Test 5: Open a test-target-app on 3rd level   |
   // |         process then crash its parent-process |
   // +-----------------------------------------------+
   //
--- a/dom/tv/test/mochitest/head.js
+++ b/dom/tv/test/mochitest/head.js
@@ -17,18 +17,19 @@ function installApp(aTestToken, aTemplat
                           + aTestToken + '&template=' + aTemplate;
   var request = navigator.mozApps.install(hostedManifestURL);
   request.onerror = cbError;
   request.onsuccess = function() {
     gApp = request.result;
 
     var appId = gAppsService.getAppLocalIdByManifestURL(gApp.manifestURL);
     SpecialPowers.addPermission("tv", true, { url: gApp.origin,
-                                              appId: appId,
-                                              isInBrowserElement: false });
+                                              originAttributes: {
+                                                appId: appId
+                                              }});
 
     runTest();
   }
 }
 
 function uninstallApp() {
   var request = navigator.mozApps.mgmt.uninstall(gApp);
   request.onerror = cbError;
--- a/testing/mochitest/tests/Harness_sanity/test_SpecialPowersPushAppPermissions.html
+++ b/testing/mochitest/tests/Harness_sanity/test_SpecialPowersPushAppPermissions.html
@@ -64,46 +64,44 @@ function installApp(aTestToken, aTemplat
     gApp = request.result; // Assign to global variable
     pushPermissionsToApp();
   }
 }
 
 function pushPermissionsToApp() {
   var appId = gAppsService.getAppLocalIdByManifestURL(gApp.manifestURL);
   var context = { url: gApp.origin,
-                  appId: appId,
-                  isInBrowserElement: false };
+                  originAttributes: {appId: appId}};
   SpecialPowers.pushPermissions([
       { "type": "pAppPermission", "allow": true, "context": context }
     ], testPermissionsForApp);
 }
 
 function testPermissionsForApp() {
   var appId = gAppsService.getAppLocalIdByManifestURL(gApp.manifestURL);
   var context = { url: gApp.origin,
-                  appId: appId,
-                  isInBrowserElement: false };
+                  originAttributes: {appId: appId}};
   ok(SpecialPowers.hasPermission('pAppPermission', context), 'pAppPermission should have permission');
   uninstallApp();
 }
 
 function uninstallApp() {
   var request = navigator.mozApps.mgmt.uninstall(gApp);
   request.onerror = cbError;
   request.onsuccess = function() {
     testPermissionsForSelfAndApp();
   }
 }
 
 function testPermissionsForSelfAndApp() {
   var appId = gAppsService.getAppLocalIdByManifestURL(gApp.manifestURL);
-  var context = { url: gApp.origin,
-                  appId: appId,
-                  isInBrowserElement: false };
-  ok(!SpecialPowers.hasPermission('pAppPermission', context), 'pAppPermission should not have permission');
+  is(appId, 0, "appId should become NO_APP_ID");
+  // since gApp is uninstalled, calling SpecialPowers.hasPermission with the
+  // app's properties (manifestURL, origin, principal, ... etc) will throw.
+  // So we don't need to test hasPermission for the app.
 
   ok(SpecialPowers.hasPermission('pAppPermission', document), 'pAppPermission should have permission');
 
   SimpleTest.finish();
 }
 </script>
 </pre>
 </body>
--- a/testing/mochitest/tests/Harness_sanity/test_bug816847.html
+++ b/testing/mochitest/tests/Harness_sanity/test_bug816847.html
@@ -52,35 +52,33 @@ function starttest(){
   var origin = app.origin 
   var nodePrincipal = SpecialPowers.wrap(document).nodePrincipal;
   var appPrincipal = createPrincipal(manifest, true);
   var noappPrincipal = createPrincipal(origin, false);
 
   SpecialPowers.addPermission(perms[0], true, origin);
   SpecialPowers.addPermission(perms[1], true, {manifestURL: manifest});
   SpecialPowers.addPermission(perms[2], true, document);
-  SpecialPowers.addPermission(perms[3], true, {url: origin,
-                                               appId: Ci.nsIScriptSecurityManager.NO_APP_ID});
+  SpecialPowers.addPermission(perms[3], true, {url: origin});
 
   is(Services.perms.testPermissionFromPrincipal(noappPrincipal, perms[0]),
      allow, "Set permission by string");
   is(Services.perms.testPermissionFromPrincipal(appPrincipal, perms[1]),
      allow, "Set permission by manifestURL");
   is(Services.perms.testPermissionFromPrincipal(nodePrincipal, perms[2]),
      allow, "Set permission by principal");
   is(Services.perms.testPermissionFromPrincipal(noappPrincipal, perms[3]),
      allow, "Set permission by other");
   is(Services.perms.testPermissionFromPrincipal(noappPrincipal, perms[1]),
      unknown, "Check that app permission doesn't leak to normal page");
 
   SpecialPowers.removePermission(perms[0], origin);
   SpecialPowers.removePermission(perms[1], {manifestURL: manifest});
   SpecialPowers.removePermission(perms[2], document);
-  SpecialPowers.removePermission(perms[3], {url: origin,
-                                            appId: Ci.nsIScriptSecurityManager.NO_APP_ID});
+  SpecialPowers.removePermission(perms[3], {url: origin});
 
   is(Services.perms.testPermissionFromPrincipal(noappPrincipal, perms[0]),
      unknown, "Removed permission by string");
   is(Services.perms.testPermissionFromPrincipal(appPrincipal, perms[1]),
      unknown, "Removed permission by manifestURL");
   is(Services.perms.testPermissionFromPrincipal(nodePrincipal, perms[2]),
      unknown, "Removed permission by principal");
   is(Services.perms.testPermissionFromPrincipal(noappPrincipal, perms[3]),
--- a/testing/specialpowers/components/SpecialPowersObserver.js
+++ b/testing/specialpowers/components/SpecialPowersObserver.js
@@ -229,17 +229,19 @@ SpecialPowersObserver.prototype = new Sp
           var permission = aSubject.QueryInterface(Ci.nsIPermission);
 
           // specialPowersAPI will consume this value, and it is used as a
           // fake permission, but only type and principal.appId will be used.
           //
           // We need to ensure that it looks the same as a real permission,
           // so we fake these properties.
           msg.permission = {
-            principal: { appId: permission.principal.appId },
+            principal: {
+              originAttributes: {appId: permission.principal.appId}
+            },
             type: permission.type
           };
         default:
           this._self._sendAsyncMessage("specialpowers-" + aTopic, msg);
       }
     }
   };
 
--- a/testing/specialpowers/content/SpecialPowersObserverAPI.js
+++ b/testing/specialpowers/content/SpecialPowersObserverAPI.js
@@ -316,42 +316,31 @@ SpecialPowersObserverAPI.prototype = {
           default:
             throw new SpecialPowersError("Invalid operation for SPProcessCrashService");
         }
         return undefined;	// See comment at the beginning of this function.
       }
 
       case "SPPermissionManager": {
         let msg = aMessage.json;
-
-        let secMan = Services.scriptSecurityManager;
-        // TODO: Bug 1196665 - Add originAttributes into SpecialPowers
-        let attrs = {appId: msg.appId, inBrowser: msg.isInBrowserElement};
-        let principal = secMan.createCodebasePrincipal(this._getURI(msg.url), attrs);
+        let principal = msg.principal;
 
         switch (msg.op) {
           case "add":
             Services.perms.addFromPrincipal(principal, msg.type, msg.permission, msg.expireType, msg.expireTime);
             break;
           case "remove":
             Services.perms.removeFromPrincipal(principal, msg.type);
             break;
           case "has":
             let hasPerm = Services.perms.testPermissionFromPrincipal(principal, msg.type);
-            if (hasPerm == Ci.nsIPermissionManager.ALLOW_ACTION) 
-              return true;
-            return false;
-            break;
+            return hasPerm == Ci.nsIPermissionManager.ALLOW_ACTION;
           case "test":
             let testPerm = Services.perms.testPermissionFromPrincipal(principal, msg.type, msg.value);
-            if (testPerm == msg.value)  {
-              return true;
-            }
-            return false;
-            break;
+            return testPerm == msg.value;
           default:
             throw new SpecialPowersError(
               "Invalid operation for SPPermissionManager");
         }
         return undefined;	// See comment at the beginning of this function.
       }
 
       case "SPSetTestPluginEnabledState": {
@@ -505,28 +494,23 @@ SpecialPowersObserverAPI.prototype = {
       case 'SPQuotaManager': {
         let qm = Cc['@mozilla.org/dom/quota/manager;1']
                    .getService(Ci.nsIQuotaManager);
         let mm = aMessage.target
                          .QueryInterface(Ci.nsIFrameLoaderOwner)
                          .frameLoader
                          .messageManager;
         let msg = aMessage.data;
+        let principal = msg.principal;
         let op = msg.op;
 
         if (op != 'clear' && op != 'getUsage' && op != 'reset') {
           throw new SpecialPowersError('Invalid operation for SPQuotaManager');
         }
 
-        let secMan = Services.scriptSecurityManager;
-        let principal = secMan.createCodebasePrincipal(this._getURI(msg.uri), {
-          appId: msg.appId,
-          inBrowser: msg.inBrowser,
-        });
-
         if (op == 'clear') {
           qm.clearStoragesForPrincipal(principal);
         } else if (op == 'reset') {
           qm.reset();
         }
 
         // We always use the getUsageForPrincipal callback even if we're clearing
         // since we know that clear and getUsageForPrincipal are synchronized by the
--- a/testing/specialpowers/content/specialpowersAPI.js
+++ b/testing/specialpowers/content/specialpowersAPI.js
@@ -781,18 +781,18 @@ SpecialPowersAPI.prototype = {
         } else if (this.testPermission(permission.type, Ci.nsICookiePermission.ACCESS_SESSION, context)) {
           originalValue = Ci.nsICookiePermission.ACCESS_SESSION;
         } else if (this.testPermission(permission.type, Ci.nsICookiePermission.ACCESS_ALLOW_FIRST_PARTY_ONLY, context)) {
           originalValue = Ci.nsICookiePermission.ACCESS_ALLOW_FIRST_PARTY_ONLY;
         } else if (this.testPermission(permission.type, Ci.nsICookiePermission.ACCESS_LIMIT_THIRD_PARTY, context)) {
           originalValue = Ci.nsICookiePermission.ACCESS_LIMIT_THIRD_PARTY;
         }
 
-        let [url, appId, isInBrowserElement, isSystem] = this._getInfoFromPermissionArg(context);
-        if (isSystem) {
+        let principal = this._getPrincipalFromArg(context);
+        if (principal.isSystemPrincipal) {
           continue;
         }
 
         let perm;
         if (typeof permission.allow !== 'boolean') {
           perm = permission.allow;
         } else {
           perm = permission.allow ? Ci.nsIPermissionManager.ALLOW_ACTION
@@ -805,19 +805,17 @@ SpecialPowersAPI.prototype = {
         if (originalValue == perm) {
           continue;
         }
 
         var todo = {'op': 'add',
                     'type': permission.type,
                     'permission': perm,
                     'value': perm,
-                    'url': url,
-                    'appId': appId,
-                    'isInBrowserElement': isInBrowserElement,
+                    'principal': principal,
                     'expireType': (typeof permission.expireType === "number") ?
                       permission.expireType : 0, // default: EXPIRE_NEVER
                     'expireTime': (typeof permission.expireTime === "number") ?
                       permission.expireTime : 0};
 
         var cleanupTodo = Object.assign({}, todo);
 
         if (permission.remove == true)
@@ -962,17 +960,17 @@ SpecialPowersAPI.prototype = {
         }
       } else {
         var found = false;
         for (var i = 0; !found && i < this._self._permissionsUndoStack.length; i++) {
           var undos = this._self._permissionsUndoStack[i];
           for (var j = 0; j < undos.length; j++) {
             var undo = undos[j];
             if (undo.op == this._obsDataMap[aData] &&
-                undo.appId == permission.principal.appId &&
+                undo.principal.originAttributes.appId == permission.principal.originAttributes.appId &&
                 undo.type == permission.type) {
               // Remove this undo item if it has been done by others(not
               // specialpowers itself.)
               undos.splice(j,1);
               found = true;
               break;
             }
           }
@@ -1815,138 +1813,114 @@ SpecialPowersAPI.prototype = {
    * Get the message manager associated with an <iframe mozbrowser>.
    */
   getBrowserFrameMessageManager: function(aFrameElement) {
     return this.wrap(aFrameElement.QueryInterface(Ci.nsIFrameLoaderOwner)
                                   .frameLoader
                                   .messageManager);
   },
 
-  _getInfoFromPermissionArg: function(arg) {
-    let url = "";
-    let appId = Ci.nsIScriptSecurityManager.NO_APP_ID;
-    let isInBrowserElement = false;
-    let isSystem = false;
+  _getPrincipalFromArg: function(arg) {
+    let principal;
+    let secMan = Services.scriptSecurityManager;
 
     if (typeof(arg) == "string") {
       // It's an URL.
-      url = Cc["@mozilla.org/network/io-service;1"]
-              .getService(Ci.nsIIOService)
-              .newURI(arg, null, null)
-              .spec;
+      let uri = Services.io.newURI(arg, null, null);
+      principal = secMan.createCodebasePrincipal(uri, {});
     } else if (arg.manifestURL) {
       // It's a thing representing an app.
       let appsSvc = Cc["@mozilla.org/AppsService;1"]
                       .getService(Ci.nsIAppsService)
       let app = appsSvc.getAppByManifestURL(arg.manifestURL);
-
       if (!app) {
         throw "No app for this manifest!";
       }
 
-      appId = appsSvc.getAppLocalIdByManifestURL(arg.manifestURL);
-      url = app.origin;
-      isInBrowserElement = arg.isInBrowserElement || false;
+      principal = app.principal;
     } else if (arg.nodePrincipal) {
       // It's a document.
-      isSystem = (arg.nodePrincipal instanceof Ci.nsIPrincipal) &&
-                 Cc["@mozilla.org/scriptsecuritymanager;1"].
-                 getService(Ci.nsIScriptSecurityManager).
-                 isSystemPrincipal(arg.nodePrincipal);
-      if (!isSystem) {
-        // System principals don't have a URL associated with them, and they
-        // don't really need any permissions to be registered with the
-        // permission manager anyway.
-        url = arg.nodePrincipal.URI.spec;
-        appId = arg.nodePrincipal.appId;
-        isInBrowserElement = arg.nodePrincipal.isInBrowserElement;
-      }
+      // In some tests the arg is a wrapped DOM element, so we unwrap it first.
+      principal = unwrapIfWrapped(arg).nodePrincipal;
     } else {
-      url = arg.url;
-      appId = arg.appId;
-      isInBrowserElement = arg.isInBrowserElement;
+      let uri = Services.io.newURI(arg.url, null, null);
+      let attrs = arg.originAttributes || {};
+      principal = secMan.createCodebasePrincipal(uri, attrs);
     }
 
-    return [ url, appId, isInBrowserElement, isSystem ];
+    return principal;
   },
 
   addPermission: function(type, allow, arg, expireType, expireTime) {
-    let [url, appId, isInBrowserElement, isSystem] = this._getInfoFromPermissionArg(arg);
-    if (isSystem) {
+    let principal = this._getPrincipalFromArg(arg);
+    if (principal.isSystemPrincipal) {
       return; // nothing to do
     }
 
     let permission;
     if (typeof allow !== 'boolean') {
       permission = allow;
     } else {
       permission = allow ? Ci.nsIPermissionManager.ALLOW_ACTION
                          : Ci.nsIPermissionManager.DENY_ACTION;
     }
 
     var msg = {
       'op': 'add',
       'type': type,
       'permission': permission,
-      'url': url,
-      'appId': appId,
-      'isInBrowserElement': isInBrowserElement,
+      'principal': principal,
       'expireType': (typeof expireType === "number") ? expireType : 0,
       'expireTime': (typeof expireTime === "number") ? expireTime : 0
     };
 
     this._sendSyncMessage('SPPermissionManager', msg);
   },
 
   removePermission: function(type, arg) {
-    let [url, appId, isInBrowserElement, isSystem] = this._getInfoFromPermissionArg(arg);
-    if (isSystem) {
+    let principal = this._getPrincipalFromArg(arg);
+    if (principal.isSystemPrincipal) {
       return; // nothing to do
     }
 
     var msg = {
       'op': 'remove',
       'type': type,
-      'url': url,
-      'appId': appId,
-      'isInBrowserElement': isInBrowserElement
+      'principal': principal
     };
 
     this._sendSyncMessage('SPPermissionManager', msg);
   },
 
   hasPermission: function (type, arg) {
-    let [url, appId, isInBrowserElement, isSystem] = this._getInfoFromPermissionArg(arg);
-    if (isSystem) {
+    let principal = this._getPrincipalFromArg(arg);
+    if (principal.isSystemPrincipal) {
       return true; // system principals have all permissions
     }
 
     var msg = {
       'op': 'has',
       'type': type,
-      'url': url,
-      'appId': appId,
-      'isInBrowserElement': isInBrowserElement
+      'principal': principal
     };
 
     return this._sendSyncMessage('SPPermissionManager', msg)[0];
   },
+
   testPermission: function (type, value, arg) {
-    let [url, appId, isInBrowserElement, isSystem] = this._getInfoFromPermissionArg(arg);
-    if (isSystem) {
+    let principal = this._getPrincipalFromArg(arg);
+    if (principal.isSystemPrincipal) {
       return true; // system principals have all permissions
     }
 
     var msg = {
       'op': 'test',
       'type': type,
-      'value': value, 
-      'url': url,
-      'appId': appId,
-      'isInBrowserElement': isInBrowserElement
+      'value': value,
+      'principal': principal
     };
     return this._sendSyncMessage('SPPermissionManager', msg)[0];
   },
 
   isContentWindowPrivate: function(win) {
     return PrivateBrowsingUtils.isContentWindowPrivate(win);
   },
 
@@ -1961,38 +1935,30 @@ SpecialPowersAPI.prototype = {
     var msg = {
       'op': 'notify',
       'observerTopic': topic,
       'observerData': data
     };
     this._sendSyncMessage('SPObserverService', msg);
   },
 
-  clearStorageForURI: function(uri, callback, appId, inBrowser) {
-    this._quotaManagerRequest('clear', uri, appId, inBrowser, callback);
-  },
-
-  getStorageUsageForURI: function(uri, callback, appId, inBrowser) {
-    this._quotaManagerRequest('getUsage', uri, appId, inBrowser, callback);
+  clearStorageForDoc: function(wrappedDocument, callback) {
+    this._quotaManagerRequest('clear', wrappedDocument, callback);
   },
 
-  // Technically this restarts the QuotaManager for all URIs, but we need
-  // a specific one to perform the synchronized callback when the reset is
-  // complete.
-  resetStorageForURI: function(uri, callback, appId, inBrowser) {
-    this._quotaManagerRequest('reset', uri, appId, inBrowser, callback);
+  getStorageUsageForDoc: function(wrappedDocument, callback) {
+    this._quotaManagerRequest('getUsage', wrappedDocument, callback);
   },
 
-  _quotaManagerRequest: function(op, uri, appId, inBrowser, callback) {
-    const messageTopic = "SPQuotaManager";
+  resetStorageForDoc: function(wrappedDocument, callback) {
+    this._quotaManagerRequest('reset', wrappedDocument, callback);
+  },
 
-    if (uri instanceof Ci.nsIURI) {
-      uri = uri.spec;
-    }
-
+  _quotaManagerRequest: function(op, wrappedDocument, callback) {
+    const messageTopic = "SPQuotaManager";
     const id = Cc["@mozilla.org/uuid-generator;1"]
                  .getService(Ci.nsIUUIDGenerator)
                  .generateUUID()
                  .toString();
 
     let callbackInfo = { id: id, callback: callback };
 
     if (this._quotaManagerCallbackInfos) {
@@ -2019,17 +1985,18 @@ SpecialPowersAPI.prototype = {
           }
         }
       }.bind(this);
 
       this._addMessageListener(messageTopic, callbackInfo.listener);
       this._quotaManagerCallbackInfos = [ callbackInfo ];
     }
 
-    let msg = { op: op, uri: uri, appId: appId, inBrowser: inBrowser, id: id };
+    let principal = unwrapIfWrapped(wrappedDocument).nodePrincipal;
+    let msg = { op: op, principal: principal, id: id };
     this._sendAsyncMessage(messageTopic, msg);
   },
 
   createDOMFile: function(path, options) {
     return new File(path, options);
   },
 
   startPeriodicServiceWorkerUpdates: function() {