Merge m-c to inbound a=merge
authorWes Kocher <wkocher@mozilla.com>
Mon, 20 Oct 2014 19:08:15 -0700
changeset 227586 0808729b24e876d8a308d60e1105ed3e339c2205
parent 227585 187b1aea9615661894387ca887733115962cf6c1 (current diff)
parent 227575 29fbfc1b31aabafb8fba87402267e09f9fb43e06 (diff)
child 227587 04142473004fc03fdba51d753cd16b11f03e8e5a
push id7326
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:58:42 +0000
treeherdermozilla-aurora@d3a3b2a0f2f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.0a1
Merge m-c to inbound a=merge
browser/devtools/webaudioeditor/test/doc_connect-toggle-param.html
browser/devtools/webaudioeditor/test/doc_connect-toggle.html
--- a/b2g/chrome/content/devtools/adb.js
+++ b/b2g/chrome/content/devtools/adb.js
@@ -3,18 +3,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // This file is only loaded on Gonk to manage ADB state
 
-const { utils: Cu } = Components;
-
 const DEBUG = false;
 var debug = function(str) {
   dump("AdbController: " + str + "\n");
 }
 
 let AdbController = {
   locked: undefined,
   remoteDebuggerEnabled: undefined,
--- a/b2g/components/LogShake.jsm
+++ b/b2g/components/LogShake.jsm
@@ -4,16 +4,18 @@
 
 /**
  * LogShake is a module which listens for log requests sent by Gaia. In
  * response to a sufficiently large acceleration (a shake), it will save log
  * files to an arbitrary directory which it will then return on a
  * 'capture-logs-success' event with detail.logFilenames representing each log
  * file's filename in the directory. If an error occurs it will instead produce
  * a 'capture-logs-error' event.
+ * We send a capture-logs-start events to notify the system app and the user,
+ * since dumping can be a bit long sometimes.
  */
 
 /* enable Mozilla javascript extensions and global strictness declaration,
  * disable valid this checking */
 /* jshint moz: true */
 /* jshint -W097 */
 /* jshint -W040 */
 /* global Services, Components, dump, LogCapture, LogParser,
@@ -49,16 +51,17 @@ function debug(msg) {
 
 /**
  * An empirically determined amount of acceleration corresponding to a
  * shake
  */
 const EXCITEMENT_THRESHOLD = 500;
 const DEVICE_MOTION_EVENT = 'devicemotion';
 const SCREEN_CHANGE_EVENT = 'screenchange';
+const CAPTURE_LOGS_START_EVENT = 'capture-logs-start';
 const CAPTURE_LOGS_ERROR_EVENT = 'capture-logs-error';
 const CAPTURE_LOGS_SUCCESS_EVENT = 'capture-logs-success';
 
 // Map of files which have log-type information to their parsers
 const LOGS_WITH_PARSERS = {
   '/dev/__properties__': LogParser.prettyPrintPropertiesArray,
   '/dev/log/main': LogParser.prettyPrintLogArray,
   '/dev/log/system': LogParser.prettyPrintLogArray,
@@ -160,16 +163,17 @@ let LogShake = {
 
     var acc = event.accelerationIncludingGravity;
 
     var excitement = acc.x * acc.x + acc.y * acc.y + acc.z * acc.z;
 
     if (excitement > EXCITEMENT_THRESHOLD) {
       if (!this.captureRequested) {
         this.captureRequested = true;
+        SystemAppProxy._sendCustomEvent(CAPTURE_LOGS_START_EVENT, {});
         captureLogs().then(logResults => {
           // On resolution send the success event to the requester
           SystemAppProxy._sendCustomEvent(CAPTURE_LOGS_SUCCESS_EVENT, {
             logFilenames: logResults.logFilenames,
             logPrefix: logResults.logPrefix
           });
           this.captureRequested = false;
         },
@@ -213,17 +217,17 @@ function getSdcardPrefix() {
   return volumeService.getVolumeByName('sdcard').mountPoint;
 }
 
 function getLogDirectory() {
   let d = new Date();
   d = new Date(d.getTime() - d.getTimezoneOffset() * 60000);
   let timestamp = d.toISOString().slice(0, -5).replace(/[:T]/g, '-');
   // return directory name of format 'logs/timestamp/'
-  return OS.Path.join('logs', timestamp, '');
+  return OS.Path.join('logs', timestamp);
 }
 
 /**
  * Captures and saves the current device logs, returning a promise that will
  * resolve to an array of log filenames.
  */
 function captureLogs() {
   let logArrays = readLogs();
@@ -276,17 +280,17 @@ function saveLogs(logArrays) {
     let saveRequests = [];
 
     for (let logLocation in logArrays) {
       debug('requesting save of ' + logLocation);
       let logArray = logArrays[logLocation];
       // The filename represents the relative path within the SD card, not the
       // absolute path because Gaia will refer to it using the DeviceStorage
       // API
-      let filename = dirName + getLogFilename(logLocation);
+      let filename = OS.Path.join(dirName, getLogFilename(logLocation));
       logFilenames.push(filename);
       let saveRequest = OS.File.writeAtomic(OS.Path.join(sdcardPrefix, filename), logArray);
       saveRequests.push(saveRequest);
     }
 
     return Promise.all(saveRequests).then(function() {
       debug('returning logfilenames: '+logFilenames.toSource());
       return {
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,19 +10,19 @@
   <!--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="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="dc496d04907dd314f9736ff78bab3bd27156f79a"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="457a54fc3200b80e4f5e1cd3acaa062309230732"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <!-- 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"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,18 +14,18 @@
   <!--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="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="dc496d04907dd314f9736ff78bab3bd27156f79a"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="457a54fc3200b80e4f5e1cd3acaa062309230732"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,18 +12,18 @@
   <!--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="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="dc496d04907dd314f9736ff78bab3bd27156f79a"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="457a54fc3200b80e4f5e1cd3acaa062309230732"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
@@ -129,12 +129,12 @@
   <project name="android-development" path="development" remote="b2g" revision="dab55669da8f48b6e57df95d5af9f16b4a87b0b1"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="197cd9492b9fadaa915c5daf36ff557f8f4a8d1c"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="libnfcemu" path="external/libnfcemu" remote="b2g" revision="125ccf9bd5986c7728ea44508b3e1d1185ac028b"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d259117b4976decbe2f76eeed85218bf0109190f"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9f28c4faea3b2f01db227b2467b08aeba96d9bec"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="7047fcaa8bb55888ec7b84997e1bab41185ba3a3"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="a6cfdff6e9198a0f0aec5be024d26ecf2d36c614"/>
   <project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/>
   <project name="darwinstreamingserver" path="system/darwinstreamingserver" remote="b2g" revision="cf85968c7f85e0ec36e72c87ceb4837a943b8af6"/>
 </manifest>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,19 +10,19 @@
   <!--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="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="dc496d04907dd314f9736ff78bab3bd27156f79a"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="457a54fc3200b80e4f5e1cd3acaa062309230732"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <!-- 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"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,18 +14,18 @@
   <!--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="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="dc496d04907dd314f9736ff78bab3bd27156f79a"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="457a54fc3200b80e4f5e1cd3acaa062309230732"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,19 +10,19 @@
   <!--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="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="dc496d04907dd314f9736ff78bab3bd27156f79a"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="457a54fc3200b80e4f5e1cd3acaa062309230732"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <!-- 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"/>
@@ -146,13 +146,13 @@
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="2a1ded216a91bf62a72b1640cf01ab4998f37028"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="e5a971282719907f73fb1da964ca40aad67a3be0"/>
   <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="9883ea57b0668d8f60dba025d4522dfa69a1fbfa"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="a558dc844bf5144fc38603fd8f4df8d9557052a5"/>
   <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="57ee1320ed7b4a1a1274d8f3f6c177cd6b9becb2"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="12b1977cc704b35f2e9db2bb423fa405348bc2f3"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="985bf15264d865fe7b9c5b45f61c451cbaafa43d"/>
   <project name="platform/system/core" path="system/core" revision="350eac5403124dacb2a5fd9e28ac290a59fc3b8e"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="7047fcaa8bb55888ec7b84997e1bab41185ba3a3"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="a6cfdff6e9198a0f0aec5be024d26ecf2d36c614"/>
   <project name="platform/system/qcom" path="system/qcom" revision="63e3f6f176caad587d42bba4c16b66d953fb23c2"/>
   <project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="d8952a42771045fca73ec600e2b42a4c7129d723"/>
   <project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="7704e16da545f4207812e593743d6743e1afb9c5"/>
 </manifest>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,18 +12,18 @@
   <!--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="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="dc496d04907dd314f9736ff78bab3bd27156f79a"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="457a54fc3200b80e4f5e1cd3acaa062309230732"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
   <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"/>
@@ -140,13 +140,13 @@
   <project name="platform/hardware/qcom/camera" path="hardware/qcom/camera" revision="5e110615212302c5d798a3c223dcee458817651c"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="fa9ffd47948eb24466de227e48fe9c4a7c5e7711"/>
   <project name="platform/hardware/qcom/gps" path="hardware/qcom/gps" revision="cd76b19aafd4229ccf83853d02faef8c51ca8b34"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="8a0d0b0d9889ef99c4c6317c810db4c09295f15a"/>
   <project name="platform/hardware/qcom/wlan" path="hardware/qcom/wlan" revision="2208fa3537ace873b8f9ec2355055761c79dfd5f"/>
   <project name="platform/hardware/ril" path="hardware/ril" revision="c4e2ac95907a5519a0e09f01a0d8e27fec101af0"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="e1eb226fa3ad3874ea7b63c56a9dc7012d7ff3c2"/>
   <project name="platform/system/core" path="system/core" revision="adc485d8755af6a61641d197de7cfef667722580"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="7047fcaa8bb55888ec7b84997e1bab41185ba3a3"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="a6cfdff6e9198a0f0aec5be024d26ecf2d36c614"/>
   <project name="platform/system/qcom" path="system/qcom" revision="1cdab258b15258b7f9657da70e6f06ebd5a2fc25"/>
   <project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="4ae5df252123591d5b941191790e7abed1bce5a4"/>
   <project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="ce18b47b4a4f93a581d672bbd5cb6d12fe796ca9"/>
 </manifest>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "f486771c1a2a76bfea1a5c7eac8debe14f29927b", 
+    "revision": "162be54d45ece9196921eb2b342490ec2ab9e1a6", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,18 +12,18 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="dc496d04907dd314f9736ff78bab3bd27156f79a"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="457a54fc3200b80e4f5e1cd3acaa062309230732"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,18 +10,18 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="dc496d04907dd314f9736ff78bab3bd27156f79a"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="457a54fc3200b80e4f5e1cd3acaa062309230732"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="575fdbf046e966a5915b1f1e800e5d6ad0ea14c0"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,18 +12,18 @@
   <!--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="8986df0f82e15ac2798df0b6c2ee3435400677ac">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="dc496d04907dd314f9736ff78bab3bd27156f79a"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="457a54fc3200b80e4f5e1cd3acaa062309230732"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
@@ -124,17 +124,17 @@
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
   <!-- Nexus 4 specific things -->
   <project name="device-mako" path="device/lge/mako" remote="b2g" revision="78d17f0c117f0c66dd55ee8d5c5dde8ccc93ecba"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
   <project name="device/lge/mako-kernel" path="device/lge/mako-kernel" revision="d1729e53d71d711c8fde25eab8728ff2b9b4df0e"/>
-  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="7047fcaa8bb55888ec7b84997e1bab41185ba3a3"/>
+  <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="a6cfdff6e9198a0f0aec5be024d26ecf2d36c614"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
   <project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/>
   <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="b0a528d839cfd9d170d092fe3743b5252b4243a6"/>
   <project name="platform/hardware/qcom/bt" path="hardware/qcom/bt" revision="380945eaa249a2dbdde0daa4c8adb8ca325edba6"/>
   <project name="platform/hardware/qcom/display" path="hardware/qcom/display" revision="6f3b0272cefaffeaed2a7d2bb8f633059f163ddc"/>
   <project name="platform/hardware/qcom/keymaster" path="hardware/qcom/keymaster" revision="16da8262c997a5a0d797885788a64a0771b26910"/>
   <project name="platform/hardware/qcom/media" path="hardware/qcom/media" revision="689b476ba3eb46c34b81343295fe144a0e81a18e"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,18 +12,18 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="84923f1940625c47ff4c1fdf01b10fde3b7d909e">
     <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="dc496d04907dd314f9736ff78bab3bd27156f79a"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="457a54fc3200b80e4f5e1cd3acaa062309230732"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -1043,28 +1043,32 @@ if (Services.prefs.getBoolPref("privacy.
     _updateHeights: function(aContainer, aSetHeights) {
       // Make sure we don't get stuck not finding anything because of the XBL binding between
       // the popup and the radio/label/description elements:
       let view = aContainer.ownerDocument.getElementById("PanelUI-panicView");
       let variableHeightItems = view.querySelectorAll("radio, label, description");
       let win = aContainer.ownerDocument.defaultView;
       for (let item of variableHeightItems) {
         if (aSetHeights) {
-          let height = win.getComputedStyle(item, null).getPropertyValue("height");
+          let cs = win.getComputedStyle(item, null);
+          let height = cs.getPropertyValue("height");
+          let width = cs.getPropertyValue("width");
           item.style.height = height;
+          item.style.width = width;
           // In the main menu panel, need to set the height of the container of this
           // description because otherwise the text will overflow:
           if (item.id == "PanelUI-panic-mainDesc" &&
               view.getAttribute("current") == "true" &&
               // Ensure we don't make this less than the size of the icon:
               parseInt(height) > 32) {
             item.parentNode.style.minHeight = height;
           }
         } else {
           item.style.removeProperty("height");
+          item.style.removeProperty("width");
           if (item.id == "PanelUI-panic-mainDesc") {
             item.parentNode.style.removeProperty("min-height");
           }
         }
       }
     },
     onViewShowing: function(aEvent) {
       let view = aEvent.target;
--- a/browser/components/loop/content/js/conversation.js
+++ b/browser/components/loop/content/js/conversation.js
@@ -395,19 +395,22 @@ loop.conversation = (function(mozL10n) {
         return;
 
       if (progressData.reason === "cancel" ||
           progressData.reason === "closed") {
         this._abortIncomingCall();
         return;
       }
 
-      if (progressData.reason === "timeout" &&
-          (previousState === "init" || previousState === "alerting")) {
-        this._abortIncomingCall();
+      if (progressData.reason === "timeout") {
+        if (previousState === "init" || previousState === "alerting") {
+          this._abortIncomingCall();
+        } else {
+          this.setState({callFailed: true, callStatus: "end"});
+        }
       }
     },
 
     /**
      * Silently aborts an incoming call - stops the alerting, and
      * closes the websocket.
      */
     _abortIncomingCall: function() {
--- a/browser/components/loop/content/js/conversation.jsx
+++ b/browser/components/loop/content/js/conversation.jsx
@@ -395,19 +395,22 @@ loop.conversation = (function(mozL10n) {
         return;
 
       if (progressData.reason === "cancel" ||
           progressData.reason === "closed") {
         this._abortIncomingCall();
         return;
       }
 
-      if (progressData.reason === "timeout" &&
-          (previousState === "init" || previousState === "alerting")) {
-        this._abortIncomingCall();
+      if (progressData.reason === "timeout") {
+        if (previousState === "init" || previousState === "alerting") {
+          this._abortIncomingCall();
+        } else {
+          this.setState({callFailed: true, callStatus: "end"});
+        }
       }
     },
 
     /**
      * Silently aborts an incoming call - stops the alerting, and
      * closes the websocket.
      */
     _abortIncomingCall: function() {
--- a/browser/components/loop/standalone/content/js/webapp.js
+++ b/browser/components/loop/standalone/content/js/webapp.js
@@ -828,17 +828,19 @@ loop.webapp = (function($, _, OT, mozL10
       this.props.notifications.errorL10n("call_timeout_notification_text");
       this.setState({callStatus: "failure"});
     },
 
     /**
      * Handles ending a call by resetting the view to the start state.
      */
     _endCall: function() {
-      this.setState({callStatus: "end"});
+      if (this.state.callStatus !== "failure") {
+        this.setState({callStatus: "end"});
+      }
     },
   });
 
   /**
    * Webapp Root View. This is the main, single, view that controls the display
    * of the webapp page.
    */
   var WebappRootView = React.createClass({displayName: 'WebappRootView',
--- a/browser/components/loop/standalone/content/js/webapp.jsx
+++ b/browser/components/loop/standalone/content/js/webapp.jsx
@@ -828,17 +828,19 @@ loop.webapp = (function($, _, OT, mozL10
       this.props.notifications.errorL10n("call_timeout_notification_text");
       this.setState({callStatus: "failure"});
     },
 
     /**
      * Handles ending a call by resetting the view to the start state.
      */
     _endCall: function() {
-      this.setState({callStatus: "end"});
+      if (this.state.callStatus !== "failure") {
+        this.setState({callStatus: "end"});
+      }
     },
   });
 
   /**
    * Webapp Root View. This is the main, single, view that controls the display
    * of the webapp page.
    */
   var WebappRootView = React.createClass({
--- a/browser/components/loop/test/desktop-local/conversation_test.js
+++ b/browser/components/loop/test/desktop-local/conversation_test.js
@@ -34,17 +34,17 @@ describe("loop.conversation", function()
       doNotDisturb: true,
       getStrings: function() {
         return JSON.stringify({textContent: "fakeText"});
       },
       get locale() {
         return "en-US";
       },
       setLoopCharPref: sinon.stub(),
-      getLoopCharPref: sinon.stub().returns(null),
+      getLoopCharPref: sinon.stub().returns("http://fakeurl"),
       getLoopBoolPref: sinon.stub(),
       getCallData: sinon.stub(),
       releaseCallData: sinon.stub(),
       startAlerting: sinon.stub(),
       stopAlerting: sinon.stub(),
       ensureRegistered: sinon.stub(),
       get appVersionInfo() {
         return {
@@ -405,16 +405,18 @@ describe("loop.conversation", function()
               done();
             });
           });
         });
 
         describe("WebSocket Events", function() {
           describe("Call cancelled or timed out before acceptance", function() {
             beforeEach(function() {
+              // Mounting the test component automatically calls the required
+              // setup functions
               icView = mountTestComponent();
               promise = new Promise(function(resolve, reject) {
                 resolve();
               });
 
               sandbox.stub(loop.CallConnectionWebSocket.prototype, "promiseConnect").returns(promise);
               sandbox.stub(loop.CallConnectionWebSocket.prototype, "close");
               sandbox.stub(window, "close");
@@ -534,16 +536,32 @@ describe("loop.conversation", function()
 
                   sandbox.clock.tick(1);
 
                   sinon.assert.calledOnce(window.close);
                   done();
                 });
               });
             });
+
+            describe("progress - terminated - timeout (previousState not init" +
+                     " nor alerting)",
+              function() {
+                it("should set the state to end", function(done) {
+                  promise.then(function() {
+                    icView._websocket.trigger("progress", {
+                      state: "terminated",
+                      reason: "timeout"
+                    }, "connecting");
+
+                    expect(icView.state.callStatus).eql("end");
+                    done();
+                  });
+                });
+              });
           });
         });
       });
 
       describe("#accept", function() {
         beforeEach(function() {
           icView = mountTestComponent();
           conversation.setIncomingSessionData({
--- a/browser/components/loop/test/standalone/webapp_test.js
+++ b/browser/components/loop/test/standalone/webapp_test.js
@@ -303,22 +303,34 @@ describe("loop.webapp", function() {
             ocView.startCall();
 
             TestUtils.findRenderedComponentWithType(ocView,
               loop.webapp.PendingConversationView);
           });
       });
 
       describe("session:ended", function() {
-        it("should set display the StartConversationView", function() {
+        it("should display the StartConversationView", function() {
           conversation.trigger("session:ended");
 
           TestUtils.findRenderedComponentWithType(ocView,
             loop.webapp.EndedConversationView);
         });
+
+        it("should display the FailedConversationView if callStatus is failure",
+          function() {
+            ocView.setState({
+              callStatus: "failure"
+            });
+            conversation.trigger("session:ended");
+
+            var failedView = TestUtils.findRenderedComponentWithType(ocView,
+                loop.webapp.FailedConversationView);
+            expect(failedView).to.not.equal(null);
+          });
       });
 
       describe("session:peer-hungup", function() {
         it("should set display the StartConversationView", function() {
           conversation.trigger("session:peer-hungup");
 
           TestUtils.findRenderedComponentWithType(ocView,
             loop.webapp.EndedConversationView);
--- a/browser/devtools/inspector/inspector-panel.js
+++ b/browser/devtools/inspector/inspector-panel.js
@@ -101,16 +101,20 @@ InspectorPanel.prototype = {
   get isOuterHTMLEditable() {
     return this._target.client.traits.editOuterHTML;
   },
 
   get hasUrlToImageDataResolver() {
     return this._target.client.traits.urlToImageDataResolver;
   },
 
+  get canGetUniqueSelector() {
+    return this._target.client.traits.getUniqueSelector;
+  },
+
   _deferredOpen: function(defaultSelection) {
     let deferred = promise.defer();
 
     this.onNewRoot = this.onNewRoot.bind(this);
     this.walker.on("new-root", this.onNewRoot);
 
     this.nodemenu = this.panelDoc.getElementById("inspector-node-popup");
     this.lastNodemenuItem = this.nodemenu.lastChild;
@@ -619,16 +623,19 @@ InspectorPanel.prototype = {
       unique.removeAttribute("disabled");
       copyInnerHTML.removeAttribute("disabled");
       copyOuterHTML.removeAttribute("disabled");
     } else {
       unique.setAttribute("disabled", "true");
       copyInnerHTML.setAttribute("disabled", "true");
       copyOuterHTML.setAttribute("disabled", "true");
     }
+    if (!this.canGetUniqueSelector) {
+      unique.hidden = true;
+    }
 
     // Enable the "edit HTML" item if the selection is an element and the root
     // actor has the appropriate trait (isOuterHTMLEditable)
     let editHTML = this.panelDoc.getElementById("node-menu-edithtml");
     if (isEditableElement && this.isOuterHTMLEditable) {
       editHTML.removeAttribute("disabled");
     } else {
       editHTML.setAttribute("disabled", "true");
@@ -837,20 +844,19 @@ InspectorPanel.prototype = {
    * Copy a unique selector of the selected Node to the clipboard.
    */
   copyUniqueSelector: function InspectorPanel_copyUniqueSelector()
   {
     if (!this.selection.isNode()) {
       return;
     }
 
-    let toCopy = CssLogic.findCssSelector(this.selection.node);
-    if (toCopy) {
-      clipboardHelper.copyString(toCopy);
-    }
+    this.selection.nodeFront.getUniqueSelector().then((selector) => {
+      clipboardHelper.copyString(selector);
+    }).then(null, console.error);
   },
 
   /**
    * Delete the selected node.
    */
   deleteNode: function IUI_deleteNode() {
     if (!this.selection.isNode() ||
          this.selection.isRoot()) {
--- a/browser/devtools/webaudioeditor/test/browser.ini
+++ b/browser/devtools/webaudioeditor/test/browser.ini
@@ -2,18 +2,16 @@
 subsuite = devtools
 support-files =
   doc_simple-context.html
   doc_complex-context.html
   doc_simple-node-creation.html
   doc_buffer-and-array.html
   doc_media-node-creation.html
   doc_destroy-nodes.html
-  doc_connect-toggle.html
-  doc_connect-toggle-param.html
   doc_connect-param.html
   doc_connect-multi-param.html
   doc_iframe-context.html
   440hz_sine.ogg
   head.js
 
 [browser_audionode-actor-get-param-flags.js]
 [browser_audionode-actor-get-params-01.js]
--- a/browser/devtools/webaudioeditor/test/browser_wa_graph-render-03.js
+++ b/browser/devtools/webaudioeditor/test/browser_wa_graph-render-03.js
@@ -1,34 +1,37 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests to ensure that selected nodes stay selected on graph redraw.
  */
 
 function spawnTest() {
-  let { target, panel } = yield initWebAudioEditor(CONNECT_TOGGLE_URL);
+  let { target, panel } = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
   let { panelWin } = panel;
   let { gFront, $, $$, EVENTS } = panelWin;
 
   reload(target);
 
   let [actors] = yield Promise.all([
     getN(gFront, "create-node", 3),
     waitForGraphRendered(panelWin, 3, 2)
   ]);
 
-  let nodeIDs = actors.map(actor => actor.actorID);
+  let [dest, osc, gain] = actors;
 
-  yield clickGraphNode(panelWin, nodeIDs[1]);
-  ok(findGraphNode(panelWin, nodeIDs[1]).classList.contains("selected"),
+  yield clickGraphNode(panelWin, gain.actorID);
+  ok(findGraphNode(panelWin, gain.actorID).classList.contains("selected"),
     "Node selected once.");
 
+  // Disconnect a node to trigger a rerender
+  osc.disconnect();
+
   yield once(panelWin, EVENTS.UI_GRAPH_RENDERED);
   
-  ok(findGraphNode(panelWin, nodeIDs[1]).classList.contains("selected"),
+  ok(findGraphNode(panelWin, gain.actorID).classList.contains("selected"),
     "Node still selected after rerender.");
 
   yield teardown(panel);
   finish();
 }
 
--- a/browser/devtools/webaudioeditor/test/browser_wa_graph-render-05.js
+++ b/browser/devtools/webaudioeditor/test/browser_wa_graph-render-05.js
@@ -1,27 +1,31 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests to ensure that param connections trigger graph redraws
  */
 
 function spawnTest() {
-  let { target, panel } = yield initWebAudioEditor(CONNECT_TOGGLE_PARAM_URL);
+  let { target, panel } = yield initWebAudioEditor(SIMPLE_CONTEXT_URL);
   let { panelWin } = panel;
   let { gFront, $, $$, EVENTS } = panelWin;
 
   reload(target);
 
   let [actors] = yield Promise.all([
     getN(gFront, "create-node", 3),
-    waitForGraphRendered(panelWin, 3, 1, 0)
+    waitForGraphRendered(panelWin, 3, 2, 0)
   ]);
-  ok(true, "Graph rendered without param connection");
+
+  let [dest, osc, gain] = actors;
 
+  yield osc.disconnect();
+
+  osc.connectParam(gain, "gain");
   yield waitForGraphRendered(panelWin, 3, 1, 1);
   ok(true, "Graph re-rendered upon param connection");
 
   yield teardown(panel);
   finish();
 }
 
deleted file mode 100644
--- a/browser/devtools/webaudioeditor/test/doc_connect-toggle-param.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!-- Any copyright is dedicated to the Public Domain.
-     http://creativecommons.org/publicdomain/zero/1.0/ -->
-<!doctype html>
-
-<html>
-  <head>
-    <meta charset="utf-8"/>
-    <title>Web Audio Editor test page</title>
-  </head>
-
-  <body>
-
-    <script type="text/javascript;version=1.8">
-      "use strict";
-
-      let i = 0;
-      let ctx = new AudioContext();
-      let osc = ctx.createOscillator();
-      let gain = ctx.createGain();
-      gain.gain.value = 0;
-      gain.connect(ctx.destination);
-      osc.start(0);
-      setTimeout(() => osc.connect(gain.gain), 500);
-    </script>
-  </body>
-
-</html>
deleted file mode 100644
--- a/browser/devtools/webaudioeditor/test/doc_connect-toggle.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!-- Any copyright is dedicated to the Public Domain.
-     http://creativecommons.org/publicdomain/zero/1.0/ -->
-<!doctype html>
-
-<html>
-  <head>
-    <meta charset="utf-8"/>
-    <title>Web Audio Editor test page</title>
-  </head>
-
-  <body>
-
-    <script type="text/javascript;version=1.8">
-      "use strict";
-
-      let i = 0;
-      let ctx = new AudioContext();
-      let osc = ctx.createOscillator();
-      let gain = ctx.createGain();
-      gain.gain.value = 0;
-      gain.connect(ctx.destination);
-      osc.start(0);
-      setInterval(() => ++i && (i % 2 ? osc.connect(gain) : osc.disconnect()), 1000);
-    </script>
-  </body>
-
-</html>
--- a/browser/devtools/webaudioeditor/test/head.js
+++ b/browser/devtools/webaudioeditor/test/head.js
@@ -22,18 +22,16 @@ let TargetFactory = devtools.TargetFacto
 
 const EXAMPLE_URL = "http://example.com/browser/browser/devtools/webaudioeditor/test/";
 const SIMPLE_CONTEXT_URL = EXAMPLE_URL + "doc_simple-context.html";
 const COMPLEX_CONTEXT_URL = EXAMPLE_URL + "doc_complex-context.html";
 const SIMPLE_NODES_URL = EXAMPLE_URL + "doc_simple-node-creation.html";
 const MEDIA_NODES_URL = EXAMPLE_URL + "doc_media-node-creation.html";
 const BUFFER_AND_ARRAY_URL = EXAMPLE_URL + "doc_buffer-and-array.html";
 const DESTROY_NODES_URL = EXAMPLE_URL + "doc_destroy-nodes.html";
-const CONNECT_TOGGLE_URL = EXAMPLE_URL + "doc_connect-toggle.html";
-const CONNECT_TOGGLE_PARAM_URL = EXAMPLE_URL + "doc_connect-toggle-param.html";
 const CONNECT_PARAM_URL = EXAMPLE_URL + "doc_connect-param.html";
 const CONNECT_MULTI_PARAM_URL = EXAMPLE_URL + "doc_connect-multi-param.html";
 const IFRAME_CONTEXT_URL = EXAMPLE_URL + "doc_iframe-context.html";
 
 // All tests are asynchronous.
 waitForExplicitFinish();
 
 let gToolEnabled = Services.prefs.getBoolPref("devtools.webaudioeditor.enabled");
--- a/browser/devtools/webconsole/console-output.js
+++ b/browser/devtools/webconsole/console-output.js
@@ -2449,24 +2449,24 @@ Widgets.ObjectRenderers.add({
 
   render: function()
   {
     let {preview} = this.objectActor;
     this.element = this.el("span.class-" + this.objectActor.class);
 
     let anchorText = this.objectActor.class;
     let anchorClass = "cm-variable";
-    if ("timestamp" in preview && typeof preview.timestamp != "number") {
+    if (preview && "timestamp" in preview && typeof preview.timestamp != "number") {
       anchorText = new Date(preview.timestamp).toString(); // invalid date
       anchorClass = "";
     }
 
     this._anchor(anchorText, { className: anchorClass });
 
-    if (!("timestamp" in preview) || typeof preview.timestamp != "number") {
+    if (!preview || !("timestamp" in preview) || typeof preview.timestamp != "number") {
       return;
     }
 
     this._text(" ");
 
     let elem = this.el("span.cm-string-2", new Date(preview.timestamp).toISOString());
     this.element.appendChild(elem);
   },
--- a/browser/devtools/webconsole/test/browser_webconsole_output_05.js
+++ b/browser/devtools/webconsole/test/browser_webconsole_output_05.js
@@ -57,22 +57,31 @@ let inputTests = [
     output: "Invalid Date",
     printOutput: "Invalid Date",
     inspectable: true,
     variablesViewLabel: "Invalid Date",
   },
 
   // 7
   {
+    input: "Date.prototype",
+    output: "Date",
+    printOutput: "Invalid Date",
+    inspectable: true,
+    variablesViewLabel: "Date",
+  },
+
+  // 8
+  {
     input: "new Number(43)",
     output: "43",
     inspectable: true,
   },
 
-  // 8
+  // 9
   {
     input: "new String('hello')",
     output: 'String [ "h", "e", "l", "l", "o" ]',
     printOutput: "hello",
     inspectable: true,
     variablesViewLabel: "String[5]"
   },
 ];
--- a/browser/modules/PanelFrame.jsm
+++ b/browser/modules/PanelFrame.jsm
@@ -45,17 +45,17 @@ let PanelFrameInternal = {
    * @param {String} aSize The initial size of the panel (width and height are the same
    *                       if specified).
    */
   _attachNotificatonPanel: function(aWindow, aParent, aButton, aType, aOrigin, aSrc, aSize) {
     aParent.hidden = false;
     let notificationFrameId = aOrigin ? aType + "-status-" + aOrigin : aType;
     let frame = aWindow.document.getElementById(notificationFrameId);
 
-    // If the button was customized to a new location, we we'll destroy the
+    // If the button was customized to a new location, destroy the
     // iframe and start fresh.
     if (frame && frame.parentNode != aParent) {
       SharedFrame.forgetGroup(frame.id);
       frame.parentNode.removeChild(frame);
       frame = null;
     }
 
     if (!frame) {
@@ -152,28 +152,28 @@ let PanelFrame = {
         dynamicResizer.stop();
       notificationFrame.docShell.isActive = false;
       dispatchPanelEvent(aType + "FrameHide");
     });
 
     panel.addEventListener("popupshown", function onpopupshown() {
       panel.removeEventListener("popupshown", onpopupshown);
       SharedFrame.setOwner(notificationFrameId, notificationFrame);
-      // This attribute is needed on both the button and the
-      // containing toolbaritem since the buttons on OS X have
-      // moz-appearance:none, while their container gets
-      // moz-appearance:toolbarbutton due to the way that toolbar buttons
-      // get combined on OS X.
       let initFrameShow = () => {
         notificationFrame.docShell.isActive = true;
         notificationFrame.docShell.isAppTab = true;
         if (dynamicResizer)
           dynamicResizer.start(panel, notificationFrame);
         dispatchPanelEvent(aType + "FrameShow");
       };
+      // This attribute is needed on both the button and the
+      // containing toolbaritem since the buttons on OS X have
+      // moz-appearance:none, while their container gets
+      // moz-appearance:toolbarbutton due to the way that toolbar buttons
+      // get combined on OS X.
       anchorBtn.setAttribute("open", "true");
       if (notificationFrame.contentDocument &&
           notificationFrame.contentDocument.readyState == "complete") {
         initFrameShow();
       } else {
         // first time load, wait for load and dispatch after load
         notificationFrame.addEventListener("load", function panelBrowserOnload(e) {
           notificationFrame.removeEventListener("load", panelBrowserOnload, true);
--- a/browser/modules/Social.jsm
+++ b/browser/modules/Social.jsm
@@ -416,23 +416,27 @@ function sizeSocialPanelToContent(panel,
   // if the panel is preloaded prior to being shown, cs will be null.  in that
   // case use the minimum size for the panel until it is shown.
   if (cs) {
     let computedHeight = parseInt(cs.marginTop) + body.offsetHeight + parseInt(cs.marginBottom);
     height = Math.max(computedHeight, height);
     let computedWidth = parseInt(cs.marginLeft) + body.offsetWidth + parseInt(cs.marginRight);
     width = Math.max(computedWidth, width);
   }
-  // add extra space the panel needs if any
-  width += panel.boxObject.width - iframe.boxObject.width;
-  height += panel.boxObject.height - iframe.boxObject.height;
+
+  // only add the extra space if the iframe has been loaded
+  if (iframe.boxObject.width && iframe.boxObject.height) {
+    // add extra space the panel needs if any
+    width += panel.boxObject.width - iframe.boxObject.width;
+    height += panel.boxObject.height - iframe.boxObject.height;
+  }
 
   // when size is computed, we want to be sure changes are "significant" since
   // some sites will resize when the iframe is resized by a small amount, making
-  // the panel slowely shrink to some minimum.
+  // the panel slowly shrink to some minimum.
   if (Math.abs(panel.boxObject.width - width) > 2 || Math.abs(panel.boxObject.height - height) > 2) {
     panel.sizeTo(width, height);
   }
 }
 
 function DynamicResizeWatcher() {
   this._mutationObserver = null;
 }
--- a/content/media/MediaDecoderStateMachine.cpp
+++ b/content/media/MediaDecoderStateMachine.cpp
@@ -2702,17 +2702,18 @@ void MediaDecoderStateMachine::AdvanceFr
   if (currentFrame) {
     // Decode one frame and display it.
     TimeStamp presTime = mPlayStartTime - UsecsToDuration(mPlayDuration) +
                           UsecsToDuration(currentFrame->mTime - mStartTime);
     NS_ASSERTION(currentFrame->mTime >= mStartTime, "Should have positive frame time");
     // Filter out invalid frames by checking the frame time. FrameTime could be
     // zero if it's a initial frame.
     int64_t frameTime = currentFrame->mTime - mStartTime;
-    if (frameTime > 0  || (frameTime == 0 && mPlayDuration == 0)) {
+    if (frameTime > 0  || (frameTime == 0 && mPlayDuration == 0) ||
+        mScheduler->IsRealTime()) {
       ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
       // If we have video, we want to increment the clock in steps of the frame
       // duration.
       RenderVideoFrame(currentFrame, presTime);
     }
     // If we're no longer playing after dropping and reacquiring the lock,
     // playback must've been stopped on the decode thread (by a seek, for
     // example).  In that case, the current frame is probably out of date.
--- a/dom/bluetooth/bluedroid/BluetoothSocket.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothSocket.cpp
@@ -358,28 +358,31 @@ public:
     MOZ_ASSERT(mImpl);
   }
 
   void Accept(int aFd, const nsAString& aBdAddress,
               int aConnectionStatus) MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
 
+    mozilla::ScopedClose fd(aFd); // Close received socket fd on error
+
     if (mImpl->IsShutdownOnMainThread()) {
       BT_LOGD("mConsumer is null, aborting receive!");
       return;
     }
 
     if (aConnectionStatus != 0) {
       mImpl->mConsumer->NotifyError();
       return;
     }
 
     mImpl->mConsumer->SetAddress(aBdAddress);
-    XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new AcceptTask(mImpl, aFd));
+    XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
+                                     new AcceptTask(mImpl, fd.forget()));
   }
 
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
     BT_LOGR("BluetoothSocketInterface::Accept failed: %d", (int)aStatus);
 
     if (!mImpl->IsShutdownOnMainThread()) {
--- a/dom/bluetooth/bluedroid/BluetoothSocketHALInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothSocketHALInterface.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BluetoothSocketHALInterface.h"
 #include <errno.h>
 #include <unistd.h>
 #include <sys/socket.h>
 #include "BluetoothHALHelpers.h"
+#include "mozilla/FileUtils.h"
 #include "nsClassHashtable.h"
 #include "nsXULAppAPI.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 typedef
   BluetoothHALInterfaceRunnable1<BluetoothSocketResultHandler, void,
                                  int, int>
@@ -480,16 +481,20 @@ class AcceptWatcher MOZ_FINAL : public S
 {
 public:
   AcceptWatcher(int aFd, BluetoothSocketResultHandler* aRes)
   : SocketMessageWatcher(aFd, aRes)
   { }
 
   void Proceed(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
+    if ((aStatus != STATUS_SUCCESS) && (GetClientFd() != -1)) {
+      mozilla::ScopedClose(GetClientFd()); // Close received socket fd on error
+    }
+
     DispatchBluetoothSocketHALResult(
       GetResultHandler(), &BluetoothSocketResultHandler::Accept,
       GetClientFd(), GetBdAddress(), GetConnectionStatus(), aStatus);
 
     MessageLoopForIO::current()->PostTask(
       FROM_HERE, new DeleteTask<AcceptWatcher>(this));
   }
 };
--- a/dom/bluetooth2/bluedroid/BluetoothSocket.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothSocket.cpp
@@ -358,28 +358,31 @@ public:
     MOZ_ASSERT(mImpl);
   }
 
   void Accept(int aFd, const nsAString& aBdAddress,
               int aConnectionStatus) MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
 
+    mozilla::ScopedClose fd(aFd); // Close received socket fd on error
+
     if (mImpl->IsShutdownOnMainThread()) {
       BT_LOGD("mConsumer is null, aborting receive!");
       return;
     }
 
     if (aConnectionStatus != 0) {
       mImpl->mConsumer->NotifyError();
       return;
     }
 
     mImpl->mConsumer->SetAddress(aBdAddress);
-    XRE_GetIOMessageLoop()->PostTask(FROM_HERE, new AcceptTask(mImpl, aFd));
+    XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
+                                     new AcceptTask(mImpl, fd.forget()));
   }
 
   void OnError(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
     MOZ_ASSERT(NS_IsMainThread());
     BT_LOGR("BluetoothSocketInterface::Accept failed: %d", (int)aStatus);
 
     if (!mImpl->IsShutdownOnMainThread()) {
--- a/dom/bluetooth2/bluedroid/BluetoothSocketHALInterface.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothSocketHALInterface.cpp
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BluetoothSocketHALInterface.h"
 #include <errno.h>
 #include <sys/socket.h>
 #include <unistd.h>
 #include "BluetoothHALHelpers.h"
+#include "mozilla/FileUtils.h"
 #include "nsClassHashtable.h"
 #include "nsXULAppAPI.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 typedef
   BluetoothHALInterfaceRunnable1<BluetoothSocketResultHandler, void,
                                  int, int>
@@ -480,16 +481,20 @@ class AcceptWatcher MOZ_FINAL : public S
 {
 public:
   AcceptWatcher(int aFd, BluetoothSocketResultHandler* aRes)
   : SocketMessageWatcher(aFd, aRes)
   { }
 
   void Proceed(BluetoothStatus aStatus) MOZ_OVERRIDE
   {
+    if ((aStatus != STATUS_SUCCESS) && (GetClientFd() != -1)) {
+      mozilla::ScopedClose(GetClientFd()); // Close received socket fd on error
+    }
+
     DispatchBluetoothSocketHALResult(
       GetResultHandler(), &BluetoothSocketResultHandler::Accept,
       GetClientFd(), GetBdAddress(), GetConnectionStatus(), aStatus);
 
     MessageLoopForIO::current()->PostTask(
       FROM_HERE, new DeleteTask<AcceptWatcher>(this));
   }
 };
--- a/dom/contacts/ContactManager.js
+++ b/dom/contacts/ContactManager.js
@@ -243,25 +243,26 @@ ContactManager.prototype = {
         access = "unknown";
       }
 
     // Shortcut for ALLOW_ACTION so we avoid a parent roundtrip
     let principal = this._window.document.nodePrincipal;
     let type = "contacts-" + access;
     let permValue =
       Services.perms.testExactPermissionFromPrincipal(principal, type);
+    DEBUG && debug("Existing permission " + permValue);
     if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
       if (aAllowCallback) {
         aAllowCallback();
       }
       return;
     } else if (permValue == Ci.nsIPermissionManager.DENY_ACTION ||
                permValue == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
       if (aCancelCallback) {
-        aCancelCallback();
+        aCancelCallback("PERMISSION_DENIED");
       }
       return;
     }
 
     // Create an array with a single nsIContentPermissionType element.
     type = {
       type: "contacts",
       access: access,
@@ -271,26 +272,24 @@ ContactManager.prototype = {
     let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
     typeArray.appendElement(type, false);
 
     // create a nsIContentPermissionRequest
     let request = {
       types: typeArray,
       principal: principal,
       QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
-      allow: aAllowCallback ||
-             function() {
-               if (DEBUG)
-                 debug("Default allow contacts callback. " + access +"\n");
-             },
-      cancel: aCancelCallback ||
-              function() {
-                if (DEBUG)
-                  debug("Default cancel contacts callback. " + access +"\n");
-              },
+      allow: function() {
+        aAllowCallback && aAllowCallback();
+        DEBUG && debug("Permission granted. Access " + access +"\n");
+      },
+      cancel: function() {
+        aCancelCallback && aCancelCallback("PERMISSION_DENIED");
+        DEBUG && debug("Permission denied. Access " + access +"\n");
+      },
       window: this._window
     };
 
     // Using askPermission from nsIDOMWindowUtils that takes care of the
     // remoting if needed.
     let windowUtils = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
                           .getInterface(Ci.nsIDOMWindowUtils);
     windowUtils.askPermission(request);
@@ -331,30 +330,47 @@ ContactManager.prototype = {
     newContact.id = aContact.id;
     newContact.published = aContact.published;
     newContact.updated = aContact.updated;
 
     if (DEBUG) debug("send: " + JSON.stringify(newContact));
 
     let options = { contact: newContact, reason: reason };
     let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contact:Save", {requestID: requestID, options: options});
-    }.bind(this)
-    this.askPermission(reason, request, allowCallback);
+      cpmm.sendAsyncMessage("Contact:Save", {
+        requestID: requestID,
+        options: options
+      });
+    }.bind(this);
+
+    let cancelCallback = function(reason) {
+      Services.DOMRequest.fireErrorAsync(request, reason);
+    };
+
+    this.askPermission(reason, request, allowCallback, cancelCallback);
     return request;
   },
 
   find: function(aOptions) {
     if (DEBUG) debug("find! " + JSON.stringify(aOptions));
     let request = this.createRequest();
     let options = { findOptions: aOptions };
+
     let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contacts:Find", {requestID: this.getRequestId({request: request, reason: "find"}), options: options});
-    }.bind(this)
-    this.askPermission("find", request, allowCallback);
+      cpmm.sendAsyncMessage("Contacts:Find", {
+        requestID: this.getRequestId({request: request, reason: "find"}),
+        options: options
+      });
+    }.bind(this);
+
+    let cancelCallback = function(reason) {
+      Services.DOMRequest.fireErrorAsync(request, reason);
+    };
+
+    this.askPermission("find", request, allowCallback, cancelCallback);
     return request;
   },
 
   createCursor: function CM_createCursor(aRequest) {
     let data = {
       cursor: Services.DOMRequest.createCursor(this._window, function() {
         this.handleContinue(id);
       }.bind(this)),
@@ -364,21 +380,29 @@ ContactManager.prototype = {
     let id = this.getRequestId(data);
     if (DEBUG) debug("saved cursor id: " + id);
     return [id, data.cursor];
   },
 
   getAll: function CM_getAll(aOptions) {
     if (DEBUG) debug("getAll: " + JSON.stringify(aOptions));
     let [cursorId, cursor] = this.createCursor();
+
     let allowCallback = function() {
       cpmm.sendAsyncMessage("Contacts:GetAll", {
-        cursorId: cursorId, findOptions: aOptions});
+        cursorId: cursorId,
+        findOptions: aOptions
+      });
     }.bind(this);
-    this.askPermission("find", cursor, allowCallback);
+
+    let cancelCallback = function(reason) {
+      Services.DOMRequest.fireErrorAsync(cursor, reason);
+    };
+
+    this.askPermission("find", cursor, allowCallback, cancelCallback);
     return cursor;
   },
 
   nextTick: function nextTick(aCallback) {
     Services.tm.currentThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL);
   },
 
   handleContinue: function CM_handleContinue(aCursorId) {
@@ -407,62 +431,80 @@ ContactManager.prototype = {
     } else if (!aRecordOrId || !aRecordOrId.id) {
       Services.DOMRequest.fireErrorAsync(request, true);
       return request;
     } else {
       id = aRecordOrId.id;
     }
 
     let options = { id: id };
+
     let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contact:Remove", {requestID: this.getRequestId({request: request, reason: "remove"}), options: options});
+      cpmm.sendAsyncMessage("Contact:Remove", {
+        requestID: this.getRequestId({request: request, reason: "remove"}),
+        options: options
+      });
     }.bind(this);
-    this.askPermission("remove", request, allowCallback);
+
+    let cancelCallback = function(reason) {
+      Services.DOMRequest.fireErrorAsync(request, reason);
+    };
+
+    this.askPermission("remove", request, allowCallback, cancelCallback);
     return request;
   },
 
   clear: function() {
     if (DEBUG) debug("clear");
     let request = this.createRequest();
     let options = {};
+
     let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contacts:Clear", {requestID: this.getRequestId({request: request, reason: "remove"}), options: options});
+      cpmm.sendAsyncMessage("Contacts:Clear", {
+        requestID: this.getRequestId({request: request, reason: "remove"}),
+        options: options
+      });
     }.bind(this);
-    this.askPermission("remove", request, allowCallback);
+
+    let cancelCallback = function(reason) {
+      Services.DOMRequest.fireErrorAsync(request, reason);
+    };
+
+    this.askPermission("remove", request, allowCallback, cancelCallback);
     return request;
   },
 
   getRevision: function() {
     let request = this.createRequest();
 
     let allowCallback = function() {
       cpmm.sendAsyncMessage("Contacts:GetRevision", {
         requestID: this.getRequestId({ request: request })
       });
     }.bind(this);
 
-    let cancelCallback = function() {
-      Services.DOMRequest.fireError(request, "");
+    let cancelCallback = function(reason) {
+      Services.DOMRequest.fireErrorAsync(request, reason);
     };
 
     this.askPermission("revision", request, allowCallback, cancelCallback);
     return request;
   },
 
   getCount: function() {
     let request = this.createRequest();
 
     let allowCallback = function() {
       cpmm.sendAsyncMessage("Contacts:GetCount", {
         requestID: this.getRequestId({ request: request })
       });
     }.bind(this);
 
-    let cancelCallback = function() {
-      Services.DOMRequest.fireError(request, "");
+    let cancelCallback = function(reason) {
+      Services.DOMRequest.fireErrorAsync(request, reason);
     };
 
     this.askPermission("count", request, allowCallback, cancelCallback);
     return request;
   },
 
   init: function(aWindow) {
     // DOMRequestIpcHelper.initHelper sets this._window
--- a/dom/contacts/tests/mochitest.ini
+++ b/dom/contacts/tests/mochitest.ini
@@ -16,9 +16,9 @@ skip-if = (toolkit == 'gonk' && debug) #
 [test_contacts_international.html]
 [test_contacts_substringmatching.html]
 [test_contacts_substringmatchingVE.html]
 [test_contacts_substringmatchingCL.html]
 [test_migration.html]
   support-files =
     test_migration_chrome.js
   skip-if = os == "android"
-
+[test_permission_denied.html]
new file mode 100644
--- /dev/null
+++ b/dom/contacts/tests/test_permission_denied.html
@@ -0,0 +1,120 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1081873
+-->
+<head>
+  <title>Test for Bug 1081873</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081873">Mozilla Bug 1081873</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+"use strict";
+
+SpecialPowers.addPermission("contacts-write", false, document);
+SpecialPowers.addPermission("contacts-read", false, document);
+SpecialPowers.addPermission("contacts-create", false, document);
+
+function onUnexpectedSuccess() {
+  ok(false, "Unexpected success");
+  next();
+}
+
+function onExpectedError(event) {
+  is(event.target.error.name, PERMISSION_DENIED, "Expected PERMISSION_DENIED");
+  next();
+}
+
+const PERMISSION_DENIED = "PERMISSION_DENIED";
+
+var index = 0;
+
+function next() {
+  info("Step " + index);
+  if (index >= steps.length) {
+    ok(false, "Shouldn't get here!");
+    return;
+  }
+  try {
+    var i = index++;
+    steps[i]();
+  } catch(ex) {
+    ok(false, "Caught exception", ex);
+  }
+}
+
+var steps = [
+  function() {
+    ok(true, "Add contact without permission");
+    var req = navigator.mozContacts.save(new mozContact({}));
+    req.onsuccess = onUnexpectedSuccess;
+    req.onerror = onExpectedError;
+  },
+  function() {
+    ok(true, "Find contact without permission");
+    var req = navigator.mozContacts.find({});
+    req.onsuccess = onUnexpectedSuccess;
+    req.onerror = onExpectedError;
+  },
+  function() {
+    ok(true, "Get all contacts without permission");
+    var req = navigator.mozContacts.getAll();
+    req.onsuccess = onUnexpectedSuccess;
+    req.onerror = onExpectedError;
+  },
+  function() {
+    ok(true, "Remove contact without permission");
+    var req = navigator.mozContacts.remove("aId");
+    req.onsuccess = onUnexpectedSuccess;
+    req.onerror = onExpectedError;
+  },
+  function() {
+    ok(true, "Clear contacts without permission");
+    var req = navigator.mozContacts.clear();
+    req.onsuccess = onUnexpectedSuccess;
+    req.onerror = onExpectedError;
+  },
+  function() {
+    ok(true, "Get revision without permission");
+    var req = navigator.mozContacts.getRevision();
+    req.onsuccess = onUnexpectedSuccess;
+    req.onerror = onExpectedError;
+  },
+  function() {
+    ok(true, "Get count without permission");
+    var req = navigator.mozContacts.getCount();
+    req.onsuccess = onUnexpectedSuccess;
+    req.onerror = function() {
+      is(req.error.name, PERMISSION_DENIED, "Expected PERMISSION_DENIED");
+      SimpleTest.finish();
+    };
+  }
+];
+
+SimpleTest.waitForExplicitFinish();
+
+const DENY = SpecialPowers.Ci.nsIPermissionManager.DENY_ACTION;
+var interval = setInterval(function() {
+  if (!SpecialPowers.testPermission("contacts-read", DENY, document) ||
+      !SpecialPowers.testPermission("contacts-write", DENY, document) ||
+      !SpecialPowers.testPermission("contacts-create", DENY, document)) {
+    return;
+  }
+  clearInterval(interval);
+  next();
+}, 1000);
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/webidl/MozWifiManager.webidl
+++ b/dom/webidl/MozWifiManager.webidl
@@ -23,16 +23,18 @@ enum ConnectionStatus {
 dictionary WifiWPSInfo {
   WifiWPSMethod method;
   DOMString? pin;
   DOMString? bssid;
 };
 
 dictionary NetworkProperties {
   DOMString ssid;
+  long mode;
+  long frequency;
   sequence<DOMString>? security;
   sequence<DOMString>? capabilities;
   boolean known;
   boolean connected;
   boolean hidden;
   DOMString bssid;
   DOMString signalStrength;
   long relSignalStrength;
@@ -58,16 +60,18 @@ dictionary NetworkProperties {
   DOMString subjectMatch;
 };
 
 [Constructor(optional NetworkProperties properties),
  JSImplementation="@mozilla.org/mozwifinetwork;1",
  Func="Navigator::HasWifiManagerSupport"]
 interface MozWifiNetwork {
   readonly attribute DOMString ssid;
+  readonly attribute long mode;
+  readonly attribute long frequency;
   [Constant, Cached] readonly attribute sequence<DOMString>? security;
   [Constant, Cached] readonly attribute sequence<DOMString>? capabilities;
   readonly attribute boolean known;
   readonly attribute boolean connected;
   readonly attribute boolean hidden;
 
            attribute DOMString? bssid;
            attribute DOMString? signalStrength;
--- a/dom/wifi/DOMWifiP2pManager.js
+++ b/dom/wifi/DOMWifiP2pManager.js
@@ -144,17 +144,17 @@ MozWifiP2pManager.prototype = {
 
       case "WifiP2pManager:setScanEnabled:Return:NO":
         request = this.takeRequest(msg.rid);
         Services.DOMRequest.fireError(request, "Unable to enable/disable Wifi P2P peer discovery.");
         break;
 
      case "WifiP2pManager:getPeerList:Return:OK":
         request = this.takeRequest(msg.rid);
-        Services.DOMRequest.fireSuccess(request, msg.data);
+        Services.DOMRequest.fireSuccess(request, Cu.cloneInto(msg.data, this._window));
         break;
 
       case "WifiP2pManager:getPeerList:Return:NO":
         request = this.takeRequest(msg.rid);
         Services.DOMRequest.fireError(request, "Unable to disable Wifi P2P peer discovery.");
         break;
 
       case "WifiP2pManager:connect:Return:OK":
--- a/dom/wifi/WifiCommand.jsm
+++ b/dom/wifi/WifiCommand.jsm
@@ -21,16 +21,23 @@ this.WifiCommand = function(aControlMess
     if (DEBUG) {
       dump('-------------- WifiCommand: ' + msg);
     }
   }
 
   var command = {};
 
   //-------------------------------------------------
+  // Utilities.
+  //-------------------------------------------------
+  command.getSdkVersion = function() {
+    return aSdkVersion;
+  };
+
+  //-------------------------------------------------
   // General commands.
   //-------------------------------------------------
 
   command.loadDriver = function (callback) {
     voidControlMessage("load_driver", function(status) {
       callback(status);
     });
   };
--- a/dom/wifi/WifiP2pManager.jsm
+++ b/dom/wifi/WifiP2pManager.jsm
@@ -603,28 +603,38 @@ function P2pStateMachine(aP2pCommand, aN
       function onSuccess()
       {
         _onEnabled(true);
         _sm.gotoState(stateInactive);
       }
 
       _sm.pause();
 
-      // Step 1: Connect to p2p0.
-      aP2pCommand.connectToSupplicant(function (status) {
-        let detail;
-
-        if (0 !== status) {
-          debug('Failed to connect to p2p0');
-          onFailure();
+      // This function will only call back on success.
+      function connectToSupplicantIfNeeded(callback) {
+        if (aP2pCommand.getSdkVersion() >= 19) {
+          // No need to connect to supplicant on KK. Call back directly.
+          callback();
           return;
         }
+        aP2pCommand.connectToSupplicant(function (status) {
+          if (0 !== status) {
+            debug('Failed to connect to p2p0');
+            onFailure();
+            return;
+          }
+          debug('wpa_supplicant p2p0 connected!');
+          _onSupplicantConnected();
+          callback();
+        });
+      }
 
-        debug('wpa_supplicant p2p0 connected!');
-        _onSupplicantConnected();
+      // Step 1: Connect to p2p0 if needed.
+      connectToSupplicantIfNeeded(function callback () {
+        let detail;
 
         // Step 2: Get MAC address.
         if (!_localDevice.address) {
           aP2pCommand.getMacAddress(function (address) {
             if (!address) {
               debug('Failed to get MAC address....');
               onFailure();
               return;
--- a/dom/wifi/WifiProxyService.cpp
+++ b/dom/wifi/WifiProxyService.cpp
@@ -169,16 +169,24 @@ WifiProxyService::FactoryCreate()
 NS_IMETHODIMP
 WifiProxyService::Start(nsIWifiEventListener* aListener,
                         const char ** aInterfaces,
                         uint32_t aNumOfInterfaces)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aListener);
 
+#if ANDROID_VERSION >= 19
+  // KK changes the way mux'ing/demux'ing different supplicant interfaces
+  // (e.g. wlan0/p2p0) from multi-sockets to single socket embedded with
+  // prefixed interface name (e.g. IFNAME=wlan0 xxxxxx). Therefore, we use
+  // the first given interface as the global interface for KK.
+  aNumOfInterfaces = 1;
+#endif
+
   nsresult rv;
 
   // Since EventRunnable runs in the manner of blocking, we have to
   // spin a thread for each interface.
   // (See the WpaSupplicant::WaitForEvent)
   mEventThreadList.SetLength(aNumOfInterfaces);
   for (uint32_t i = 0; i < aNumOfInterfaces; i++) {
     mEventThreadList[i].mInterface = aInterfaces[i];
@@ -245,24 +253,33 @@ WifiProxyService::SendCommand(JS::Handle
   return NS_OK;
 }
 
 NS_IMETHODIMP
 WifiProxyService::WaitForEvent(const nsACString& aInterface)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+#if ANDROID_VERSION >= 19
+  // We will only have one global interface for KK.
+  if (!mEventThreadList.IsEmpty()) {
+    nsCOMPtr<nsIRunnable> runnable = new EventRunnable(aInterface);
+    mEventThreadList[0].mThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
+    return NS_OK;
+  }
+#else
   // Dispatch to the event thread which has the given interface name
   for (size_t i = 0; i < mEventThreadList.Length(); i++) {
     if (mEventThreadList[i].mInterface.Equals(aInterface)) {
       nsCOMPtr<nsIRunnable> runnable = new EventRunnable(aInterface);
       mEventThreadList[i].mThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL);
       return NS_OK;
     }
   }
+#endif
 
   return NS_ERROR_FAILURE;
 }
 
 void
 WifiProxyService::DispatchWifiResult(const WifiResultOptions& aOptions, const nsACString& aInterface)
 {
   MOZ_ASSERT(NS_IsMainThread());
@@ -277,26 +294,37 @@ WifiProxyService::DispatchWifiResult(con
   // Call the listener with a JS value.
   mListener->OnCommand(val, aInterface);
 }
 
 void
 WifiProxyService::DispatchWifiEvent(const nsAString& aEvent, const nsACString& aInterface)
 {
   MOZ_ASSERT(NS_IsMainThread());
+
+#if ANDROID_VERSION < 19
+  mListener->OnWaitEvent(aEvent, aInterface);
+#else
+  // The interface might be embedded in the event string such as
+  // "IFNAME=wlan0 CTRL-EVENT-BSS-ADDED 65 3c:94:d5:7c:11:8b".
+  // Parse the interface name from the event string and use p2p0
+  // as the default interface if "IFNAME" is not found.
   nsAutoString event;
+  nsAutoString embeddedInterface(NS_LITERAL_STRING("p2p0"));
   if (StringBeginsWith(aEvent, NS_LITERAL_STRING("IFNAME"))) {
-    // Jump over IFNAME for gonk-kk.
+    int32_t ifnameFrom = aEvent.FindChar('=') + 1;
+    int32_t ifnameTo = aEvent.FindChar(' ') - 1;
+    embeddedInterface = Substring(aEvent, ifnameFrom, ifnameTo - ifnameFrom + 1);
     event = Substring(aEvent, aEvent.FindChar(' ') + 1);
   }
   else {
     event = aEvent;
   }
-  // Call the listener.
-  mListener->OnWaitEvent(event, aInterface);
+  mListener->OnWaitEvent(event, NS_ConvertUTF16toUTF8(embeddedInterface));
+#endif
 }
 
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(WifiProxyService,
                                          WifiProxyService::FactoryCreate)
 
 NS_DEFINE_NAMED_CID(NS_WIFIPROXYSERVICE_CID);
 
 static const mozilla::Module::CIDEntry kWifiProxyServiceCIDs[] = {
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -77,16 +77,19 @@ const DEFAULT_WLAN_INTERFACE = "wlan0";
 
 const DRIVER_READY_WAIT = 2000;
 
 const SUPP_PROP = "init.svc.wpa_supplicant";
 const WPA_SUPPLICANT = "wpa_supplicant";
 const DHCP_PROP = "init.svc.dhcpcd";
 const DHCP = "dhcpcd";
 
+const MODE_ESS = 0;
+const MODE_IBSS = 1;
+
 XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
                                    "@mozilla.org/network/manager;1",
                                    "nsINetworkManager");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService",
                                    "@mozilla.org/network/service;1",
                                    "nsINetworkService");
 
@@ -107,39 +110,48 @@ var WifiManager = (function() {
   function getStartupPrefs() {
     return {
       sdkVersion: parseInt(libcutils.property_get("ro.build.version.sdk"), 10),
       unloadDriverEnabled: libcutils.property_get("ro.moz.wifi.unloaddriver") === "1",
       schedScanRecovery: libcutils.property_get("ro.moz.wifi.sched_scan_recover") === "false" ? false : true,
       driverDelay: libcutils.property_get("ro.moz.wifi.driverDelay"),
       p2pSupported: libcutils.property_get("ro.moz.wifi.p2p_supported") === "1",
       eapSimSupported: libcutils.property_get("ro.moz.wifi.eapsim_supported") === "1",
+      ibssSupported: libcutils.property_get("ro.moz.wifi.ibss_supported", "true") === "true",
       ifname: libcutils.property_get("wifi.interface")
     };
   }
 
   let {sdkVersion, unloadDriverEnabled, schedScanRecovery,
-       driverDelay, p2pSupported, eapSimSupported, ifname} = getStartupPrefs();
+       driverDelay, p2pSupported, eapSimSupported, ibssSupported, ifname} = getStartupPrefs();
 
   let capabilities = {
     security: ["OPEN", "WEP", "WPA-PSK", "WPA-EAP"],
     eapMethod: ["PEAP", "TTLS"],
     eapPhase2: ["MSCHAPV2"],
-    certificate: ["SERVER"]
+    certificate: ["SERVER"],
+    mode: [MODE_ESS]
   };
   if (eapSimSupported) {
     capabilities.eapMethod.unshift("SIM");
   }
+  if (ibssSupported) {
+    capabilities.mode.push(MODE_IBSS);
+  }
 
   let wifiListener = {
     onWaitEvent: function(event, iface) {
       if (manager.ifname === iface && handleEvent(event)) {
         waitForEvent(iface);
       } else if (p2pSupported) {
-        if (WifiP2pManager.INTERFACE_NAME === iface) {
+        // Please refer to
+        // http://androidxref.com/4.4.2_r1/xref/frameworks/base/wifi/java/android/net/wifi/WifiMonitor.java#519
+        // for interface event mux/demux rules. In short words, both
+        // 'p2p0' and 'p2p-' should go to Wifi P2P state machine.
+        if (WifiP2pManager.INTERFACE_NAME === iface || -1 !== iface.indexOf('p2p-')) {
           // If the connection is closed, wifi.c::wifi_wait_for_event()
           // will still return 'CTRL-EVENT-TERMINATING  - connection closed'
           // rather than blocking. So when we see this special event string,
           // just return immediately.
           const TERMINATED_EVENT = 'CTRL-EVENT-TERMINATING  - connection closed';
           if (-1 !== event.indexOf(TERMINATED_EVENT)) {
             return;
           }
@@ -1179,17 +1191,23 @@ var WifiManager = (function() {
     {name: "password",      type: "string"},
     {name: "auth_alg",      type: "string"},
     {name: "phase1",        type: "string"},
     {name: "phase2",        type: "string"},
     {name: "eap",           type: "string"},
     {name: "pin",           type: "string"},
     {name: "pcsc",          type: "string"},
     {name: "ca_cert",       type: "string"},
-    {name: "subject_match", type: "string"}
+    {name: "subject_match", type: "string"},
+    {name: "frequency",     type: "integer"},
+    {name: "mode",          type: "integer"}
+  ];
+  // These fields are only handled in IBSS (aka ad-hoc) mode
+  var ibssNetworkConfigurationFields = [
+    "frequency", "mode"
   ];
 
   manager.getNetworkConfiguration = function(config, callback) {
     var netId = config.netId;
     var done = 0;
     for (var n = 0; n < networkConfigurationFields.length; ++n) {
       let fieldName = networkConfigurationFields[n].name;
       let fieldType = networkConfigurationFields[n].type;
@@ -1214,19 +1232,33 @@ var WifiManager = (function() {
 
     function hasValidProperty(name) {
       return ((name in config) &&
                config[name] != null &&
                (["password", "wep_key0", "psk"].indexOf(name) === -1 ||
                 config[name] !== '*'));
     }
 
+    function getModeFromConfig() {
+      /* we use the mode from the config, or ESS as default */
+      return hasValidProperty("mode") ? config["mode"] : MODE_ESS;
+    }
+
+    var mode = getModeFromConfig();
+
+    function validForMode(name, mode) {
+            /* all fields are valid for IBSS */
+      return (mode == MODE_IBSS) ||
+            /* IBSS fields are not valid for ESS */
+            ((mode == MODE_ESS) && !(name in ibssNetworkConfigurationFields));
+    }
+
     for (var n = 0; n < networkConfigurationFields.length; ++n) {
       let fieldName = networkConfigurationFields[n].name;
-      if (!hasValidProperty(fieldName)) {
+      if (!hasValidProperty(fieldName) || !validForMode(fieldName, mode)) {
         ++done;
       } else {
         wifiCommand.setNetworkVariable(netId, fieldName, config[fieldName], function(ok) {
           if (!ok)
             ++errors;
           if (++done == networkConfigurationFields.length)
             callback(errors == 0);
         });
@@ -1547,16 +1579,28 @@ function getNetworkKey(network)
 
   // ssid here must be dequoted, and it's safer to esacpe it.
   // encryption won't be empty and always be assigned one of the followings :
   // "OPEN"/"WEP"/"WPA-PSK"/"WPA-EAP".
   // So for a invalid network object, the returned key will be "OPEN".
   return escape(ssid) + encryption;
 }
 
+function getMode(flags) {
+  if (!flags)
+    return -1;
+
+  if (/\[ESS/.test(flags))
+    return MODE_ESS;
+  if (/\[IBSS/.test(flags))
+    return MODE_IBSS;
+
+  return -1;
+}
+
 function getKeyManagement(flags) {
   var types = [];
   if (!flags)
     return types;
 
   if (/\[WPA2?-PSK/.test(flags))
     types.push("WPA-PSK");
   if (/\[WPA2?-EAP/.test(flags))
@@ -1593,31 +1637,35 @@ function calculateSignal(strength) {
 
   if (strength <= MIN_RSSI)
     return 0;
   if (strength >= MAX_RSSI)
     return 100;
   return Math.floor(((strength - MIN_RSSI) / (MAX_RSSI - MIN_RSSI)) * 100);
 }
 
-function Network(ssid, security, password, capabilities) {
+function Network(ssid, mode, frequency, security, password, capabilities) {
   this.ssid = ssid;
+  this.mode = mode;
+  this.frequency = frequency;
   this.security = security;
 
   if (typeof password !== "undefined")
     this.password = password;
   if (capabilities !== undefined)
     this.capabilities = capabilities;
   // TODO connected here as well?
 
   this.__exposedProps__ = Network.api;
 }
 
 Network.api = {
   ssid: "r",
+  mode: "r",
+  frequency: "r",
   security: "r",
   capabilities: "r",
   known: "r",
 
   password: "rw",
   keyManagement: "rw",
   psk: "rw",
   identity: "rw",
@@ -1627,19 +1675,19 @@ Network.api = {
   pin: "rw",
   phase1: "rw",
   phase2: "rw",
   serverCertificate: "rw"
 };
 
 // Note: We never use ScanResult.prototype, so the fact that it's unrelated to
 // Network.prototype is OK.
-function ScanResult(ssid, bssid, flags, signal) {
-  Network.call(this, ssid, getKeyManagement(flags), undefined,
-               getCapabilities(flags));
+function ScanResult(ssid, bssid, frequency, flags, signal) {
+  Network.call(this, ssid, getMode(flags), frequency,
+               getKeyManagement(flags), undefined, getCapabilities(flags));
   this.bssid = bssid;
   this.signalStrength = signal;
   this.relSignalStrength = calculateSignal(Number(signal));
 
   this.__exposedProps__ = ScanResult.api;
 }
 
 // XXX This should probably live in the DOM-facing side, but it's hard to do
@@ -1841,27 +1889,29 @@ function WifiWorker() {
 
   // Given a connection status network, takes a network from
   // self.configuredNetworks and prepares it for the DOM.
   netToDOM = function(net) {
     if (!net) {
       return null;
     }
     var ssid = dequote(net.ssid);
+    var mode = net.mode;
+    var frequency = net.frequency;
     var security = (net.key_mgmt === "NONE" && net.wep_key0) ? ["WEP"] :
                    (net.key_mgmt && net.key_mgmt !== "NONE") ? [net.key_mgmt.split(" ")[0]] :
                    [];
     var password;
     if (("psk" in net && net.psk) ||
         ("password" in net && net.password) ||
         ("wep_key0" in net && net.wep_key0)) {
       password = "*";
     }
 
-    var pub = new Network(ssid, security, password);
+    var pub = new Network(ssid, mode, frequency, security, password);
     if (net.identity)
       pub.identity = dequote(net.identity);
     if ("netId" in net)
       pub.known = true;
     if (net.scan_ssid === 1)
       pub.hidden = true;
     if ("ca_cert" in net && net.ca_cert &&
         net.ca_cert.indexOf("keystore://WIFI_SERVERCERT_" === 0)) {
@@ -2053,20 +2103,22 @@ function WifiWorker() {
         // automatically connect. Try to knock us out of it. We only
         // hit this state when we've failed to run DHCP, so trying
         // again isn't the worst thing we can do. Eventually, we'll
         // need to detect if we're looping in this state and bail out.
         WifiManager.reconnect(function(){});
         break;
       case "ASSOCIATING":
         // id has not yet been filled in, so we can only report the ssid and
-        // bssid.
+        // bssid. mode and frequency are simply made up.
         self.currentNetwork =
           { bssid: WifiManager.connectionInfo.bssid,
-            ssid: quote(WifiManager.connectionInfo.ssid) };
+            ssid: quote(WifiManager.connectionInfo.ssid),
+            mode: MODE_ESS,
+            frequency: 0};
         self._fireEvent("onconnecting", { network: netToDOM(self.currentNetwork) });
         break;
       case "ASSOCIATED":
         if (!self.currentNetwork) {
           self.currentNetwork =
             { bssid: WifiManager.connectionInfo.bssid,
               ssid: quote(WifiManager.connectionInfo.ssid) };
         }
@@ -2252,40 +2304,43 @@ function WifiWorker() {
     WifiManager.getScanResults(function(r) {
       // Failure.
       if (!r) {
         self.wantScanResults.forEach(function(callback) { callback(null) });
         self.wantScanResults = [];
         return;
       }
 
+      let capabilities = WifiManager.getCapabilities();
+
       // Now that we have scan results, there's no more need to continue
       // scanning. Ignore any errors from this command.
       WifiManager.setScanMode("inactive", function() {});
       let lines = r.split("\n");
       // NB: Skip the header line.
       self.networksArray = [];
       for (let i = 1; i < lines.length; ++i) {
         // bssid / frequency / signal level / flags / ssid
         var match = /([\S]+)\s+([\S]+)\s+([\S]+)\s+(\[[\S]+\])?\s(.*)/.exec(lines[i]);
 
         if (match && match[5]) {
           let ssid = match[5],
               bssid = match[1],
+              frequency = match[2],
               signalLevel = match[3],
               flags = match[4];
 
-          // Skip ad-hoc networks which aren't supported (bug 811635).
-          if (flags && flags.indexOf("[IBSS]") >= 0)
+          /* Skip networks with unknown or unsupported modes. */
+          if (capabilities.mode.indexOf(getMode(flags)) == -1)
             continue;
 
           // If this is the first time that we've seen this SSID in the scan
           // results, add it to the list along with any other information.
           // Also, we use the highest signal strength that we see.
-          let network = new ScanResult(ssid, bssid, flags, signalLevel);
+          let network = new ScanResult(ssid, bssid, frequency, flags, signalLevel);
 
           let networkKey = getNetworkKey(network);
           let eapIndex = -1;
           if (networkKey in self.configuredNetworks) {
             let known = self.configuredNetworks[networkKey];
             network.known = true;
 
             if ("identity" in known && known.identity)
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -1205,22 +1205,23 @@ public class BrowserApp extends GeckoApp
     @Override
     public void onPanZoomStopped() {
         if (!mDynamicToolbar.isEnabled() || isHomePagerVisible()) {
             return;
         }
 
         // Make sure the toolbar is fully hidden or fully shown when the user
         // lifts their finger. If the page is shorter than the viewport or if
-        // the user has reached the end of the page, the toolbar is always
-        // shown.
+        // the user has reached the end of a long (longer than twice the viewport height) page,
+        // the toolbar is always shown.
         ImmutableViewportMetrics metrics = mLayerView.getViewportMetrics();
+        final float height = metrics.viewportRectBottom - metrics.viewportRectTop;
         if (metrics.getPageHeight() < metrics.getHeight()
               || metrics.marginTop >= mToolbarHeight / 2
-              || metrics.pageRectBottom == metrics.viewportRectBottom) {
+              || (metrics.pageRectBottom == metrics.viewportRectBottom && metrics.pageRectBottom > 2*height)) {
             mDynamicToolbar.setVisible(true, VisibilityTransition.ANIMATE);
         } else {
             mDynamicToolbar.setVisible(false, VisibilityTransition.ANIMATE);
         }
     }
 
     public void refreshToolbarHeight() {
         ThreadUtils.assertOnUiThread();
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -1185,34 +1185,25 @@ public abstract class GeckoApp
             }
         });
 
         // Workaround for <http://code.google.com/p/android/issues/detail?id=20915>.
         try {
             Class.forName("android.os.AsyncTask");
         } catch (ClassNotFoundException e) {}
 
-        MemoryMonitor.getInstance().init(getApplicationContext());
-
         // GeckoAppShell is tightly coupled to us, rather than
         // the app context, because various parts of Fennec (e.g.,
         // GeckoScreenOrientation) use GAS to access the Activity in
         // the guise of fetching a Context.
         // When that's fixed, `this` can change to
         // `(GeckoApplication) getApplication()` here.
         GeckoAppShell.setContextGetter(this);
         GeckoAppShell.setGeckoInterface(this);
 
-        Tabs.getInstance().attachToContext(this);
-        try {
-            Favicons.initializeWithContext(this);
-        } catch (Exception e) {
-            Log.e(LOGTAG, "Exception starting favicon cache. Corrupt resources?", e);
-        }
-
         // Did the OS locale change while we were backgrounded? If so,
         // we need to die so that Gecko will re-init add-ons that touch
         // the UI.
         // This is using a sledgehammer to crack a nut, but it'll do for
         // now.
         // Our OS locale pref will be detected as invalid after the
         // restart, and will be propagated to Gecko accordingly, so there's
         // no need to touch that here.
@@ -1249,16 +1240,30 @@ public abstract class GeckoApp
                 @Override
                 public void run() {
                     GeckoThread.setLaunchState(GeckoThread.LaunchState.Launched);
                     GeckoThread.createAndStart();
                 }
             }, 1000 * 5 /* 5 seconds */);
         }
 
+        // Heavy load on the Gecko thread can slow down the time it takes for UI to appear on
+        // single-core devices. By minimizing the Gecko thread priority, we ensure that the UI
+        // appears quickly. The priority is reset to normal once thumbnails are loaded.
+        ThreadUtils.reduceGeckoPriority();
+
+        MemoryMonitor.getInstance().init(getApplicationContext());
+
+        Tabs.getInstance().attachToContext(this);
+        try {
+            Favicons.initializeWithContext(this);
+        } catch (Exception e) {
+            Log.e(LOGTAG, "Exception starting favicon cache. Corrupt resources?", e);
+        }
+
         Bundle stateBundle = getIntent().getBundleExtra(EXTRA_STATE_BUNDLE);
         if (stateBundle != null) {
             // Use the state bundle if it was given as an intent extra. This is
             // only intended to be used internally via Robocop, so a boolean
             // is read from a private shared pref to prevent other apps from
             // injecting states.
             final SharedPreferences prefs = getSharedPreferences();
             if (prefs.getBoolean(PREFS_ALLOW_STATE_BUNDLE, false)) {
@@ -1625,16 +1630,20 @@ public abstract class GeckoApp
             GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null));
         }
 
         if (ACTION_ALERT_CALLBACK.equals(action)) {
             processAlertCallback(intent);
         } else if (NotificationHelper.HELPER_BROADCAST_ACTION.equals(action)) {
             NotificationHelper.getInstance(getApplicationContext()).handleNotificationIntent(intent);
         }
+
+        // Reset Gecko to normal priority. We may reduce the
+        // priority again later, e.g. for loading thumbnails.
+        ThreadUtils.resetGeckoPriority();
     }
 
     private String restoreSessionTabs(final boolean isExternalURL) throws SessionRestoreException {
         try {
             String sessionString = getProfile().readSessionFile(false);
             if (sessionString == null) {
                 throw new SessionRestoreException("Could not read from session file");
             }
--- a/mobile/android/base/GeckoThread.java
+++ b/mobile/android/base/GeckoThread.java
@@ -46,16 +46,17 @@ public class GeckoThread extends Thread 
     private final String mAction;
     private final String mUri;
 
     public static boolean ensureInit() {
         ThreadUtils.assertOnUiThread();
         if (isCreated())
             return false;
         sGeckoThread = new GeckoThread(sArgs, sAction, sUri);
+        ThreadUtils.sGeckoThread = sGeckoThread;
         return true;
     }
 
     public static String sArgs;
     public static String sAction;
     public static String sUri;
 
     public static void setArgs(String args) {
@@ -159,17 +160,16 @@ public class GeckoThread extends Thread 
         }
 
         return (args != null ? args : "") + profileArg + guestArg;
     }
 
     @Override
     public void run() {
         Looper.prepare();
-        ThreadUtils.sGeckoThread = this;
         ThreadUtils.sGeckoHandler = new Handler();
         ThreadUtils.sGeckoQueue = Looper.myQueue();
 
         String path = initGeckoEnvironment();
 
         // This can only happen after the call to initGeckoEnvironment
         // above, because otherwise the JNI code hasn't been loaded yet.
         ThreadUtils.postToUiThread(new Runnable() {
--- a/mobile/android/base/RestrictedProfiles.java
+++ b/mobile/android/base/RestrictedProfiles.java
@@ -158,33 +158,33 @@ public class RestrictedProfiles {
     }
 
     public static boolean isAllowed(Restriction action) {
         return isAllowed(action.id, null);
     }
 
     @WrapElementForJNI
     public static boolean isAllowed(int action, String url) {
-        // Guest users can't do anything.
-        if (getInGuest()) {
-            return false;
-        }
-
         final Restriction restriction;
         try {
             restriction = geckoActionToRestriction(action);
         } catch (IllegalArgumentException ex) {
             // Unknown actions represent a coding error, so we
             // refuse the action and log.
             Log.e(LOGTAG, "Unknown action " + action + "; check calling code.");
             return false;
         }
 
-        if (Restriction.DISALLOW_BROWSE_FILES == restriction) {
-            return canLoadUrl(url);
+        if (getInGuest()) {
+            if (Restriction.DISALLOW_BROWSE_FILES == restriction) {
+                return canLoadUrl(url);
+            }
+
+            // Guest users can't do anything.
+            return false;
         }
 
         // NOTE: Restrictions hold the opposite intention, so we need to flip it.
         return !getRestriction(restriction.name);
     }
 
     @WrapElementForJNI
     public static String getUserRestrictions() {
--- a/mobile/android/base/home/TopSitesPanel.java
+++ b/mobile/android/base/home/TopSitesPanel.java
@@ -93,19 +93,16 @@ public class TopSitesPanel extends HomeF
     private ThumbnailsLoaderCallbacks mThumbnailsLoaderCallbacks;
 
     // Listener for editing pinned sites.
     private EditPinnedSiteListener mEditPinnedSiteListener;
 
     // Max number of entries shown in the grid from the cursor.
     private int mMaxGridEntries;
 
-    // Time in ms until the Gecko thread is reset to normal priority.
-    private static final long PRIORITY_RESET_TIMEOUT = 10000;
-
     public static TopSitesPanel newInstance() {
         return new TopSitesPanel();
     }
 
     private static final boolean logDebug = Log.isLoggable(LOGTAG, Log.DEBUG);
     private static final boolean logVerbose = Log.isLoggable(LOGTAG, Log.VERBOSE);
 
     private static void debug(final String message) {
@@ -342,17 +339,17 @@ public class TopSitesPanel extends HomeF
         getLoaderManager().initLoader(LOADER_ID_TOP_SITES, null, mCursorLoaderCallbacks);
 
         // Since this is the primary fragment that loads whenever about:home is
         // visited, we want to load it as quickly as possible. Heavy load on
         // the Gecko thread can slow down the time it takes for thumbnails to
         // appear, especially during startup (bug 897162). By minimizing the
         // Gecko thread priority, we ensure that the UI appears quickly. The
         // priority is reset to normal once thumbnails are loaded.
-        ThreadUtils.reduceGeckoPriority(PRIORITY_RESET_TIMEOUT);
+        ThreadUtils.reduceGeckoPriority();
     }
 
     /**
      * Listener for editing pinned sites.
      */
     private class EditPinnedSiteListener implements OnEditPinnedSiteListener,
                                                     OnSiteSelectedListener {
         // Tag for the PinSiteDialog fragment.
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -409,16 +409,17 @@ gbjar.sources += [
     'toolbar/BrowserToolbarNewTablet.java',
     'toolbar/BrowserToolbarPhone.java',
     'toolbar/BrowserToolbarPhoneBase.java',
     'toolbar/BrowserToolbarPreHC.java',
     'toolbar/BrowserToolbarTablet.java',
     'toolbar/BrowserToolbarTabletBase.java',
     'toolbar/CanvasDelegate.java',
     'toolbar/ForwardButton.java',
+    'toolbar/NavButton.java',
     'toolbar/PageActionLayout.java',
     'toolbar/PhoneTabsButton.java',
     'toolbar/ShapedButton.java',
     'toolbar/SiteIdentityPopup.java',
     'toolbar/TabCounter.java',
     'toolbar/TabletTabsButton.java',
     'toolbar/ToolbarDisplayLayout.java',
     'toolbar/ToolbarEditLayout.java',
--- a/mobile/android/base/resources/layout/fxaccount_custom_server_view.xml
+++ b/mobile/android/base/resources/layout/fxaccount_custom_server_view.xml
@@ -30,28 +30,28 @@
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:orientation="vertical"
             android:paddingBottom="6dip"
             android:paddingRight="10dip"
             android:paddingTop="6dip" >
 
             <TextView
-                android:id="@+android:id/account_server_title"
+                android:id="@+id/account_server_title"
                 style="@style/FxAccountTextItem"
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_horizontal"
                 android:layout_marginBottom="0dp"
                 android:gravity="center_vertical"
                 android:text="@string/fxaccount_custom_server_account_title" >
             </TextView>
 
             <TextView
-                android:id="@+android:id/account_server_summary"
+                android:id="@+id/account_server_summary"
                 style="@style/FxAccountTextItem"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginBottom="0dp"
                 android:ellipsize="middle"
                 android:focusable="true"
                 android:focusableInTouchMode="true"
                 android:singleLine="true"
@@ -83,34 +83,34 @@
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:orientation="vertical"
             android:paddingBottom="6dip"
             android:paddingRight="10dip"
             android:paddingTop="6dip" >
 
             <TextView
-                android:id="@+android:id/sync_server_title"
+                android:id="@+id/sync_server_title"
                 style="@style/FxAccountTextItem"
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center_horizontal"
                 android:layout_marginBottom="0dp"
                 android:gravity="center_vertical"
                 android:text="@string/fxaccount_custom_server_sync_title" >
             </TextView>
 
             <TextView
-                android:id="@+android:id/sync_server_summary"
+                android:id="@+id/sync_server_summary"
                 style="@style/FxAccountTextItem"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginBottom="0dp"
                 android:ellipsize="marquee"
                 android:focusable="true"
                 android:focusableInTouchMode="true"
                 android:singleLine="true"
                 android:textAppearance="?android:attr/textAppearanceSmall"
                 android:textSize="12sp" />
         </LinearLayout>
     </LinearLayout>
 
-</merge>
\ No newline at end of file
+</merge>
--- a/mobile/android/base/resources/values/colors.xml
+++ b/mobile/android/base/resources/values/colors.xml
@@ -105,16 +105,19 @@
   <color name="textbox_stroke_disabled">#666</color>
 
   <color name="url_bar_urltext">#A6A6A6</color>
   <color name="url_bar_domaintext">#000</color>
   <color name="url_bar_domaintext_private">#FFF</color>
   <color name="url_bar_blockedtext">#b14646</color>
   <color name="url_bar_shadow">#12000000</color>
 
+  <color name="nav_button_border_color">#BFBFBF</color>
+  <color name="nav_button_border_color_private">#5F6368</color>
+
   <color name="home_button_bar_bg">#FFF5F7F9</color>
 
   <!-- Colour used for share overlay button labels -->
   <color name="home_text_color">@color/text_color_primary</color>
   <color name="home_text_color_disabled">#AFB1B3</color>
 
   <color name="panel_image_item_background">#D1D9E1</color>
 
--- a/mobile/android/base/tests/testLinkContextMenu.java
+++ b/mobile/android/base/tests/testLinkContextMenu.java
@@ -9,18 +9,18 @@ public class testLinkContextMenu extends
     private static final String LINK_PAGE_TITLE = "Big Link";
     private static final String linkMenuItems [] = StringHelper.CONTEXT_MENU_ITEMS_IN_NORMAL_TAB;
 
     public void testLinkContextMenu() {
         blockForGeckoReady();
 
         LINK_PAGE_URL=getAbsoluteUrl(StringHelper.ROBOCOP_BIG_LINK_URL);
         BLANK_PAGE_URL=getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL);
-        inputAndLoadUrl(LINK_PAGE_URL);
-        waitForText(LINK_PAGE_TITLE);
+        loadAndPaint(LINK_PAGE_URL);
+        verifyPageTitle(LINK_PAGE_TITLE, LINK_PAGE_URL);
 
         verifyContextMenuItems(linkMenuItems); // Verify context menu items are correct
         openTabFromContextMenu(linkMenuItems[0],2); // Test the "Open in New Tab" option - expecting 2 tabs: the original and the new one
         openTabFromContextMenu(linkMenuItems[1],2); // Test the "Open in Private Tab" option - expecting only 2 tabs in normal mode
         verifyCopyOption(linkMenuItems[2], BLANK_PAGE_URL); // Test the "Copy Link" option
         verifyShareOption(linkMenuItems[3], LINK_PAGE_TITLE); // Test the "Share Link" option
         verifyBookmarkLinkOption(linkMenuItems[4], BLANK_PAGE_URL); // Test the "Bookmark Link" option
     }
--- a/mobile/android/base/tests/testMailToContextMenu.java
+++ b/mobile/android/base/tests/testMailToContextMenu.java
@@ -7,16 +7,16 @@ public class testMailToContextMenu exten
     private static String MAILTO_PAGE_URL;
     private static final String MAILTO_PAGE_TITLE = StringHelper.ROBOCOP_BIG_MAILTO_TITLE;
     private static final String mailtoMenuItems [] = {"Copy Email Address", "Share Email Address"};
 
     public void testMailToContextMenu() {
         blockForGeckoReady();
 
         MAILTO_PAGE_URL=getAbsoluteUrl(StringHelper.ROBOCOP_BIG_MAILTO_URL);
-        inputAndLoadUrl(MAILTO_PAGE_URL);
-        waitForText(MAILTO_PAGE_TITLE);
+        loadAndPaint(MAILTO_PAGE_URL);
+        verifyPageTitle(MAILTO_PAGE_TITLE, MAILTO_PAGE_URL);
 
         verifyContextMenuItems(mailtoMenuItems);
         verifyCopyOption(mailtoMenuItems[0], "foo.bar@example.com"); // Test the "Copy Email Address" option
         verifyShareOption(mailtoMenuItems[1], MAILTO_PAGE_TITLE); // Test the "Share Email Address" option
     }
 }
--- a/mobile/android/base/toolbar/BackButton.java
+++ b/mobile/android/base/toolbar/BackButton.java
@@ -1,88 +1,26 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.toolbar;
 
-import org.mozilla.gecko.R;
-
 import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.LinearGradient;
-import android.graphics.Paint;
 import android.graphics.Path;
-import android.graphics.Shader;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.StateListDrawable;
 import android.util.AttributeSet;
 
-public class BackButton extends ShapedButton { 
-    private final Path mBorderPath;
-    private final Paint mBorderPaint;
-    private final float mBorderWidth;
-
+public class BackButton extends NavButton {
     public BackButton(Context context, AttributeSet attrs) {
         super(context, attrs);
-
-        mBorderWidth = getResources().getDimension(R.dimen.nav_button_border_width);
-
-        // Paint to draw the border.
-        mBorderPaint = new Paint();
-        mBorderPaint.setAntiAlias(true);
-        mBorderPaint.setStrokeWidth(mBorderWidth);
-        mBorderPaint.setStyle(Paint.Style.STROKE);
-
-        // Path is masked.
-        mBorderPath = new Path();
-
-        setPrivateMode(false);
-    }
-
-    @Override
-    public void setPrivateMode(boolean isPrivate) {
-        super.setPrivateMode(isPrivate);
-        mBorderPaint.setColor(isPrivate ? 0xFF363B40 : 0xFFB5B5B5);
     }
 
     @Override
     protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
         super.onSizeChanged(width, height, oldWidth, oldHeight);
 
         mPath.reset();
         mPath.addCircle(width/2, height/2, width/2, Path.Direction.CW);
 
         mBorderPath.reset();
         mBorderPath.addCircle(width/2, height/2, (width/2) - (mBorderWidth/2), Path.Direction.CW);
     }
-
-    @Override
-    public void draw(Canvas canvas) {
-        mCanvasDelegate.draw(canvas, mPath, getWidth(), getHeight());
-
-        // Draw the border on top.
-        canvas.drawPath(mBorderPath, mBorderPaint);
-    }
-
-    // The drawable is constructed as per @drawable/url_bar_nav_button.
-    @Override
-    public void onLightweightThemeChanged() {
-        final Drawable drawable = mTheme.getDrawable(this);
-        if (drawable == null)
-            return;
-
-        final StateListDrawable stateList = new StateListDrawable();
-        stateList.addState(PRIVATE_PRESSED_STATE_SET, getColorDrawable(R.color.highlight_nav_pb));
-        stateList.addState(PRESSED_ENABLED_STATE_SET, getColorDrawable(R.color.highlight_nav));
-        stateList.addState(PRIVATE_FOCUSED_STATE_SET, getColorDrawable(R.color.highlight_nav_focused_pb));
-        stateList.addState(FOCUSED_STATE_SET, getColorDrawable(R.color.highlight_nav_focused));
-        stateList.addState(PRIVATE_STATE_SET, getColorDrawable(R.color.background_private));
-        stateList.addState(EMPTY_STATE_SET, drawable);
-
-        setBackgroundDrawable(stateList);
-    }
-
-    @Override
-    public void onLightweightThemeReset() {
-        setBackgroundResource(R.drawable.url_bar_nav_button);
-    }
 }
--- a/mobile/android/base/toolbar/ForwardButton.java
+++ b/mobile/android/base/toolbar/ForwardButton.java
@@ -1,85 +1,23 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.toolbar;
 
-import org.mozilla.gecko.R;
-
 import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.LinearGradient;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Shader;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.StateListDrawable;
 import android.util.AttributeSet;
 
-public class ForwardButton extends ShapedButton { 
-    private final Path mBorderPath;
-    private final Paint mBorderPaint;
-    private final float mBorderWidth;
-
+public class ForwardButton extends NavButton {
     public ForwardButton(Context context, AttributeSet attrs) {
         super(context, attrs);
-
-        mBorderWidth = getResources().getDimension(R.dimen.nav_button_border_width);
-
-        // Paint to draw the border.
-        mBorderPaint = new Paint();
-        mBorderPaint.setAntiAlias(true);
-        mBorderPaint.setStrokeWidth(mBorderWidth);
-        mBorderPaint.setStyle(Paint.Style.STROKE);
-
-        mBorderPath = new Path();
-
-        setPrivateMode(false);
-    }
-
-    @Override
-    public void setPrivateMode(boolean isPrivate) {
-        super.setPrivateMode(isPrivate);
-        mBorderPaint.setColor(isPrivate ? 0xFF363B40 : 0xFFBFBFBF);
     }
 
     @Override
     protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
         super.onSizeChanged(width, height, oldWidth, oldHeight);
 
         mBorderPath.reset();
         mBorderPath.moveTo(width - mBorderWidth, 0);
         mBorderPath.lineTo(width - mBorderWidth, height);
     }
-
-    @Override
-    public void draw(Canvas canvas) {
-        super.draw(canvas);
-
-        // Draw the border on top.
-        canvas.drawPath(mBorderPath, mBorderPaint);
-    }
-
-    // The drawable is constructed as per @drawable/url_bar_nav_button.
-    @Override
-    public void onLightweightThemeChanged() {
-        final Drawable drawable = mTheme.getDrawable(this);
-        if (drawable == null)
-            return;
-
-        final StateListDrawable stateList = new StateListDrawable();
-        stateList.addState(PRIVATE_PRESSED_STATE_SET, getColorDrawable(R.color.highlight_nav_pb));
-        stateList.addState(PRESSED_ENABLED_STATE_SET, getColorDrawable(R.color.highlight_nav));
-        stateList.addState(PRIVATE_FOCUSED_STATE_SET, getColorDrawable(R.color.highlight_nav_focused_pb));
-        stateList.addState(FOCUSED_STATE_SET, getColorDrawable(R.color.highlight_nav_focused));
-        stateList.addState(PRIVATE_STATE_SET, getColorDrawable(R.color.background_private));
-        stateList.addState(EMPTY_STATE_SET, drawable);
-        
-        setBackgroundDrawable(stateList);
-    }
-
-    @Override
-    public void onLightweightThemeReset() {
-        setBackgroundResource(R.drawable.url_bar_nav_button);
-    }
 }
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/toolbar/NavButton.java
@@ -0,0 +1,82 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.toolbar;
+
+import org.mozilla.gecko.R;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
+import android.util.AttributeSet;
+
+abstract class NavButton extends ShapedButton {
+    protected final Path mBorderPath;
+    protected final Paint mBorderPaint;
+    protected final float mBorderWidth;
+
+    protected final int mBorderColor;
+    protected final int mBorderColorPrivate;
+
+    public NavButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        final Resources res = getResources();
+        mBorderColor = res.getColor(R.color.nav_button_border_color);
+        mBorderColorPrivate = res.getColor(R.color.nav_button_border_color_private);
+        mBorderWidth = res.getDimension(R.dimen.nav_button_border_width);
+
+        // Paint to draw the border.
+        mBorderPaint = new Paint();
+        mBorderPaint.setAntiAlias(true);
+        mBorderPaint.setStrokeWidth(mBorderWidth);
+        mBorderPaint.setStyle(Paint.Style.STROKE);
+
+        // Path is masked.
+        mBorderPath = new Path();
+
+        setPrivateMode(false);
+    }
+
+    @Override
+    public void setPrivateMode(boolean isPrivate) {
+        super.setPrivateMode(isPrivate);
+        mBorderPaint.setColor(isPrivate ? mBorderColorPrivate : mBorderColor);
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        super.draw(canvas);
+
+        // Draw the border on top.
+        canvas.drawPath(mBorderPath, mBorderPaint);
+    }
+
+    // The drawable is constructed as per @drawable/url_bar_nav_button.
+    @Override
+    public void onLightweightThemeChanged() {
+        final Drawable drawable = mTheme.getDrawable(this);
+        if (drawable == null)
+            return;
+
+        final StateListDrawable stateList = new StateListDrawable();
+        stateList.addState(PRIVATE_PRESSED_STATE_SET, getColorDrawable(R.color.highlight_nav_pb));
+        stateList.addState(PRESSED_ENABLED_STATE_SET, getColorDrawable(R.color.highlight_nav));
+        stateList.addState(PRIVATE_FOCUSED_STATE_SET, getColorDrawable(R.color.highlight_nav_focused_pb));
+        stateList.addState(FOCUSED_STATE_SET, getColorDrawable(R.color.highlight_nav_focused));
+        stateList.addState(PRIVATE_STATE_SET, getColorDrawable(R.color.background_private));
+        stateList.addState(EMPTY_STATE_SET, drawable);
+
+        setBackgroundDrawable(stateList);
+    }
+
+    @Override
+    public void onLightweightThemeReset() {
+        setBackgroundResource(R.drawable.url_bar_nav_button);
+    }
+}
--- a/mobile/android/base/util/ThreadUtils.java
+++ b/mobile/android/base/util/ThreadUtils.java
@@ -12,16 +12,19 @@ import java.util.Map;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.MessageQueue;
 import android.util.Log;
 
 public final class ThreadUtils {
     private static final String LOGTAG = "ThreadUtils";
 
+    // Time in ms until the Gecko thread is reset to normal priority.
+    private static final long PRIORITY_RESET_TIMEOUT = 10000;
+
     /**
      * Controls the action taken when a method like
      * {@link ThreadUtils#assertOnUiThread(AssertBehavior)} detects a problem.
      */
     public static enum AssertBehavior {
         NONE,
         THROW,
     }
@@ -204,30 +207,28 @@ public final class ThreadUtils {
     }
 
     /**
      * Reduces the priority of the Gecko thread, allowing other operations
      * (such as those related to the UI and database) to take precedence.
      *
      * Note that there are no guards in place to prevent multiple calls
      * to this method from conflicting with each other.
-     *
-     * @param timeout Timeout in ms after which the priority will be reset
      */
-    public static void reduceGeckoPriority(long timeout) {
+    public static void reduceGeckoPriority() {
         if (Runtime.getRuntime().availableProcessors() > 1) {
             // Don't reduce priority for multicore devices. We use availableProcessors()
             // for its fast performance. It may give false negatives (i.e. multicore
             // detected as single-core), but we can tolerate this behavior.
             return;
         }
         if (!sIsGeckoPriorityReduced && sGeckoThread != null) {
             sIsGeckoPriorityReduced = true;
             sGeckoThread.setPriority(Thread.MIN_PRIORITY);
-            getUiHandler().postDelayed(sPriorityResetRunnable, timeout);
+            getUiHandler().postDelayed(sPriorityResetRunnable, PRIORITY_RESET_TIMEOUT);
         }
     }
 
     /**
      * Resets the priority of a thread whose priority has been reduced
      * by reduceGeckoPriority.
      */
     public static void resetGeckoPriority() {
--- a/mobile/android/confvars.sh
+++ b/mobile/android/confvars.sh
@@ -81,22 +81,18 @@ if test ! "$RELEASE_BUILD"; then
   MOZ_ANDROID_NEW_TABLET_UI=1
 fi
 
 # Enable the share handler in pre-release builds.
 if test ! "$RELEASE_BUILD"; then
   MOZ_ANDROID_SHARE_OVERLAY=1
 fi
 
-# Enable the Mozilla Location Service stumbler in Nightly.
-if test "$NIGHTLY_BUILD"; then
-  MOZ_ANDROID_MLS_STUMBLER=1
-else
-  MOZ_ANDROID_MLS_STUMBLER=
-fi
+# Enable the Mozilla Location Service stumbler.
+MOZ_ANDROID_MLS_STUMBLER=1
 
 # Enable adding to the system downloads list in pre-release builds.
 if test ! "$RELEASE_BUILD"; then
   MOZ_ANDROID_DOWNLOADS_INTEGRATION=1
 fi
 
 # Enable generational GC on mobile.
 JSGC_GENERATIONAL=1
--- a/mobile/android/themes/core/aboutFeedback.css
+++ b/mobile/android/themes/core/aboutFeedback.css
@@ -179,27 +179,34 @@ footer {
 #thanks-sad-message {
   margin: 20px 0px;
 }
 
 .send-feedback {
   padding: 15px;
   font-size: 16px;
   width: 100%;
-  background-color: #0092DB;
   border-radius: 4px;
   border-width: 0;
   color: #fff;
 }
 
 .link {
   color: #222;
   text-decoration: underline;
 }
 
+.description:invalid ~ .send-feedback {
+  background-color: #8698A8;
+}
+
+.description:valid ~ .send-feedback {
+  background-color: #0092DB;
+}
+
 @media screen and (max-height: 400px) {
   body {
     padding-top: 40px;
   }
 
   .bottom-links {
     margin-top: 20px;
   }
--- a/netwerk/protocol/rtsp/rtsp/AAMRAssembler.cpp
+++ b/netwerk/protocol/rtsp/rtsp/AAMRAssembler.cpp
@@ -132,75 +132,87 @@ ARTPAssembler::AssemblyStatus AAMRAssemb
     }
 
     // hexdump(buffer->data(), buffer->size());
 
     if (buffer->size() < 1) {
         queue->erase(queue->begin());
         ++mNextExpectedSeqNo;
 
-        LOGV("AMR packet too short.");
+        LOGW("AMR packet too short.");
 
         return MALFORMED_PACKET;
     }
 
     unsigned payloadHeader = buffer->data()[0];
-    CHECK_EQ(payloadHeader & 0x0f, 0u);  // RR
+    if (payloadHeader & 0x0f != 0u) {
+        queue->erase(queue->begin());
+        ++mNextExpectedSeqNo;
+
+        LOGW("Wrong payload header");
+
+        return MALFORMED_PACKET;
+    }
 
     Vector<uint8_t> tableOfContents;
 
     size_t offset = 1;
     size_t totalSize = 0;
     for (;;) {
         if (offset >= buffer->size()) {
             queue->erase(queue->begin());
             ++mNextExpectedSeqNo;
 
-            LOGV("Unable to parse TOC.");
+            LOGW("Unable to parse TOC.");
 
             return MALFORMED_PACKET;
         }
 
         uint8_t toc = buffer->data()[offset++];
 
         unsigned FT = (toc >> 3) & 0x0f;
         if ((toc & 3) != 0
                 || (mIsWide && FT > 9 && FT != 15)
                 || (!mIsWide && FT > 8 && FT != 15)) {
             queue->erase(queue->begin());
             ++mNextExpectedSeqNo;
 
-            LOGV("Illegal TOC entry.");
+            LOGW("Illegal TOC entry.");
 
             return MALFORMED_PACKET;
         }
 
         totalSize += getFrameSize(mIsWide, (toc >> 3) & 0x0f);
 
         tableOfContents.push(toc);
 
         if (0 == (toc & 0x80)) {
             break;
         }
     }
 
     sp<ABuffer> accessUnit = new ABuffer(totalSize);
-    CopyTimes(accessUnit, buffer);
+    if (!CopyTimes(accessUnit, buffer)) {
+        queue->erase(queue->begin());
+        ++mNextExpectedSeqNo;
+
+        return MALFORMED_PACKET;
+    }
 
     size_t dstOffset = 0;
     for (size_t i = 0; i < tableOfContents.size(); ++i) {
         uint8_t toc = tableOfContents[i];
 
         size_t frameSize = getFrameSize(mIsWide, (toc >> 3) & 0x0f);
 
         if (offset + frameSize - 1 > buffer->size()) {
             queue->erase(queue->begin());
             ++mNextExpectedSeqNo;
 
-            LOGV("AMR packet too short.");
+            LOGW("AMR packet too short.");
 
             return MALFORMED_PACKET;
         }
 
         accessUnit->data()[dstOffset++] = toc;
         memcpy(accessUnit->data() + dstOffset,
                buffer->data() + offset, frameSize - 1);
 
--- a/netwerk/protocol/rtsp/rtsp/AAVCAssembler.cpp
+++ b/netwerk/protocol/rtsp/rtsp/AAVCAssembler.cpp
@@ -16,16 +16,18 @@
 
 #define LOG_TAG "AAVCAssembler"
 #include "RtspPrlog.h"
 
 #include "AAVCAssembler.h"
 
 #include "ARTPSource.h"
 
+#include "mozilla/Assertions.h"
+
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/hexdump.h>
 
 #include <stdint.h>
 
 namespace android {
@@ -77,29 +79,30 @@ ARTPAssembler::AssemblyStatus AAVCAssemb
     }
 
     const uint8_t *data = buffer->data();
     size_t size = buffer->size();
 
     if (size < 1 || (data[0] & 0x80)) {
         // Corrupt.
 
-        LOGV("Ignoring corrupt buffer.");
+        LOGW("Ignoring corrupt buffer.");
         queue->erase(queue->begin());
 
         ++mNextExpectedSeqNo;
         return MALFORMED_PACKET;
     }
 
     unsigned nalType = data[0] & 0x1f;
     if (nalType >= 1 && nalType <= 23) {
-        addSingleNALUnit(buffer);
+        bool success = addSingleNALUnit(buffer);
         queue->erase(queue->begin());
         ++mNextExpectedSeqNo;
-        return OK;
+
+        return success ? OK : MALFORMED_PACKET;
     } else if (nalType == 28) {
         // FU-A
         return addFragmentedNALUnit(queue);
     } else if (nalType == 24) {
         // STAP-A
         bool success = addSingleTimeAggregationPacket(buffer);
         queue->erase(queue->begin());
         ++mNextExpectedSeqNo;
@@ -110,31 +113,39 @@ ARTPAssembler::AssemblyStatus AAVCAssemb
 
         queue->erase(queue->begin());
         ++mNextExpectedSeqNo;
 
         return MALFORMED_PACKET;
     }
 }
 
-void AAVCAssembler::addSingleNALUnit(const sp<ABuffer> &buffer) {
+bool AAVCAssembler::addSingleNALUnit(const sp<ABuffer> &buffer) {
     LOGV("addSingleNALUnit of size %d", buffer->size());
 #if !LOG_NDEBUG
     hexdump(buffer->data(), buffer->size());
 #endif
 
     uint32_t rtpTime;
-    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+    if (!buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)) {
+        LOGW("Cannot find rtp-time");
+        return false;
+    }
 
     if (!mNALUnits.empty() && rtpTime != mAccessUnitRTPTime) {
-        submitAccessUnit();
+        if (!submitAccessUnit()) {
+            LOGW("Cannot find rtp-time. Malformed packet.");
+
+            return false;
+        }
     }
     mAccessUnitRTPTime = rtpTime;
 
     mNALUnits.push_back(buffer);
+    return true;
 }
 
 bool AAVCAssembler::addSingleTimeAggregationPacket(const sp<ABuffer> &buffer) {
     const uint8_t *data = buffer->data();
     size_t size = buffer->size();
 
     if (size < 3) {
         LOGV("Discarding too small STAP-A packet.");
@@ -149,56 +160,73 @@ bool AAVCAssembler::addSingleTimeAggrega
         if (size < nalSize + 2) {
             LOGV("Discarding malformed STAP-A packet.");
             return false;
         }
 
         sp<ABuffer> unit = new ABuffer(nalSize);
         memcpy(unit->data(), &data[2], nalSize);
 
-        CopyTimes(unit, buffer);
+        if (!CopyTimes(unit, buffer)) {
+            return false;
+        }
 
-        addSingleNALUnit(unit);
+        if (!addSingleNALUnit(unit)) {
+            LOGW("addSingleNALUnit() failed");
+            return false;
+        }
 
         data += 2 + nalSize;
         size -= 2 + nalSize;
     }
 
     if (size != 0) {
         LOGV("Unexpected padding at end of STAP-A packet.");
     }
 
     return true;
 }
 
 ARTPAssembler::AssemblyStatus AAVCAssembler::addFragmentedNALUnit(
         List<sp<ABuffer> > *queue) {
-    CHECK(!queue->empty());
+    MOZ_ASSERT(!queue->empty());
 
     sp<ABuffer> buffer = *queue->begin();
     const uint8_t *data = buffer->data();
     size_t size = buffer->size();
 
-    CHECK(size > 0);
+    if (size <= 0) {
+        LOGW("Buffer is empty");
+
+        queue->erase(queue->begin());
+        ++mNextExpectedSeqNo;
+        return MALFORMED_PACKET;
+    }
     unsigned indicator = data[0];
 
-    CHECK((indicator & 0x1f) == 28);
+    if ((indicator & 0x1f) != 28) {
+        LOGW("Indicator is wrong");
+
+        queue->erase(queue->begin());
+        ++mNextExpectedSeqNo;
+        return MALFORMED_PACKET;
+    }
 
     if (size < 2) {
-        LOGV("Ignoring malformed FU buffer (size = %d)", size);
+        LOGW("Ignoring malformed FU buffer (size = %d)", size);
 
         queue->erase(queue->begin());
         ++mNextExpectedSeqNo;
         return MALFORMED_PACKET;
     }
 
     if (!(data[1] & 0x80)) {
         // Start bit not set on the first buffer.
 
-        LOGV("Start bit not set on first buffer");
+        LOGW("Start bit not set on first buffer");
 
         queue->erase(queue->begin());
         ++mNextExpectedSeqNo;
         return MALFORMED_PACKET;
     }
 
     uint32_t nalType = data[1] & 0x1f;
     uint32_t nri = (data[0] >> 5) & 3;
@@ -230,17 +258,17 @@ ARTPAssembler::AssemblyStatus AAVCAssemb
 
                 return WRONG_SEQUENCE_NUMBER;
             }
 
             if (size < 2
                     || data[0] != indicator
                     || (data[1] & 0x1f) != nalType
                     || (data[1] & 0x80)) {
-                LOGV("Ignoring malformed FU buffer.");
+                LOGW("Ignoring malformed FU buffer.");
 
                 // Delete the whole start of the FU.
 
                 it = queue->begin();
                 for (size_t i = 0; i <= totalCount; ++i) {
                     it = queue->erase(it);
                 }
 
@@ -272,17 +300,19 @@ ARTPAssembler::AssemblyStatus AAVCAssemb
 
     // We found all the fragments that make up the complete NAL unit.
 
     // Leave room for the header. So far totalSize did not include the
     // header byte.
     ++totalSize;
 
     sp<ABuffer> unit = new ABuffer(totalSize);
-    CopyTimes(unit, *queue->begin());
+    if (!CopyTimes(unit, *queue->begin())) {
+        return MALFORMED_PACKET;
+    }
 
     unit->data()[0] = (nri << 5) | nalType;
 
     size_t offset = 1;
     List<sp<ABuffer> >::iterator it = queue->begin();
     for (size_t i = 0; i < totalCount; ++i) {
         const sp<ABuffer> &buffer = *it;
 
@@ -294,25 +324,27 @@ ARTPAssembler::AssemblyStatus AAVCAssemb
         memcpy(unit->data() + offset, buffer->data() + 2, buffer->size() - 2);
         offset += buffer->size() - 2;
 
         it = queue->erase(it);
     }
 
     unit->setRange(0, totalSize);
 
-    addSingleNALUnit(unit);
+    if (!addSingleNALUnit(unit)) {
+        return MALFORMED_PACKET;
+    }
 
     LOGV("successfully assembled a NAL unit from fragments.");
 
     return OK;
 }
 
-void AAVCAssembler::submitAccessUnit() {
-    CHECK(!mNALUnits.empty());
+bool AAVCAssembler::submitAccessUnit() {
+    MOZ_ASSERT(!mNALUnits.empty());
 
     LOGV("Access unit complete (%d nal units)", mNALUnits.size());
 
     size_t totalSize = 0;
     for (List<sp<ABuffer> >::iterator it = mNALUnits.begin();
          it != mNALUnits.end(); ++it) {
         totalSize += 4 + (*it)->size();
     }
@@ -324,33 +356,36 @@ void AAVCAssembler::submitAccessUnit() {
         memcpy(accessUnit->data() + offset, "\x00\x00\x00\x01", 4);
         offset += 4;
 
         sp<ABuffer> nal = *it;
         memcpy(accessUnit->data() + offset, nal->data(), nal->size());
         offset += nal->size();
     }
 
-    CopyTimes(accessUnit, *mNALUnits.begin());
+    if (!CopyTimes(accessUnit, *mNALUnits.begin())) {
+        return false;
+    }
 
 #if 0
     printf(mAccessUnitDamaged ? "X" : ".");
     fflush(stdout);
 #endif
 
     if (mAccessUnitDamaged) {
         accessUnit->meta()->setInt32("damaged", true);
     }
 
     mNALUnits.clear();
     mAccessUnitDamaged = false;
 
     sp<AMessage> msg = mNotifyMsg->dup();
     msg->setObject("access-unit", accessUnit);
     msg->post();
+    return true;
 }
 
 ARTPAssembler::AssemblyStatus AAVCAssembler::assembleMore(
         const sp<ARTPSource> &source) {
     AssemblyStatus status = addNALUnit(source);
     if (status == MALFORMED_PACKET) {
         mAccessUnitDamaged = true;
     }
--- a/netwerk/protocol/rtsp/rtsp/AAVCAssembler.h
+++ b/netwerk/protocol/rtsp/rtsp/AAVCAssembler.h
@@ -44,20 +44,20 @@ private:
 
     uint32_t mAccessUnitRTPTime;
     bool mNextExpectedSeqNoValid;
     uint32_t mNextExpectedSeqNo;
     bool mAccessUnitDamaged;
     List<sp<ABuffer> > mNALUnits;
 
     AssemblyStatus addNALUnit(const sp<ARTPSource> &source);
-    void addSingleNALUnit(const sp<ABuffer> &buffer);
+    bool addSingleNALUnit(const sp<ABuffer> &buffer);
     AssemblyStatus addFragmentedNALUnit(List<sp<ABuffer> > *queue);
     bool addSingleTimeAggregationPacket(const sp<ABuffer> &buffer);
 
-    void submitAccessUnit();
+    bool submitAccessUnit();
 
     DISALLOW_EVIL_CONSTRUCTORS(AAVCAssembler);
 };
 
 }  // namespace android
 
 #endif  // A_AVC_ASSEMBLER_H_
--- a/netwerk/protocol/rtsp/rtsp/AH263Assembler.cpp
+++ b/netwerk/protocol/rtsp/rtsp/AH263Assembler.cpp
@@ -14,16 +14,18 @@
  * limitations under the License.
  */
 
 #include "AH263Assembler.h"
 
 #include "ARTPSource.h"
 #include "RtspPrlog.h"
 
+#include "mozilla/Assertions.h"
+
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/Utils.h>
 
 namespace android {
 
@@ -79,20 +81,34 @@ ARTPAssembler::AssemblyStatus AH263Assem
 #if VERBOSE
         LOG(VERBOSE) << "Not the sequence number I expected";
 #endif
 
         return WRONG_SEQUENCE_NUMBER;
     }
 
     uint32_t rtpTime;
-    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+    if (!buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)) {
+        queue->erase(queue->begin());
+        ++mNextExpectedSeqNo;
+
+        LOGW("Cannot find rtp-time. Malformed packet.");
+
+        return MALFORMED_PACKET;
+    }
 
     if (mPackets.size() > 0 && rtpTime != mAccessUnitRTPTime) {
-        submitAccessUnit();
+        if (!submitAccessUnit()) {
+            queue->erase(queue->begin());
+            ++mNextExpectedSeqNo;
+
+            LOGW("Cannot find rtp-time. Malformed packet.");
+
+            return MALFORMED_PACKET;
+        }
     }
     mAccessUnitRTPTime = rtpTime;
 
     // hexdump(buffer->data(), buffer->size());
 
     if (buffer->size() < 2) {
         queue->erase(queue->begin());
         ++mNextExpectedSeqNo;
@@ -169,18 +185,18 @@ ARTPAssembler::AssemblyStatus AH263Assem
     mPackets.push_back(buffer);
 
     queue->erase(queue->begin());
     ++mNextExpectedSeqNo;
 
     return OK;
 }
 
-void AH263Assembler::submitAccessUnit() {
-    CHECK(!mPackets.empty());
+bool AH263Assembler::submitAccessUnit() {
+    MOZ_ASSERT(!mPackets.empty());
 
 #if VERBOSE
     LOG(VERBOSE) << "Access unit complete (" << mPackets.size() << " packets)";
 #endif
 
     size_t totalSize = 0;
     List<sp<ABuffer> >::iterator it = mPackets.begin();
     while (it != mPackets.end()) {
@@ -199,33 +215,37 @@ void AH263Assembler::submitAccessUnit() 
         memcpy((uint8_t *)accessUnit->data() + offset,
                unit->data(), unit->size());
 
         offset += unit->size();
 
         ++it;
     }
 
-    CopyTimes(accessUnit, *mPackets.begin());
+    if (!CopyTimes(accessUnit, *mPackets.begin())) {
+        return false;
+    }
 
 #if 0
     printf(mAccessUnitDamaged ? "X" : ".");
     fflush(stdout);
 #endif
 
     if (mAccessUnitDamaged) {
         accessUnit->meta()->setInt32("damaged", true);
     }
 
     mPackets.clear();
     mAccessUnitDamaged = false;
 
     sp<AMessage> msg = mNotifyMsg->dup();
     msg->setObject("access-unit", accessUnit);
     msg->post();
+
+    return true;
 }
 
 void AH263Assembler::packetLost() {
     CHECK(mNextExpectedSeqNoValid);
     ++mNextExpectedSeqNo;
 
     mAccessUnitDamaged = true;
 }
--- a/netwerk/protocol/rtsp/rtsp/AH263Assembler.h
+++ b/netwerk/protocol/rtsp/rtsp/AH263Assembler.h
@@ -43,16 +43,16 @@ private:
     sp<AMessage> mNotifyMsg;
     uint32_t mAccessUnitRTPTime;
     bool mNextExpectedSeqNoValid;
     uint32_t mNextExpectedSeqNo;
     bool mAccessUnitDamaged;
     List<sp<ABuffer> > mPackets;
 
     AssemblyStatus addPacket(const sp<ARTPSource> &source);
-    void submitAccessUnit();
+    bool submitAccessUnit();
 
     DISALLOW_EVIL_CONSTRUCTORS(AH263Assembler);
 };
 
 }  // namespace android
 
 #endif  // A_H263_ASSEMBLER_H_
--- a/netwerk/protocol/rtsp/rtsp/AMPEG4AudioAssembler.cpp
+++ b/netwerk/protocol/rtsp/rtsp/AMPEG4AudioAssembler.cpp
@@ -16,16 +16,18 @@
 
 #define LOG_TAG "AMPEG4AudioAssembler"
 #include "RtspPrlog.h"
 
 #include "AMPEG4AudioAssembler.h"
 
 #include "ARTPSource.h"
 
+#include "mozilla/Assertions.h"
+
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaErrors.h>
 
 #include <ctype.h>
@@ -131,28 +133,32 @@ static status_t parseGASpecificConfig(
         } else if (audioObjectType == 17 || audioObjectType == 19
                 || audioObjectType == 20 || audioObjectType == 23) {
             /* unsigned aacSectionDataResilienceFlag = */bits->getBits(1);
             /* unsigned aacScalefactorDataResilienceFlag = */bits->getBits(1);
             /* unsigned aacSpectralDataResilienceFlag = */bits->getBits(1);
         }
 
         unsigned extensionFlag3 = bits->getBits(1);
-        CHECK_EQ(extensionFlag3, 0u);  // TBD in version 3
+        if (extensionFlag3 != 0u) {
+            return ERROR_UNSUPPORTED; // TBD in version 3
+        }
     }
 
     return OK;
 }
 
 static status_t parseAudioSpecificConfig(ABitReader *bits, sp<ABuffer> *asc) {
     const uint8_t *dataStart = bits->data();
     size_t totalNumBits = bits->numBitsLeft();
 
     unsigned audioObjectType;
-    CHECK_EQ(parseAudioObjectType(bits, &audioObjectType), (status_t)OK);
+    if (parseAudioObjectType(bits, &audioObjectType) != (status_t)OK) {
+        return ERROR_UNSUPPORTED;
+    }
 
     unsigned samplingFreqIndex = bits->getBits(4);
     if (samplingFreqIndex == 0x0f) {
         /* unsigned samplingFrequency = */bits->getBits(24);
     }
 
     unsigned channelConfiguration = bits->getBits(4);
 
@@ -161,50 +167,60 @@ static status_t parseAudioSpecificConfig
 
     if (audioObjectType == 5) {
         extensionAudioObjectType = audioObjectType;
         sbrPresent = 1;
         unsigned extensionSamplingFreqIndex = bits->getBits(4);
         if (extensionSamplingFreqIndex == 0x0f) {
             /* unsigned extensionSamplingFrequency = */bits->getBits(24);
         }
-        CHECK_EQ(parseAudioObjectType(bits, &audioObjectType), (status_t)OK);
+        if (parseAudioObjectType(bits, &audioObjectType) != (status_t)OK) {
+            return ERROR_UNSUPPORTED;
+        }
     }
 
-    CHECK((audioObjectType >= 1 && audioObjectType <= 4)
-        || (audioObjectType >= 6 && audioObjectType <= 7)
-        || audioObjectType == 17
-        || (audioObjectType >= 19 && audioObjectType <= 23));
+    if (!((audioObjectType >= 1 && audioObjectType <= 4) ||
+          (audioObjectType >= 6 && audioObjectType <= 7) ||
+          audioObjectType == 17 ||
+          (audioObjectType >= 19 && audioObjectType <= 23))) {
+        return ERROR_UNSUPPORTED;
+    }
 
-    CHECK_EQ(parseGASpecificConfig(
-                bits, audioObjectType, channelConfiguration), (status_t)OK);
+    if (parseGASpecificConfig(bits, audioObjectType, channelConfiguration)
+        != (status_t)OK) {
+        return ERROR_UNSUPPORTED;
+    }
 
     if (audioObjectType == 17
             || (audioObjectType >= 19 && audioObjectType <= 27)) {
         unsigned epConfig = bits->getBits(2);
         if (epConfig == 2 || epConfig == 3) {
             // ErrorProtectionSpecificConfig
             return ERROR_UNSUPPORTED;  // XXX to be implemented
 
             if (epConfig == 3) {
                 unsigned directMapping = bits->getBits(1);
-                CHECK_EQ(directMapping, 1u);
+                if (directMapping != 1u) {
+                    return ERROR_UNSUPPORTED;
+                }
             }
         }
     }
 
     if (extensionAudioObjectType != 5 && bits->numBitsLeft() >= 16) {
         size_t numBitsLeftAtStart = bits->numBitsLeft();
 
         unsigned syncExtensionType = bits->getBits(11);
         if (syncExtensionType == 0x2b7) {
             LOGI("found syncExtension");
 
-            CHECK_EQ(parseAudioObjectType(bits, &extensionAudioObjectType),
-                     (status_t)OK);
+            if (parseAudioObjectType(bits, &extensionAudioObjectType)
+                != (status_t)OK) {
+                return ERROR_UNSUPPORTED;
+            }
 
             sbrPresent = bits->getBits(1);
 
             if (sbrPresent == 1) {
                 unsigned extensionSamplingFreqIndex = bits->getBits(4);
                 if (extensionSamplingFreqIndex == 0x0f) {
                     /* unsigned extensionSamplingFrequency = */bits->getBits(24);
                 }
@@ -261,38 +277,47 @@ static status_t parseStreamMuxConfig(
         unsigned *otherDataLenBits) {
     unsigned audioMuxVersion = bits->getBits(1);
 
     unsigned audioMuxVersionA = 0;
     if (audioMuxVersion == 1) {
         audioMuxVersionA = bits->getBits(1);
     }
 
-    CHECK_EQ(audioMuxVersionA, 0u);  // otherwise future spec
+    if (audioMuxVersionA != 0u) {
+        return ERROR_UNSUPPORTED;  // future spec
+    }
 
-    if (audioMuxVersion != 0) {
+    if (audioMuxVersion != 0u) {
         return ERROR_UNSUPPORTED;  // XXX to be implemented;
     }
-    CHECK_EQ(audioMuxVersion, 0u);  // XXX to be implemented
 
     unsigned allStreamsSameTimeFraming = bits->getBits(1);
-    CHECK_EQ(allStreamsSameTimeFraming, 1u);  // There's only one stream.
+    if (allStreamsSameTimeFraming != 1u) {
+        return ERROR_UNSUPPORTED;  // There's only one stream.
+    }
 
     *numSubFrames = bits->getBits(6);
     unsigned numProgram = bits->getBits(4);
-    CHECK_EQ(numProgram, 0u);  // disabled in RTP LATM
+    if (numProgram != 0u) {
+        return ERROR_UNSUPPORTED;  // disabled in RTP LATM
+    }
 
     unsigned numLayer = bits->getBits(3);
-    CHECK_EQ(numLayer, 0u);  // disabled in RTP LATM
+    if (numLayer != 0u) {
+        return ERROR_UNSUPPORTED;  // disabled in RTP LATM
+    }
 
     if (audioMuxVersion == 0) {
         // AudioSpecificConfig
-        CHECK_EQ(parseAudioSpecificConfig(bits, NULL /* asc */), (status_t)OK);
+        if (parseAudioSpecificConfig(bits, NULL /* asc */) != (status_t)OK) {
+            return ERROR_UNSUPPORTED;
+        }
     } else {
-        TRESPASS();  // XXX to be implemented
+        return ERROR_UNSUPPORTED; // XXX to be implemented
     }
 
     *frameLengthType = bits->getBits(3);
     *fixedFrameLength = -1;
 
     switch (*frameLengthType) {
         case 0:
         {
@@ -334,17 +359,17 @@ static status_t parseStreamMuxConfig(
         default:
             break;
     }
 
     *otherDataPresent = bits->getBits(1);
     *otherDataLenBits = 0;
     if (*otherDataPresent) {
         if (audioMuxVersion == 1) {
-            TRESPASS();  // XXX to be implemented
+            return ERROR_UNSUPPORTED;  // XXX to be implemented
         } else {
             *otherDataLenBits = 0;
 
             unsigned otherDataLenEsc;
             do {
                 (*otherDataLenBits) <<= 8;
                 otherDataLenEsc = bits->getBits(1);
                 unsigned otherDataLenTmp = bits->getBits(8);
@@ -357,17 +382,19 @@ static status_t parseStreamMuxConfig(
     if (crcCheckPresent) {
         /* unsigned crcCheckSum = */bits->getBits(8);
     }
 
     return OK;
 }
 
 sp<ABuffer> AMPEG4AudioAssembler::removeLATMFraming(const sp<ABuffer> &buffer) {
-    CHECK(!mMuxConfigPresent);  // XXX to be implemented
+    if (mMuxConfigPresent) {
+        return NULL;  // XXX to be implemented
+    }
 
     sp<ABuffer> out = new ABuffer(buffer->size());
     out->setRange(0, 0);
 
     size_t offset = 0;
     uint8_t *ptr = buffer->data();
 
     for (size_t i = 0; i <= mNumSubFrames; ++i) {
@@ -399,17 +426,19 @@ sp<ABuffer> AMPEG4AudioAssembler::remove
                 // reserved
 
                 TRESPASS();
                 break;
             }
 
             default:
             {
-                CHECK_GE(mFixedFrameLength, 0);
+                if (mFixedFrameLength < 0) {
+                    return NULL;
+                }
 
                 payloadLength = mFixedFrameLength;
                 break;
             }
         }
 
         if ((offset + payloadLength) > buffer->size()) {
             LOGI("Malformed packet found in removeLATMFraming");
@@ -420,18 +449,24 @@ sp<ABuffer> AMPEG4AudioAssembler::remove
         memcpy(out->data() + out->size(), &ptr[offset], payloadLength);
         out->setRange(0, out->size() + payloadLength);
 
         offset += payloadLength;
 
         if (mOtherDataPresent) {
             // We want to stay byte-aligned.
 
-            CHECK((mOtherDataLenBits % 8) == 0);
-            CHECK_LE(offset + (mOtherDataLenBits / 8), buffer->size());
+            if (mOtherDataLenBits % 8 != 0) {
+                mAccessUnitDamaged = true;
+                return out;
+            }
+            if (offset + (mOtherDataLenBits / 8) > buffer->size()) {
+                mAccessUnitDamaged = true;
+                return out;
+            }
             offset += mOtherDataLenBits / 8;
         }
     }
 
     if (offset < buffer->size()) {
         LOGI("ignoring %d bytes of trailing data", buffer->size() - offset);
     }
     CHECK_LE(offset, buffer->size());
@@ -515,33 +550,40 @@ ARTPAssembler::AssemblyStatus AMPEG4Audi
 #if VERBOSE
         LOG(VERBOSE) << "Not the sequence number I expected";
 #endif
 
         return WRONG_SEQUENCE_NUMBER;
     }
 
     uint32_t rtpTime;
-    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+    if (!buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)) {
+        LOGW("Cannot find rtp-time. Malformed packet.");
+
+        return MALFORMED_PACKET;
+    }
 
     if (mPackets.size() > 0 && rtpTime != mAccessUnitRTPTime) {
-        submitAccessUnit();
+        if (!submitAccessUnit()) {
+            LOGW("Cannot find rtp-time. Malformed packet.");
+            return MALFORMED_PACKET;
+        }
     }
     mAccessUnitRTPTime = rtpTime;
 
     mPackets.push_back(buffer);
 
     queue->erase(queue->begin());
     ++mNextExpectedSeqNo;
 
     return OK;
 }
 
-void AMPEG4AudioAssembler::submitAccessUnit() {
-    CHECK(!mPackets.empty());
+bool AMPEG4AudioAssembler::submitAccessUnit() {
+    MOZ_ASSERT(!mPackets.empty());
 
 #if VERBOSE
     LOG(VERBOSE) << "Access unit complete (" << mPackets.size() << " packets)";
 #endif
 
     size_t totalSize = 0;
     List<sp<ABuffer> >::iterator it = mPackets.begin();
     while (it != mPackets.end()) {
@@ -560,28 +602,31 @@ void AMPEG4AudioAssembler::submitAccessU
         memcpy((uint8_t *)accessUnit->data() + offset,
                unit->data(), unit->size());
 
         offset += unit->size();
         ++it;
     }
 
     accessUnit = removeLATMFraming(accessUnit);
-    CopyTimes(accessUnit, *mPackets.begin());
+    if (!accessUnit.get() || !CopyTimes(accessUnit, *mPackets.begin())) {
+        return false;
+    }
 
     if (mAccessUnitDamaged) {
         accessUnit->meta()->setInt32("damaged", true);
     }
 
     mPackets.clear();
     mAccessUnitDamaged = false;
 
     sp<AMessage> msg = mNotifyMsg->dup();
     msg->setObject("access-unit", accessUnit);
     msg->post();
+    return true;
 }
 
 void AMPEG4AudioAssembler::packetLost() {
     CHECK(mNextExpectedSeqNoValid);
     ++mNextExpectedSeqNo;
 
     mAccessUnitDamaged = true;
 }
--- a/netwerk/protocol/rtsp/rtsp/AMPEG4AudioAssembler.h
+++ b/netwerk/protocol/rtsp/rtsp/AMPEG4AudioAssembler.h
@@ -53,17 +53,17 @@ private:
 
     uint32_t mAccessUnitRTPTime;
     bool mNextExpectedSeqNoValid;
     uint32_t mNextExpectedSeqNo;
     bool mAccessUnitDamaged;
     List<sp<ABuffer> > mPackets;
 
     AssemblyStatus addPacket(const sp<ARTPSource> &source);
-    void submitAccessUnit();
+    bool submitAccessUnit();
 
     sp<ABuffer> removeLATMFraming(const sp<ABuffer> &buffer);
 
     DISALLOW_EVIL_CONSTRUCTORS(AMPEG4AudioAssembler);
 };
 
 }  // namespace android
 
--- a/netwerk/protocol/rtsp/rtsp/AMPEG4ElementaryAssembler.cpp
+++ b/netwerk/protocol/rtsp/rtsp/AMPEG4ElementaryAssembler.cpp
@@ -16,16 +16,18 @@
 
 #define LOG_TAG "AMPEG4ElementaryAssembler"
 #include "RtspPrlog.h"
 
 #include "AMPEG4ElementaryAssembler.h"
 
 #include "ARTPSource.h"
 
+#include "mozilla/Assertions.h"
+
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/Utils.h>
 
 #include <ctype.h>
@@ -211,40 +213,56 @@ ARTPAssembler::AssemblyStatus AMPEG4Elem
         mNextExpectedSeqNo = (uint32_t)buffer->int32Data();
     } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) {
         LOGV("Not the sequence number I expected");
 
         return WRONG_SEQUENCE_NUMBER;
     }
 
     uint32_t rtpTime;
-    CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+    if (!buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)) {
+        LOGW("Cannot find rtp-time. Malformed packet.");
+
+        return MALFORMED_PACKET;
+    }
 
     if (mPackets.size() > 0 && rtpTime != mAccessUnitRTPTime) {
-        submitAccessUnit();
+        if (!submitAccessUnit()) {
+            LOGW("Cannot find rtp-time. Malformed packet.");
+
+            return MALFORMED_PACKET;
+        }
     }
 
     // If constantDuration and CTSDelta are not present. We should assume the
     // stream has fixed duration and calculate the mConstantDuration.
     if (!mConstantDuration && !mCTSDeltaLength && mPreviousAUCount
         && rtpTime > mAccessUnitRTPTime) {
         mConstantDuration = (rtpTime - mAccessUnitRTPTime) / mPreviousAUCount;
     }
 
     mAccessUnitRTPTime = rtpTime;
 
     if (!mIsGeneric) {
         mPackets.push_back(buffer);
     } else {
         // hexdump(buffer->data(), buffer->size());
 
-        CHECK_GE(buffer->size(), 2u);
+        if (buffer->size() < 2u) {
+            LOGW("Payload format error. Malformed packet.");
+
+            return MALFORMED_PACKET;
+        }
         unsigned AU_headers_length = U16_AT(buffer->data());  // in bits
 
-        CHECK_GE(buffer->size(), 2 + (AU_headers_length + 7) / 8);
+        if (buffer->size() < 2 + (AU_headers_length + 7) / 8) {
+            LOGW("Payload format error. Malformed packet.");
+
+            return MALFORMED_PACKET;
+        }
 
         List<AUHeader> headers;
 
         ABitReader bits(buffer->data() + 2, buffer->size() - 2);
         unsigned numBitsLeft = AU_headers_length;
 
         unsigned AU_serial = 0;
         for (;;) {
@@ -325,42 +343,50 @@ ARTPAssembler::AssemblyStatus AMPEG4Elem
         }
 
         mPreviousAUCount = 0;
         for (List<AUHeader>::iterator it = headers.begin();
              it != headers.end(); ++it) {
             mPreviousAUCount++;
             const AUHeader &header = *it;
             const AUHeader &first = *headers.begin();
-            CHECK_LE(offset + header.mSize, buffer->size());
+            if (offset + header.mSize > buffer->size()) {
+                LOGW("Payload format error. Malformed packet.");
+
+                return MALFORMED_PACKET;
+            }
 
             sp<ABuffer> accessUnit = new ABuffer(header.mSize);
             memcpy(accessUnit->data(), buffer->data() + offset, header.mSize);
 
             offset += header.mSize;
 
             int rtpTime = mAccessUnitRTPTime +
                           mConstantDuration * (header.mSerial - first.mSerial);
             accessUnit->meta()->setInt32("rtp-time", rtpTime);
             accessUnit->setInt32Data(buffer->int32Data());
 
             mPackets.push_back(accessUnit);
         }
 
-        CHECK_EQ(offset, buffer->size());
+        if (offset != buffer->size()) {
+            LOGW("Payload format error. Malformed packet.");
+
+            return MALFORMED_PACKET;
+        }
     }
 
     queue->erase(queue->begin());
     ++mNextExpectedSeqNo;
 
     return OK;
 }
 
-void AMPEG4ElementaryAssembler::submitAccessUnit() {
-    CHECK(!mPackets.empty());
+bool AMPEG4ElementaryAssembler::submitAccessUnit() {
+    MOZ_ASSERT(mPackets.empty());
 
     LOGV("Access unit complete (%d nal units)", mPackets.size());
 
     if (mIsGeneric) {
         /*
          * Bug 877116.
          * In order to remedy a latency problem caused by hardware decoder for
          * mpeg4-generic audios, we artificially divide AUs into more smaller
@@ -369,17 +395,19 @@ void AMPEG4ElementaryAssembler::submitAc
          * TODO: However, we are not sure this solution is appropriate to video
          * or not. Need more investigation on this. Refer to RFC 3640.
          */
         for (List<sp<ABuffer> >::iterator it = mPackets.begin();
              it != mPackets.end(); ++it) {
             sp<ABuffer> accessUnit = new ABuffer((*it)->size());
             sp<ABuffer> nal = *it;
             memcpy(accessUnit->data(), nal->data(), nal->size());
-            CopyTimes(accessUnit, nal);
+            if (!CopyTimes(accessUnit, nal)) {
+                return false;
+            }
 
             if (mAccessUnitDamaged) {
                 accessUnit->meta()->setInt32("damaged", true);
             }
 
             sp<AMessage> msg = mNotifyMsg->dup();
             msg->setObject("access-unit", accessUnit);
             msg->post();
@@ -399,29 +427,32 @@ void AMPEG4ElementaryAssembler::submitAc
         sp<ABuffer> accessUnit = new ABuffer(totalSize);
         size_t offset = 0;
         for (List<sp<ABuffer> >::iterator it = mPackets.begin();
              it != mPackets.end(); ++it) {
             sp<ABuffer> nal = *it;
             memcpy(accessUnit->data() + offset, nal->data(), nal->size());
             offset += nal->size();
         }
-        CopyTimes(accessUnit, *mPackets.begin());
+        if (!CopyTimes(accessUnit, *mPackets.begin())) {
+            return false;
+        }
 
         if (mAccessUnitDamaged) {
             accessUnit->meta()->setInt32("damaged", true);
         }
 
         sp<AMessage> msg = mNotifyMsg->dup();
         msg->setObject("access-unit", accessUnit);
         msg->post();
     }
 
     mPackets.clear();
     mAccessUnitDamaged = false;
+    return true;
 }
 
 ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::assembleMore(
         const sp<ARTPSource> &source) {
     AssemblyStatus status = addPacket(source);
     if (status == MALFORMED_PACKET) {
         mAccessUnitDamaged = true;
     }
--- a/netwerk/protocol/rtsp/rtsp/AMPEG4ElementaryAssembler.h
+++ b/netwerk/protocol/rtsp/rtsp/AMPEG4ElementaryAssembler.h
@@ -62,16 +62,16 @@ private:
 
     uint32_t mAccessUnitRTPTime;
     bool mNextExpectedSeqNoValid;
     uint32_t mNextExpectedSeqNo;
     bool mAccessUnitDamaged;
     List<sp<ABuffer> > mPackets;
 
     AssemblyStatus addPacket(const sp<ARTPSource> &source);
-    void submitAccessUnit();
+    bool submitAccessUnit();
 
     DISALLOW_EVIL_CONSTRUCTORS(AMPEG4ElementaryAssembler);
 };
 
 }  // namespace android
 
 #endif  // A_MPEG4_ELEM_ASSEMBLER_H_
--- a/netwerk/protocol/rtsp/rtsp/APacketSource.cpp
+++ b/netwerk/protocol/rtsp/rtsp/APacketSource.cpp
@@ -109,18 +109,21 @@ static sp<ABuffer> MakeAVCCodecSpecificD
     *height = 0;
 
     AString val;
     if (!GetAttribute(params, "profile-level-id", &val)) {
         return NULL;
     }
 
     sp<ABuffer> profileLevelID = decodeHex(val);
-    CHECK(profileLevelID != NULL);
-    CHECK_EQ(profileLevelID->size(), 3u);
+    if (!profileLevelID.get() || profileLevelID->size() != 3u) {
+        LOGW("Format error in profile-level-id");
+
+        return NULL;
+    }
 
     Vector<sp<ABuffer> > paramSets;
 
     size_t numSeqParameterSets = 0;
     size_t totalSeqParameterSetSize = 0;
     size_t numPicParameterSets = 0;
     size_t totalPicParameterSetSize = 0;
 
@@ -130,46 +133,56 @@ static sp<ABuffer> MakeAVCCodecSpecificD
 
     size_t start = 0;
     for (;;) {
         ssize_t commaPos = val.find(",", start);
         size_t end = (commaPos < 0) ? val.size() : commaPos;
 
         AString nalString(val, start, end - start);
         sp<ABuffer> nal = decodeBase64(nalString);
-        CHECK(nal != NULL);
-        CHECK_GT(nal->size(), 0u);
-        CHECK_LE(nal->size(), 65535u);
+        if (!nal.get() || nal->size() <= 0u || nal->size() > 65535u) {
+            return NULL;
+        }
 
         uint8_t nalType = nal->data()[0] & 0x1f;
         if (numSeqParameterSets == 0) {
-            CHECK_EQ((unsigned)nalType, 7u);
+            if ((unsigned)nalType !=  7u) {
+                return NULL;
+            }
         } else if (numPicParameterSets > 0) {
-            CHECK_EQ((unsigned)nalType, 8u);
+            if ((unsigned)nalType != 8u) {
+                return NULL;
+            }
         }
         if (nalType == 7) {
             ++numSeqParameterSets;
             totalSeqParameterSetSize += nal->size();
         } else  {
-            CHECK_EQ((unsigned)nalType, 8u);
+            if ((unsigned)nalType != 8u) {
+                return NULL;
+            }
             ++numPicParameterSets;
             totalPicParameterSetSize += nal->size();
         }
 
         paramSets.push(nal);
 
         if (commaPos < 0) {
             break;
         }
 
         start = commaPos + 1;
     }
 
-    CHECK_LT(numSeqParameterSets, 32u);
-    CHECK_LE(numPicParameterSets, 255u);
+    if (numSeqParameterSets >= 32u) {
+        return NULL;
+    }
+    if (numPicParameterSets > 255u) {
+        return NULL;
+    }
 
     size_t csdSize =
         1 + 3 + 1 + 1
         + 2 * numSeqParameterSets + totalSeqParameterSetSize
         + 1 + 2 * numPicParameterSets + totalPicParameterSetSize;
 
     sp<ABuffer> csd = new ABuffer(csdSize);
     uint8_t *out = csd->data();
@@ -263,29 +276,39 @@ sp<ABuffer> MakeAACCodecSpecificData(con
 // From mpeg4-generic configuration data.
 sp<ABuffer> MakeAACCodecSpecificData2(const char *params) {
     AString val;
     unsigned long objectType;
     if (GetAttribute(params, "objectType", &val)) {
         const char *s = val.c_str();
         char *end;
         objectType = strtoul(s, &end, 10);
-        CHECK(end > s && *end == '\0');
+        if (end <= s || *end != '\0') {
+            return NULL;
+        }
     } else {
         objectType = 0x40;  // Audio ISO/IEC 14496-3
     }
 
-    CHECK(GetAttribute(params, "config", &val));
+    if (!GetAttribute(params, "config", &val)) {
+        LOGW("Cannot find attribute config");
+
+        return NULL;
+    }
 
     sp<ABuffer> config = decodeHex(val);
-    CHECK(config != NULL);
+    if (!config.get()) {
+        return NULL;
+    }
 
     // Make sure size fits into a single byte and doesn't have to
     // be encoded.
-    CHECK_LT(20 + config->size(), 128u);
+    if (20 + config->size() >= 128u) {
+        return NULL;
+    }
 
     static const uint8_t kStaticESDS[] = {
         0x03, 22,
         0x00, 0x00,     // ES_ID
         0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
 
         0x04, 17,
         0x40,                       // Audio ISO/IEC 14496-3
@@ -363,20 +386,26 @@ static bool ExtractDimensionsMPEG4Config
 }
 
 static sp<ABuffer> MakeMPEG4VideoCodecSpecificData(
         const char *params, int32_t *width, int32_t *height) {
     *width = 0;
     *height = 0;
 
     AString val;
-    CHECK(GetAttribute(params, "config", &val));
+    if (!GetAttribute(params, "config", &val)) {
+        LOGW("Cannot find attribute config");
+
+        return NULL;
+    }
 
     sp<ABuffer> config = decodeHex(val);
-    CHECK(config != NULL);
+    if (!config.get()) {
+        return NULL;
+    }
 
     if (!ExtractDimensionsMPEG4Config(config, width, height)) {
         return NULL;
     }
 
     LOGI("VOL dimensions = %dx%d", *width, *height);
 
     size_t len1 = config->size() + GetSizeWidth(config->size()) + 1;
@@ -472,18 +501,21 @@ APacketSource::APacketSource(
         }
 
         mFormat->setInt32(kKeyWidth, width);
         mFormat->setInt32(kKeyHeight, height);
     } else if (!strncmp(desc.c_str(), "MP4A-LATM/", 10)) {
         mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
 
         int32_t sampleRate, numChannels;
-        ASessionDescription::ParseFormatDesc(
-                desc.c_str(), &sampleRate, &numChannels);
+        if (!ASessionDescription::ParseFormatDesc(
+                desc.c_str(), &sampleRate, &numChannels)) {
+            mInitCheck = ERROR_UNSUPPORTED;
+            return;
+        }
 
         mFormat->setInt32(kKeySampleRate, sampleRate);
         mFormat->setInt32(kKeyChannelCount, numChannels);
 
         sp<ABuffer> codecSpecificData =
             MakeAACCodecSpecificData(params.c_str());
         if (!codecSpecificData.get()) {
             mInitCheck = ERROR_UNSUPPORTED;
@@ -492,31 +524,37 @@ APacketSource::APacketSource(
 
         mFormat->setData(
                 kKeyESDS, 0,
                 codecSpecificData->data(), codecSpecificData->size());
     } else if (!strncmp(desc.c_str(), "AMR/", 4)) {
         mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
 
         int32_t sampleRate, numChannels;
-        ASessionDescription::ParseFormatDesc(
-                desc.c_str(), &sampleRate, &numChannels);
+        if (!ASessionDescription::ParseFormatDesc(
+                desc.c_str(), &sampleRate, &numChannels)) {
+            mInitCheck = ERROR_UNSUPPORTED;
+            return;
+        }
 
         mFormat->setInt32(kKeySampleRate, sampleRate);
         mFormat->setInt32(kKeyChannelCount, numChannels);
 
         if (sampleRate != 8000 || numChannels != 1) {
             mInitCheck = ERROR_UNSUPPORTED;
         }
     } else if (!strncmp(desc.c_str(), "AMR-WB/", 7)) {
         mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
 
         int32_t sampleRate, numChannels;
-        ASessionDescription::ParseFormatDesc(
-                desc.c_str(), &sampleRate, &numChannels);
+        if (!ASessionDescription::ParseFormatDesc(
+                desc.c_str(), &sampleRate, &numChannels)) {
+            mInitCheck = ERROR_UNSUPPORTED;
+            return;
+        }
 
         mFormat->setInt32(kKeySampleRate, sampleRate);
         mFormat->setInt32(kKeyChannelCount, numChannels);
 
         if (sampleRate != 16000 || numChannels != 1) {
             mInitCheck = ERROR_UNSUPPORTED;
         }
     } else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)) {
@@ -556,30 +594,38 @@ APacketSource::APacketSource(
                     && strcasecmp(val.c_str(), "AAC-hbr"))) {
             mInitCheck = ERROR_UNSUPPORTED;
             return;
         }
 
         mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
 
         int32_t sampleRate, numChannels;
-        ASessionDescription::ParseFormatDesc(
-                desc.c_str(), &sampleRate, &numChannels);
+        if (!ASessionDescription::ParseFormatDesc(
+                desc.c_str(), &sampleRate, &numChannels)) {
+            mInitCheck = ERROR_UNSUPPORTED;
+            return;
+        }
 
         mFormat->setInt32(kKeySampleRate, sampleRate);
         mFormat->setInt32(kKeyChannelCount, numChannels);
 
         sp<ABuffer> codecSpecificData =
             MakeAACCodecSpecificData2(params.c_str());
-
+        if (!codecSpecificData.get()) {
+            mInitCheck = ERROR_UNSUPPORTED;
+            return;
+        }
         mFormat->setData(
                 kKeyESDS, 0,
                 codecSpecificData->data(), codecSpecificData->size());
     } else if (ARawAudioAssembler::Supports(desc.c_str())) {
-        ARawAudioAssembler::MakeFormat(desc.c_str(), mFormat);
+        if (!ARawAudioAssembler::MakeFormat(desc.c_str(), mFormat)) {
+            mInitCheck = ERROR_UNSUPPORTED;
+        }
     } else {
         mInitCheck = ERROR_UNSUPPORTED;
     }
 }
 
 APacketSource::~APacketSource() {
 }
 
--- a/netwerk/protocol/rtsp/rtsp/ARTPAssembler.cpp
+++ b/netwerk/protocol/rtsp/rtsp/ARTPAssembler.cpp
@@ -11,16 +11,18 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 #include "ARTPAssembler.h"
 
+#include "RtspPrlog.h"
+
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 
 #include <stdint.h>
 
 namespace android {
 
@@ -59,19 +61,24 @@ void ARTPAssembler::onPacketReceived(con
             if (status == NOT_ENOUGH_DATA) {
                 break;
             }
         }
     }
 }
 
 // static
-void ARTPAssembler::CopyTimes(const sp<ABuffer> &to, const sp<ABuffer> &from) {
+bool ARTPAssembler::CopyTimes(const sp<ABuffer> &to, const sp<ABuffer> &from) {
     uint32_t rtpTime;
-    CHECK(from->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+    if (!from->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)) {
+        LOGW("CopyTimes: Cannot find rtp-time");
+
+        return false;
+    }
 
     to->meta()->setInt32("rtp-time", rtpTime);
 
     // Copy the seq number.
     to->setInt32Data(from->int32Data());
+    return true;
 }
 
 }  // namespace android
--- a/netwerk/protocol/rtsp/rtsp/ARTPAssembler.h
+++ b/netwerk/protocol/rtsp/rtsp/ARTPAssembler.h
@@ -39,17 +39,17 @@ struct ARTPAssembler : public RefBase {
 
     void onPacketReceived(const sp<ARTPSource> &source);
     virtual void onByeReceived() = 0;
 
 protected:
     virtual AssemblyStatus assembleMore(const sp<ARTPSource> &source) = 0;
     virtual void packetLost() = 0;
 
-    static void CopyTimes(const sp<ABuffer> &to, const sp<ABuffer> &from);
+    static bool CopyTimes(const sp<ABuffer> &to, const sp<ABuffer> &from);
 
 private:
     int64_t mFirstFailureTimeUs;
 
     DISALLOW_EVIL_CONSTRUCTORS(ARTPAssembler);
 };
 
 }  // namespace android
--- a/netwerk/protocol/rtsp/rtsp/ARTPSession.cpp
+++ b/netwerk/protocol/rtsp/rtsp/ARTPSession.cpp
@@ -39,17 +39,20 @@ using namespace mozilla::net;
 
 namespace android {
 
 ARTPSession::ARTPSession()
     : mInitCheck(NO_INIT) {
 }
 
 status_t ARTPSession::setup(const sp<ASessionDescription> &desc) {
-    CHECK_EQ(mInitCheck, (status_t)NO_INIT);
+    if (mInitCheck != (status_t)NO_INIT) {
+        LOGE("Unexpected mInitCheck");
+        return NO_INIT;
+    }
 
     mDesc = desc;
 
     mRTPConn = new ARTPConnection(ARTPConnection::kRegularlyRequestFIR);
 
     looper()->registerHandler(mRTPConn);
 
     for (size_t i = 1; i < mDesc->countTracks(); ++i) {
@@ -152,22 +155,31 @@ void ARTPSession::onMessageReceived(cons
             if (msg->findInt32("eos", &eos) && eos) {
                 TrackInfo *info = &mTracks.editItemAt(trackIndex);
                 info->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
                 break;
             }
 
             sp<RefBase> obj;
             CHECK(msg->findObject("access-unit", &obj));
+            if (!msg->findObject("access-unit", &obj)) {
+                LOGW("Cannot find access-unit");
+
+                break;
+            }
 
             sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get());
 
             uint64_t ntpTime;
-            CHECK(accessUnit->meta()->findInt64(
-                        "ntp-time", (int64_t *)&ntpTime));
+            if (!accessUnit->meta()->findInt64(
+                        "ntp-time", (int64_t *)&ntpTime)) {
+                LOGW("Cannot find ntp-time");
+
+                break;
+            }
 
 #if 0
 #if 0
             printf("access unit complete size=%d\tntp-time=0x%016llx\n",
                    accessUnit->size(), ntpTime);
 #else
             LOGI("access unit complete, size=%d, ntp-time=%llu",
                  accessUnit->size(), ntpTime);
--- a/netwerk/protocol/rtsp/rtsp/ARTPWriter.cpp
+++ b/netwerk/protocol/rtsp/rtsp/ARTPWriter.cpp
@@ -135,17 +135,19 @@ status_t ARTPWriter::start(MetaData *par
     mRTPTimeBase = rand();
     mNumRTPSent = 0;
     mNumRTPOctetsSent = 0;
     mLastRTPTime = 0;
     mLastNTPTime = 0;
     mNumSRsSent = 0;
 
     const char *mime;
-    CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime));
+    if (!mSource->getFormat()->findCString(kKeyMIMEType, &mime)) {
+        return ERROR_UNSUPPORTED;
+    }
 
     mMode = INVALID;
     if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
         mMode = H264;
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_H263)) {
         mMode = H263;
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) {
         mMode = AMR_NB;
--- a/netwerk/protocol/rtsp/rtsp/ARTSPConnection.cpp
+++ b/netwerk/protocol/rtsp/rtsp/ARTSPConnection.cpp
@@ -743,18 +743,19 @@ bool ARTSPConnection::receiveRTSPRespons
             return false;
         }
     }
 
     if (response->mStatusCode == 401) {
         if (mAuthType == NONE && mUser.size() > 0
                 && parseAuthMethod(response)) {
             ssize_t i;
-            CHECK_EQ((status_t)OK, findPendingRequest(response, &i));
-            CHECK_GE(i, 0);
+            if ((status_t)OK != findPendingRequest(response, &i) || i < 0) {
+                return false;
+            }
 
             sp<AMessage> reply = mPendingRequests.valueAt(i);
             mPendingRequests.removeItemsAt(i);
 
             AString request;
             CHECK(reply->findString("original-request", &request));
 
             sp<AMessage> msg = new AMessage(kWhatSendRequest, id());
@@ -774,17 +775,19 @@ bool ARTSPConnection::receiveRTSPRespons
 }
 
 bool ARTSPConnection::handleServerRequest(const sp<ARTSPResponse> &request) {
     // Implementation of server->client requests is optional for all methods
     // but we do need to respond, even if it's just to say that we don't
     // support the method.
 
     ssize_t space1 = request->mStatusLine.find(" ");
-    CHECK_GE(space1, 0);
+    if (space1 < 0) {
+        return false;
+    }
 
     AString response;
     response.append("RTSP/1.0 501 Not Implemented\r\n");
 
     ssize_t i = request->mHeaders.indexOfKey("cseq");
 
     if (i >= 0) {
         AString value = request->mHeaders.valueAt(i);
@@ -904,25 +907,29 @@ bool ARTSPConnection::parseAuthMethod(co
         return false;
     }
 
     AString value = response->mHeaders.valueAt(i);
 
     if (!strncmp(value.c_str(), "Basic", 5)) {
         mAuthType = BASIC;
     } else {
-
-        CHECK(!strncmp(value.c_str(), "Digest", 6));
+        if (strncmp(value.c_str(), "Digest", 6)) {
+            return false;
+        }
         mAuthType = DIGEST;
 
         i = value.find("nonce=");
-        CHECK_GE(i, 0);
-        CHECK_EQ(value.c_str()[i + 6], '\"');
+        if (i < 0 || value.c_str()[i + 6] != '\"') {
+            return false;
+        }
         ssize_t j = value.find("\"", i + 7);
-        CHECK_GE(j, 0);
+        if (j < 0) {
+            return false;
+        }
 
         mNonce.setTo(value, i + 7, j - i - 7);
     }
 
     return true;
 }
 
 static void H(const AString &s, AString *out) {
@@ -978,36 +985,44 @@ static void H(const AString &s, AString 
             nibble += '0';
         } else {
             nibble += 'a' - 10;
         }
         out->append(&nibble, 1);
     }
 }
 
-static void GetMethodAndURL(
+static bool GetMethodAndURL(
         const AString &request, AString *method, AString *url) {
     ssize_t space1 = request.find(" ");
-    CHECK_GE(space1, 0);
+    if (space1 < 0) {
+        return false;
+    }
 
     ssize_t space2 = request.find(" ", space1 + 1);
-    CHECK_GE(space2, 0);
+    if (space2 < 0) {
+        return false;
+    }
 
     method->setTo(request, 0, space1);
     url->setTo(request, space1 + 1, space2 - space1);
+    return true;
 }
 
 void ARTSPConnection::addAuthentication(AString *request) {
     if (mAuthType == NONE) {
         return;
     }
 
     // Find the boundary between headers and the body.
     ssize_t i = request->find("\r\n\r\n");
-    CHECK_GE(i, 0);
+    if (i < 0) {
+        LOGE("Failed to find the boundary between headers and the body");
+        return;
+    }
 
     if (mAuthType == BASIC) {
         AString tmp;
         tmp.append(mUser);
         tmp.append(":");
         tmp.append(mPass);
 
         AString out;
@@ -1021,17 +1036,20 @@ void ARTSPConnection::addAuthentication(
         request->insert(fragment, i + 2);
 
         return;
     }
 
     CHECK_EQ((int)mAuthType, (int)DIGEST);
 
     AString method, url;
-    GetMethodAndURL(*request, &method, &url);
+    if (!GetMethodAndURL(*request, &method, &url)) {
+        LOGE("Fail to get method and url");
+        return;
+    }
 
     AString A1;
     A1.append(mUser);
     A1.append(":");
     A1.append("Streaming Server");
     A1.append(":");
     A1.append(mPass);
 
@@ -1071,17 +1089,19 @@ void ARTSPConnection::addAuthentication(
     fragment.append("\r\n");
 
     request->insert(fragment, i + 2);
 }
 
 void ARTSPConnection::addUserAgent(AString *request) const {
     // Find the boundary between headers and the body.
     ssize_t i = request->find("\r\n\r\n");
-    CHECK_GE(i, 0);
+    if (i < 0) {
+        LOGE("Failed to find the boundary between headers and the body");
+    }
 
     request->insert(mUserAgent, i + 2);
 }
 
 void ARTSPConnection::closeSocket() {
     PR_Close(mSocket);
     mSocket = nullptr;
 }
--- a/netwerk/protocol/rtsp/rtsp/ARawAudioAssembler.cpp
+++ b/netwerk/protocol/rtsp/rtsp/ARawAudioAssembler.cpp
@@ -82,17 +82,17 @@ ARTPAssembler::AssemblyStatus ARawAudioA
     }
 
     // hexdump(buffer->data(), buffer->size());
 
     if (buffer->size() < 1) {
         queue->erase(queue->begin());
         ++mNextExpectedSeqNo;
 
-        LOGV("raw audio packet too short.");
+        LOGW("raw audio packet too short.");
 
         return MALFORMED_PACKET;
     }
 
     sp<AMessage> msg = mNotifyMsg->dup();
     msg->setObject("access-unit", buffer);
     msg->post();
 
@@ -115,28 +115,31 @@ void ARawAudioAssembler::onByeReceived()
 
 // static
 bool ARawAudioAssembler::Supports(const char *desc) {
     return !strncmp(desc, "PCMU/", 5)
         || !strncmp(desc, "PCMA/", 5);
 }
 
 // static
-void ARawAudioAssembler::MakeFormat(
+bool ARawAudioAssembler::MakeFormat(
         const char *desc, const sp<MetaData> &format) {
     if (!strncmp(desc, "PCMU/", 5)) {
         format->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_MLAW);
     } else if (!strncmp(desc, "PCMA/", 5)) {
         format->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_ALAW);
     } else {
-        TRESPASS();
+        return false;
     }
 
     int32_t sampleRate, numChannels;
-    ASessionDescription::ParseFormatDesc(
-            desc, &sampleRate, &numChannels);
+    if (!ASessionDescription::ParseFormatDesc(
+                desc, &sampleRate, &numChannels)) {
+        return false;
+    }
 
     format->setInt32(kKeySampleRate, sampleRate);
     format->setInt32(kKeyChannelCount, numChannels);
+    return true;
 }
 
 }  // namespace android
 
--- a/netwerk/protocol/rtsp/rtsp/ARawAudioAssembler.h
+++ b/netwerk/protocol/rtsp/rtsp/ARawAudioAssembler.h
@@ -29,17 +29,17 @@ struct MOZ_EXPORT MetaData;
 
 struct ARawAudioAssembler : public ARTPAssembler {
     ARawAudioAssembler(
             const sp<AMessage> &notify,
             const char *desc, const AString &params);
 
     static bool Supports(const char *desc);
 
-    static void MakeFormat(
+    static bool MakeFormat(
             const char *desc, const sp<MetaData> &format);
 
 protected:
     virtual ~ARawAudioAssembler();
 
     virtual AssemblyStatus assembleMore(const sp<ARTPSource> &source);
     virtual void onByeReceived();
     virtual void packetLost();
--- a/netwerk/protocol/rtsp/rtsp/ASessionDescription.cpp
+++ b/netwerk/protocol/rtsp/rtsp/ASessionDescription.cpp
@@ -196,22 +196,25 @@ bool ASessionDescription::findAttribute(
 
 bool ASessionDescription::getFormatType(
         size_t index, unsigned long *PT,
         AString *desc, AString *params) const {
     AString format;
     getFormat(index, &format);
 
     const char *lastSpacePos = strrchr(format.c_str(), ' ');
-    CHECK(lastSpacePos != NULL);
+    if (!lastSpacePos) {
+        return false;
+    }
 
     char *end;
     unsigned long x = strtoul(lastSpacePos + 1, &end, 10);
-    CHECK_GT(end, lastSpacePos + 1);
-    CHECK_EQ(*end, '\0');
+    if (end <= lastSpacePos + 1 || *end != '\0') {
+        return false;
+    }
 
     *PT = x;
 
     char key[20];
     sprintf(key, "a=rtpmap:%lu", x);
 
     if (!findAttribute(index, key, desc)) {
         // We only support dynamic payload type assignment for now.
@@ -239,31 +242,35 @@ bool ASessionDescription::getDimensions(
     AString value;
     if (!findAttribute(index, key, &value)) {
         return false;
     }
 
     const char *s = value.c_str();
     char *end;
     *width = strtoul(s, &end, 10);
-    CHECK_GT(end, s);
-    CHECK_EQ(*end, '-');
+    if (end <= s || *end != '-') {
+        return false;
+    }
 
     s = end + 1;
     *height = strtoul(s, &end, 10);
-    CHECK_GT(end, s);
-    CHECK_EQ(*end, '\0');
+    if (end <= s || *end != '\0') {
+        return false;
+    }
 
     return true;
 }
 
 bool ASessionDescription::getDurationUs(int64_t *durationUs) const {
     *durationUs = 0;
 
-    CHECK(mIsValid);
+    if (!mIsValid) {
+        return false;
+    }
 
     AString value;
     if (!findAttribute(0, "a=range", &value)) {
         return false;
     }
 
     if (strncmp(value.c_str(), "npt=", 4)) {
         return false;
@@ -275,38 +282,46 @@ bool ASessionDescription::getDurationUs(
     }
 
     *durationUs = (int64_t)((to - from) * 1E6);
 
     return true;
 }
 
 // static
-void ASessionDescription::ParseFormatDesc(
+bool ASessionDescription::ParseFormatDesc(
         const char *desc, int32_t *timescale, int32_t *numChannels) {
     const char *slash1 = strchr(desc, '/');
-    CHECK(slash1 != NULL);
+    if (!slash1) {
+        return false;
+    }
 
     const char *s = slash1 + 1;
     char *end;
     unsigned long x = strtoul(s, &end, 10);
-    CHECK_GT(end, s);
-    CHECK(*end == '\0' || *end == '/');
+    if (end <= s) {
+        return false;
+    }
+    if (*end != '\0' && *end != '/') {
+        return false;
+    }
 
     *timescale = x;
     *numChannels = 1;
 
     if (*end == '/') {
         s = end + 1;
         unsigned long x = strtoul(s, &end, 10);
-        CHECK_GT(end, s);
-        CHECK_EQ(*end, '\0');
+        if (end <= s || *end != '\0') {
+            return false;
+        }
 
         *numChannels = x;
     }
+    return true;
 }
 
 // static
 bool ASessionDescription::parseNTPRange(
         const char *s, float *npt1, float *npt2) {
     if (s[0] == '-') {
         return false;  // no start time available.
     }
--- a/netwerk/protocol/rtsp/rtsp/ASessionDescription.h
+++ b/netwerk/protocol/rtsp/rtsp/ASessionDescription.h
@@ -46,17 +46,17 @@ struct ASessionDescription : public RefB
             AString *desc, AString *params) const;
 
     bool getDimensions(
             size_t index, unsigned long PT,
             int32_t *width, int32_t *height) const;
 
     bool getDurationUs(int64_t *durationUs) const;
 
-    static void ParseFormatDesc(
+    static bool ParseFormatDesc(
             const char *desc, int32_t *timescale, int32_t *numChannels);
 
     bool findAttribute(size_t index, const char *key, AString *value) const;
 
     // parses strings of the form
     //   npt      := npt-time "-" npt-time? | "-" npt-time
     //   npt-time := "now" | [0-9]+("." [0-9]*)?
     //
--- a/netwerk/protocol/rtsp/rtsp/RTSPConnectionHandler.h
+++ b/netwerk/protocol/rtsp/rtsp/RTSPConnectionHandler.h
@@ -17,16 +17,18 @@
 #ifndef RTSP_CONNECTION_HANDLER_H_
 #define RTSP_CONNECTION_HANDLER_H_
 
 #include "APacketSource.h"
 #include "ARTPConnection.h"
 #include "ARTSPConnection.h"
 #include "ASessionDescription.h"
 
+#include "RtspPrlog.h"
+
 #include <ctype.h>
 #include <cutils/properties.h>
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/MediaErrors.h>
@@ -556,20 +558,23 @@ struct RtspConnectionHandler : public AH
                                 // it with the absolute session URL to get
                                 // something usable...
 
                                 LOGW("Server specified a non-absolute base URL"
                                      ", combining it with the session URL to "
                                      "get something usable...");
 
                                 AString tmp;
-                                CHECK(MakeURL(
+                                if (!MakeURL(
                                             mSessionURL.c_str(),
                                             mBaseURL.c_str(),
-                                            &tmp));
+                                            &tmp)) {
+                                    LOGE("Fail to make url");
+                                    result = ERROR_UNSUPPORTED;
+                                }
 
                                 mBaseURL = tmp;
                             }
 
                             int64_t duration = 0;
                             if (mSessionDesc->getDurationUs(&duration) > 0) {
                                 // This is not a live stream and therefore seekable.
                                 LOGI("This is not a live stream");
@@ -771,19 +776,19 @@ struct RtspConnectionHandler : public AH
 
                 if (result == OK) {
                     sp<RefBase> obj;
                     CHECK(msg->findObject("response", &obj));
                     sp<ARTSPResponse> response =
                         static_cast<ARTSPResponse *>(obj.get());
                     if (response->mStatusCode != 200) {
                         result = UNKNOWN_ERROR;
+                    } else if (!parsePlayResponse(response)) {
+                        result = UNKNOWN_ERROR;
                     } else {
-                        parsePlayResponse(response);
-
                         sp<AMessage> timeout = new AMessage(kWhatTimeout, id());
                         timeout->post(kPlayTimeoutUs);
                         mPausePending = false;
                         mNumPlayTimeoutsPending++;
                     }
                 }
 
                 if (result != OK) {
@@ -1140,21 +1145,24 @@ struct RtspConnectionHandler : public AH
                 if (result == OK) {
                     sp<RefBase> obj;
                     CHECK(msg->findObject("response", &obj));
                     sp<ARTSPResponse> response =
                         static_cast<ARTSPResponse *>(obj.get());
 
                     if (response->mStatusCode != 200) {
                         result = UNKNOWN_ERROR;
+                    } else if (!parsePlayResponse(response)) {
+                        result = UNKNOWN_ERROR;
                     } else {
-                        parsePlayResponse(response);
-
                         ssize_t i = response->mHeaders.indexOfKey("rtp-info");
-                        CHECK_GE(i, 0);
+                        if (i < 0) {
+                            LOGE("No RTP info in response");
+                            (new AMessage(kWhatAbort, id()))->post();
+                        }
 
                         LOGV("rtp-info: %s", response->mHeaders.valueAt(i).c_str());
 
                         LOGI("seek completed.");
                     }
                 }
 
                 if (result != OK) {
@@ -1173,17 +1181,20 @@ struct RtspConnectionHandler : public AH
 
             case kWhatBinary:
             {
                 sp<RefBase> obj;
                 CHECK(msg->findObject("buffer", &obj));
                 sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get());
 
                 int32_t index;
-                CHECK(buffer->meta()->findInt32("index", &index));
+                if (!buffer->meta()->findInt32("index", &index)) {
+                    LOGW("Cannot find index");
+                    break;
+                }
 
                 mRTPConn->injectPacket(index, buffer);
                 break;
             }
 
             case kWhatTimeout:
             {
                 CHECK(mNumPlayTimeoutsPending >= 1);
@@ -1261,77 +1272,95 @@ struct RtspConnectionHandler : public AH
                 break;
             }
 
             items->push_back(AString(s, start, offset - start));
             start = offset + strlen(separator);
         }
     }
 
-    void parsePlayResponse(const sp<ARTSPResponse> &response) {
+    bool parsePlayResponse(const sp<ARTSPResponse> &response) {
         mSeekable = false;
 
         for (size_t i = 0; i < mTracks.size(); ++i) {
           TrackInfo *info = &mTracks.editItemAt(i);
           info->mIsPlayAcked = true;
         }
 
         ssize_t i = response->mHeaders.indexOfKey("range");
         if (i < 0) {
             // Server doesn't even tell use what range it is going to
             // play, therefore we won't support seeking.
-            return;
+            return false;
         }
 
         AString range = response->mHeaders.valueAt(i);
         LOGV("Range: %s", range.c_str());
 
         AString val;
-        CHECK(GetAttribute(range.c_str(), "npt", &val));
+        if (!GetAttribute(range.c_str(), "npt", &val)) {
+            LOGE("No npt attribute in range");
+            return false;
+        }
 
         float npt1, npt2;
         if (!ASessionDescription::parseNTPRange(val.c_str(), &npt1, &npt2)) {
             // This is a live stream and therefore not seekable.
 
             LOGI("This is a live stream");
-            return;
+            return false;
         }
 
         i = response->mHeaders.indexOfKey("rtp-info");
-        CHECK_GE(i, 0);
+        if (i < 0) {
+            LOGE("No RTP info");
+            return false;
+        }
 
         AString rtpInfo = response->mHeaders.valueAt(i);
         List<AString> streamInfos;
         SplitString(rtpInfo, ",", &streamInfos);
 
         int n = 1;
         for (List<AString>::iterator it = streamInfos.begin();
              it != streamInfos.end(); ++it) {
             (*it).trim();
             LOGV("streamInfo[%d] = %s", n, (*it).c_str());
 
-            CHECK(GetAttribute((*it).c_str(), "url", &val));
+            if (!GetAttribute((*it).c_str(), "url", &val)) {
+                LOGE("No url attribute");
+                return false;
+            }
 
             size_t trackIndex = 0;
             while (trackIndex < mTracks.size()
                     && !(val == mTracks.editItemAt(trackIndex).mURL)) {
                 ++trackIndex;
             }
-            CHECK_LT(trackIndex, mTracks.size());
+            if (trackIndex >= mTracks.size()) {
+                LOGE("No matching url");
+                return false;
+            }
 
-            CHECK(GetAttribute((*it).c_str(), "seq", &val));
+            if (!GetAttribute((*it).c_str(), "seq", &val)) {
+                LOGE("No seq attribute");
+                return false;
+            }
 
             char *end;
             unsigned long seq = strtoul(val.c_str(), &end, 10);
 
             TrackInfo *info = &mTracks.editItemAt(trackIndex);
             info->mFirstSeqNumInSegment = seq;
             info->mNewSegment = true;
 
-            CHECK(GetAttribute((*it).c_str(), "rtptime", &val));
+            if (!GetAttribute((*it).c_str(), "rtptime", &val)) {
+                LOGE("No rtptime attribute");
+                return false;
+            }
 
             uint32_t rtpTime = strtoul(val.c_str(), &end, 10);
 
             LOGV("track #%d: rtpTime=%u <=> npt=%.2f", n, rtpTime, npt1);
 
             info->mNormalPlayTimeRTP = rtpTime;
             info->mNormalPlayTimeUs = (int64_t)(npt1 * 1E6);
 
@@ -1340,16 +1369,17 @@ struct RtspConnectionHandler : public AH
                         trackIndex,
                         info->mNormalPlayTimeRTP, info->mNormalPlayTimeUs);
             }
 
             ++n;
         }
 
         mSeekable = true;
+        return true;
     }
 
     sp<MetaData> getTrackFormat(size_t index, int32_t *timeScale) {
         CHECK_GE(index, 0u);
         CHECK_LT(index, mTracks.size());
 
         const TrackInfo &info = mTracks.itemAt(index);
 
@@ -1435,20 +1465,36 @@ private:
             sp<AMessage> reply = new AMessage(kWhatSetup, id());
             reply->setSize("index", index);
             reply->setInt32("result", ERROR_UNSUPPORTED);
             reply->post();
             return;
         }
 
         AString url;
-        CHECK(mSessionDesc->findAttribute(index, "a=control", &url));
+        if (!mSessionDesc->findAttribute(index, "a=control", &url)) {
+            LOGW("Unsupported format. Ignoring track #%d.", index);
+
+            sp<AMessage> reply = new AMessage(kWhatSetup, id());
+            reply->setSize("index", index);
+            reply->setInt32("result", ERROR_UNSUPPORTED);
+            reply->post();
+            return;
+        }
 
         AString trackURL;
-        CHECK(MakeURL(mBaseURL.c_str(), url.c_str(), &trackURL));
+        if (!MakeURL(mBaseURL.c_str(), url.c_str(), &trackURL)) {
+            LOGW("Unsupported format. Ignoring track #%d.", index);
+
+            sp<AMessage> reply = new AMessage(kWhatSetup, id());
+            reply->setSize("index", index);
+            reply->setInt32("result", ERROR_UNSUPPORTED);
+            reply->post();
+            return;
+        }
 
         mTracks.push(TrackInfo());
         TrackInfo *info = &mTracks.editItemAt(mTracks.size() - 1);
         info->mURL = trackURL;
         info->mPacketSource = source;
         info->mUsingInterleavedTCP = false;
         info->mFirstSeqNumInSegment = 0;
         info->mNewSegment = true;
@@ -1462,18 +1508,26 @@ private:
 
         unsigned long PT;
         AString formatDesc;
         AString formatParams;
         mSessionDesc->getFormatType(index, &PT, &formatDesc, &formatParams);
 
         int32_t timescale;
         int32_t numChannels;
-        ASessionDescription::ParseFormatDesc(
-                formatDesc.c_str(), &timescale, &numChannels);
+        if (!ASessionDescription::ParseFormatDesc(
+                    formatDesc.c_str(), &timescale, &numChannels)) {
+            LOGW("Unsupported format. Ignoring track #%d.", index);
+
+            sp<AMessage> reply = new AMessage(kWhatSetup, id());
+            reply->setSize("index", index);
+            reply->setInt32("result", ERROR_UNSUPPORTED);
+            reply->post();
+            return;
+        }
 
         info->mTimeScale = timescale;
 
         LOGV("track #%d URL=%s", mTracks.size(), trackURL.c_str());
 
         AString request = "SETUP ";
         request.append(trackURL);
         request.append(" RTSP/1.0\r\n");
@@ -1612,18 +1666,21 @@ private:
             postQueueAccessUnit(trackIndex, accessUnit);
         }
     }
 
     bool addMediaTimestamp(
             int32_t trackIndex, const TrackInfo *track,
             const sp<ABuffer> &accessUnit) {
         uint32_t rtpTime;
-        CHECK(accessUnit->meta()->findInt32(
-                    "rtp-time", (int32_t *)&rtpTime));
+        if (!accessUnit->meta()->findInt32(
+                    "rtp-time", (int32_t *)&rtpTime)) {
+            LOGE("No RTP time in access unit meta");
+            return false;
+        }
 
         int64_t relRtpTimeUs =
             (((int64_t)rtpTime - (int64_t)track->mNormalPlayTimeRTP) * 1000000ll)
                 / track->mTimeScale;
 
         int64_t ntpTimeUs = track->mNTPAnchorUs + relRtpTimeUs;
 
         int64_t mediaTimeUs = mMediaAnchorUs + ntpTimeUs - mNTPAnchorUs;
--- a/netwerk/protocol/rtsp/rtsp/RTSPSource.cpp
+++ b/netwerk/protocol/rtsp/rtsp/RTSPSource.cpp
@@ -226,19 +226,20 @@ void RTSPSource::performPlay(int64_t pla
     }
     // Use the latest received frame time if we were paused.
     if (mState == PAUSED) {
         playTimeUs = mLatestPausedUnit;
     }
 
     int64_t duration = 0;
     getDuration(&duration);
-    MOZ_ASSERT(playTimeUs < duration,
+    MOZ_ASSERT(duration == 0 || playTimeUs < duration,
                "Should never receive an out of bounds play time!");
-    if (playTimeUs >= duration) {
+    if (duration > 0 && playTimeUs >= duration) {
+        // if not a live stream and play time out of bounds
         return;
     }
 
     LOGI("performPlay : duration=%lld playTimeUs=%lld", duration, playTimeUs);
     mState = PLAYING;
     mHandler->play(playTimeUs);
 }
 
@@ -589,30 +590,36 @@ void RTSPSource::onConnected(bool isSeek
         nsRefPtr<nsIStreamingProtocolMetaData> meta;
         int32_t int32Value;
         int64_t int64Value;
 
         meta = new mozilla::net::RtspMetaData();
         meta->SetTotalTracks(numTracks);
         meta->SetMimeType(mimeType);
 
-        CHECK(format->findInt64(kKeyDuration, &int64Value));
+        bool success;
+        success = format->findInt64(kKeyDuration, &int64Value);
+        MOZ_ASSERT(success);
         meta->SetDuration(int64Value);
 
         if (isAudio) {
-            CHECK(format->findInt32(kKeyChannelCount, &int32Value));
+            success = format->findInt32(kKeyChannelCount, &int32Value);
+            MOZ_ASSERT(success);
             meta->SetChannelCount(int32Value);
 
-            CHECK(format->findInt32(kKeySampleRate, &int32Value));
+            success = format->findInt32(kKeySampleRate, &int32Value);
+            MOZ_ASSERT(success);
             meta->SetSampleRate(int32Value);
         } else {
-            CHECK(format->findInt32(kKeyWidth, &int32Value));
+            success = format->findInt32(kKeyWidth, &int32Value);
+            MOZ_ASSERT(success);
             meta->SetWidth(int32Value);
 
-            CHECK(format->findInt32(kKeyHeight, &int32Value));
+            success = format->findInt32(kKeyHeight, &int32Value);
+            MOZ_ASSERT(success);
             meta->SetHeight(int32Value);
         }
 
         // Optional meta data.
         const void *data;
         uint32_t type;
         size_t length = 0;
 
@@ -700,18 +707,19 @@ void RTSPSource::onTrackDataAvailable(si
         return;
     }
 
     nsRefPtr<nsIStreamingProtocolMetaData> meta;
     int64_t int64Value;
 
     meta = new mozilla::net::RtspMetaData();
 
-    CHECK(accessUnit != NULL);
-    CHECK(accessUnit->meta()->findInt64("timeUs", &int64Value));
+    MOZ_ASSERT(accessUnit != NULL);
+    bool success = accessUnit->meta()->findInt64("timeUs", &int64Value);
+    MOZ_ASSERT(success);
     meta->SetTimeStamp(int64Value);
 
     meta->SetFrameType(MEDIASTREAM_FRAMETYPE_NORMAL);
     data.Assign((const char *) accessUnit->data(), accessUnit->size());
 
     if (mListener) {
         mListener->OnMediaDataAvailable(trackIndex, data, data.Length(), 0, meta.get());
     }
--- a/netwerk/protocol/rtsp/rtsp/RTSPTransmitter.h
+++ b/netwerk/protocol/rtsp/rtsp/RTSPTransmitter.h
@@ -261,38 +261,47 @@ struct MyTransmitter : public AHandler {
                 nibble += '0';
             } else {
                 nibble += 'a' - 10;
             }
             out->append(&nibble, 1);
         }
     }
 
-    void authenticate(const sp<ARTSPResponse> &response) {
+    bool authenticate(const sp<ARTSPResponse> &response) {
         ssize_t i = response->mHeaders.indexOfKey("www-authenticate");
-        CHECK_GE(i, 0);
+        if (i < 0) {
+            return false;
+        }
 
         AString value = response->mHeaders.valueAt(i);
 
         if (!strncmp(value.c_str(), "Basic", 5)) {
             mAuthType = BASIC;
         } else {
-            CHECK(!strncmp(value.c_str(), "Digest", 6));
+            if (strncmp(value.c_str(), "Digest", 6)) {
+                return false;
+            }
+
             mAuthType = DIGEST;
 
             i = value.find("nonce=");
-            CHECK_GE(i, 0);
-            CHECK_EQ(value.c_str()[i + 6], '\"');
+            if (i < 0 || value.c_str()[i + 6] != '\"') {
+                return false;
+            }
             ssize_t j = value.find("\"", i + 7);
-            CHECK_GE(j, 0);
+            if (j < 0) {
+                return false;
+            }
 
             mNonce.setTo(value, i + 7, j - i - 7);
         }
 
         issueAnnounce();
+        return true;
     }
 
     void addAuthentication(
             AString *request, const char *method, const char *url) {
         if (mAuthType == NONE) {
             return;
         }
 
@@ -378,23 +387,21 @@ struct MyTransmitter : public AHandler {
                 CHECK(msg->findObject("response", &obj));
                 sp<ARTSPResponse> response;
 
                 if (result == OK) {
                     response = static_cast<ARTSPResponse *>(obj.get());
                     CHECK(response != NULL);
 
                     if (response->mStatusCode == 401) {
-                        if (mAuthType != NONE) {
+                        if (mAuthType != NONE || !authenticate(response)) {
                             LOG(INFO) << "FAILED to authenticate";
                             (new AMessage(kWhatQuit, id()))->post();
                             break;
                         }
-
-                        authenticate(response);
                         break;
                     }
                 }
 
                 if (result != OK || response->mStatusCode != 200) {
                     (new AMessage(kWhatQuit, id()))->post();
                     break;
                 }
@@ -457,24 +464,34 @@ struct MyTransmitter : public AHandler {
                 int32_t result;
                 CHECK(msg->findInt32("result", &result));
 
                 LOG(INFO) << "SETUP completed with result "
                      << result << " (" << strerror(-result) << ")";
 
                 sp<RefBase> obj;
                 CHECK(msg->findObject("response", &obj));
+                if (!obj.get()) {
+                    LOGE("No response to SETUP");
+                    (new AMessage(kWhatQuit, id()))->post();
+                    break;
+                }
                 sp<ARTSPResponse> response;
 
                 if (result == OK) {
                     response = static_cast<ARTSPResponse *>(obj.get());
-                    CHECK(response != NULL);
+                    if (!response.get()) {
+                        LOGE("No response to SETUP");
+                        (new AMessage(kWhatQuit, id()))->post();
+                        break;
+                    }
                 }
 
                 if (result != OK || response->mStatusCode != 200) {
+                    LOGE("SETUP error")
                     (new AMessage(kWhatQuit, id()))->post();
                     break;
                 }
 
                 ssize_t i = response->mHeaders.indexOfKey("session");
                 CHECK_GE(i, 0);
                 mSessionID = response->mHeaders.valueAt(i);
                 i = mSessionID.find(";");
--- a/netwerk/protocol/rtsp/rtsp/UDPPusher.cpp
+++ b/netwerk/protocol/rtsp/rtsp/UDPPusher.cpp
@@ -81,38 +81,48 @@ bool UDPPusher::onPush() {
     uint32_t length;
     if (fread(&length, 1, sizeof(length), mFile) < sizeof(length)) {
         LOGI("No more data to push.");
         return false;
     }
 
     length = fromlel(length);
 
-    CHECK_GT(length, 0u);
+    if (length <= 0u) {
+        LOGE("Zero length");
+        return false;
+    }
 
     sp<ABuffer> buffer = new ABuffer(length);
     if (fread(buffer->data(), 1, length, mFile) < length) {
         LOGE("File truncated?.");
         return false;
     }
 
     ssize_t n = PR_SendTo(
             mSocket, buffer->data(), buffer->size(), 0,
             &mRemoteAddr, PR_INTERVAL_NO_WAIT);
 
     CHECK_EQ(n, (ssize_t)buffer->size());
+    if (n != (ssize_t)buffer->size()) {
+        LOGE("Sizes don't match");
+        return false;
+    }
 
     uint32_t timeMs;
     if (fread(&timeMs, 1, sizeof(timeMs), mFile) < sizeof(timeMs)) {
         LOGI("No more data to push.");
         return false;
     }
 
     timeMs = fromlel(timeMs);
-    CHECK_GE(timeMs, mFirstTimeMs);
+    if (timeMs < mFirstTimeMs) {
+        LOGE("Time is wrong");
+        return false;
+    }
 
     timeMs -= mFirstTimeMs;
     int64_t whenUs = mFirstTimeUs + timeMs * 1000ll;
     int64_t nowUs = ALooper::GetNowUs();
     (new AMessage(kWhatPush, id()))->post(whenUs - nowUs);
 
     return true;
 }
@@ -138,17 +148,17 @@ void UDPPusher::onMessageReceived(const 
 
                 struct sockaddr_in tmp = mRemoteAddr;
                 tmp.sin_port = htons(ntohs(mRemoteAddr.sin_port) | 1);
 
                 ssize_t n = PR_SendTo(
                         mSocket, buffer->data(), buffer->size(), 0,
                         &tmp, PR_INTERVAL_NO_WAIT);
 
-                CHECK_EQ(n, (ssize_t)buffer->size());
+                MOZ_ASSERT(n, (ssize_t)buffer->size());
             }
             break;
         }
 
         default:
             TRESPASS();
             break;
     }
--- a/security/sandbox/linux/SandboxFilter.cpp
+++ b/security/sandbox/linux/SandboxFilter.cpp
@@ -24,16 +24,17 @@
 
 namespace mozilla {
 
 class SandboxFilterImpl : public SandboxAssembler
 {
 public:
   virtual void Build() = 0;
   virtual ~SandboxFilterImpl() { }
+  void AllowThreadClone();
 };
 
 // Some helper macros to make the code that builds the filter more
 // readable, and to help deal with differences among architectures.
 
 #define SYSCALL_EXISTS(name) (defined(__NR_##name))
 
 #define SYSCALL(name) (Condition(__NR_##name))
@@ -67,16 +68,36 @@ public:
 // i386 multiplexes all the SysV-IPC-related interfaces into a single
 // syscall.
 #if SYSCALL_EXISTS(ipc)
 #define SYSVIPCCALL(name, NAME) SYSCALL_WITH_ARG(ipc, 0, NAME)
 #else
 #define SYSVIPCCALL(name, NAME) SYSCALL(name)
 #endif
 
+void SandboxFilterImpl::AllowThreadClone() {
+  // WARNING: s390 and cris pass the flags in a different arg -- see
+  // CLONE_BACKWARDS2 in arch/Kconfig in the kernel source -- but we
+  // don't support seccomp-bpf on those archs yet.
+  //
+  // The glibc source hasn't changed the thread creation clone flags
+  // since 2004, so this *should* be safe to hard-code.  Bionic's
+  // value has changed a few times, and has converged on the same one
+  // as glibc; allow any of them.
+  static const int flags_common = CLONE_VM | CLONE_FS | CLONE_FILES |
+    CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM;
+  Allow(SYSCALL_WITH_ARG(clone, 0,
+#ifdef ANDROID
+                         flags_common | CLONE_DETACHED, // <= JB 4.2
+                         flags_common, // JB 4.3 or KK 4.4
+#endif
+                         flags_common | CLONE_SETTLS // Android L or glibc
+                         | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID));
+}
+
 #ifdef MOZ_CONTENT_SANDBOX
 class SandboxFilterImplContent : public SandboxFilterImpl {
 protected:
   virtual void Build() MOZ_OVERRIDE;
 };
 
 void
 SandboxFilterImplContent::Build() {
@@ -129,17 +150,17 @@ SandboxFilterImplContent::Build() {
   /* ioctl() is for GL. Remove when GL proxy is implemented.
    * Additionally ioctl() might be a place where we want to have
    * argument filtering */
   Allow(SYSCALL(ioctl));
   Allow(SYSCALL(close));
   Allow(SYSCALL(munmap));
   Allow(SYSCALL(mprotect));
   Allow(SYSCALL(writev));
-  Allow(SYSCALL(clone));
+  AllowThreadClone();
   Allow(SYSCALL(brk));
 #if SYSCALL_EXISTS(set_thread_area)
   Allow(SYSCALL(set_thread_area));
 #endif
 
   Allow(SYSCALL(getpid));
   Allow(SYSCALL(gettid));
   Allow(SYSCALL(getrusage));
@@ -349,33 +370,17 @@ void SandboxFilterImplGMP::Build() {
   Allow(SYSCALL(mmap));
 #endif
   Allow(SYSCALL_LARGEFILE(fstat, fstat64));
   Allow(SYSCALL(munmap));
 
   Allow(SYSCALL(getpid));
   Allow(SYSCALL(gettid));
 
-  // The glibc source hasn't changed the thread creation clone flags
-  // since 2004, so this *should* be safe to hard-code.  Bionic is
-  // different, but MOZ_GMP_SANDBOX isn't supported there yet.
-  //
-  // At minimum we should require CLONE_THREAD, so that a single
-  // SIGKILL from the parent will destroy all descendant tasks.  In
-  // general, pinning down as much of the flags word as possible is a
-  // good idea, because it exposes a lot of subtle (and probably not
-  // well tested in all cases) kernel functionality.
-  //
-  // WARNING: s390 and cris pass the flags in a different arg -- see
-  // CLONE_BACKWARDS2 in arch/Kconfig in the kernel source -- but we
-  // don't support seccomp-bpf on those archs yet.
-  static const int new_thread_flags = CLONE_VM | CLONE_FS | CLONE_FILES |
-    CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | CLONE_SETTLS |
-    CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID;
-  Allow(SYSCALL_WITH_ARG(clone, 0, new_thread_flags));
+  AllowThreadClone();
 
   Allow(SYSCALL_WITH_ARG(prctl, 0, PR_GET_SECCOMP, PR_SET_NAME));
 
 #if SYSCALL_EXISTS(set_robust_list)
   Allow(SYSCALL(set_robust_list));
 #endif
 
   // NSPR can call this when creating a thread, but it will accept a
--- a/testing/mochitest/tests/SimpleTest/SimpleTest.js
+++ b/testing/mochitest/tests/SimpleTest/SimpleTest.js
@@ -675,17 +675,17 @@ SimpleTest.waitForFocus = function (call
     }
 
     function maybeRunTests() {
         if (SimpleTest.waitForFocus_loaded &&
             SimpleTest.waitForFocus_focused &&
             !SimpleTest.waitForFocus_started) {
             SimpleTest._pendingWaitForFocusCount--;
             SimpleTest.waitForFocus_started = true;
-            setTimeout(callback, 0, targetWindow);
+            SimpleTest.executeSoon(function() { callback(targetWindow) });
         }
     }
 
     function waitForEvent(event) {
         try {
             // Check to make sure that this isn't a load event for a blank or
             // non-blank page that wasn't desired.
             if (event.type == "load" && (expectBlankPage != (event.target.location == "about:blank")))
--- a/toolkit/components/places/UnifiedComplete.js
+++ b/toolkit/components/places/UnifiedComplete.js
@@ -738,18 +738,18 @@ Search.prototype = {
 
     yield this._sleep(Prefs.delay);
     if (!this.pending)
       return;
 
     for (let [query, params] of queries) {
       let hasResult = yield conn.executeCached(query, params, this._onResultRow.bind(this));
 
-      if (this.pending && params.query_type == QUERYTYPE_AUTOFILL_URL &&
-          !hasResult) {
+      if (this.pending && this._enableActions && !hasResult &&
+          params.query_type == QUERYTYPE_AUTOFILL_URL) {
         // If we predicted that our URL autofill query might have gotten a
         // result, but it didn't, then we need to recover.
         yield this._matchHeuristicFallback();
       }
 
       if (!this.pending)
         return;
     }
--- a/toolkit/components/places/tests/unifiedcomplete/test_autoFill_default_behavior.js
+++ b/toolkit/components/places/tests/unifiedcomplete/test_autoFill_default_behavior.js
@@ -178,16 +178,17 @@ add_task(function* test_default_behavior
     { uri: uri4, title: "tpbk", transition: TRANSITION_TYPED },
   ]);
   addBookmark( { uri: uri3, title: "bookmarked" } );
   addBookmark( { uri: uri4, title: "tpbk" } );
 
   // RESTRICT TO HISTORY.
   Services.prefs.setIntPref("browser.urlbar.default.behavior", 1);
   Services.prefs.setBoolPref("browser.urlbar.autoFill.typed", true);
+  Services.prefs.setBoolPref("browser.urlbar.autoFill.searchEngines", false);
 
   do_log_info("URL: Restrict history, common visit, should not autoFill");
   yield check_autocomplete({
     search: "visited/v",
     matches: [ { uri: uri2, title: "visited" } ],
     autofilled: "visited/v",
     completed: "visited/v"
   });
--- a/toolkit/devtools/server/actors/inspector.js
+++ b/toolkit/devtools/server/actors/inspector.js
@@ -558,16 +558,28 @@ var NodeActor = exports.NodeActor = prot
   setNodeValue: method(function(value) {
     this.rawNode.nodeValue = value;
   }, {
     request: { value: Arg(0) },
     response: {}
   }),
 
   /**
+   * Get a unique selector string for this node.
+   */
+  getUniqueSelector: method(function() {
+    return CssLogic.findCssSelector(this.rawNode);
+  }, {
+    request: {},
+    response: {
+      value: RetVal("string")
+    }
+  }),
+
+  /**
    * Get the node's image data if any (for canvas and img nodes).
    * Returns an imageData object with the actual data being a LongStringActor
    * and a size json object.
    * The image data is transmitted as a base64 encoded png data-uri.
    * The method rejects if the node isn't an image or if the image is missing
    *
    * Accepts a maxDim request parameter to resize images that are larger. This
    * is important as the resizing occurs server-side so that image-data being
--- a/toolkit/devtools/server/actors/root.js
+++ b/toolkit/devtools/server/actors/root.js
@@ -138,17 +138,19 @@ RootActor.prototype = {
     // Whether conditional breakpoints are supported
     conditionalBreakpoints: true,
     bulk: true,
     // Whether the style rule actor implements the modifySelector method
     // that modifies the rule's selector
     selectorEditable: true,
     // Whether the page style actor implements the addNewRule method that
     // adds new rules to the page
-    addNewRule: true
+    addNewRule: true,
+    // Whether the dom node actor implements the getUniqueSelector method
+    getUniqueSelector: true
   },
 
   /**
    * Return a 'hello' packet as specified by the Remote Debugging Protocol.
    */
   sayHello: function() {
     return {
       from: this.actorID,
--- a/toolkit/devtools/server/actors/timeline.js
+++ b/toolkit/devtools/server/actors/timeline.js
@@ -133,30 +133,34 @@ let TimelineActor = exports.TimelineActo
   /**
    * At regular intervals, pop the markers from the docshell, and forward
    * markers if any.
    */
   _pullTimelineData: function() {
     if (!this._isRecording) {
       return;
     }
+    if (!this.docShells.length) {
+      return;
+    }
 
+    let endTime = this.docShells[0].now();
     let markers = [];
+
     for (let docShell of this.docShells) {
       markers = [...markers, ...docShell.popProfileTimelineMarkers()];
     }
     if (markers.length > 0) {
-      let endTime = this.docShells[0].now();
       events.emit(this, "markers", markers, endTime);
     }
     if (this._memoryActor) {
-      events.emit(this, "memory", Date.now(), this._memoryActor.measure());
+      events.emit(this, "memory", endTime, this._memoryActor.measure());
     }
     if (this._framerateActor) {
-      events.emit(this, "ticks", Date.now(), this._framerateActor.getPendingTicks());
+      events.emit(this, "ticks", endTime, this._framerateActor.getPendingTicks());
     }
 
     this._dataPullTimeout = setTimeout(() => {
       this._pullTimelineData();
     }, DEFAULT_TIMELINE_DATA_PULL_TIMEOUT);
   },
 
   /**
--- a/toolkit/mozapps/extensions/test/xpinstall/browser.ini
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser.ini
@@ -1,10 +1,9 @@
 [DEFAULT]
-skip-if = e10s # Bug ?????? - addon installation seems broken (gXPInstallObserver._findChildShell tries to directly use a content docShell)
 support-files =
   authRedirect.sjs
   bug540558.html
   bug638292.html
   bug645699.html
   concurrent_installs.html
   cookieRedirect.sjs
   corrupt.xpi
@@ -29,66 +28,77 @@ support-files =
   theme.xpi
   triggerredirect.html
   unsigned.xpi
 
 [browser_auth.js]
 [browser_auth2.js]
 [browser_auth3.js]
 [browser_auth4.js]
+skip-if = e10s # Bug 1082871
 [browser_badargs.js]
 [browser_badargs2.js]
 [browser_badhash.js]
 [browser_badhashtype.js]
 [browser_bug540558.js]
 [browser_bug611242.js]
 [browser_bug638292.js]
+skip-if = e10s # Bug 1083269
 [browser_bug645699.js]
 # [browser_bug672485.js]
 # disabled due to a leak. See bug 682410.
 [browser_cancel.js]
 [browser_concurrent_installs.js]
 [browser_cookies.js]
 [browser_cookies2.js]
 [browser_cookies3.js]
 [browser_cookies4.js]
+skip-if = true # Bug 1084646
 [browser_corrupt.js]
 [browser_empty.js]
 [browser_enabled.js]
 [browser_enabled2.js]
 [browser_enabled3.js]
 [browser_hash.js]
 [browser_httphash.js]
 [browser_httphash2.js]
 [browser_httphash3.js]
 [browser_httphash4.js]
 [browser_httphash5.js]
 [browser_httphash6.js]
+skip-if = e10s # Bug 1084558
 [browser_installchrome.js]
 [browser_localfile.js]
+skip-if = e10s # Bug 1082764
 [browser_localfile2.js]
 [browser_localfile3.js]
+skip-if = e10s # Bug 1082764
 [browser_localfile4.js]
 [browser_multipackage.js]
+skip-if = e10s # bug 1082764
 [browser_navigateaway.js]
 [browser_navigateaway2.js]
 [browser_offline.js]
 [browser_relative.js]
 [browser_signed_multiple.js]
 [browser_signed_naming.js]
 [browser_signed_tampered.js]
 [browser_signed_trigger.js]
 [browser_signed_untrusted.js]
 [browser_signed_url.js]
+skip-if = e10s # bug 1082764
 [browser_softwareupdate.js]
 [browser_trigger_redirect.js]
 [browser_unsigned_trigger.js]
 [browser_unsigned_trigger_iframe.js]
 skip-if = buildapp == "mulet"
 [browser_unsigned_url.js]
+skip-if = e10s # bug 1082764
 [browser_whitelist.js]
 [browser_whitelist2.js]
 [browser_whitelist3.js]
+skip-if = e10s # bug 1082764
 [browser_whitelist4.js]
+skip-if = e10s # bug 1082764
 [browser_whitelist5.js]
 [browser_whitelist6.js]
 [browser_whitelist7.js]
 skip-if = (os == 'win' || os == 'mac') && debug # bug 986458 - leaked 1 docshell until shutdown on chunked debug bc
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_badargs.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_badargs.js
@@ -6,17 +6,21 @@ function test() {
 
   var triggers = encodeURIComponent(JSON.stringify(TESTROOT + "unsigned.xpi"));
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     // Allow the in-page load handler to run first
     executeSoon(page_loaded);
   }, true);
-  expectUncaughtException();
+
+  // In non-e10s the exception in the content page would trigger a test failure
+  if (!gMultiProcessBrowser)
+    expectUncaughtException();
+
   gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
 }
 
 function page_loaded() {
   var doc = gBrowser.contentDocument;
   is(doc.getElementById("return").textContent, "exception", "installTrigger should have failed");
   gBrowser.removeCurrentTab();
   finish();
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_badargs2.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_badargs2.js
@@ -10,17 +10,21 @@ function test() {
     }
   }));
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     // Allow the in-page load handler to run first
     executeSoon(page_loaded);
   }, true);
-  expectUncaughtException();
+
+  // In non-e10s the exception in the content page would trigger a test failure
+  if (!gMultiProcessBrowser)
+    expectUncaughtException();
+
   gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
 }
 
 function page_loaded() {
   var doc = gBrowser.contentDocument;
   is(doc.getElementById("return").textContent, "exception", "installTrigger should have failed");
   gBrowser.removeCurrentTab();
   finish();
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_bug645699.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_bug645699.js
@@ -11,17 +11,21 @@ function test() {
   var pm = Services.perms;
   pm.add(makeURI("http://example.org/"), "install", pm.ALLOW_ACTION);
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.loadURI(TESTROOT + "bug645699.html");
 }
 
 function allow_blocked(installInfo) {
-  is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
+  // installInfo.originator is different depending on whether we are in e10s(!)
+  if (gMultiProcessBrowser)
+    is(installInfo.originator, gBrowser.selectedBrowser, "Install should have been triggered by the right browser");
+  else
+    is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
   is(installInfo.originatingURI.spec, gBrowser.currentURI.spec, "Install should have been triggered by the right uri");
   return false;
 }
 
 function confirm_install(window) {
   ok(false, "Should not see the install dialog");
   return false;
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_concurrent_installs.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_concurrent_installs.js
@@ -2,16 +2,30 @@
 // cause callback ID conflicts (discussed in bug 926712)
 
 let {Promise} = Cu.import("resource://gre/modules/Promise.jsm");
 
 let gConcurrentTabs = [];
 let gQueuedForInstall = [];
 let gResults = [];
 
+function frame_script() {
+  addMessageListener("Test:StartInstall", () => {
+    content.document.getElementById("installnow").click()
+  });
+
+  addEventListener("load", () => {
+    sendAsyncMessage("Test:Loaded");
+
+    content.addEventListener("InstallComplete", (e) => {
+      sendAsyncMessage("Test:InstallComplete", e.detail);
+    }, true);
+  }, true);
+}
+
 let gAddonAndWindowListener = {
   onOpenWindow: function(win) {
     var window = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindow);
     info("Window opened");
 
     waitForFocus(function() {
       info("Focused!");
       // Initially the accept button is disabled on a countdown timer
@@ -28,21 +42,35 @@ let gAddonAndWindowListener = {
   onInstallEnded: function(install) {
     install.cancel();
   },
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIWindowMediatorListener])
 };
 
 function installNext() {
   let tab = gQueuedForInstall.shift();
-  tab.linkedBrowser.contentDocument.getElementById("installnow").click();
+  tab.linkedBrowser.messageManager.sendAsyncMessage("Test:StartInstall");
 }
 
 function winForTab(t) {
-  return t.linkedBrowser.contentDocument.defaultView;
+  return t.linkedBrowser.contentWindow;
+}
+
+function createTab(url) {
+  let tab = gBrowser.addTab(url);
+  tab.linkedBrowser.messageManager.loadFrameScript("data:,(" + frame_script.toString() + ")();", true);
+
+  tab.linkedBrowser.messageManager.addMessageListener("Test:InstallComplete", ({data}) => {
+    gResults.push(data);
+    if (gResults.length == 2) {
+      executeSoon(endThisTest);
+    }
+  });
+
+  return tab;
 }
 
 function test() {
   waitForExplicitFinish();
 
   Services.prefs.setBoolPref(PREF_LOGGING_ENABLED, true);
   Services.wm.addListener(gAddonAndWindowListener);
   AddonManager.addInstallListener(gAddonAndWindowListener);
@@ -58,34 +86,23 @@ function test() {
       gBrowser.removeTab(gConcurrentTabs.shift());
     }
   });
 
   let pm = Services.perms;
   pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
   pm.add(makeURI("http://example.org/"), "install", pm.ALLOW_ACTION);
 
-  gConcurrentTabs.push(gBrowser.addTab(TESTROOT + "concurrent_installs.html"));
-  gConcurrentTabs.push(gBrowser.addTab(TESTROOT2 + "concurrent_installs.html"));
+  gConcurrentTabs.push(createTab(TESTROOT + "concurrent_installs.html"));
+  gConcurrentTabs.push(createTab(TESTROOT2 + "concurrent_installs.html"));
 
   let promises = gConcurrentTabs.map((t) => {
-    let deferred = Promise.defer();
-    t.linkedBrowser.addEventListener("load", () => {
-      let win = winForTab(t);
-      if (win.location.host.startsWith("example")) {
-        win.wrappedJSObject.installTriggerCallback = function(rv) {
-          gResults.push(rv);
-          if (gResults.length == 2) {
-            executeSoon(endThisTest);
-          }
-        };
-        deferred.resolve();
-      }
-    }, true);
-    return deferred.promise;
+    return new Promise(resolve => {
+      t.linkedBrowser.messageManager.addMessageListener("Test:Loaded", resolve);
+    });
   });
 
   Promise.all(promises).then(() => {
     gQueuedForInstall = [...gConcurrentTabs];
     installNext();
   });
 }
 
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_cookies4.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_cookies4.js
@@ -5,17 +5,17 @@
 // This verifies bug 462739
 function test() {
   Harness.downloadFailedCallback = download_failed;
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
   var cm = Components.classes["@mozilla.org/cookiemanager;1"]
                      .getService(Components.interfaces.nsICookieManager2);
-  cm.add("example.com", "/browser/" + RELATIVE_DIR, "xpinstall", "true", false,
+  cm.add("example.org", "/browser/" + RELATIVE_DIR, "xpinstall", "true", false,
          false, true, (Date.now() / 1000) + 60);
 
   var pm = Services.perms;
   pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
   Services.prefs.setIntPref("network.cookie.cookieBehavior", 1);
 
   var triggers = encodeURIComponent(JSON.stringify({
@@ -28,16 +28,16 @@ function test() {
 function download_failed(install) {
   is(install.error, AddonManager.ERROR_NETWORK_FAILURE, "Install should fail");
 }
 
 function finish_test(count) {
   is(count, 0, "No add-ons should have been installed");
   var cm = Components.classes["@mozilla.org/cookiemanager;1"]
                      .getService(Components.interfaces.nsICookieManager2);
-  cm.remove("example.com", "xpinstall", "/browser/" + RELATIVE_DIR, false);
+  cm.remove("example.org", "xpinstall", "/browser/" + RELATIVE_DIR, false);
 
   Services.prefs.clearUserPref("network.cookie.cookieBehavior");
   Services.perms.remove("example.com", "install");
 
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_corrupt.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_corrupt.js
@@ -1,13 +1,14 @@
 // ----------------------------------------------------------------------------
 // Test whether an install fails when the xpi is corrupt.
 function test() {
   Harness.downloadFailedCallback = download_failed;
   Harness.installsCompletedCallback = finish_test;
+  Harness.finalContentEvent = "InstallComplete";
   Harness.setup();
 
   var pm = Services.perms;
   pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
   var triggers = encodeURIComponent(JSON.stringify({
     "Corrupt XPI": TESTROOT + "corrupt.xpi"
   }));
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_enabled.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_enabled.js
@@ -1,20 +1,24 @@
 // ----------------------------------------------------------------------------
 // Test whether an InstallTrigger.enabled is working
 function test() {
   waitForExplicitFinish();
 
   gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    // Allow the in-page load handler to run first
-    executeSoon(page_loaded);
-  }, true);
+
+  function loadListener() {
+    gBrowser.selectedBrowser.removeEventListener("load", loadListener, true);
+    gBrowser.contentWindow.addEventListener("PageLoaded", page_loaded, false);
+  }
+
+  gBrowser.selectedBrowser.addEventListener("load", loadListener, true);
   gBrowser.loadURI(TESTROOT + "enabled.html");
 }
 
 function page_loaded() {
+  gBrowser.contentWindow.removeEventListener("PageLoaded", page_loaded, false);
+
   var doc = gBrowser.contentDocument;
   is(doc.getElementById("enabled").textContent, "true", "installTrigger should have been enabled");
   gBrowser.removeCurrentTab();
   finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_enabled2.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_enabled2.js
@@ -1,24 +1,27 @@
 // ----------------------------------------------------------------------------
 // Test whether an InstallTrigger.enabled is working
 function test() {
   waitForExplicitFinish();
 
   Services.prefs.setBoolPref("xpinstall.enabled", false);
 
   gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    // Allow the in-page load handler to run first
-    executeSoon(page_loaded);
-  }, true);
+
+  function loadListener() {
+    gBrowser.selectedBrowser.removeEventListener("load", loadListener, true);
+    gBrowser.contentWindow.addEventListener("PageLoaded", page_loaded, false);
+  }
+
+  gBrowser.selectedBrowser.addEventListener("load", loadListener, true);
   gBrowser.loadURI(TESTROOT + "enabled.html");
 }
 
 function page_loaded() {
+  gBrowser.contentWindow.removeEventListener("PageLoaded", page_loaded, false);
   Services.prefs.clearUserPref("xpinstall.enabled");
 
   var doc = gBrowser.contentDocument;
   is(doc.getElementById("enabled").textContent, "false", "installTrigger should have not been enabled");
   gBrowser.removeCurrentTab();
   finish();
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_enabled3.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_enabled3.js
@@ -7,21 +7,23 @@ function test() {
   Harness.setup();
 
   Services.prefs.setBoolPref("xpinstall.enabled", false);
 
   var triggers = encodeURIComponent(JSON.stringify({
     "Unsigned XPI": TESTROOT + "unsigned.xpi"
   }));
   gBrowser.selectedTab = gBrowser.addTab();
-  gBrowser.selectedBrowser.addEventListener("load", function() {
-    gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
-    // Allow the in-page load handler to run first
-    executeSoon(page_loaded);
-  }, true);
+
+  function loadListener() {
+    gBrowser.selectedBrowser.removeEventListener("load", loadListener, true);
+    gBrowser.contentWindow.addEventListener("InstallTriggered", page_loaded, false);
+  }
+
+  gBrowser.selectedBrowser.addEventListener("load", loadListener, true);
   gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
 }
 
 function install_disabled(installInfo) {
   ok(true, "Saw installation disabled");
 }
 
 function allow_blocked(installInfo) {
@@ -30,16 +32,17 @@ function allow_blocked(installInfo) {
 }
 
 function confirm_install(window) {
   ok(false, "Should never see an install confirmation dialog");
   return false;
 }
 
 function page_loaded() {
+  gBrowser.contentWindow.removeEventListener("InstallTriggered", page_loaded, false);
   Services.prefs.clearUserPref("xpinstall.enabled");
 
   var doc = gBrowser.contentDocument;
   is(doc.getElementById("return").textContent, "false", "installTrigger should have not been enabled");
   gBrowser.removeCurrentTab();
   Harness.finish();
 }
 // ----------------------------------------------------------------------------
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_localfile2.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_localfile2.js
@@ -18,17 +18,21 @@ function test() {
     "Unsigned XPI": xpipath
   }));
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function() {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
     // Allow the in-page load handler to run first
     executeSoon(page_loaded);
   }, true);
-  expectUncaughtException();
+
+  // In non-e10s the exception in the content page would trigger a test failure
+  if (!gMultiProcessBrowser)
+    expectUncaughtException();
+
   gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
 }
 
 function page_loaded() {
   var doc = gBrowser.contentDocument;
   is(doc.getElementById("return").textContent, "exception", "installTrigger should have failed");
   gBrowser.removeCurrentTab();
   finish();
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_relative.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_relative.js
@@ -1,14 +1,15 @@
 // ----------------------------------------------------------------------------
 // Tests that InstallTrigger deals with relative urls correctly.
 function test() {
   Harness.installConfirmCallback = confirm_install;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
+  Harness.finalContentEvent = "InstallComplete";
   Harness.setup();
 
   var pm = Services.perms;
   pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
   var triggers = encodeURIComponent(JSON.stringify({
     "Unsigned XPI": {
       URL: "unsigned.xpi",
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_trigger_redirect.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_trigger_redirect.js
@@ -1,14 +1,15 @@
 // ----------------------------------------------------------------------------
 // Tests that the InstallTrigger callback can redirect to a relative url.
 function test() {
   Harness.installConfirmCallback = confirm_install;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
+  Harness.finalContentEvent = "InstallComplete";
   Harness.setup();
 
   var pm = Services.perms;
   pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.loadURI(TESTROOT + "triggerredirect.html");
 }
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger.js
@@ -1,15 +1,16 @@
 // ----------------------------------------------------------------------------
 // Tests installing an unsigned add-on through an InstallTrigger call in web
 // content.
 function test() {
   Harness.installConfirmCallback = confirm_install;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
+  Harness.finalContentEvent = "InstallComplete";
   Harness.setup();
 
   var pm = Services.perms;
   pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
   var triggers = encodeURIComponent(JSON.stringify({
     "Unsigned XPI": {
       URL: TESTROOT + "unsigned.xpi",
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_iframe.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_unsigned_trigger_iframe.js
@@ -1,16 +1,17 @@
 // ----------------------------------------------------------------------------
 // Test for bug 589598 - Ensure that installing through InstallTrigger
 // works in an iframe in web content.
 
 function test() {
   Harness.installConfirmCallback = confirm_install;
   Harness.installEndedCallback = install_ended;
   Harness.installsCompletedCallback = finish_test;
+  Harness.finalContentEvent = "InstallComplete";
   Harness.setup();
 
   var pm = Services.perms;
   pm.add(makeURI("http://example.com/"), "install", pm.ALLOW_ACTION);
 
   var triggers = encodeURIComponent(JSON.stringify({
     "Unsigned XPI": {
       URL: TESTROOT + "unsigned.xpi",
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist.js
@@ -12,17 +12,21 @@ function test() {
   var triggers = encodeURIComponent(JSON.stringify({
     "Unsigned XPI": TESTROOT + "unsigned.xpi"
   }));
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
 }
 
 function allow_blocked(installInfo) {
-  is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
+  // installInfo.originator is different depending on whether we are in e10s(!)
+  if (gMultiProcessBrowser)
+    is(installInfo.originator, gBrowser.selectedBrowser, "Install should have been triggered by the right browser");
+  else
+    is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
   is(installInfo.originatingURI.spec, gBrowser.currentURI.spec, "Install should have been triggered by the right uri");
   return true;
 }
 
 function confirm_install(window) {
   var items = window.document.getElementById("itemList").childNodes;
   is(items.length, 1, "Should only be 1 item listed in the confirmation dialog");
   is(items[0].name, "XPI Test", "Should have seen the name from the trigger list");
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist2.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist2.js
@@ -13,17 +13,21 @@ function test() {
   var triggers = encodeURIComponent(JSON.stringify({
     "Unsigned XPI": TESTROOT2 + "unsigned.xpi"
   }));
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.loadURI(TESTROOT + "installtrigger.html?" + triggers);
 }
 
 function allow_blocked(installInfo) {
-  is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
+  // installInfo.originator is different depending on whether we are in e10s(!)
+  if (gMultiProcessBrowser)
+    is(installInfo.originator, gBrowser.selectedBrowser, "Install should have been triggered by the right browser");
+  else
+    is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
   is(installInfo.originatingURI.spec, gBrowser.currentURI.spec, "Install should have been triggered by the right uri");
   return false;
 }
 
 function finish_test() {
   Services.perms.remove("example.org", "install");
 
   gBrowser.removeCurrentTab();
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist4.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist4.js
@@ -12,17 +12,21 @@ function test() {
   var triggers = encodeURIComponent(JSON.stringify({
     "Unsigned XPI": TESTROOT2 + "unsigned.xpi"
   }));
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.loadURI(TESTROOT + "unsigned.xpi", makeURI(TESTROOT2 + "test.html"));
 }
 
 function allow_blocked(installInfo) {
-  is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
+  // installInfo.originator is different depending on whether we are in e10s(!)
+  if (gMultiProcessBrowser)
+    is(installInfo.originator, gBrowser.selectedBrowser, "Install should have been triggered by the right browser");
+  else
+    is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
   is(installInfo.originatingURI.spec, TESTROOT2 + "test.html", "Install should have been triggered by the right uri");
   return false;
 }
 
 function finish_test(count) {
   is(count, 0, "No add-ons should have been installed");
   Services.perms.remove("example.com", "install");
 
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist5.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist5.js
@@ -7,17 +7,21 @@ function test() {
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.loadURI(TESTROOT + "startsoftwareupdate.html? " + encodeURIComponent(TESTROOT + "unsigned.xpi"));
 }
 
 function allow_blocked(installInfo) {
-  is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
+  // installInfo.originator is different depending on whether we are in e10s(!)
+  if (gMultiProcessBrowser)
+    is(installInfo.originator, gBrowser.selectedBrowser, "Install should have been triggered by the right browser");
+  else
+    is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
   is(installInfo.originatingURI.spec, gBrowser.currentURI.spec, "Install should have been triggered by the right uri");
   return false;
 }
 
 function finish_test(count) {
   is(count, 0, "No add-ons should have been installed");
   gBrowser.removeCurrentTab();
   Harness.finish();
--- a/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist6.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/browser_whitelist6.js
@@ -7,18 +7,21 @@ function test() {
   Harness.installsCompletedCallback = finish_test;
   Harness.setup();
 
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.loadURI(TESTROOT + "installchrome.html? " + encodeURIComponent(TESTROOT + "unsigned.xpi"));
 }
 
 function allow_blocked(installInfo) {
-  // XXX Check this for e10s.
-  is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
+  // installInfo.originator is different depending on whether we are in e10s(!)
+  if (gMultiProcessBrowser)
+    is(installInfo.originator, gBrowser.selectedBrowser, "Install should have been triggered by the right browser");
+  else
+    is(installInfo.originator, gBrowser.contentWindow, "Install should have been triggered by the right window");
   is(installInfo.originatingURI.spec, gBrowser.currentURI.spec, "Install should have been triggered by the right uri");
   return false;
 }
 
 function finish_test(count) {
   is(count, 0, "No add-ons should have been installed");
   gBrowser.removeCurrentTab();
   Harness.finish();
--- a/toolkit/mozapps/extensions/test/xpinstall/concurrent_installs.html
+++ b/toolkit/mozapps/extensions/test/xpinstall/concurrent_installs.html
@@ -3,18 +3,21 @@
 
 <html>
 
 <head>
   <meta charset="utf-8">
 <title>Concurrent InstallTrigger tests</title>
 <script type="text/javascript">
 function installCallback(url, status) {
-  window.installTriggerCallback({loc: location.href, xpi: url});
   document.getElementById("status").textContent = status;
+
+  dump("Sending InstallComplete\n");
+  var event = new CustomEvent("InstallComplete", {detail: {loc: location.href, xpi: url}});
+  window.dispatchEvent(event);
 }
 
 function startInstall() {
   var root = location.href.replace("concurrent_installs.html", "");
   var triggers = {
     "Unsigned XPI": root + "unsigned.xpi"
   };
   try {
--- a/toolkit/mozapps/extensions/test/xpinstall/enabled.html
+++ b/toolkit/mozapps/extensions/test/xpinstall/enabled.html
@@ -5,16 +5,19 @@
 
 <!-- This page will test if InstallTrigger seems to be enabled -->
 
 <head>
 <title>InstallTrigger tests</title>
 <script type="text/javascript">
 function init() {
   document.getElementById("enabled").textContent = InstallTrigger.enabled() ? "true" : "false";
+  dump("Sending PageLoaded\n");
+  var event = new CustomEvent("PageLoaded");
+  window.dispatchEvent(event);
 }
 </script>
 </head>
 <body onload="init()">
 <p>InstallTrigger tests</p>
 <p id="enabled"></p>
 </body>
 </html>
--- a/toolkit/mozapps/extensions/test/xpinstall/head.js
+++ b/toolkit/mozapps/extensions/test/xpinstall/head.js
@@ -66,17 +66,21 @@ var Harness = {
   // If set will be called when an xpi fails to install.
   installFailedCallback: null,
   // If set will be called when each xpi item to be installed completes
   // installation.
   installEndedCallback: null,
   // If set will be called when all triggered items are installed or the install
   // is canceled.
   installsCompletedCallback: null,
+  // If set the harness will wait for this DOM event before calling
+  // installsCompletedCallback
+  finalContentEvent: null,
 
+  waitingForEvent: false,
   pendingCount: null,
   installCount: null,
   runningInstalls: null,
 
   waitingForFinish: false,
 
   // Setup and tear down functions
   setup: function() {
@@ -123,45 +127,40 @@ var Harness = {
     this.runningInstalls = [];
   },
 
   finish: function() {
     finish();
   },
 
   endTest: function() {
-    // Defer the final notification to allow things like the InstallTrigger
-    // callback to complete
-    var self = this;
-    executeSoon(function() {
-      let callback = self.installsCompletedCallback;
-      let count = self.installCount;
+    let callback = this.installsCompletedCallback;
+    let count = this.installCount;
 
-      is(self.runningInstalls.length, 0, "Should be no running installs left");
-      self.runningInstalls.forEach(function(aInstall) {
-        info("Install for " + aInstall.sourceURI + " is in state " + aInstall.state);
-      });
+    is(this.runningInstalls.length, 0, "Should be no running installs left");
+    this.runningInstalls.forEach(function(aInstall) {
+      info("Install for " + aInstall.sourceURI + " is in state " + aInstall.state);
+    });
 
-      self.installBlockedCallback = null;
-      self.authenticationCallback = null;
-      self.installConfirmCallback = null;
-      self.downloadStartedCallback = null;
-      self.downloadProgressCallback = null;
-      self.downloadCancelledCallback = null;
-      self.downloadFailedCallback = null;
-      self.downloadEndedCallback = null;
-      self.installStartedCallback = null;
-      self.installFailedCallback = null;
-      self.installEndedCallback = null;
-      self.installsCompletedCallback = null;
-      self.runningInstalls = null;
+    this.installBlockedCallback = null;
+    this.authenticationCallback = null;
+    this.installConfirmCallback = null;
+    this.downloadStartedCallback = null;
+    this.downloadProgressCallback = null;
+    this.downloadCancelledCallback = null;
+    this.downloadFailedCallback = null;
+    this.downloadEndedCallback = null;
+    this.installStartedCallback = null;
+    this.installFailedCallback = null;
+    this.installEndedCallback = null;
+    this.installsCompletedCallback = null;
+    this.runningInstalls = null;
 
-      if (callback)
-        callback(count);
-    });
+    if (callback)
+      callback(count);
   },
 
   // Window open handling
   windowReady: function(window) {
     if (window.document.location.href == XPINSTALL_URL) {
       if (this.installBlockedCallback)
         ok(false, "Should have been blocked by the whitelist");
       this.pendingCount = window.document.getElementById("itemList").childNodes.length;
@@ -269,16 +268,30 @@ var Harness = {
 
   onCloseWindow: function(window) {
   },
 
   // Addon Install Listener
 
   onNewInstall: function(install) {
     this.runningInstalls.push(install);
+
+    if (this.finalContentEvent && !this.waitingForEvent) {
+      this.waitingForEvent = true;
+      info("Waiting for " + this.finalContentEvent);
+      let win = gBrowser.contentWindow;
+      let listener = () => {
+        info("Saw " + this.finalContentEvent);
+        win.removeEventListener(this.finalContentEvent, listener, false);
+        this.waitingForEvent = false;
+        if (this.pendingCount == 0)
+          this.endTest();
+      }
+      win.addEventListener(this.finalContentEvent, listener, false);
+    }
   },
 
   onDownloadStarted: function(install) {
     this.pendingCount++;
     if (this.downloadStartedCallback)
       this.downloadStartedCallback(install);
   },
 
@@ -322,17 +335,17 @@ var Harness = {
 
   onInstallFailed: function(install) {
     if (this.installFailedCallback)
       this.installFailedCallback(install);
     this.checkTestEnded();
   },
 
   checkTestEnded: function() {
-    if (--this.pendingCount == 0)
+    if (--this.pendingCount == 0 && !this.waitingForEvent)
       this.endTest();
   },
 
   // nsIObserver
 
   observe: function(subject, topic, data) {
     var installInfo = subject.QueryInterface(Components.interfaces.amIWebInstallInfo);
     switch (topic) {
--- a/toolkit/mozapps/extensions/test/xpinstall/installtrigger.html
+++ b/toolkit/mozapps/extensions/test/xpinstall/installtrigger.html
@@ -5,26 +5,36 @@
 
 <!-- This page will accept some json as the uri query and pass it to InstallTrigger.install -->
 
 <head>
 <title>InstallTrigger tests</title>
 <script type="text/javascript">
 function installCallback(url, status) {
   document.getElementById("status").textContent = status;
+
+  dump("Sending InstallComplete\n");
+  var event = new CustomEvent("InstallComplete");
+  var target = window.parent ? window.parent : window;
+  target.dispatchEvent(event);
 }
 
 function startInstall() {
+  var event = new CustomEvent("InstallTriggered");
   var text = decodeURIComponent(document.location.search.substring(1));
   var triggers = JSON.parse(text);
   try {
     document.getElementById("return").textContent = InstallTrigger.install(triggers, installCallback);
+    dump("Sending InstallTriggered\n");
+    window.dispatchEvent(event);
   }
   catch (e) {
     document.getElementById("return").textContent = "exception";
+    dump("Sending InstallTriggered\n");
+    window.dispatchEvent(event);
     throw e;
   }
 }
 </script>
 </head>
 <body onload="startInstall()">
 <p>InstallTrigger tests</p>
 <p id="return"></p>
--- a/toolkit/mozapps/extensions/test/xpinstall/triggerredirect.html
+++ b/toolkit/mozapps/extensions/test/xpinstall/triggerredirect.html
@@ -5,16 +5,20 @@
 
 <!-- This page will attempt an install and then try to load a new page in the tab -->
 
 <head>
 <title>InstallTrigger tests</title>
 <script type="text/javascript">
 function installCallback(url, status) {
   document.location = "#foo";
+
+  dump("Sending InstallComplete\n");
+  var event = new CustomEvent("InstallComplete");
+  window.dispatchEvent(event);
 }
 
 function startInstall() {
   InstallTrigger.install({
     "Unsigned XPI": {
       URL: "unsigned.xpi",
       IconURL: "icon.png",
       toString: function() { return this.URL; }