Merge m-c to fx-team. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 02 Jul 2015 16:00:46 -0400
changeset 251176 98101796b275e229828430c6c622085e6c21fece
parent 251127 0105f77365edd07b16f13a3286ffc92b49701218 (current diff)
parent 251175 2f25351c5b058aa1ce52ab8eafe89efce07fff51 (diff)
child 251177 69d9848dd6a5807f67edf4ac377fbe26d29a5c23
child 251222 cad68cc746563d1a2b330c4d9fee09e665e6a59f
push id13833
push userryanvm@gmail.com
push dateThu, 02 Jul 2015 20:00:55 +0000
treeherderfx-team@98101796b275 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone42.0a1
Merge m-c to fx-team. a=merge
--- a/accessible/mac/mozAccessible.mm
+++ b/accessible/mac/mozAccessible.mm
@@ -20,34 +20,35 @@
 #include "TableCellAccessible.h"
 
 #include "mozilla/Services.h"
 #include "nsRect.h"
 #include "nsCocoaUtils.h"
 #include "nsCoord.h"
 #include "nsObjCExceptions.h"
 #include "nsWhitespaceTokenizer.h"
+#include <prdtoa.h>
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 #define NSAccessibilityMathRootRadicandAttribute @"AXMathRootRadicand"
 #define NSAccessibilityMathRootIndexAttribute @"AXMathRootIndex"
 #define NSAccessibilityMathFractionNumeratorAttribute @"AXMathFractionNumerator"
 #define NSAccessibilityMathFractionDenominatorAttribute @"AXMathFractionDenominator"
 #define NSAccessibilityMathBaseAttribute @"AXMathBase"
 #define NSAccessibilityMathSubscriptAttribute @"AXMathSubscript"
 #define NSAccessibilityMathSuperscriptAttribute @"AXMathSuperscript"
 #define NSAccessibilityMathUnderAttribute @"AXMathUnder"
 #define NSAccessibilityMathOverAttribute @"AXMathOver"
+#define NSAccessibilityMathLineThicknessAttribute @"AXMathLineThickness"
 // XXX WebKit also defines the following attributes.
-// See bugs 1176970, 1176973 and 1176983.
+// See bugs 1176970 and 1176983.
 // - NSAccessibilityMathFencedOpenAttribute @"AXMathFencedOpen"
 // - NSAccessibilityMathFencedCloseAttribute @"AXMathFencedClose"
-// - NSAccessibilityMathLineThicknessAttribute @"AXMathLineThickness"
 // - NSAccessibilityMathPrescriptsAttribute @"AXMathPrescripts"
 // - NSAccessibilityMathPostscriptsAttribute @"AXMathPostscripts"
 
 // returns the passed in object if it is not ignored. if it's ignored, will return
 // the first unignored ancestor.
 static inline id
 GetClosestInterestingAccessible(id anObject)
 {
@@ -167,18 +168,17 @@ ConvertToNSArray(nsTArray<Accessible*>& 
       [additional addObject:NSAccessibilityMathRootRadicandAttribute];
       break;
     case roles::MATHML_SQUARE_ROOT:
       [additional addObject:NSAccessibilityMathRootRadicandAttribute];
       break;
     case roles::MATHML_FRACTION:
       [additional addObject:NSAccessibilityMathFractionNumeratorAttribute];
       [additional addObject:NSAccessibilityMathFractionDenominatorAttribute];
-      // XXX bug 1176973
-      // WebKit also defines NSAccessibilityMathLineThicknessAttribute
+      [additional addObject:NSAccessibilityMathLineThicknessAttribute];
       break;
     case roles::MATHML_SUB:
     case roles::MATHML_SUP:
     case roles::MATHML_SUB_SUP:
       [additional addObject:NSAccessibilityMathBaseAttribute];
       [additional addObject:NSAccessibilityMathSubscriptAttribute];
       [additional addObject:NSAccessibilityMathSuperscriptAttribute];
       break;
@@ -417,18 +417,34 @@ ConvertToNSArray(nsTArray<Accessible*>& 
     if ([attribute isEqualToString:NSAccessibilityMathRootRadicandAttribute])
       return [self childAt:0];
     break;
   case roles::MATHML_FRACTION:
     if ([attribute isEqualToString:NSAccessibilityMathFractionNumeratorAttribute])
       return [self childAt:0];
     if ([attribute isEqualToString:NSAccessibilityMathFractionDenominatorAttribute])
       return [self childAt:1];
-    // XXX bug 1176973
-    // WebKit also defines NSAccessibilityMathLineThicknessAttribute
+    if ([attribute isEqualToString:NSAccessibilityMathLineThicknessAttribute]) {
+      // WebKit sets line thickness to some logical value parsed in the
+      // renderer object of the <mfrac> element. It's not clear whether the
+      // exact value is relevant to assistive technologies. From a semantic
+      // point of view, the only important point is to distinguish between
+      // <mfrac> elements that have a fraction bar and those that do not.
+      // Per the MathML 3 spec, the latter happens iff the linethickness
+      // attribute is of the form [zero-float][optional-unit]. In that case we
+      // set line thickness to zero and in the other cases we set it to one.
+      nsCOMPtr<nsIPersistentProperties> attributes = accWrap->Attributes();
+      nsAutoString thickness;
+      nsAccUtils::GetAccAttr(attributes, nsGkAtoms::linethickness_, thickness);
+      double value = 1.0;
+      if (!thickness.IsEmpty())
+        value = PR_strtod(NS_LossyConvertUTF16toASCII(thickness).get(),
+                          nullptr);
+      return [NSNumber numberWithInteger:(value ? 1 : 0)];
+    }
     break;
   case roles::MATHML_SUB:
     if ([attribute isEqualToString:NSAccessibilityMathBaseAttribute])
       return [self childAt:0];
     if ([attribute isEqualToString:NSAccessibilityMathSubscriptAttribute])
       return [self childAt:1];
 #ifdef DEBUG
     if ([attribute isEqualToString:NSAccessibilityMathSuperscriptAttribute])
--- a/b2g/chrome/content/devtools/hud.js
+++ b/b2g/chrome/content/devtools/hud.js
@@ -26,28 +26,38 @@ XPCOMUtils.defineLazyGetter(this, 'Event
 });
 
 XPCOMUtils.defineLazyGetter(this, 'MemoryFront', function() {
   return devtools.require('devtools/server/actors/memory').MemoryFront;
 });
 
 Cu.import('resource://gre/modules/Frames.jsm');
 
+let _telemetryDebug = true;
+
+function telemetryDebug(...args) {
+  if (_telemetryDebug) {
+    args.unshift('[AdvancedTelemetry]');
+    console.log(...args);
+  }
+}
+
 /**
  * The Developer HUD is an on-device developer tool that displays widgets,
  * showing visual debug information about apps. Each widget corresponds to a
  * metric as tracked by a metric watcher (e.g. consoleWatcher).
  */
 let developerHUD = {
 
   _targets: new Map(),
   _client: null,
   _conn: null,
   _watchers: [],
   _logging: true,
+  _telemetry: false,
 
   /**
    * This method registers a metric watcher that will watch one or more metrics
    * on app frames that are being tracked. A watcher must implement the
    * `trackTarget(target)` and `untrackTarget(target)` methods, register
    * observed metrics with `target.register(metric)`, and keep them up-to-date
    * with `target.update(metric, message)` when necessary.
    */
@@ -85,16 +95,20 @@ let developerHUD = {
     let appFrames = Frames.list().filter(frame => frame.getAttribute('mozapp'));
     for (let frame of appFrames) {
       this.trackFrame(frame);
     }
 
     SettingsListener.observe('hud.logging', this._logging, enabled => {
       this._logging = enabled;
     });
+
+    SettingsListener.observe('debug.performance_data.advanced_telemetry', this._telemetry, enabled => {
+      this._telemetry = enabled;
+    });
   },
 
   uninit: function dwp_uninit() {
     if (!this._client) {
       return;
     }
 
     for (let frame of this._targets.keys()) {
@@ -164,23 +178,34 @@ let developerHUD = {
 
 
 /**
  * A Target object represents all there is to know about a Firefox OS app frame
  * that is being tracked, e.g. a pointer to the frame, current values of watched
  * metrics, and how to notify the front-end when metrics have changed.
  */
 function Target(frame, actor) {
-  this.frame = frame;
+  this._frame = frame;
   this.actor = actor;
   this.metrics = new Map();
 }
 
 Target.prototype = {
 
+  get frame() {
+    let frame = this._frame;
+    let systemapp = document.querySelector('#systemapp');
+
+    return (frame === systemapp ? getContentWindow() : frame);
+  },
+
+  get manifest() {
+    return this._frame.appManifestURL;
+  },
+
   /**
    * Register a metric that can later be updated. Does not update the front-end.
    */
   register: function target_register(metric) {
     this.metrics.set(metric, 0);
   },
 
   /**
@@ -198,31 +223,32 @@ Target.prototype = {
 
     let metrics = this.metrics;
     if (metrics) {
       metrics.set(metric.name, metric.value);
     }
 
     let data = {
       metrics: [], // FIXME(Bug 982066) Remove this field.
-      manifest: this.frame.appManifestURL,
+      manifest: this.manifest,
       metric: metric,
       message: message
     };
 
     // FIXME(Bug 982066) Remove this loop.
     if (metrics && metrics.size > 0) {
       for (let name of metrics.keys()) {
         data.metrics.push({name: name, value: metrics.get(name)});
       }
     }
 
     if (message) {
       developerHUD.log('[' + data.manifest + '] ' + data.message);
     }
+
     this._send(data);
   },
 
   /**
    * Nicer way to call update() when the metric value is a number that needs
    * to be incremented.
    */
   bump: function target_bump(metric, message) {
@@ -246,24 +272,43 @@ Target.prototype = {
   destroy: function target_destroy() {
     delete this.metrics;
     this._send({});
   },
 
   _send: function target_send(data) {
     let frame = this.frame;
 
-    let systemapp = document.querySelector('#systemapp');
-    if (this.frame === systemapp) {
-      frame = getContentWindow();
+    shell.sendEvent(frame, 'developer-hud-update', Cu.cloneInto(data, frame));
+    this._sendTelemetryEvent(data.metric);
+  },
+
+  _sendTelemetryEvent: function target_sendTelemetryEvent(metric) {
+    if (!developerHUD._telemetry || !metric || metric.skipTelemetry) {
+      return;
     }
 
-    shell.sendEvent(frame, 'developer-hud-update', Cu.cloneInto(data, frame));
+    if (!this.appName) {
+      let manifest = this.manifest;
+      if (!manifest) {
+        return;
+      }
+      let start = manifest.indexOf('/') + 2;
+      let end = manifest.indexOf('.', start);
+      this.appName = manifest.substring(start, end).toLowerCase();
+    }
+
+    metric.appName = this.appName;
+
+    let data = { metric: metric };
+    let frame = this.frame;
+
+    telemetryDebug('sending advanced-telemetry-update with this data: ' + JSON.stringify(data));
+    shell.sendEvent(frame, 'advanced-telemetry-update', Cu.cloneInto(data, frame));
   }
-
 };
 
 
 /**
  * The Console Watcher tracks the following metrics in apps: reflows, warnings,
  * and errors, with security errors reported separately.
  */
 let consoleWatcher = {
@@ -354,16 +399,28 @@ let consoleWatcher = {
           output += 'Warning (';
         } else {
           metric.name = 'errors';
           output += 'Error (';
         }
 
         if (this._security.indexOf(pageError.category) > -1) {
           metric.name = 'security';
+
+          // Telemetry sends the security error category not the
+          // count of security errors.
+          target._sendTelemetryEvent({
+            name: 'security',
+            value: pageError.category,
+          });
+
+          // Indicate that the 'hud' security metric (the count of security
+          // errors) should not be sent as a telemetry metric since the
+          // security error category is being sent instead.
+          metric.skipTelemetry = true;
         }
 
         let {errorMessage, sourceName, category, lineNumber, columnNumber} = pageError;
         output += category + '): "' + (errorMessage.initial || errorMessage) +
           '" in ' + sourceName + ':' + lineNumber + ':' + columnNumber;
         break;
 
       case 'consoleAPICall':
@@ -374,31 +431,44 @@ let consoleWatcher = {
             output += 'Error (console)';
             break;
 
           case 'warn':
             metric.name = 'warnings';
             output += 'Warning (console)';
             break;
 
+          case 'info':
+            this.handleTelemetryMessage(target, packet);
+
+            // Currently, informational log entries are tracked only by
+            // advanced telemetry. Nonetheless, for consistency, we
+            // continue here and let the function return normally, when it
+            // concludes 'info' entries are not being watched.
+            metric.name = 'info';
+            break;
+
           default:
             return;
         }
         break;
 
       case 'reflowActivity':
         metric.name = 'reflows';
 
         let {start, end, sourceURL, interruptible} = packet;
         metric.interruptible = interruptible;
         let duration = Math.round((end - start) * 100) / 100;
         output += 'Reflow: ' + duration + 'ms';
         if (sourceURL) {
           output += ' ' + this.formatSourceURL(packet);
         }
+
+        // Telemetry also records reflow duration.
+        target._sendTelemetryEvent({name: 'reflow-duration', value: Math.round(duration)});
         break;
 
       default:
         return;
     }
 
     if (!this._watching[metric.name]) {
       return;
@@ -412,16 +482,59 @@ let consoleWatcher = {
     let source = WebConsoleUtils.abbreviateSourceURL(packet.sourceURL);
 
     // Add function name and line number
     let {functionName, sourceLine} = packet;
     source = 'in ' + (functionName || '<anonymousFunction>') +
       ', ' + source + ':' + sourceLine;
 
     return source;
+  },
+
+  handleTelemetryMessage:
+    function cw_handleTelemetryMessage(target, packet) {
+
+    if (!developerHUD._telemetry) {
+      return;
+    }
+
+    // If this is a 'telemetry' log entry, create a telemetry metric from
+    // the log content.
+    let separator = '|';
+    let logContent = packet.message.arguments.toString();
+
+    if (logContent.indexOf('telemetry') < 0) {
+      return;
+    }
+
+    let telemetryData = logContent.split(separator);
+
+    // Positions of the components of a telemetry log entry.
+    let TELEMETRY_IDENTIFIER_IDX = 0;
+    let NAME_IDX = 1;
+    let VALUE_IDX = 2;
+    let CONTEXT_IDX = 3;
+
+    if (telemetryData[TELEMETRY_IDENTIFIER_IDX] != 'telemetry' ||
+        telemetryData.length < 3 || telemetryData.length > 4) {
+      return;
+    }
+
+    let metric = {
+      name: telemetryData[NAME_IDX],
+      value: telemetryData[VALUE_IDX]
+    };
+
+    // The metric's app name, if a 'context' was provided, is the
+    // specified context appended to the specified app name.
+    if (telemetryData.length === 4) {
+      metric.context = telemetryData[CONTEXT_IDX];
+    }
+
+    target._sendTelemetryEvent(metric);
   }
 };
 developerHUD.registerWatcher(consoleWatcher);
 
 
 let eventLoopLagWatcher = {
   _client: null,
   _fronts: new Map(),
--- a/b2g/components/AboutServiceWorkers.jsm
+++ b/b2g/components/AboutServiceWorkers.jsm
@@ -144,25 +144,25 @@ this.AboutServiceWorkers = {
         self.sendResult(message.id, true);
         break;
 
       case "unregister":
         if (!message.principal ||
             !message.principal.origin ||
             !message.principal.originAttributes ||
             !message.principal.originAttributes.appId ||
-            !message.principal.originAttributes.isInBrowser) {
+            (message.principal.originAttributes.inBrowser == null)) {
           self.sendError(message.id, "MissingPrincipal");
           return;
         }
 
         let principal = Services.scriptSecurityManager.getAppCodebasePrincipal(
           Services.io.newURI(message.principal.origin, null, null),
           message.principal.originAttributes.appId,
-          message.principal.originAttributes.isInBrowser
+          message.principal.originAttributes.inBrowser
         );
 
         if (!message.scope) {
           self.sendError(message.id, "MissingScope");
           return;
         }
 
         let serviceWorkerUnregisterCallback = {
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4b7ad0dde990bdc44e166818c0bb09a35cd1207f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="49192a4e48d080e44a0d66f059e6897f07cf67f8"/>
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4b7ad0dde990bdc44e166818c0bb09a35cd1207f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="49192a4e48d080e44a0d66f059e6897f07cf67f8"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="173b3104bfcbd23fc9dccd4b0035fc49aae3d444">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4b7ad0dde990bdc44e166818c0bb09a35cd1207f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="87a2d8ab9248540910e56921654367b78a587095"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="9d0e5057ee5404a31ec1bf76131cb11336a7c3b6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4efd19d199ae52656604f794c5a77518400220fd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4b7ad0dde990bdc44e166818c0bb09a35cd1207f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="49192a4e48d080e44a0d66f059e6897f07cf67f8"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4b7ad0dde990bdc44e166818c0bb09a35cd1207f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="49192a4e48d080e44a0d66f059e6897f07cf67f8"/>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4b7ad0dde990bdc44e166818c0bb09a35cd1207f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="49192a4e48d080e44a0d66f059e6897f07cf67f8"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="173b3104bfcbd23fc9dccd4b0035fc49aae3d444">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="4b7ad0dde990bdc44e166818c0bb09a35cd1207f"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="87a2d8ab9248540910e56921654367b78a587095"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="9d0e5057ee5404a31ec1bf76131cb11336a7c3b6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4b7ad0dde990bdc44e166818c0bb09a35cd1207f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="49192a4e48d080e44a0d66f059e6897f07cf67f8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "4b7ad0dde990bdc44e166818c0bb09a35cd1207f", 
+        "git_revision": "722028715a56a03f327e2e70f2c32dcb6d819d4c", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "4dd94426a71c70db03184cb1e2d9c4c2ad065461", 
+    "revision": "547f049d7e7510b628b5b1074f73b204ab6627df", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,17 +12,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4efd19d199ae52656604f794c5a77518400220fd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4b7ad0dde990bdc44e166818c0bb09a35cd1207f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="49192a4e48d080e44a0d66f059e6897f07cf67f8"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="4b7ad0dde990bdc44e166818c0bb09a35cd1207f"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="722028715a56a03f327e2e70f2c32dcb6d819d4c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="49192a4e48d080e44a0d66f059e6897f07cf67f8"/>
--- a/browser/base/content/browser-fullScreen.js
+++ b/browser/base/content/browser-fullScreen.js
@@ -121,22 +121,24 @@ var FullScreen = {
         // request was initiated from an in-process browser, we need
         // to get its corresponding browser here.
         let browser;
         if (event.target == gBrowser) {
           browser = event.originalTarget;
         } else {
           let topWin = event.target.ownerDocument.defaultView.top;
           browser = gBrowser.getBrowserForContentWindow(topWin);
-          if (!browser) {
-            document.mozCancelFullScreen();
-            break;
+        }
+        if (!browser || !this.enterDomFullscreen(browser)) {
+          if (document.mozFullScreen) {
+            // MozDOMFullscreen:Entered is dispatched synchronously in
+            // fullscreen change, hence we have to avoid calling this
+            // method synchronously here.
+            setTimeout(() => document.mozCancelFullScreen(), 0);
           }
-        }
-        if (!this.enterDomFullscreen(browser)) {
           break;
         }
         // If it is a remote browser, send a message to ask the content
         // to enter fullscreen state. We don't need to do so if it is an
         // in-process browser, since all related document should have
         // entered fullscreen state at this point.
         if (this._isRemoteBrowser(browser)) {
           browser.messageManager.sendAsyncMessage("DOMFullscreen:Entered");
@@ -171,25 +173,23 @@ var FullScreen = {
     if (!document.mozFullScreen)
       return false;
 
     // If we've received a fullscreen notification, we have to ensure that the
     // element that's requesting fullscreen belongs to the browser that's currently
     // active. If not, we exit fullscreen since the "full-screen document" isn't
     // actually visible now.
     if (gBrowser.selectedBrowser != aBrowser) {
-      document.mozCancelFullScreen();
       return false;
     }
 
     let focusManager = Services.focus;
     if (focusManager.activeWindow != window) {
       // The top-level window has lost focus since the request to enter
       // full-screen was made. Cancel full-screen.
-      document.mozCancelFullScreen();
       return false;
     }
 
     document.documentElement.setAttribute("inDOMFullscreen", true);
 
     if (gFindBarInitialized)
       gFindBar.close();
 
--- a/dom/base/Console.h
+++ b/dom/base/Console.h
@@ -13,16 +13,17 @@
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsIObserver.h"
 #include "nsWrapperCache.h"
 #include "nsDOMNavigationTiming.h"
 #include "nsPIDOMWindow.h"
 
 class nsIConsoleAPIStorage;
+class nsIPrincipal;
 class nsIProfiler;
 class nsIXPConnectJSObjectHolder;
 
 namespace mozilla {
 namespace dom {
 
 class ConsoleCallData;
 struct ConsoleStackEntry;
--- a/dom/base/PerformanceEntry.cpp
+++ b/dom/base/PerformanceEntry.cpp
@@ -1,17 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PerformanceEntry.h"
+#include "MainThreadUtils.h"
+#include "mozilla/dom/PerformanceEntryBinding.h"
 #include "nsIURI.h"
-#include "mozilla/dom/PerformanceEntryBinding.h"
 
 using namespace mozilla::dom;
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PerformanceEntry, mParent)
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(PerformanceEntry)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(PerformanceEntry)
 
--- a/dom/base/PerformanceEntry.h
+++ b/dom/base/PerformanceEntry.h
@@ -3,16 +3,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_PerformanceEntry_h___
 #define mozilla_dom_PerformanceEntry_h___
 
 #include "nsDOMNavigationTiming.h"
+#include "nsString.h"
+#include "nsWrapperCache.h"
 
 class nsISupports;
 
 namespace mozilla {
 namespace dom {
 
 // http://www.w3.org/TR/performance-timeline/#performanceentry
 class PerformanceEntry : public nsISupports,
--- a/dom/base/PerformanceMark.cpp
+++ b/dom/base/PerformanceMark.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PerformanceMark.h"
+#include "MainThreadUtils.h"
 #include "mozilla/dom/PerformanceMarkBinding.h"
 
 using namespace mozilla::dom;
 
 PerformanceMark::PerformanceMark(nsISupports* aParent,
                                  const nsAString& aName,
                                  DOMHighResTimeStamp aStartTime)
   : PerformanceEntry(aParent, aName, NS_LITERAL_STRING("mark"))
--- a/dom/base/PerformanceMeasure.cpp
+++ b/dom/base/PerformanceMeasure.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PerformanceMeasure.h"
+#include "MainThreadUtils.h"
 #include "mozilla/dom/PerformanceMeasureBinding.h"
 
 using namespace mozilla::dom;
 
 PerformanceMeasure::PerformanceMeasure(nsISupports* aParent,
                                        const nsAString& aName,
                                        DOMHighResTimeStamp aStartTime,
                                        DOMHighResTimeStamp aEndTime)
--- a/dom/base/PostMessageEvent.cpp
+++ b/dom/base/PostMessageEvent.cpp
@@ -11,16 +11,17 @@
 #include "mozilla/dom/MessagePort.h"
 #include "mozilla/dom/MessagePortBinding.h"
 #include "mozilla/dom/PMessagePort.h"
 #include "mozilla/dom/StructuredCloneTags.h"
 #include "mozilla/EventDispatcher.h"
 #include "nsGlobalWindow.h"
 #include "nsIPresShell.h"
 #include "nsIPrincipal.h"
+#include "nsPresContext.h"
 
 namespace mozilla {
 namespace dom {
 
 namespace {
 
 struct StructuredCloneInfo
 {
--- a/dom/base/PostMessageEvent.h
+++ b/dom/base/PostMessageEvent.h
@@ -6,19 +6,21 @@
 
 #ifndef mozilla_dom_PostMessageEvent_h
 #define mozilla_dom_PostMessageEvent_h
 
 #include "js/StructuredClone.h"
 #include "nsCOMPtr.h"
 #include "nsRefPtr.h"
 #include "nsTArray.h"
+#include "nsThreadUtils.h"
 
 class nsGlobalWindow;
 class nsIPrincipal;
+class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 class MessagePortBase;
 class MessagePortIdentifier;
 
 /**
--- a/dom/base/ProcessGlobal.cpp
+++ b/dom/base/ProcessGlobal.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ProcessGlobal.h"
 
 #include "nsContentCID.h"
 #include "nsDOMClassInfoID.h"
+#include "mozilla/HoldDropJSObjects.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 ProcessGlobal::ProcessGlobal(nsFrameMessageManager* aMessageManager)
  : mInitialized(false),
    mMessageManager(aMessageManager)
 {
--- a/dom/base/SameProcessMessageQueue.cpp
+++ b/dom/base/SameProcessMessageQueue.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SameProcessMessageQueue.h"
+#include "nsThreadUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 SameProcessMessageQueue* SameProcessMessageQueue::sSingleton;
 
 SameProcessMessageQueue::SameProcessMessageQueue()
 {
--- a/dom/base/nsCCUncollectableMarker.cpp
+++ b/dom/base/nsCCUncollectableMarker.cpp
@@ -28,16 +28,17 @@
 #include "nsJSEnvironment.h"
 #include "nsInProcessTabChildGlobal.h"
 #include "nsFrameLoader.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/dom/Element.h"
 #include "xpcpublic.h"
 #include "nsObserverService.h"
 #include "nsFocusManager.h"
+#include "nsIInterfaceRequestorUtils.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 static bool sInited = 0;
 uint32_t nsCCUncollectableMarker::sGeneration = 0;
 #ifdef MOZ_XUL
 #include "nsXULPrototypeCache.h"
--- a/dom/base/nsContentPolicy.cpp
+++ b/dom/base/nsContentPolicy.cpp
@@ -11,21 +11,23 @@
 #include "mozilla/Logging.h"
 
 #include "nsISupports.h"
 #include "nsXPCOM.h"
 #include "nsContentPolicyUtils.h"
 #include "nsContentPolicy.h"
 #include "nsIURI.h"
 #include "nsIDocShell.h"
+#include "nsIDOMElement.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMWindow.h"
 #include "nsIContent.h"
 #include "nsILoadContext.h"
 #include "nsCOMArray.h"
+#include "nsContentUtils.h"
 
 using mozilla::LogLevel;
 
 NS_IMPL_ISUPPORTS(nsContentPolicy, nsIContentPolicy)
 
 static PRLogModuleInfo* gConPolLog;
 
 nsresult
--- a/dom/base/nsDOMMutationObserver.cpp
+++ b/dom/base/nsDOMMutationObserver.cpp
@@ -12,16 +12,18 @@
 #include "nsContentUtils.h"
 #include "nsThreadUtils.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsTextFragment.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/dom/Animation.h"
 #include "mozilla/dom/KeyframeEffect.h"
 
+using mozilla::dom::Animation;
+
 nsAutoTArray<nsRefPtr<nsDOMMutationObserver>, 4>*
   nsDOMMutationObserver::sScheduledMutationObservers = nullptr;
 
 nsDOMMutationObserver* nsDOMMutationObserver::sCurrentObserver = nullptr;
 
 uint32_t nsDOMMutationObserver::sMutationLevel = 0;
 uint64_t nsDOMMutationObserver::sCount = 0;
 
@@ -340,22 +342,22 @@ void nsMutationReceiver::NodeWillBeDestr
   NS_ASSERTION(!mParent, "Shouldn't have mParent here!");
   Disconnect(true);
 }
 
 void
 nsAnimationReceiver::RecordAnimationMutation(Animation* aAnimation,
                                              AnimationMutation aMutationType)
 {
-  KeyframeEffectReadOnly* effect = aAnimation->GetEffect();
+  mozilla::dom::KeyframeEffectReadOnly* effect = aAnimation->GetEffect();
   if (!effect) {
     return;
   }
 
-  Element* animationTarget = effect->GetTarget();
+  mozilla::dom::Element* animationTarget = effect->GetTarget();
   if (!animationTarget) {
     return;
   }
 
   if (!Animations() || !(Subtree() || animationTarget == Target()) ||
       animationTarget->ChromeOnlyAccess()) {
     return;
   }
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -3531,27 +3531,37 @@ nsDOMWindowUtils::RequestCompositorPrope
   }
 
   return NS_ERROR_NOT_AVAILABLE;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetOMTAStyle(nsIDOMElement* aElement,
                                const nsAString& aProperty,
+                               const nsAString& aPseudoElement,
                                nsAString& aResult)
 {
   MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome());
 
   nsCOMPtr<Element> element = do_QueryInterface(aElement);
   if (!element) {
     return NS_ERROR_INVALID_ARG;
   }
 
   nsRefPtr<nsROCSSPrimitiveValue> cssValue = nullptr;
   nsIFrame* frame = element->GetPrimaryFrame();
+  if (frame && !aPseudoElement.IsEmpty()) {
+    if (aPseudoElement.EqualsLiteral("::before")) {
+      frame = nsLayoutUtils::GetBeforeFrame(frame);
+    } else if (aPseudoElement.EqualsLiteral("::after")) {
+      frame = nsLayoutUtils::GetAfterFrame(frame);
+    } else {
+      return NS_ERROR_INVALID_ARG;
+    }
+  }
   if (frame && nsLayoutUtils::AreAsyncAnimationsEnabled()) {
     if (aProperty.EqualsLiteral("opacity")) {
       Layer* layer =
         FrameLayerBuilder::GetDedicatedLayer(frame,
                                              nsDisplayItem::TYPE_OPACITY);
       if (layer) {
         float value;
         ShadowLayerForwarder* forwarder = layer->Manager()->AsShadowForwarder();
--- a/dom/base/nsDocument.cpp
+++ b/dom/base/nsDocument.cpp
@@ -3899,16 +3899,19 @@ PLDHashOperator RequestDiscardEnumerator
 
 void
 nsDocument::DeleteShell()
 {
   mExternalResourceMap.HideViewers();
   if (IsEventHandlingEnabled()) {
     RevokeAnimationFrameNotifications();
   }
+  if (nsPresContext* presContext = mPresShell->GetPresContext()) {
+    presContext->RefreshDriver()->CancelPendingEvents(this);
+  }
 
   // When our shell goes away, request that all our images be immediately
   // discarded, so we don't carry around decoded image data for a document we
   // no longer intend to paint.
   mImageTracker.EnumerateRead(RequestDiscardEnumerator, nullptr);
 
   // Now that we no longer have a shell, we need to forget about any FontFace
   // objects for @font-face rules that came from the style set.
@@ -9209,24 +9212,41 @@ static bool
 NotifyPageHide(nsIDocument* aDocument, void* aData)
 {
   const bool* aPersistedPtr = static_cast<const bool*>(aData);
   aDocument->OnPageHide(*aPersistedPtr, nullptr);
   return true;
 }
 
 static void
+DispatchCustomEventWithFlush(nsINode* aTarget, const nsAString& aEventType,
+                             bool aBubbles, bool aOnlyChromeDispatch)
+{
+  nsCOMPtr<nsIDOMEvent> event;
+  NS_NewDOMEvent(getter_AddRefs(event), aTarget, nullptr, nullptr);
+  nsresult rv = event->InitEvent(aEventType, aBubbles, false);
+  if (NS_FAILED(rv)) {
+    return;
+  }
+  event->SetTrusted(true);
+  if (aOnlyChromeDispatch) {
+    event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
+  }
+  if (nsIPresShell* shell = aTarget->OwnerDoc()->GetShell()) {
+    shell->GetPresContext()->
+      RefreshDriver()->ScheduleEventDispatch(aTarget, event);
+  }
+}
+
+static void
 DispatchFullScreenChange(nsIDocument* aTarget)
 {
-  nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
-    new AsyncEventDispatcher(aTarget,
-                             NS_LITERAL_STRING("mozfullscreenchange"),
-                             true,
-                             false);
-  asyncDispatcher->PostDOMEvent();
+  DispatchCustomEventWithFlush(
+    aTarget, NS_LITERAL_STRING("mozfullscreenchange"),
+    /* Bubbles */ true, /* OnlyChrome */ false);
 }
 
 void
 nsDocument::OnPageHide(bool aPersisted,
                        EventTarget* aDispatchStartTarget)
 {
   // Send out notifications that our <link> elements are detached,
   // but only if this is not a full unload.
@@ -11162,21 +11182,20 @@ ExitFullscreenInDocTree(nsIDocument* aMa
   }
 
   NS_ASSERTION(!root->IsFullScreenDoc(),
     "Fullscreen root should no longer be a fullscreen doc...");
 
   // Dispatch MozDOMFullscreen:Exited to the last document in
   // the list since we want this event to follow the same path
   // MozDOMFullscreen:Entered dispatched.
-  nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
-    new AsyncEventDispatcher(changed.LastElement(),
-                             NS_LITERAL_STRING("MozDOMFullscreen:Exited"),
-                             true, true);
-  asyncDispatcher->PostDOMEvent();
+  nsContentUtils::DispatchEventOnlyToChrome(
+    changed.LastElement(), ToSupports(changed.LastElement()),
+    NS_LITERAL_STRING("MozDOMFullscreen:Exited"),
+    /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
   // Move the top-level window out of fullscreen mode.
   FullscreenRoots::Remove(root);
   SetWindowFullScreen(root, false);
 }
 
 /* static */
 void
 nsDocument::ExitFullscreen(nsIDocument* aDoc)
@@ -11245,19 +11264,20 @@ nsDocument::RestorePreviousFullScreenSta
       exitingFullscreen = false;
       break;
     }
   }
   if (exitingFullscreen) {
     // If we are fully exiting fullscreen, don't touch anything here,
     // just wait for the window to get out from fullscreen first.
     if (XRE_GetProcessType() == GeckoProcessType_Content) {
-      (new AsyncEventDispatcher(
-        this, NS_LITERAL_STRING("MozDOMFullscreen:Exit"),
-        /* Bubbles */ true, /* ChromeOnly */ true))->PostDOMEvent();
+      nsContentUtils::DispatchEventOnlyToChrome(
+        this, ToSupports(this), NS_LITERAL_STRING("MozDOMFullscreen:Exit"),
+        /* Bubbles */ true, /* Cancelable */ false,
+        /* DefaultAction */ nullptr);
     } else {
       SetWindowFullScreen(this, false);
     }
     return;
   }
 
   // If fullscreen mode is updated the pointer should be unlocked
   UnlockPointer();
@@ -11290,21 +11310,19 @@ nsDocument::RestorePreviousFullScreenSta
       if (fullScreenDoc != doc) {
         // We've popped so enough off the stack that we've rolled back to
         // a fullscreen element in a parent document. If this document isn't
         // approved for fullscreen, or if it's cross origin, dispatch an
         // event to chrome so it knows to show the authorization/warning UI.
         if (!nsContentUtils::HaveEqualPrincipals(fullScreenDoc, doc) ||
             (!nsContentUtils::IsSitePermAllow(doc->NodePrincipal(), "fullscreen") &&
              !static_cast<nsDocument*>(doc)->mIsApprovedForFullscreen)) {
-          nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
-            new AsyncEventDispatcher(
-                doc, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"),
-                /* Bubbles */ true, /* ChromeOnly */ true);
-          asyncDispatcher->PostDOMEvent();
+          DispatchCustomEventWithFlush(
+            doc, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"),
+            /* Bubbles */ true, /* ChromeOnly */ true);
         }
       }
       break;
     }
   }
 
   MOZ_ASSERT(doc, "If we were going to exit from fullscreen on all documents "
              "in this doctree, we should've asked the window to exit first "
@@ -11686,19 +11704,19 @@ nsDocument::RequestFullScreen(UniquePtr<
   if (!FullscreenElementReadyCheck(elem, aRequest->mIsCallerChrome)) {
     return;
   }
 
   sPendingFullscreenRequests.insertBack(aRequest.release());
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     // If we are not the top level process, dispatch an event to make
     // our parent process go fullscreen first.
-    (new AsyncEventDispatcher(
-       this, NS_LITERAL_STRING("MozDOMFullscreen:Request"),
-       /* Bubbles */ true, /* ChromeOnly */ true))->PostDOMEvent();
+    nsContentUtils::DispatchEventOnlyToChrome(
+      this, ToSupports(this), NS_LITERAL_STRING("MozDOMFullscreen:Request"),
+      /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
   } else {
     // Make the window fullscreen.
     FullscreenRequest* lastRequest = sPendingFullscreenRequests.getLast();
     SetWindowFullScreen(this, true, lastRequest->mVRHMDDevice);
   }
 }
 
 /* static */ bool
@@ -11815,65 +11833,61 @@ nsDocument::ApplyFullscreen(const Fullsc
       // We've reached either the root, or a point in the doctree where the
       // new full-screen element container is the same as the previous
       // full-screen element's container. No more changes need to be made
       // to the full-screen stacks of documents further up the tree.
       break;
     }
   }
 
-  // Dispatch "mozfullscreenchange" events. Note this loop is in reverse
-  // order so that the events for the root document arrives before the leaf
-  // document, as required by the spec.
-  for (uint32_t i = 0; i < changed.Length(); ++i) {
-    DispatchFullScreenChange(changed[changed.Length() - i - 1]);
-  }
-
   // If this document hasn't already been approved in this session,
   // check to see if the user has granted the fullscreen access
   // to the document's principal's host, if it has one. Note that documents
   // in web apps which are the same origin as the web app are considered
   // trusted and so are automatically approved.
   if (!mIsApprovedForFullscreen) {
     mIsApprovedForFullscreen =
       !Preferences::GetBool("full-screen-api.approval-required") ||
       NodePrincipal()->GetAppStatus() >= nsIPrincipal::APP_STATUS_INSTALLED ||
       nsContentUtils::IsSitePermAllow(NodePrincipal(), "fullscreen");
   }
 
+  FullscreenRoots::Add(this);
+
   // If it is the first entry of the fullscreen, trigger an event so
   // that the UI can response to this change, e.g. hide chrome, or
   // notifying parent process to enter fullscreen. Note that chrome
   // code may also want to listen to MozDOMFullscreen:NewOrigin event
   // to pop up warning/approval UI.
   if (!previousFullscreenDoc) {
-    nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
-      new AsyncEventDispatcher(
-        elem, NS_LITERAL_STRING("MozDOMFullscreen:Entered"),
-        /* Bubbles */ true, /* ChromeOnly */ true);
-    asyncDispatcher->PostDOMEvent();
+    nsContentUtils::DispatchEventOnlyToChrome(
+      this, ToSupports(elem), NS_LITERAL_STRING("MozDOMFullscreen:Entered"),
+      /* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
   }
 
   // The origin which is fullscreen gets changed. Trigger an event so
   // that the chrome knows to pop up a warning/approval UI. Note that
   // previousFullscreenDoc == nullptr upon first entry, so we always
   // take this path on the first entry. Also note that, in a multi-
   // process browser, the code in content process is responsible for
   // sending message with the origin to its parent, and the parent
   // shouldn't rely on this event itself.
   if (aRequest.mShouldNotifyNewOrigin &&
       !nsContentUtils::HaveEqualPrincipals(previousFullscreenDoc, this)) {
-    nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
-      new AsyncEventDispatcher(
-        this, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"),
-        /* Bubbles */ true, /* ChromeOnly */ true);
-    asyncDispatcher->PostDOMEvent();
-  }
-
-  FullscreenRoots::Add(this);
+    DispatchCustomEventWithFlush(
+      this, NS_LITERAL_STRING("MozDOMFullscreen:NewOrigin"),
+      /* Bubbles */ true, /* ChromeOnly */ true);
+  }
+
+  // Dispatch "mozfullscreenchange" events. Note this loop is in reverse
+  // order so that the events for the root document arrives before the leaf
+  // document, as required by the spec.
+  for (uint32_t i = 0; i < changed.Length(); ++i) {
+    DispatchFullScreenChange(changed[changed.Length() - i - 1]);
+  }
 }
 
 NS_IMETHODIMP
 nsDocument::GetMozFullScreenElement(nsIDOMElement **aFullScreenElement)
 {
   ErrorResult rv;
   Element* el = GetMozFullScreenElement(rv);
   if (rv.Failed()) {
--- a/dom/base/nsHostObjectProtocolHandler.cpp
+++ b/dom/base/nsHostObjectProtocolHandler.cpp
@@ -201,17 +201,17 @@ class BlobURLsReporter final : public ns
   }
 
   static PLDHashOperator ReportCallback(nsCStringHashKey::KeyType aKey,
                                         DataInfo* aInfo,
                                         void* aUserArg)
   {
     EnumArg* envp = static_cast<EnumArg*>(aUserArg);
     nsCOMPtr<nsIDOMBlob> tmp = do_QueryInterface(aInfo->mObject);
-    nsRefPtr<Blob> blob = static_cast<Blob*>(tmp.get());
+    nsRefPtr<mozilla::dom::Blob> blob = static_cast<mozilla::dom::Blob*>(tmp.get());
 
     if (blob) {
       NS_NAMED_LITERAL_CSTRING
         (desc, "A blob URL allocated with URL.createObjectURL; the referenced "
          "blob cannot be freed until all URLs for it have been explicitly "
          "invalidated with URL.revokeObjectURL.");
       nsAutoCString path, url, owner, specialDesc;
       nsCOMPtr<nsIURI> principalURI;
--- a/dom/base/nsHostObjectURI.cpp
+++ b/dom/base/nsHostObjectURI.cpp
@@ -101,17 +101,17 @@ nsHostObjectURI::Serialize(mozilla::ipc:
     PrincipalInfo info;
     nsresult rv = PrincipalToPrincipalInfo(mPrincipal, &info);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return;
     }
 
     hostParams.principal() = info;
   } else {
-    hostParams.principal() = void_t();
+    hostParams.principal() = mozilla::void_t();
   }
 
   aParams = hostParams;
 }
 
 bool
 nsHostObjectURI::Deserialize(const mozilla::ipc::URIParams& aParams)
 {
--- a/dom/base/nsIGlobalObject.cpp
+++ b/dom/base/nsIGlobalObject.cpp
@@ -1,16 +1,18 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIGlobalObject.h"
 #include "nsContentUtils.h"
+#include "nsThreadUtils.h"
+#include "nsHostObjectProtocolHandler.h"
 
 nsIGlobalObject::~nsIGlobalObject()
 {
   UnlinkHostObjectURIs();
 }
 
 nsIPrincipal*
 nsIGlobalObject::PrincipalOrNull()
--- a/dom/base/nsNoDataProtocolContentPolicy.cpp
+++ b/dom/base/nsNoDataProtocolContentPolicy.cpp
@@ -12,16 +12,17 @@
 
 #include "nsNoDataProtocolContentPolicy.h"
 #include "nsIDOMWindow.h"
 #include "nsString.h"
 #include "nsIProtocolHandler.h"
 #include "nsIIOService.h"
 #include "nsIExternalProtocolHandler.h"
 #include "nsNetUtil.h"
+#include "nsContentUtils.h"
 
 NS_IMPL_ISUPPORTS(nsNoDataProtocolContentPolicy, nsIContentPolicy)
 
 NS_IMETHODIMP
 nsNoDataProtocolContentPolicy::ShouldLoad(uint32_t aContentType,
                                           nsIURI *aContentLocation,
                                           nsIURI *aRequestingLocation,
                                           nsISupports *aRequestingContext,
--- a/dom/bluetooth/BluetoothCommon.h
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -73,22 +73,16 @@ extern bool gBluetoothDebugFlag;
     }                                                                \
   } while(0)
 
 #define BT_LOGR(msg, ...) printf("%s: " msg, __FUNCTION__, ##__VA_ARGS__)
 #define BT_WARNING(msg, ...) printf("%s: " msg, __FUNCTION__, ##__VA_ARGS__)
 #endif
 
 /**
- * Prints 'R'ELEASE build logs for WebBluetooth API v2.
- */
-#define BT_API2_LOGR(msg, ...)                                       \
-  BT_LOGR("[WEBBT-API2] " msg, ##__VA_ARGS__)
-
-/**
  * Wrap literal name and value into a BluetoothNamedValue
  * and append it to the array.
  */
 #define BT_APPEND_NAMED_VALUE(array, name, value)                    \
   array.AppendElement(BluetoothNamedValue(NS_LITERAL_STRING(name),   \
                                           BluetoothValue(value)))
 
 /**
@@ -136,29 +130,29 @@ extern bool gBluetoothDebugFlag;
   } while(0)                                                         \
 
 /**
  * Resolve |promise| with |ret| if |x| is false.
  */
 #define BT_ENSURE_TRUE_RESOLVE(x, promise, ret)                      \
   do {                                                               \
     if (MOZ_UNLIKELY(!(x))) {                                        \
-      BT_API2_LOGR("BT_ENSURE_TRUE_RESOLVE(" #x ") failed");         \
+      BT_LOGR("BT_ENSURE_TRUE_RESOLVE(" #x ") failed");              \
       (promise)->MaybeResolve(ret);                                  \
       return (promise).forget();                                     \
     }                                                                \
   } while(0)
 
 /**
  * Reject |promise| with |ret| if |x| is false.
  */
 #define BT_ENSURE_TRUE_REJECT(x, promise, ret)                       \
   do {                                                               \
     if (MOZ_UNLIKELY(!(x))) {                                        \
-      BT_API2_LOGR("BT_ENSURE_TRUE_REJECT(" #x ") failed");          \
+      BT_LOGR("BT_ENSURE_TRUE_REJECT(" #x ") failed");               \
       (promise)->MaybeReject(ret);                                   \
       return (promise).forget();                                     \
     }                                                                \
   } while(0)
 
 #define BEGIN_BLUETOOTH_NAMESPACE \
   namespace mozilla { namespace dom { namespace bluetooth {
 #define END_BLUETOOTH_NAMESPACE \
--- a/dom/bluetooth/BluetoothInterface.h
+++ b/dom/bluetooth/BluetoothInterface.h
@@ -675,17 +675,17 @@ public:
   virtual void WriteDescriptor() { }
 
   virtual void ExecuteWrite() { }
 
   virtual void RegisterNotification() { }
   virtual void DeregisterNotification() { }
 
   virtual void ReadRemoteRssi() { }
-  virtual void GetDeviceType() { }
+  virtual void GetDeviceType(BluetoothTypeOfDevice type) { }
   virtual void SetAdvData() { }
   virtual void TestCommand() { }
 
 protected:
   virtual ~BluetoothGattClientResultHandler() { }
 };
 
 // TODO: Add GattServerResultHandler
--- a/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.cpp
@@ -870,24 +870,47 @@ BluetoothDaemonGattModule::ClientReadRem
   const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
   BluetoothGattClientResultHandler* aRes)
 {
   ClientResultRunnable::Dispatch(
     aRes, &BluetoothGattClientResultHandler::ReadRemoteRssi,
     UnpackPDUInitOp(aPDU));
 }
 
+// Init operator class for ClientGetDeviceTypeRsp
+class BluetoothDaemonGattModule::ClientGetDeviceTypeInitOp final
+  : private PDUInitOp
+{
+public:
+  ClientGetDeviceTypeInitOp(DaemonSocketPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (BluetoothTypeOfDevice& aArg1) const
+  {
+    /* Read device type */
+    nsresult rv = UnpackPDU(
+      GetPDU(), UnpackConversion<uint8_t, BluetoothTypeOfDevice>(aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
 void
 BluetoothDaemonGattModule::ClientGetDeviceTypeRsp(
   const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
   BluetoothGattClientResultHandler* aRes)
 {
-  ClientResultRunnable::Dispatch(
+  ClientGetDeviceTypeResultRunnable::Dispatch(
     aRes, &BluetoothGattClientResultHandler::GetDeviceType,
-    UnpackPDUInitOp(aPDU));
+    ClientGetDeviceTypeInitOp(aPDU));
 }
 
 void
 BluetoothDaemonGattModule::ClientSetAdvDataRsp(
   const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
   BluetoothGattClientResultHandler* aRes)
 {
   ClientResultRunnable::Dispatch(
--- a/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonGattInterface.h
@@ -222,16 +222,20 @@ protected:
 
   //
   // Responses
   //
 
   typedef BluetoothResultRunnable0<BluetoothGattClientResultHandler, void>
     ClientResultRunnable;
 
+  typedef BluetoothResultRunnable1<BluetoothGattClientResultHandler, void,
+                                   BluetoothTypeOfDevice, BluetoothTypeOfDevice>
+    ClientGetDeviceTypeResultRunnable;
+
   typedef BluetoothResultRunnable0<BluetoothGattResultHandler, void>
     ResultRunnable;
 
   typedef BluetoothResultRunnable1<BluetoothGattResultHandler, void,
                                    BluetoothStatus, BluetoothStatus>
     ErrorRunnable;
 
   void ErrorRsp(const DaemonSocketPDUHeader& aHeader,
@@ -450,16 +454,17 @@ protected:
   typedef BluetoothNotificationRunnable2<
     ClientNotificationHandlerWrapper, void,
     BluetoothGattStatus, int>
     ClientListenNotification;
 
   class ClientScanResultInitOp;
   class ClientConnectDisconnectInitOp;
   class ClientReadRemoteRssiInitOp;
+  class ClientGetDeviceTypeInitOp;
 
   void ClientRegisterNtf(const DaemonSocketPDUHeader& aHeader,
                                DaemonSocketPDU& aPDU);
 
   void ClientScanResultNtf(const DaemonSocketPDUHeader& aHeader,
                            DaemonSocketPDU& aPDU);
 
   void ClientConnectNtf(const DaemonSocketPDUHeader& aHeader,
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
@@ -398,16 +398,22 @@ Convert(uint8_t aIn, BluetoothHandsfreeW
   if (NS_WARN_IF(aIn >= MOZ_ARRAY_LENGTH(sWbsConfig))) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sWbsConfig[aIn];
   return NS_OK;
 }
 
 nsresult
+Convert(uint8_t aIn, BluetoothTypeOfDevice& aOut)
+{
+  return Convert((int32_t)aIn, aOut);
+}
+
+nsresult
 Convert(uint8_t aIn, BluetoothPropertyType& aOut)
 {
   static const BluetoothPropertyType sPropertyType[] = {
     CONVERT(0x00, static_cast<BluetoothPropertyType>(0)), // invalid, required by gcc
     CONVERT(0x01, PROPERTY_BDNAME),
     CONVERT(0x02, PROPERTY_BDADDR),
     CONVERT(0x03, PROPERTY_UUIDS),
     CONVERT(0x04, PROPERTY_CLASS_OF_DEVICE),
--- a/dom/bluetooth/bluedroid/BluetoothGattHALInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothGattHALInterface.cpp
@@ -10,16 +10,21 @@
 BEGIN_BLUETOOTH_NAMESPACE
 
 typedef
   BluetoothHALInterfaceRunnable0<BluetoothGattClientResultHandler, void>
   BluetoothGattClientHALResultRunnable;
 
 typedef
   BluetoothHALInterfaceRunnable1<BluetoothGattClientResultHandler, void,
+                                 BluetoothTypeOfDevice, BluetoothTypeOfDevice>
+  BluetoothGattClientGetDeviceTypeHALResultRunnable;
+
+typedef
+  BluetoothHALInterfaceRunnable1<BluetoothGattClientResultHandler, void,
                                  BluetoothStatus, BluetoothStatus>
   BluetoothGattClientHALErrorRunnable;
 
 typedef
   BluetoothHALInterfaceRunnable0<BluetoothGattResultHandler, void>
   BluetoothGattHALResultRunnable;
 
 typedef
@@ -45,16 +50,45 @@ DispatchBluetoothGattClientHALResult(
   }
   nsresult rv = NS_DispatchToMainThread(runnable);
   if (NS_FAILED(rv)) {
     BT_WARNING("NS_DispatchToMainThread failed: %X", rv);
   }
   return rv;
 }
 
+template <typename ResultRunnable, typename Tin1, typename Arg1>
+static nsresult
+DispatchBluetoothGattClientHALResult(
+  BluetoothGattClientResultHandler* aRes,
+  void (BluetoothGattClientResultHandler::*aMethod)(Arg1),
+  Tin1 aArg1,
+  BluetoothStatus aStatus)
+{
+  MOZ_ASSERT(aRes);
+
+  nsRunnable* runnable;
+  Arg1 arg1;
+
+  if (aStatus != STATUS_SUCCESS) {
+    runnable = new BluetoothGattClientHALErrorRunnable(aRes,
+      &BluetoothGattClientResultHandler::OnError, aStatus);
+  } else if (NS_FAILED(Convert(aArg1, arg1))) {
+    runnable = new BluetoothGattClientHALErrorRunnable(aRes,
+      &BluetoothGattClientResultHandler::OnError, STATUS_PARM_INVALID);
+  } else {
+    runnable = new ResultRunnable(aRes, aMethod, arg1);
+  }
+  nsresult rv = NS_DispatchToMainThread(runnable);
+  if (NS_FAILED(rv)) {
+    BT_WARNING("NS_DispatchToMainThread failed: %X", rv);
+  }
+  return rv;
+}
+
 static nsresult
 DispatchBluetoothGattHALResult(
   BluetoothGattResultHandler* aRes,
   void (BluetoothGattResultHandler::*aMethod)(),
   BluetoothStatus aStatus)
 {
   MOZ_ASSERT(aRes);
 
@@ -1002,32 +1036,33 @@ BluetoothGattClientHALInterface::ReadRem
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothGattClientHALInterface::GetDeviceType(
   const nsAString& aBdAddr, BluetoothGattClientResultHandler* aRes)
 {
-  int status;
+  int status = BT_STATUS_FAIL;
+  bt_device_type_t type = BT_DEVICE_DEVTYPE_BLE;
 #if ANDROID_VERSION >= 19
   bt_bdaddr_t bdAddr;
 
   if (NS_SUCCEEDED(Convert(aBdAddr, bdAddr))) {
-    status = mInterface->get_device_type(&bdAddr);
-  } else {
-    status = BT_STATUS_PARM_INVALID;
+    status = BT_STATUS_SUCCESS;
+    type = static_cast<bt_device_type_t>(mInterface->get_device_type(&bdAddr));
   }
 #else
   status = BT_STATUS_UNSUPPORTED;
 #endif
 
   if (aRes) {
-    DispatchBluetoothGattClientHALResult(
-      aRes, &BluetoothGattClientResultHandler::GetDeviceType,
+    DispatchBluetoothGattClientHALResult<
+      BluetoothGattClientGetDeviceTypeHALResultRunnable>(
+      aRes, &BluetoothGattClientResultHandler::GetDeviceType, type,
       ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
 BluetoothGattClientHALInterface::SetAdvData(
   int aServerIf, bool aIsScanRsp, bool aIsNameIncluded,
   bool aIsTxPowerIncluded, int aMinInterval, int aMaxInterval, int aApperance,
--- a/dom/bluetooth/bluedroid/BluetoothGattManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothGattManager.cpp
@@ -1350,34 +1350,32 @@ BluetoothGattManager::WriteDescriptorVal
 //
 // Notification Handlers
 //
 void
 BluetoothGattManager::RegisterClientNotification(BluetoothGattStatus aStatus,
                                                  int aClientIf,
                                                  const BluetoothUuid& aAppUuid)
 {
-  BT_API2_LOGR("Client Registered, clientIf = %d", aClientIf);
   MOZ_ASSERT(NS_IsMainThread());
 
   nsString uuid;
   UuidToString(aAppUuid, uuid);
 
   size_t index = sClients->IndexOf(uuid, 0 /* Start */, UuidComparator());
   NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
 
   BluetoothService* bs = BluetoothService::Get();
   NS_ENSURE_TRUE_VOID(bs);
 
   if (aStatus != GATT_STATUS_SUCCESS) {
-    BT_API2_LOGR(
-      "RegisterClient failed, clientIf = %d, status = %d, appUuid = %s",
-      aClientIf, aStatus, NS_ConvertUTF16toUTF8(uuid).get());
+    BT_LOGD("RegisterClient failed: clientIf = %d, status = %d, appUuid = %s",
+            aClientIf, aStatus, NS_ConvertUTF16toUTF8(uuid).get());
 
     // Notify BluetoothGatt for client disconnected
     bs->DistributeSignal(
       NS_LITERAL_STRING(GATT_CONNECTION_STATE_CHANGED_ID),
       uuid, BluetoothValue(false)); // Disconnected
 
     if (client->mStartLeScanRunnable) {
       // Reject the LE scan request
@@ -1413,63 +1411,99 @@ BluetoothGattManager::RegisterClientNoti
     // Client just registered, proceed remaining connect request.
     sBluetoothGattClientInterface->Connect(
       aClientIf, client->mDeviceAddr, true /* direct connect */,
       TRANSPORT_AUTO,
       new ConnectResultHandler(client));
   }
 }
 
+class BluetoothGattManager::ScanDeviceTypeResultHandler final
+  : public BluetoothGattClientResultHandler
+{
+public:
+  ScanDeviceTypeResultHandler(const nsAString& aBdAddr, int aRssi,
+                              const BluetoothGattAdvData& aAdvData)
+  : mBdAddr(aBdAddr)
+  , mRssi(static_cast<int32_t>(aRssi))
+  {
+    mAdvData.AppendElements(aAdvData.mAdvData, sizeof(aAdvData.mAdvData));
+  }
+
+  void GetDeviceType(BluetoothTypeOfDevice type)
+  {
+    DistributeSignalDeviceFound(type);
+  }
+
+  void OnError(BluetoothStatus aStatus) override
+  {
+    DistributeSignalDeviceFound(TYPE_OF_DEVICE_BLE);
+  }
+
+private:
+  void DistributeSignalDeviceFound(BluetoothTypeOfDevice type)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    InfallibleTArray<BluetoothNamedValue> properties;
+
+    BT_APPEND_NAMED_VALUE(properties, "Address", mBdAddr);
+    BT_APPEND_NAMED_VALUE(properties, "Rssi", mRssi);
+    BT_APPEND_NAMED_VALUE(properties, "GattAdv", mAdvData);
+    BT_APPEND_NAMED_VALUE(properties, "Type", static_cast<uint32_t>(type));
+
+    BluetoothService* bs = BluetoothService::Get();
+    NS_ENSURE_TRUE_VOID(bs);
+
+    bs->DistributeSignal(NS_LITERAL_STRING("LeDeviceFound"),
+                         NS_LITERAL_STRING(KEY_ADAPTER),
+                         BluetoothValue(properties));
+  }
+
+  nsString mBdAddr;
+  int32_t mRssi;
+  nsTArray<uint8_t> mAdvData;
+};
+
 void
 BluetoothGattManager::ScanResultNotification(
   const nsAString& aBdAddr, int aRssi,
   const BluetoothGattAdvData& aAdvData)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  InfallibleTArray<BluetoothNamedValue> properties;
-
-  nsTArray<uint8_t> advData;
-  advData.AppendElements(aAdvData.mAdvData, sizeof(aAdvData.mAdvData));
+  NS_ENSURE_TRUE_VOID(sBluetoothGattClientInterface);
 
-  BT_APPEND_NAMED_VALUE(properties, "Address", nsString(aBdAddr));
-  BT_APPEND_NAMED_VALUE(properties, "Rssi", static_cast<int32_t>(aRssi));
-  BT_APPEND_NAMED_VALUE(properties, "GattAdv", advData);
-  BT_APPEND_NAMED_VALUE(properties, "Type",
-    static_cast<uint32_t>(TYPE_OF_DEVICE_BLE));
-
-  BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE_VOID(bs);
-
-  bs->DistributeSignal(NS_LITERAL_STRING("LeDeviceFound"),
-                       NS_LITERAL_STRING(KEY_ADAPTER),
-                       BluetoothValue(properties));
+  // Distribute "LeDeviceFound" signal after we know the corresponding
+  // BluetoothTypeOfDevice of the device
+  sBluetoothGattClientInterface->GetDeviceType(
+    aBdAddr,
+    new ScanDeviceTypeResultHandler(aBdAddr, aRssi, aAdvData));
 }
 
 void
 BluetoothGattManager::ConnectNotification(int aConnId,
                                           BluetoothGattStatus aStatus,
                                           int aClientIf,
                                           const nsAString& aDeviceAddr)
 {
-  BT_API2_LOGR();
   MOZ_ASSERT(NS_IsMainThread());
 
   BluetoothService* bs = BluetoothService::Get();
   NS_ENSURE_TRUE_VOID(bs);
 
   size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
                                    ClientIfComparator());
   NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
 
   if (aStatus != GATT_STATUS_SUCCESS) {
-    BT_API2_LOGR("Connect failed, clientIf = %d, connId = %d, status = %d",
-                 aClientIf, aConnId, aStatus);
+    BT_LOGD("Connect failed: clientIf = %d, connId = %d, status = %d",
+            aClientIf, aConnId, aStatus);
 
     // Notify BluetoothGatt that the client remains disconnected
     bs->DistributeSignal(
       NS_LITERAL_STRING(GATT_CONNECTION_STATE_CHANGED_ID),
       client->mAppUuid,
       BluetoothValue(false)); // Disconnected
 
     // Reject the connect request
@@ -1498,17 +1532,16 @@ BluetoothGattManager::ConnectNotificatio
 }
 
 void
 BluetoothGattManager::DisconnectNotification(int aConnId,
                                              BluetoothGattStatus aStatus,
                                              int aClientIf,
                                              const nsAString& aDeviceAddr)
 {
-  BT_API2_LOGR();
   MOZ_ASSERT(NS_IsMainThread());
 
   BluetoothService* bs = BluetoothService::Get();
   NS_ENSURE_TRUE_VOID(bs);
 
   size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
                                    ClientIfComparator());
   NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
@@ -2025,32 +2058,31 @@ BluetoothGattManager::ExecuteWriteNotifi
 { }
 
 void
 BluetoothGattManager::ReadRemoteRssiNotification(int aClientIf,
                                                  const nsAString& aBdAddr,
                                                  int aRssi,
                                                  BluetoothGattStatus aStatus)
 {
-  BT_API2_LOGR();
   MOZ_ASSERT(NS_IsMainThread());
 
   BluetoothService* bs = BluetoothService::Get();
   NS_ENSURE_TRUE_VOID(bs);
 
   size_t index = sClients->IndexOf(aClientIf, 0 /* Start */,
                                    ClientIfComparator());
   NS_ENSURE_TRUE_VOID(index != sClients->NoIndex);
 
   nsRefPtr<BluetoothGattClient> client = sClients->ElementAt(index);
 
   if (aStatus != GATT_STATUS_SUCCESS) { // operation failed
-    BT_API2_LOGR("ReadRemoteRssi failed, clientIf = %d, bdAddr = %s, " \
-                 "rssi = %d, status = %d", aClientIf,
-                 NS_ConvertUTF16toUTF8(aBdAddr).get(), aRssi, (int)aStatus);
+    BT_LOGD("ReadRemoteRssi failed: clientIf = %d, bdAddr = %s, rssi = %d, " \
+            "status = %d", aClientIf, NS_ConvertUTF16toUTF8(aBdAddr).get(),
+            aRssi, (int)aStatus);
 
     // Reject the read remote rssi request
     if (client->mReadRemoteRssiRunnable) {
       DispatchReplyError(client->mReadRemoteRssiRunnable,
                          NS_LITERAL_STRING("ReadRemoteRssi failed"));
       client->mReadRemoteRssiRunnable = nullptr;
     }
 
--- a/dom/bluetooth/bluedroid/BluetoothGattManager.h
+++ b/dom/bluetooth/bluedroid/BluetoothGattManager.h
@@ -105,16 +105,17 @@ private:
   class DiscoverResultHandler;
   class ReadRemoteRssiResultHandler;
   class RegisterNotificationsResultHandler;
   class DeregisterNotificationsResultHandler;
   class ReadCharacteristicValueResultHandler;
   class WriteCharacteristicValueResultHandler;
   class ReadDescriptorValueResultHandler;
   class WriteDescriptorValueResultHandler;
+  class ScanDeviceTypeResultHandler;
 
   BluetoothGattManager();
 
   void HandleShutdown();
 
   void RegisterClientNotification(BluetoothGattStatus aStatus,
                                   int aClientIf,
                                   const BluetoothUuid& aAppUuid) override;
--- a/dom/bluetooth/bluetooth2/BluetoothAdapter.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothAdapter.cpp
@@ -561,18 +561,16 @@ BluetoothAdapter::StartDiscovery(ErrorRe
    */
   BT_ENSURE_TRUE_REJECT(!mDiscovering, promise, NS_ERROR_DOM_INVALID_STATE_ERR);
   BT_ENSURE_TRUE_REJECT(mState == BluetoothAdapterState::Enabled,
                         promise,
                         NS_ERROR_DOM_INVALID_STATE_ERR);
   BluetoothService* bs = BluetoothService::Get();
   BT_ENSURE_TRUE_REJECT(bs, promise, NS_ERROR_NOT_AVAILABLE);
 
-  BT_API2_LOGR();
-
   // Clear unpaired devices before start discovery
   for (int32_t i = mDevices.Length() - 1; i >= 0; i--) {
     if (!mDevices[i]->Paired()) {
       mDevices.RemoveElementAt(i);
     }
   }
 
   // Return BluetoothDiscoveryHandle in StartDiscoveryTask
@@ -603,18 +601,16 @@ BluetoothAdapter::StopDiscovery(ErrorRes
    */
   BT_ENSURE_TRUE_RESOLVE(mDiscovering, promise, JS::UndefinedHandleValue);
   BT_ENSURE_TRUE_REJECT(mState == BluetoothAdapterState::Enabled,
                         promise,
                         NS_ERROR_DOM_INVALID_STATE_ERR);
   BluetoothService* bs = BluetoothService::Get();
   BT_ENSURE_TRUE_REJECT(bs, promise, NS_ERROR_NOT_AVAILABLE);
 
-  BT_API2_LOGR();
-
   nsRefPtr<BluetoothReplyRunnable> result =
     new BluetoothVoidReplyRunnable(nullptr /* DOMRequest */,
                                    promise,
                                    NS_LITERAL_STRING("StopDiscovery"));
   bs->StopDiscoveryInternal(result);
 
   return promise.forget();
 }
@@ -1188,18 +1184,16 @@ BluetoothAdapter::DispatchAttributeEvent
 
   DispatchTrustedEvent(event);
 }
 
 void
 BluetoothAdapter::DispatchDeviceEvent(const nsAString& aType,
                                       const BluetoothDeviceEventInit& aInit)
 {
-  BT_API2_LOGR("aType (%s)", NS_ConvertUTF16toUTF8(aType).get());
-
   nsRefPtr<BluetoothDeviceEvent> event =
     BluetoothDeviceEvent::Constructor(this, aType, aInit);
   DispatchTrustedEvent(event);
 }
 
 void
 BluetoothAdapter::DispatchEmptyEvent(const nsAString& aType)
 {
--- a/dom/bluetooth/bluetooth2/BluetoothGatt.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothGatt.cpp
@@ -243,17 +243,17 @@ BluetoothGatt::DiscoverServices(ErrorRes
   bs->DiscoverGattServicesInternal(mAppUuid, result);
 
   return promise.forget();
 }
 
 void
 BluetoothGatt::UpdateConnectionState(BluetoothConnectionState aState)
 {
-  BT_API2_LOGR("GATT connection state changes to: %d", int(aState));
+  BT_LOGR("GATT connection state changes to: %d", int(aState));
   mConnectionState = aState;
 
   // Dispatch connectionstatechanged event to application
   nsCOMPtr<nsIDOMEvent> event;
   nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
   NS_ENSURE_SUCCESS_VOID(rv);
 
   rv = event->InitEvent(NS_LITERAL_STRING(GATT_CONNECTION_STATE_CHANGED_ID),
--- a/dom/bluetooth/bluetooth2/BluetoothManager.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothManager.cpp
@@ -76,17 +76,16 @@ class GetAdaptersTask : public Bluetooth
     // Extract the array of all adapters' properties
     const BluetoothValue& adaptersProperties =
       mReply->get_BluetoothReplySuccess().value();
     NS_ENSURE_TRUE(adaptersProperties.type() ==
                    BluetoothValue::TArrayOfBluetoothNamedValue, false);
 
     const InfallibleTArray<BluetoothNamedValue>& adaptersPropertiesArray =
       adaptersProperties.get_ArrayOfBluetoothNamedValue();
-    BT_API2_LOGR("GetAdaptersTask: len[%d]", adaptersPropertiesArray.Length());
 
     // Append a BluetoothAdapter into adapters array for each properties array
     uint32_t numAdapters = adaptersPropertiesArray.Length();
     for (uint32_t i = 0; i < numAdapters; i++) {
       MOZ_ASSERT(adaptersPropertiesArray[i].name().EqualsLiteral("Adapter"));
 
       const BluetoothValue& properties = adaptersPropertiesArray[i].value();
       mManager->AppendAdapter(properties);
@@ -109,17 +108,16 @@ private:
 
 BluetoothManager::BluetoothManager(nsPIDOMWindow *aWindow)
   : DOMEventTargetHelper(aWindow)
   , mDefaultAdapterIndex(-1)
 {
   MOZ_ASSERT(aWindow);
 
   RegisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_MANAGER), this);
-  BT_API2_LOGR("aWindow %p", aWindow);
 
   // Query adapters list from bluetooth backend
   BluetoothService* bs = BluetoothService::Get();
   NS_ENSURE_TRUE_VOID(bs);
 
   nsRefPtr<BluetoothReplyRunnable> result = new GetAdaptersTask(this);
   NS_ENSURE_SUCCESS_VOID(bs->GetAdaptersInternal(result));
 }
@@ -134,18 +132,16 @@ BluetoothManager::DisconnectFromOwner()
 {
   DOMEventTargetHelper::DisconnectFromOwner();
   UnregisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_MANAGER), this);
 }
 
 BluetoothAdapter*
 BluetoothManager::GetDefaultAdapter()
 {
-  BT_API2_LOGR("mDefaultAdapterIndex: %d", mDefaultAdapterIndex);
-
   return DefaultAdapterExists() ? mAdapters[mDefaultAdapterIndex] : nullptr;
 }
 
 void
 BluetoothManager::AppendAdapter(const BluetoothValue& aValue)
 {
   MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
 
@@ -180,17 +176,16 @@ BluetoothManager::Create(nsPIDOMWindow* 
   nsRefPtr<BluetoothManager> manager = new BluetoothManager(aWindow);
   return manager.forget();
 }
 
 void
 BluetoothManager::HandleAdapterAdded(const BluetoothValue& aValue)
 {
   MOZ_ASSERT(aValue.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
-  BT_API2_LOGR();
 
   AppendAdapter(aValue);
 
   // Notify application of added adapter
   BluetoothAdapterEventInit init;
   init.mAdapter = mAdapters.LastElement();
   DispatchAdapterEvent(NS_LITERAL_STRING("adapteradded"), init);
 }
@@ -225,39 +220,34 @@ BluetoothManager::HandleAdapterRemoved(c
   }
 }
 
 void
 BluetoothManager::ReselectDefaultAdapter()
 {
   // Select the first of existing/remaining adapters as default adapter
   mDefaultAdapterIndex = mAdapters.IsEmpty() ? -1 : 0;
-  BT_API2_LOGR("mAdapters length: %d => NEW mDefaultAdapterIndex: %d",
-               mAdapters.Length(), mDefaultAdapterIndex);
 
   // Notify application of default adapter change
   DispatchAttributeEvent();
 }
 
 void
 BluetoothManager::DispatchAdapterEvent(const nsAString& aType,
                                        const BluetoothAdapterEventInit& aInit)
 {
-  BT_API2_LOGR("aType (%s)", NS_ConvertUTF16toUTF8(aType).get());
-
   nsRefPtr<BluetoothAdapterEvent> event =
     BluetoothAdapterEvent::Constructor(this, aType, aInit);
   DispatchTrustedEvent(event);
 }
 
 void
 BluetoothManager::DispatchAttributeEvent()
 {
   MOZ_ASSERT(NS_IsMainThread());
-  BT_API2_LOGR();
 
   Sequence<nsString> types;
   BT_APPEND_ENUM_STRING_FALLIBLE(types,
                                  BluetoothManagerAttribute,
                                  BluetoothManagerAttribute::DefaultAdapter);
 
   // Notify application of default adapter change
   BluetoothAttributeEventInit init;
--- a/dom/bluetooth/bluetooth2/BluetoothReplyRunnable.cpp
+++ b/dom/bluetooth/bluetooth2/BluetoothReplyRunnable.cpp
@@ -18,21 +18,17 @@ USING_BLUETOOTH_NAMESPACE
 
 BluetoothReplyRunnable::BluetoothReplyRunnable(nsIDOMDOMRequest* aReq,
                                                Promise* aPromise,
                                                const nsAString& aName)
   : mDOMRequest(aReq)
   , mPromise(aPromise)
   , mErrorStatus(STATUS_FAIL)
   , mName(aName)
-{
-  if (aPromise) {
-    BT_API2_LOGR("<%s>", NS_ConvertUTF16toUTF8(mName).get());
-  }
-}
+{}
 
 void
 BluetoothReplyRunnable::SetReply(BluetoothReply* aReply)
 {
   mReply = aReply;
 }
 
 void
@@ -56,17 +52,16 @@ BluetoothReplyRunnable::FireReplySuccess
       do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
     NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
 
     return rs->FireSuccessAsync(mDOMRequest, aVal);
   }
 
   // Promise
   if (mPromise) {
-    BT_API2_LOGR("<%s>", NS_ConvertUTF16toUTF8(mName).get());
     mPromise->MaybeResolve(aVal);
   }
 
   return NS_OK;
 }
 
 nsresult
 BluetoothReplyRunnable::FireErrorString()
@@ -77,18 +72,16 @@ BluetoothReplyRunnable::FireErrorString(
       do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
     NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
 
     return rs->FireErrorAsync(mDOMRequest, mErrorString);
   }
 
   // Promise
   if (mPromise) {
-    BT_API2_LOGR("<%s>", NS_ConvertUTF16toUTF8(mName).get());
-
     nsresult rv =
       NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_BLUETOOTH, mErrorStatus);
     mPromise->MaybeReject(rv);
   }
 
   return NS_OK;
 }
 
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/app/after_clear.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Test app for bug 1172562</title>
+    <script src='test.js'></script>
+    <script type='application/javascript;version=1.7'>
+
+function runTests() {
+  return Promise.resolve()
+    .then(() => { return navigator.serviceWorker.ready })
+    .then((registration) => {
+      return new Promise((resolve) => {
+        var worker = registration.waiting || registration.active;
+        worker.postMessage('read');
+        navigator.serviceWorker.onmessage = (message) => {
+          if (message.data.type == 'done') {
+            ok(!message.data.cached, 'No cached data');
+            resolve();
+          }
+        };
+      });
+    })
+    .then(done);
+}
+  </script>
+  </head>
+  <body onload='runTests()'>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/app/before_clear.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Test app for bug 1172562</title>
+    <script src='test.js'></script>
+    <script type='application/javascript;version=1.7'>
+
+function runTests() {
+  return Promise.resolve()
+    .then(() => { return navigator.serviceWorker.ready })
+    .then((registration) => {
+      return new Promise((resolve) => {
+        var worker = registration.waiting || registration.active;
+        worker.postMessage('write');
+        navigator.serviceWorker.onmessage = (message) => {
+          if (message.data.type == 'written') {
+            worker.postMessage('read');
+          } else if (message.data.type == 'done') {
+            ok(message.data.cached, 'Write success');
+            resolve();
+          }
+        };
+      });
+    })
+    .then(done);
+}
+  </script>
+  </head>
+  <body onload='runTests()'>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/app/index.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Test app for bug 1172562</title>
+    <script type='application/javascript;version=1.7'>
+function ok(aCondition, aMessage) {
+  if (aCondition) {
+    alert('OK: ' + aMessage);
+  } else {
+    alert('KO: ' + aMessage);
+  }
+}
+
+function ready() {
+  alert('READY');
+}
+
+function registerServiceWorker() {
+  return new Promise((resolve, reject) => {
+    navigator.serviceWorker.ready.then(() => {
+      ready();
+      resolve();
+    });
+    navigator.serviceWorker.register('sw.js', {scope: '.'})
+    .then(registration => {
+      ok(true, 'service worker registered');
+    })
+    .catch(reject);
+  });
+}
+
+function runTests() {
+  return Promise.resolve()
+    .then(registerServiceWorker)
+    .then(ready)
+}
+  </script>
+  </head>
+  <body onload='runTests()'>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/app/manifest.webapp
@@ -0,0 +1,5 @@
+{
+  "name": "App",
+  "launch_path": "/index.html",
+  "description": "Test app for bug 1172562"
+}
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/app/manifest.webapp^headers^
@@ -0,0 +1,1 @@
+Content-Type: application/manifest+json
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/app/sw.js
@@ -0,0 +1,18 @@
+self.addEventListener('message', (message) => {
+  caches.open('acache').then((cache) => {
+    if(message.data == 'write') {
+      cache.add('aurl').then(() => {
+        message.source.postMessage({
+          type: 'written'
+        });
+      });
+    } else if (message.data == 'read') {
+      cache.match('aurl').then((result) => {
+        message.source.postMessage({
+          type: 'done',
+          cached: !!result
+        });
+      });
+    }
+  });
+});
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/app/test.js
@@ -0,0 +1,15 @@
+function ok(aCondition, aMessage) {
+  if (aCondition) {
+    alert('OK: ' + aMessage);
+  } else {
+    alert('KO: ' + aMessage);
+  }
+}
+
+function ready() {
+  alert('READY');
+}
+
+function done() {
+  alert('DONE');
+}
--- a/dom/cache/test/mochitest/mochitest.ini
+++ b/dom/cache/test/mochitest/mochitest.ini
@@ -18,16 +18,17 @@ support-files =
   test_cache_keys.js
   test_cache_put.js
   test_cache_requestCache.js
   test_cache_delete.js
   test_cache_put_reorder.js
   test_cache_https.js
   large_url_list.js
   empty.html
+  app/*
 
 [test_cache.html]
 [test_cache_add.html]
 [test_cache_match_request.html]
 [test_cache_matchAll_request.html]
 [test_cache_overwrite.html]
 [test_cache_match_vary.html]
 [test_caches.html]
@@ -35,11 +36,13 @@ support-files =
 [test_cache_put.html]
 [test_cache_requestCache.html]
 [test_cache_delete.html]
 [test_cache_put_reorder.html]
 [test_cache_https.html]
   skip-if = buildapp == 'b2g' # bug 1162353
 [test_cache_restart.html]
 [test_cache_shrink.html]
+[test_cache_clear_on_app_uninstall.html]
+  skip-if = e10s || buildapp == 'b2g' # bug 1178685
 [test_cache_orphaned_cache.html]
 [test_cache_orphaned_body.html]
 [test_cache_untrusted.html]
new file mode 100644
--- /dev/null
+++ b/dom/cache/test/mochitest/test_cache_clear_on_app_uninstall.html
@@ -0,0 +1,163 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Bug 1172562 - Clear QuotaManager storage when uninstalling an app</title>
+  <script type='text/javascript' src='/tests/SimpleTest/SimpleTest.js'></script>
+  <link rel='stylesheet' type='text/css' href='/tests/SimpleTest/test.css' />
+</head>
+<body onload='runTests()'>
+<p id='display'></p>
+<div id='content' style='display: none'></div>
+<pre id='test'></pre>
+<script class='testbody' type='application/javascript;version=1.7'>
+
+SimpleTest.waitForExplicitFinish();
+
+const gOrigin = 'http://mochi.test:8888/tests/dom/cache/test/mochitest/app';
+const appManifestURL = gOrigin + '/manifest.webapp';
+let gApp;
+
+function setup() {
+  return new Promise((resolve, reject) => {
+    SpecialPowers.setAllAppsLaunchable(true);
+    SpecialPowers.pushPrefEnv({'set': [
+      ['dom.mozBrowserFramesEnabled', true],
+      ['dom.serviceWorkers.exemptFromPerDomainMax', true],
+      ['dom.serviceWorkers.enabled', true],
+      ['dom.serviceWorkers.testing.enabled', true],
+      ['dom.caches.enabled', true],
+    ]}, () => {
+      SpecialPowers.pushPermissions([
+        { 'type': 'webapps-manage', 'allow': 1, 'context': document },
+        { 'type': 'browser', 'allow': 1, 'context': document },
+        { 'type': 'embed-apps', 'allow': 1, 'context': document }
+      ], () => {
+        SpecialPowers.autoConfirmAppInstall(() => {
+          SpecialPowers.autoConfirmAppUninstall(resolve);
+        });
+      });
+    });
+  });
+}
+
+function installApp() {
+  return new Promise((resolve, reject) => {
+    let req = navigator.mozApps.install(appManifestURL);
+    req.onsuccess = function() {
+      gApp = req.result;
+      is(req.result.manifestURL, appManifestURL, 'app installed');
+      if (req.result.installState == 'installed') {
+        is(req.result.installState, 'installed', 'app downloaded');
+        resolve()
+      } else {
+        req.result.ondownloadapplied = function() {
+          is(req.result.installState, 'installed', 'app downloaded');
+          resolve();
+        }
+      }
+    }
+    req.onerror = reject;
+  });
+}
+
+function launchApp() {
+  if (!gApp) {
+    ok(false, 'No test application to launch');
+    return Promise.reject();
+  }
+  return new Promise((resolve, reject) => {
+    let iframe = document.createElement('iframe');
+    iframe.setAttribute('mozbrowser', 'true');
+    iframe.setAttribute('mozapp', gApp.manifestURL);
+    iframe.addEventListener('mozbrowsershowmodalprompt', function listener(e) {
+      let message = e.detail.message;
+      if (/OK/.exec(message)) {
+        ok(true, "Message from app: " + message);
+      } else if (/KO/.exec(message)) {
+        ok(false, "Message from app: " + message);
+      } else if (/READY/.exec(message)) {
+        ok(true, "Message from app: " + message);
+        resolve();
+      } else {
+        ok(false, "Unexpected message received: " + message);
+      }
+    }, false);
+    let domParent = document.getElementById('container');
+    domParent.appendChild(iframe);
+    SpecialPowers.wrap(iframe.contentWindow).location =
+      gOrigin + gApp.manifest.launch_path;
+  });
+}
+
+function loadControlled(aUrl) {
+  return new Promise((resolve, reject) => {
+    let iframe = document.createElement('iframe');
+    iframe.setAttribute('mozbrowser', 'true');
+    iframe.setAttribute('mozapp', gApp.manifestURL);
+    iframe.addEventListener('mozbrowsershowmodalprompt', function listener(e) {
+      let message = e.detail.message;
+      if (/OK/.exec(message)) {
+        ok(true, "Message from app: " + message);
+      } else if (/KO/.exec(message)) {
+        ok(false, "Message from app: " + message);
+      } else if (/DONE/.exec(message)) {
+        ok(true, "Messaging from app complete");
+        iframe.removeEventListener('mozbrowsershowmodalprompt', listener);
+        let domParent = document.getElementById('container');
+        domParent.removeChild(iframe);
+        resolve();
+      } else {
+        ok(false, "Unexpected message received: " + message);
+      }
+      }, false);
+    let domParent = document.getElementById('container');
+    domParent.appendChild(iframe);
+    SpecialPowers.wrap(iframe.contentWindow).location =
+      gOrigin + aUrl;
+  });
+}
+
+function loadBeforeClear() {
+  return loadControlled('/before_clear.html');
+}
+
+function loadAfterClear() {
+  return loadControlled('/after_clear.html');
+}
+
+function uninstallApp() {
+  return new Promise((resolve, reject) => {
+    if (!gApp) {
+      return reject();
+    }
+    let req = navigator.mozApps.mgmt.uninstall(gApp);
+    req.onsuccess = resolve;
+    req.onerror = reject;
+  });
+}
+
+function runTests() {
+  setup()
+    .then(installApp)
+    .then(launchApp)
+    .then(loadBeforeClear)
+    .then(uninstallApp)
+    .then(installApp)
+    .then(launchApp)
+    .then(loadAfterClear)
+    .then(uninstallApp)
+    .then(SimpleTest.finish)
+    .catch((e) => {
+      ok(false, 'Unexpected error ' + e.target.error.name);
+      SimpleTest.finish();
+    });
+}
+
+</script>
+<div id='container'></div>
+</body>
+</html>
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -44,17 +44,17 @@ interface nsIDOMClientRect;
 interface nsIURI;
 interface nsIDOMEventTarget;
 interface nsIRunnable;
 interface nsITranslationNodeList;
 interface nsIJSRAIIHelper;
 interface nsIContentPermissionRequest;
 interface nsIObserver;
 
-[scriptable, uuid(e7b44320-8255-4ad1-bbe9-d78a8a1867c9)]
+[scriptable, uuid(336a8683-5626-4512-a3d5-ec280c13e5c2)]
 interface nsIDOMWindowUtils : nsISupports {
 
   /**
    * Image animation mode of the window. When this attribute's value
    * is changed, the implementation should set all images in the window
    * to the given value. That is, when set to kDontAnimMode, all images
    * will stop animating. The attribute's value must be one of the
    * animationMode values from imgIContainer.
@@ -1741,17 +1741,18 @@ interface nsIDOMWindowUtils : nsISupport
     */
    void runBeforeNextEvent(in nsIRunnable runnable);
 
    /*
     * Returns the value of a given property animated on the compositor thread.
     * If the property is NOT currently being animated on the compositor thread,
     * returns an empty string.
     */
-   AString getOMTAStyle(in nsIDOMElement aElement, in AString aProperty);
+   AString getOMTAStyle(in nsIDOMElement aElement, in AString aProperty,
+                        [optional] in AString aPseudoElement);
 
    /**
     * Special function that gets a property syncronously from the last composite
     * that occured.
     *
     * Supported properties:
     *   "overdraw": Report a percentage between 0 and 999 indicate how many times
     *               each pixels on the destination window have been touched.
--- a/dom/workers/ScriptLoader.cpp
+++ b/dom/workers/ScriptLoader.cpp
@@ -5,16 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ScriptLoader.h"
 
 #include "nsIChannel.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIHttpChannel.h"
+#include "nsIHttpChannelInternal.h"
 #include "nsIInputStreamPump.h"
 #include "nsIIOService.h"
 #include "nsIProtocolHandler.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsIStreamLoader.h"
 #include "nsIStreamListenerTee.h"
 #include "nsIThreadRetargetableRequest.h"
 #include "nsIURI.h"
@@ -865,16 +866,26 @@ private:
     // We don't care about progress so just use the simple stream loader for
     // OnStreamComplete notification only.
     nsCOMPtr<nsIStreamLoader> loader;
     rv = NS_NewStreamLoader(getter_AddRefs(loader), this);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
+    // If we are loading a script for a ServiceWorker then we must not
+    // try to intercept it.  If the interception matches the current
+    // ServiceWorker's scope then we could deadlock the load.
+    if (mWorkerPrivate->IsServiceWorker()) {
+      nsCOMPtr<nsIHttpChannelInternal> internal = do_QueryInterface(channel);
+      if (internal) {
+        internal->ForceNoIntercept();
+      }
+    }
+
     if (loadInfo.mCacheStatus != ScriptLoadInfo::ToBeCached) {
       rv = channel->AsyncOpen(loader, indexSupports);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     } else {
       nsCOMPtr<nsIOutputStream> writer;
 
--- a/dom/workers/ServiceWorker.cpp
+++ b/dom/workers/ServiceWorker.cpp
@@ -46,16 +46,21 @@ ServiceWorker::ServiceWorker(nsPIDOMWind
   : DOMEventTargetHelper(aWindow),
     mInfo(aInfo),
     mSharedWorker(aSharedWorker)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aInfo);
   MOZ_ASSERT(mSharedWorker);
 
+  if (aWindow) {
+    mDocument = aWindow->GetExtantDoc();
+    mWindow = aWindow->GetOuterWindow();
+  }
+
   // This will update our state too.
   mInfo->AppendWorker(this);
 }
 
 ServiceWorker::~ServiceWorker()
 {
   AssertIsOnMainThread();
   mInfo->RemoveWorker(this);
@@ -63,17 +68,17 @@ ServiceWorker::~ServiceWorker()
 
 NS_IMPL_ADDREF_INHERITED(ServiceWorker, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(ServiceWorker, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorker)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorker, DOMEventTargetHelper,
-                                   mSharedWorker)
+                                   mSharedWorker, mDocument, mWindow)
 
 JSObject*
 ServiceWorker::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   AssertIsOnMainThread();
 
   return ServiceWorkerBinding::Wrap(aCx, this, aGivenProto);
 }
@@ -92,19 +97,22 @@ ServiceWorker::PostMessage(JSContext* aC
   WorkerPrivate* workerPrivate = GetWorkerPrivate();
   MOZ_ASSERT(workerPrivate);
 
   if (State() == ServiceWorkerState::Redundant) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
-  nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(GetParentObject());
-  nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
-  nsAutoPtr<ServiceWorkerClientInfo> clientInfo(new ServiceWorkerClientInfo(doc));
+  MOZ_ASSERT(mDocument && mWindow,
+             "Cannot call PostMessage on a ServiceWorker object that doesn't "
+             "have a window");
+
+  nsAutoPtr<ServiceWorkerClientInfo> clientInfo(
+    new ServiceWorkerClientInfo(mDocument, mWindow));
 
   workerPrivate->PostMessageToServiceWorker(aCx, aMessage, aTransferable,
                                             clientInfo, aRv);
 }
 
 WorkerPrivate*
 ServiceWorker::GetWorkerPrivate() const
 {
--- a/dom/workers/ServiceWorker.h
+++ b/dom/workers/ServiceWorker.h
@@ -6,16 +6,17 @@
 
 #ifndef mozilla_dom_workers_serviceworker_h__
 #define mozilla_dom_workers_serviceworker_h__
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/ServiceWorkerBinding.h" // For ServiceWorkerState.
 
+class nsIDocument;
 class nsPIDOMWindow;
 
 namespace mozilla {
 namespace dom {
 
 namespace workers {
 
 class ServiceWorkerInfo;
@@ -86,15 +87,19 @@ private:
   ServiceWorkerState mState;
   const nsRefPtr<ServiceWorkerInfo> mInfo;
 
   // To allow ServiceWorkers to potentially drop the backing DOMEventTargetHelper and
   // re-instantiate it later, they simply own a SharedWorker member that
   // can be released and recreated as required rather than re-implement some of
   // the SharedWorker logic.
   nsRefPtr<SharedWorker> mSharedWorker;
+  // We need to keep the document and window alive for PostMessage to be able
+  // to access them.
+  nsCOMPtr<nsIDocument> mDocument;
+  nsCOMPtr<nsPIDOMWindow> mWindow;
 };
 
 } // namespace workers
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_workers_serviceworker_h__
--- a/dom/workers/ServiceWorkerClient.cpp
+++ b/dom/workers/ServiceWorkerClient.cpp
@@ -23,17 +23,18 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Se
 NS_IMPL_CYCLE_COLLECTING_ADDREF(ServiceWorkerClient)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(ServiceWorkerClient)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerClient)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc)
+ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc,
+                                                 nsPIDOMWindow* aWindow)
   : mWindowId(0)
 {
   MOZ_ASSERT(aDoc);
   nsresult rv = aDoc->GetId(mClientId);
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to get the UUID of the document.");
   }
 
@@ -48,17 +49,17 @@ ServiceWorkerClientInfo::ServiceWorkerCl
   mVisibilityState = aDoc->VisibilityState();
 
   ErrorResult result;
   mFocused = aDoc->HasFocus(result);
   if (result.Failed()) {
     NS_WARNING("Failed to get focus information.");
   }
 
-  nsRefPtr<nsGlobalWindow> outerWindow = static_cast<nsGlobalWindow*>(aDoc->GetWindow());
+  nsRefPtr<nsGlobalWindow> outerWindow = static_cast<nsGlobalWindow*>(aWindow);
   MOZ_ASSERT(outerWindow);
   if (!outerWindow->IsTopLevelWindow()) {
     mFrameType = FrameType::Nested;
   } else if (outerWindow->HadOriginalOpener()) {
     mFrameType = FrameType::Auxiliary;
   } else {
     mFrameType = FrameType::Top_level;
   }
--- a/dom/workers/ServiceWorkerClient.h
+++ b/dom/workers/ServiceWorkerClient.h
@@ -9,32 +9,35 @@
 #define mozilla_dom_workers_serviceworkerclient_h
 
 #include "nsCOMPtr.h"
 #include "nsWrapperCache.h"
 #include "mozilla/ErrorResult.h"
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/ClientBinding.h"
 
+class nsIDocument;
+class nsPIDOMWindow;
+
 namespace mozilla {
 namespace dom {
 namespace workers {
 
 class ServiceWorkerClient;
 class ServiceWorkerWindowClient;
 
 // Used as a container object for information needed to create
 // client objects.
 class ServiceWorkerClientInfo final
 {
   friend class ServiceWorkerClient;
   friend class ServiceWorkerWindowClient;
 
 public:
-  explicit ServiceWorkerClientInfo(nsIDocument* aDoc);
+  ServiceWorkerClientInfo(nsIDocument* aDoc, nsPIDOMWindow* aWindow);
 
 private:
   nsString mClientId;
   uint64_t mWindowId;
   nsString mUrl;
 
   // Window Clients
   VisibilityState mVisibilityState;
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -3546,17 +3546,17 @@ ServiceWorkerManager::DispatchFetchEvent
     return;
   }
 
   nsAutoPtr<ServiceWorkerClientInfo> clientInfo;
 
   if (!isNavigation) {
     MOZ_ASSERT(aDoc);
     aRv = GetDocumentController(aDoc->GetInnerWindow(), getter_AddRefs(serviceWorker));
-    clientInfo = new ServiceWorkerClientInfo(aDoc);
+    clientInfo = new ServiceWorkerClientInfo(aDoc, aDoc->GetWindow());
   } else {
     nsCOMPtr<nsIChannel> internalChannel;
     aRv = aChannel->GetChannel(getter_AddRefs(internalChannel));
     if (NS_WARN_IF(aRv.Failed())) {
       return;
     }
 
     nsCOMPtr<nsIURI> uri;
@@ -3919,17 +3919,17 @@ EnumControlledDocuments(nsISupports* aKe
   }
 
   nsCOMPtr<nsIDocument> document = do_QueryInterface(aKey);
 
   if (!document || !document->GetWindow()) {
     return PL_DHASH_NEXT;
   }
 
-  ServiceWorkerClientInfo clientInfo(document);
+  ServiceWorkerClientInfo clientInfo(document, document->GetWindow());
   data->mDocuments.AppendElement(clientInfo);
 
   return PL_DHASH_NEXT;
 }
 
 static void
 FireControllerChangeOnDocument(nsIDocument* aDocument)
 {
--- a/dom/workers/ServiceWorkerWindowClient.cpp
+++ b/dom/workers/ServiceWorkerWindowClient.cpp
@@ -82,17 +82,18 @@ public:
     AssertIsOnMainThread();
     nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowId);
     UniquePtr<ServiceWorkerClientInfo> clientInfo;
 
     if (window) {
       ErrorResult result;
       //FIXME(catalinb): Bug 1144660 - check if we are allowed to focus here.
       window->Focus(result);
-      clientInfo.reset(new ServiceWorkerClientInfo(window->GetDocument()));
+      clientInfo.reset(new ServiceWorkerClientInfo(window->GetDocument(),
+                                                   window->GetOuterWindow()));
     }
 
     DispatchResult(Move(clientInfo));
     return NS_OK;
   }
 
 private:
   void
--- a/ipc/glue/BackgroundUtils.h
+++ b/ipc/glue/BackgroundUtils.h
@@ -6,16 +6,17 @@
 #define mozilla_ipc_backgroundutils_h__
 
 #include "ipc/IPCMessageUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/BasePrincipal.h"
 #include "nsCOMPtr.h"
 #include "nscore.h"
 
+class nsILoadInfo;
 class nsIPrincipal;
 
 namespace IPC {
 
 template<>
 struct ParamTraits<mozilla::OriginAttributes>
 {
   typedef mozilla::OriginAttributes paramType;
--- a/layout/base/ActiveLayerTracker.cpp
+++ b/layout/base/ActiveLayerTracker.cpp
@@ -281,22 +281,17 @@ ActiveLayerTracker::IsStyleAnimated(nsDi
   if (layerActivity) {
     if (layerActivity->RestyleCountForProperty(aProperty) >= 2) {
       return true;
     }
   }
   if (aProperty == eCSSProperty_transform && aFrame->Preserves3D()) {
     return IsStyleAnimated(aBuilder, aFrame->GetParent(), aProperty);
   }
-  nsIContent* content = aFrame->GetContent();
-  if (content) {
-    return nsLayoutUtils::HasCurrentAnimationsForProperties(content, &aProperty, 1);
-  }
-
-  return false;
+  return nsLayoutUtils::HasCurrentAnimationsForProperties(aFrame, &aProperty, 1);
 }
 
 /* static */ bool
 ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(nsIFrame* aFrame)
 {
   LayerActivity* layerActivity = GetLayerActivity(aFrame);
   if (layerActivity) {
     if (layerActivity->mLeftRestyleCount >= 2 ||
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -4768,21 +4768,20 @@ ChooseScaleAndSetTransform(FrameLayerBui
   }
 
   bool canDraw2D = transform.CanDraw2D(&transform2d);
   gfxSize scale;
   // XXX Should we do something for 3D transforms?
   if (canDraw2D) {
     // If the container's transform is animated off main thread, fix a suitable scale size
     // for animation
-    if (aContainerFrame->GetContent() &&
-        aContainerItem &&
+    if (aContainerItem &&
         aContainerItem->GetType() == nsDisplayItem::TYPE_TRANSFORM &&
         nsLayoutUtils::HasAnimationsForCompositor(
-          aContainerFrame->GetContent(), eCSSProperty_transform)) {
+          aContainerFrame, eCSSProperty_transform)) {
       // Use the size of the nearest widget as the maximum size.  This
       // is important since it might be a popup that is bigger than the
       // pres context's size.
       nsPresContext* presContext = aContainerFrame->PresContext();
       nsIWidget* widget = aContainerFrame->GetNearestWidget();
       nsSize displaySize;
       if (widget) {
         IntSize widgetSize = widget->GetClientSize();
@@ -4790,17 +4789,17 @@ ChooseScaleAndSetTransform(FrameLayerBui
         displaySize.width = NSIntPixelsToAppUnits(widgetSize.width, p2a);
         displaySize.height = NSIntPixelsToAppUnits(widgetSize.height, p2a);
       } else {
         displaySize = presContext->GetVisibleArea().Size();
       }
       // compute scale using the animation on the container (ignoring
       // its ancestors)
       scale = nsLayoutUtils::ComputeSuitableScaleForAnimation(
-                aContainerFrame->GetContent(), aVisibleRect.Size(),
+                aContainerFrame, aVisibleRect.Size(),
                 displaySize);
       // multiply by the scale inherited from ancestors
       scale.width *= aIncomingScale.mXScale;
       scale.height *= aIncomingScale.mYScale;
     } else {
       // Scale factors are normalized to a power of 2 to reduce the number of resolution changes
       scale = RoundToFloatPrecision(ThebesMatrix(transform2d).ScaleFactors(true));
       // For frames with a changing transform that's not just a translation,
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -510,24 +510,21 @@ nsDisplayListBuilder::AddAnimationsAndTr
   // any early returns since even if we don't add any animations to the
   // layer, we still need to mark it as up-to-date with regards to animations.
   // Otherwise, in RestyleManager we'll notice the discrepancy between the
   // animation generation numbers and update the layer indefinitely.
   uint64_t animationGeneration =
     RestyleManager::GetMaxAnimationGenerationForFrame(aFrame);
   aLayer->SetAnimationGeneration(animationGeneration);
 
-  nsIContent* content = aFrame->GetContent();
-  if (!content) {
-    return;
-  }
+  nsPresContext* presContext = aFrame->PresContext();
   AnimationCollection* transitions =
-    nsTransitionManager::GetAnimationsForCompositor(content, aProperty);
+    presContext->TransitionManager()->GetAnimationsForCompositor(aFrame, aProperty);
   AnimationCollection* animations =
-    nsAnimationManager::GetAnimationsForCompositor(content, aProperty);
+    presContext->AnimationManager()->GetAnimationsForCompositor(aFrame, aProperty);
 
   if (!animations && !transitions) {
     return;
   }
 
   // If the frame is not prerendered, bail out.
   // Do this check only during layer construction; during updating the
   // caller is required to check it appropriately.
@@ -718,18 +715,17 @@ void nsDisplayListBuilder::MarkOutOfFlow
       clipPtr = &clip;
     }
   }
 
   nsRect dirty = dirtyRectRelativeToDirtyFrame - aFrame->GetOffsetTo(aDirtyFrame);
   nsRect overflowRect = aFrame->GetVisualOverflowRect();
 
   if (aFrame->IsTransformed() &&
-      nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(),
-                                                eCSSProperty_transform)) {
+      nsLayoutUtils::HasAnimationsForCompositor(aFrame, eCSSProperty_transform)) {
    /**
     * Add a fuzz factor to the overflow rectangle so that elements only just
     * out of view are pulled into the display list, so they can be
     * prerendered if necessary.
     */
     overflowRect.Inflate(nsPresContext::CSSPixelsToAppUnits(32));
   }
 
@@ -3851,21 +3847,18 @@ IsItemTooSmallForActiveLayer(nsDisplayIt
 }
 
 bool
 nsDisplayOpacity::NeedsActiveLayer(nsDisplayListBuilder* aBuilder)
 {
   if (ActiveLayerTracker::IsStyleAnimated(aBuilder, mFrame, eCSSProperty_opacity) &&
       !IsItemTooSmallForActiveLayer(this))
     return true;
-  if (mFrame->GetContent()) {
-    if (nsLayoutUtils::HasAnimationsForCompositor(mFrame->GetContent(),
-                                                  eCSSProperty_opacity)) {
-      return true;
-    }
+  if (nsLayoutUtils::HasAnimationsForCompositor(mFrame, eCSSProperty_opacity)) {
+    return true;
   }
   return false;
 }
 
 void
 nsDisplayOpacity::ApplyOpacity(nsDisplayListBuilder* aBuilder,
                              float aOpacity,
                              const DisplayItemClip* aClip)
@@ -5082,19 +5075,17 @@ nsDisplayTransform::ShouldPrerenderTrans
                                                       nsIFrame* aFrame,
                                                       bool aLogAnimations)
 {
   // Elements whose transform has been modified recently, or which
   // have a compositor-animated transform, can be prerendered. An element
   // might have only just had its transform animated in which case
   // the ActiveLayerManager may not have been notified yet.
   if (!ActiveLayerTracker::IsStyleMaybeAnimated(aFrame, eCSSProperty_transform) &&
-      (!aFrame->GetContent() ||
-       !nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(),
-                                                  eCSSProperty_transform))) {
+      !nsLayoutUtils::HasAnimationsForCompositor(aFrame, eCSSProperty_transform)) {
     if (aLogAnimations) {
       nsCString message;
       message.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for transform animation");
       AnimationCollection::LogAsyncAnimationFailure(message,
                                                     aFrame->GetContent());
     }
     return false;
   }
@@ -5240,21 +5231,18 @@ nsDisplayTransform::GetLayerState(nsDisp
   if (!GetTransform().Is2D() || mFrame->Preserves3D()) {
     return LAYER_ACTIVE_FORCE;
   }
   // Here we check if the *post-transform* bounds of this item are big enough
   // to justify an active layer.
   if (ActiveLayerTracker::IsStyleAnimated(aBuilder, mFrame, eCSSProperty_transform) &&
       !IsItemTooSmallForActiveLayer(this))
     return LAYER_ACTIVE;
-  if (mFrame->GetContent()) {
-    if (nsLayoutUtils::HasAnimationsForCompositor(mFrame->GetContent(),
-                                                  eCSSProperty_transform)) {
-      return LAYER_ACTIVE;
-    }
+  if (nsLayoutUtils::HasAnimationsForCompositor(mFrame, eCSSProperty_transform)) {
+    return LAYER_ACTIVE;
   }
 
   const nsStyleDisplay* disp = mFrame->StyleDisplay();
   if ((disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_TRANSFORM)) {
     return LAYER_ACTIVE;
   }
 
   // Expect the child display items to have this frame as their animated
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -367,91 +367,89 @@ TextAlignTrueEnabledPrefChangeCallback(c
   nsCSSProps::kTextAlignKTable[sIndexOfTrueInTextAlignTable] =
     isTextAlignTrueEnabled ? eCSSKeyword_true : eCSSKeyword_UNKNOWN;
   MOZ_ASSERT(sIndexOfTrueInTextAlignLastTable >= 0);
   nsCSSProps::kTextAlignLastKTable[sIndexOfTrueInTextAlignLastTable] =
     isTextAlignTrueEnabled ? eCSSKeyword_true : eCSSKeyword_UNKNOWN;
 }
 
 bool
-nsLayoutUtils::HasAnimationsForCompositor(nsIContent* aContent,
+nsLayoutUtils::HasAnimationsForCompositor(const nsIFrame* aFrame,
                                           nsCSSProperty aProperty)
 {
-  return nsAnimationManager::GetAnimationsForCompositor(aContent, aProperty) ||
-         nsTransitionManager::GetAnimationsForCompositor(aContent, aProperty);
-}
-
-static AnimationCollection*
-GetAnimationsOrTransitions(nsIContent* aContent,
-                           nsIAtom* aAnimationProperty,
-                           nsCSSProperty aProperty)
-{
+  nsPresContext* presContext = aFrame->PresContext();
+  return presContext->AnimationManager()->GetAnimationsForCompositor(aFrame, aProperty) ||
+         presContext->TransitionManager()->GetAnimationsForCompositor(aFrame, aProperty);
+}
+
+bool
+nsLayoutUtils::HasAnimations(const nsIFrame* aFrame,
+                             nsCSSProperty aProperty)
+{
+  nsPresContext* presContext = aFrame->PresContext();
   AnimationCollection* collection =
-    static_cast<AnimationCollection*>(aContent->GetProperty(
-        aAnimationProperty));
-  if (collection) {
-    bool propertyMatches = collection->HasAnimationOfProperty(aProperty);
-    if (propertyMatches) {
-      return collection;
-    }
-  }
-  return nullptr;
+    presContext->AnimationManager()->GetAnimationCollection(aFrame);
+  if (collection &&
+      collection->HasAnimationOfProperty(aProperty)) {
+    return true;
+  }
+  collection =
+    presContext->TransitionManager()->GetAnimationCollection(aFrame);
+  if (collection &&
+      collection->HasAnimationOfProperty(aProperty)) {
+    return true;
+  }
+  return false;
 }
 
 bool
-nsLayoutUtils::HasAnimations(nsIContent* aContent,
-                             nsCSSProperty aProperty)
-{
-  if (!aContent->MayHaveAnimations())
-    return false;
-  return GetAnimationsOrTransitions(aContent, nsGkAtoms::animationsProperty,
-                                    aProperty) ||
-         GetAnimationsOrTransitions(aContent, nsGkAtoms::transitionsProperty,
-                                    aProperty);
+nsLayoutUtils::HasCurrentAnimations(const nsIFrame* aFrame)
+{
+  nsPresContext* presContext = aFrame->PresContext();
+  AnimationCollection* collection =
+    presContext->AnimationManager()->GetAnimationCollection(aFrame);
+  return collection &&
+         collection->HasCurrentAnimations();
+}
+
+bool
+nsLayoutUtils::HasCurrentTransitions(const nsIFrame* aFrame)
+{
+  nsPresContext* presContext = aFrame->PresContext();
+  AnimationCollection* collection =
+    presContext->TransitionManager()->GetAnimationCollection(aFrame);
+  return collection &&
+         collection->HasCurrentAnimations();
 }
 
 bool
-nsLayoutUtils::HasCurrentAnimations(nsIContent* aContent,
-                                    nsIAtom* aAnimationProperty)
-{
-  if (!aContent->MayHaveAnimations())
-    return false;
-
-  AnimationCollection* collection =
-    static_cast<AnimationCollection*>(
-      aContent->GetProperty(aAnimationProperty));
-  return (collection && collection->HasCurrentAnimations());
-}
-
-bool
-nsLayoutUtils::HasCurrentAnimationsForProperties(nsIContent* aContent,
+nsLayoutUtils::HasCurrentAnimationsForProperties(const nsIFrame* aFrame,
                                                  const nsCSSProperty* aProperties,
                                                  size_t aPropertyCount)
 {
-  if (!aContent->MayHaveAnimations())
-    return false;
-
-  static nsIAtom* const sAnimProps[] = { nsGkAtoms::transitionsProperty,
-                                         nsGkAtoms::animationsProperty,
-                                         nullptr };
-  for (nsIAtom* const* animProp = sAnimProps; *animProp; animProp++) {
-    AnimationCollection* collection =
-      static_cast<AnimationCollection*>(aContent->GetProperty(*animProp));
-    if (collection &&
-        collection->HasCurrentAnimationsForProperties(aProperties,
-                                                      aPropertyCount)) {
-      return true;
-    }
-  }
-
+  nsPresContext* presContext = aFrame->PresContext();
+  AnimationCollection* collection =
+    presContext->AnimationManager()->GetAnimationCollection(aFrame);
+  if (collection &&
+      collection->HasCurrentAnimationsForProperties(aProperties,
+                                                    aPropertyCount)) {
+    return true;
+  }
+  collection =
+    presContext->TransitionManager()->GetAnimationCollection(aFrame);
+  if (collection &&
+      collection->HasCurrentAnimationsForProperties(aProperties,
+                                                    aPropertyCount)) {
+    return true;
+  }
   return false;
 }
 
 static gfxSize
-GetScaleForValue(const StyleAnimationValue& aValue, nsIFrame* aFrame)
+GetScaleForValue(const StyleAnimationValue& aValue, const nsIFrame* aFrame)
 {
   if (!aFrame) {
     NS_WARNING("No frame.");
     return gfxSize();
   }
   if (aValue.GetUnit() != StyleAnimationValue::eUnit_Transform) {
     NS_WARNING("Expected a transform.");
     return gfxSize();
@@ -486,73 +484,72 @@ GetSuitableScale(float aMaxScale, float 
   // We want to rasterize based on the largest scale used during the
   // transform animation, unless that would make us rasterize something
   // larger than the screen.  But we never want to go smaller than the
   // minimum scale over the animation.
   return std::max(std::min(aMaxScale, displayVisibleRatio), aMinScale);
 }
 
 static void
-GetMinAndMaxScaleForAnimationProperty(nsIContent* aContent,
+GetMinAndMaxScaleForAnimationProperty(const nsIFrame* aFrame,
                                       AnimationCollection* aAnimations,
                                       gfxSize& aMaxScale,
                                       gfxSize& aMinScale)
 {
   for (size_t animIdx = aAnimations->mAnimations.Length(); animIdx-- != 0; ) {
     dom::Animation* anim = aAnimations->mAnimations[animIdx];
     if (!anim->GetEffect() || anim->GetEffect()->IsFinishedTransition()) {
       continue;
     }
     dom::KeyframeEffectReadOnly* effect = anim->GetEffect();
     for (size_t propIdx = effect->Properties().Length(); propIdx-- != 0; ) {
       AnimationProperty& prop = effect->Properties()[propIdx];
       if (prop.mProperty == eCSSProperty_transform) {
         for (uint32_t segIdx = prop.mSegments.Length(); segIdx-- != 0; ) {
           AnimationPropertySegment& segment = prop.mSegments[segIdx];
-          gfxSize from = GetScaleForValue(segment.mFromValue,
-                                          aContent->GetPrimaryFrame());
+          gfxSize from = GetScaleForValue(segment.mFromValue, aFrame);
           aMaxScale.width = std::max<float>(aMaxScale.width, from.width);
           aMaxScale.height = std::max<float>(aMaxScale.height, from.height);
           aMinScale.width = std::min<float>(aMinScale.width, from.width);
           aMinScale.height = std::min<float>(aMinScale.height, from.height);
-          gfxSize to = GetScaleForValue(segment.mToValue,
-                                        aContent->GetPrimaryFrame());
+          gfxSize to = GetScaleForValue(segment.mToValue, aFrame);
           aMaxScale.width = std::max<float>(aMaxScale.width, to.width);
           aMaxScale.height = std::max<float>(aMaxScale.height, to.height);
           aMinScale.width = std::min<float>(aMinScale.width, to.width);
           aMinScale.height = std::min<float>(aMinScale.height, to.height);
         }
       }
     }
   }
 }
 
 gfxSize
-nsLayoutUtils::ComputeSuitableScaleForAnimation(nsIContent* aContent,
+nsLayoutUtils::ComputeSuitableScaleForAnimation(const nsIFrame* aFrame,
                                                 const nsSize& aVisibleSize,
                                                 const nsSize& aDisplaySize)
 {
   gfxSize maxScale(std::numeric_limits<gfxFloat>::min(),
                    std::numeric_limits<gfxFloat>::min());
   gfxSize minScale(std::numeric_limits<gfxFloat>::max(),
                    std::numeric_limits<gfxFloat>::max());
+  nsPresContext* presContext = aFrame->PresContext();
 
   AnimationCollection* animations =
-    nsAnimationManager::GetAnimationsForCompositor(aContent,
-                                                   eCSSProperty_transform);
+    presContext->AnimationManager()->GetAnimationsForCompositor(
+      aFrame, eCSSProperty_transform);
   if (animations) {
-    GetMinAndMaxScaleForAnimationProperty(aContent, animations,
+    GetMinAndMaxScaleForAnimationProperty(aFrame, animations,
                                           maxScale, minScale);
   }
 
   animations =
-    nsTransitionManager::GetAnimationsForCompositor(aContent,
-                                                    eCSSProperty_transform);
+    presContext->TransitionManager()->GetAnimationsForCompositor(
+      aFrame, eCSSProperty_transform);
   if (animations) {
-    GetMinAndMaxScaleForAnimationProperty(aContent, animations,
+    GetMinAndMaxScaleForAnimationProperty(aFrame, animations,
                                           maxScale, minScale);
   }
 
   if (maxScale.width == std::numeric_limits<gfxFloat>::min()) {
     // We didn't encounter a transform
     return gfxSize(1.0, 1.0);
   }
 
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -2130,67 +2130,83 @@ public:
    *    (void)SizeOfTextRunsForFrames(rootFrame, nullptr, true);
    *    total = SizeOfTextRunsForFrames(rootFrame, mallocSizeOf, false);
    */
   static size_t SizeOfTextRunsForFrames(nsIFrame* aFrame,
                                         mozilla::MallocSizeOf aMallocSizeOf,
                                         bool clear);
 
   /**
-   * Returns true if the content node has animations or transitions that can be
+   * Given a frame with possibly animated content, finds the content node
+   * that contains its animations as well as the frame's pseudo-element type
+   * relative to the resulting content node. Returns true if animated content
+   * was found, otherwise it returns false and the output parameters are
+   * undefined.
+   */
+  static bool GetAnimationContent(const nsIFrame* aFrame,
+                                  nsIContent* &aContentResult,
+                                  nsCSSPseudoElements::Type &aPseudoTypeResult);
+
+  /**
+   * Returns true if the frame has animations or transitions that can be
    * performed on the compositor.
    */
-  static bool HasAnimationsForCompositor(nsIContent* aContent,
+  static bool HasAnimationsForCompositor(const nsIFrame* aFrame,
                                          nsCSSProperty aProperty);
 
   /**
-   * Returns true if the content node has animations or transitions for the
+   * Returns true if the frame has animations or transitions for the
    * property.
    */
-  static bool HasAnimations(nsIContent* aContent, nsCSSProperty aProperty);
+  static bool HasAnimations(const nsIFrame* aFrame, nsCSSProperty aProperty);
 
   /**
-   * Returns true if the content node has any current animations or transitions
-   * (depending on the value of |aAnimationProperty|).
+   * Returns true if the frame has any current animations.
    * A current animation is any animation that has not yet finished playing
    * including paused animations.
    */
-  static bool HasCurrentAnimations(nsIContent* aContent,
-                                   nsIAtom* aAnimationProperty);
+  static bool HasCurrentAnimations(const nsIFrame* aFrame);
 
   /**
-   * Returns true if the content node has any current animations or transitions
+   * Returns true if the frame has any current transitions.
+   * A current transition is any transition that has not yet finished playing
+   * including paused transitions.
+   */
+  static bool HasCurrentTransitions(const nsIFrame* aFrame);
+
+  /**
+   * Returns true if the frame has any current animations or transitions
    * for any of the specified properties.
    */
-  static bool HasCurrentAnimationsForProperties(nsIContent* aContent,
+  static bool HasCurrentAnimationsForProperties(const nsIFrame* aFrame,
                                                 const nsCSSProperty* aProperties,
                                                 size_t aPropertyCount);
 
   /**
    * Checks if off-main-thread animations are enabled.
    */
   static bool AreAsyncAnimationsEnabled();
 
   /**
    * Checks if we should warn about animations that can't be async
    */
   static bool IsAnimationLoggingEnabled();
 
   /**
-   * Find a suitable scale for an element (aContent) over the course of any
+   * Find a suitable scale for a element (aFrame's content) over the course of any
    * animations and transitions of the CSS transform property on the
    * element that run on the compositor thread.
    * It will check the maximum and minimum scale during the animations and
    * transitions and return a suitable value for performance and quality.
    * Will return scale(1,1) if there are no such animations.
    * Always returns a positive value.
    * @param aVisibleSize is the size of the area we want to paint
    * @param aDisplaySize is the size of the display area of the pres context
    */
-  static gfxSize ComputeSuitableScaleForAnimation(nsIContent* aContent,
+  static gfxSize ComputeSuitableScaleForAnimation(const nsIFrame* aFrame,
                                                   const nsSize& aVisibleSize,
                                                   const nsSize& aDisplaySize);
 
   /**
    * Checks if we should forcibly use nearest pixel filtering for the
    * background.
    */
   static bool UseBackgroundNearestFiltering();
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -22,16 +22,17 @@
 // mmsystem isn't part of WIN32_LEAN_AND_MEAN, so we have
 // to manually include it
 #include <mmsystem.h>
 #include "WinUtils.h"
 #endif
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/AutoRestore.h"
+#include "mozilla/IntegerRange.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "nsRefreshDriver.h"
 #include "nsITimer.h"
 #include "nsLayoutUtils.h"
 #include "nsPresContext.h"
 #include "nsComponentManagerUtils.h"
 #include "mozilla/Logging.h"
 #include "nsAutoPtr.h"
@@ -1336,16 +1337,17 @@ nsRefreshDriver::ObserverCount() const
   }
 
   // Even while throttled, we need to process layout and style changes.  Style
   // changes can trigger transitions which fire events when they complete, and
   // layout changes can affect media queries on child documents, triggering
   // style changes, etc.
   sum += mStyleFlushObservers.Length();
   sum += mLayoutFlushObservers.Length();
+  sum += mPendingEvents.Length();
   sum += mFrameRequestCallbackDocs.Length();
   sum += mThrottledFrameRequestCallbackDocs.Length();
   sum += mViewManagerFlushIsPending;
   return sum;
 }
 
 /* static */ PLDHashOperator
 nsRefreshDriver::StartTableRequestCounter(const uint32_t& aKey,
@@ -1472,16 +1474,27 @@ static void
 TakeFrameRequestCallbacksFrom(nsIDocument* aDocument,
                               nsTArray<DocumentFrameCallbacks>& aTarget)
 {
   aTarget.AppendElement(aDocument);
   aDocument->TakeFrameRequestCallbacks(aTarget.LastElement().mCallbacks);
 }
 
 void
+nsRefreshDriver::DispatchPendingEvents()
+{
+  // Swap out the current pending events
+  nsTArray<PendingEvent> pendingEvents(Move(mPendingEvents));
+  for (PendingEvent& event : pendingEvents) {
+    bool dummy;
+    event.mTarget->DispatchEvent(event.mEvent, &dummy);
+  }
+}
+
+void
 nsRefreshDriver::RunFrameRequestCallbacks(int64_t aNowEpoch, TimeStamp aNowTime)
 {
   // Grab all of our frame request callbacks up front.
   nsTArray<DocumentFrameCallbacks>
     frameRequestCallbacks(mFrameRequestCallbackDocs.Length() +
                           mThrottledFrameRequestCallbackDocs.Length());
 
   // First, grab throttled frame request callbacks.
@@ -1652,16 +1665,17 @@ nsRefreshDriver::Tick(int64_t aNowEpoch,
         StopTimer();
         return;
       }
     }
 
     if (i == 0) {
       // This is the Flush_Style case.
 
+      DispatchPendingEvents();
       RunFrameRequestCallbacks(aNowEpoch, aNowTime);
 
       if (mPresContext && mPresContext->GetPresShell()) {
         bool tracingStyleFlush = false;
         nsAutoTArray<nsIPresShell*, 16> observers;
         observers.AppendElements(mStyleFlushObservers);
         for (uint32_t j = observers.Length();
              j && mPresContext && mPresContext->GetPresShell(); --j) {
@@ -2126,9 +2140,27 @@ nsRefreshDriver::RevokeFrameRequestCallb
 {
   mFrameRequestCallbackDocs.RemoveElement(aDocument);
   mThrottledFrameRequestCallbackDocs.RemoveElement(aDocument);
   ConfigureHighPrecision();
   // No need to worry about restarting our timer in slack mode if it's already
   // running; that will happen automatically when it fires.
 }
 
+void
+nsRefreshDriver::ScheduleEventDispatch(nsINode* aTarget, nsIDOMEvent* aEvent)
+{
+  mPendingEvents.AppendElement(PendingEvent{aTarget, aEvent});
+  // make sure that the timer is running
+  EnsureTimerStarted();
+}
+
+void
+nsRefreshDriver::CancelPendingEvents(nsIDocument* aDocument)
+{
+  for (auto i : Reversed(MakeRange(mPendingEvents.Length()))) {
+    if (mPendingEvents[i].mTarget->OwnerDoc() == aDocument) {
+      mPendingEvents.RemoveElementAt(i);
+    }
+  }
+}
+
 #undef LOG
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -24,16 +24,18 @@
 #include "mozilla/Maybe.h"
 #include "GeckoProfiler.h"
 #include "mozilla/layers/TransactionIdAllocator.h"
 
 class nsPresContext;
 class nsIPresShell;
 class nsIDocument;
 class imgIRequest;
+class nsIDOMEvent;
+class nsINode;
 
 namespace mozilla {
 class RefreshDriverTimer;
 namespace layout {
 class VsyncChild;
 }
 }
 
@@ -218,16 +220,27 @@ public:
   void ScheduleFrameRequestCallbacks(nsIDocument* aDocument);
 
   /**
    * Remove a document for which we have nsIFrameRequestCallbacks
    */
   void RevokeFrameRequestCallbacks(nsIDocument* aDocument);
 
   /**
+   * Queue a new event to dispatch in next tick before the style flush
+   */
+  void ScheduleEventDispatch(nsINode* aTarget, nsIDOMEvent* aEvent);
+
+  /**
+   * Cancel all pending events scheduled by ScheduleEventDispatch which
+   * targets any node in aDocument.
+   */
+  void CancelPendingEvents(nsIDocument* aDocument);
+
+  /**
    * Tell the refresh driver that it is done driving refreshes and
    * should stop its timer and forget about its pres context.  This may
    * be called from within a refresh.
    */
   void Disconnect() {
     StopTimer();
     mPresContext = nullptr;
   }
@@ -303,16 +316,17 @@ private:
     {
     }
 
     mozilla::Maybe<mozilla::TimeStamp> mStartTime;
     RequestTable mEntries;
   };
   typedef nsClassHashtable<nsUint32HashKey, ImageStartData> ImageStartTable;
 
+  void DispatchPendingEvents();
   void RunFrameRequestCallbacks(int64_t aNowEpoch, mozilla::TimeStamp aNowTime);
 
   void Tick(int64_t aNowEpoch, mozilla::TimeStamp aNowTime);
 
   enum EnsureTimerStartedFlags {
     eNone = 0,
     eAdjustingTimer = 1 << 0,
     eAllowTimeToGoBackwards = 1 << 1
@@ -398,23 +412,29 @@ private:
   mozilla::TimeStamp mNextThrottledFrameRequestTick;
   mozilla::TimeStamp mNextRecomputeVisibilityTick;
 
   // separate arrays for each flush type we support
   ObserverArray mObservers[3];
   RequestTable mRequests;
   ImageStartTable mStartTable;
 
+  struct PendingEvent {
+    nsCOMPtr<nsINode> mTarget;
+    nsCOMPtr<nsIDOMEvent> mEvent;
+  };
+
   nsAutoTArray<nsIPresShell*, 16> mStyleFlushObservers;
   nsAutoTArray<nsIPresShell*, 16> mLayoutFlushObservers;
   nsAutoTArray<nsIPresShell*, 16> mPresShellsToInvalidateIfHidden;
   // nsTArray on purpose, because we want to be able to swap.
   nsTArray<nsIDocument*> mFrameRequestCallbackDocs;
   nsTArray<nsIDocument*> mThrottledFrameRequestCallbackDocs;
   nsTObserverArray<nsAPostRefreshObserver*> mPostRefreshObservers;
+  nsTArray<PendingEvent> mPendingEvents;
 
   // Helper struct for processing image requests
   struct ImageRequestParameters {
     mozilla::TimeStamp mCurrent;
     mozilla::TimeStamp mPrevious;
     RequestTable* mRequests;
     mozilla::TimeStamp mDesired;
   };
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1077,31 +1077,31 @@ nsIFrame::GetMarginRectRelativeToSelf() 
 
 bool
 nsIFrame::IsTransformed() const
 {
   return ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
           (StyleDisplay()->HasTransform(this) ||
            IsSVGTransformed() ||
            (mContent &&
-            nsLayoutUtils::HasAnimationsForCompositor(mContent,
+            nsLayoutUtils::HasAnimationsForCompositor(this,
                                                       eCSSProperty_transform) &&
             IsFrameOfType(eSupportsCSSTransforms) &&
             mContent->GetPrimaryFrame() == this)));
 }
 
 bool
 nsIFrame::HasOpacityInternal(float aThreshold) const
 {
   MOZ_ASSERT(0.0 <= aThreshold && aThreshold <= 1.0, "Invalid argument");
   const nsStyleDisplay* displayStyle = StyleDisplay();
   return StyleDisplay()->mOpacity < aThreshold ||
          (displayStyle->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) ||
          (mContent &&
-           nsLayoutUtils::HasAnimationsForCompositor(mContent,
+           nsLayoutUtils::HasAnimationsForCompositor(this,
                                                      eCSSProperty_opacity) &&
            mContent->GetPrimaryFrame() == this);
 }
 
 bool
 nsIFrame::IsSVGTransformed(gfx::Matrix *aOwnTransforms,
                            gfx::Matrix *aFromParentTransforms) const
 {
@@ -1941,17 +1941,17 @@ nsIFrame::BuildDisplayListForStackingCon
   // we're painting, and we're not animating opacity. Don't do this
   // if we're going to compute plugin geometry, since opacity-0 plugins
   // need to have display items built for them.
   bool needEventRegions = aBuilder->IsBuildingLayerEventRegions() &&
       StyleVisibility()->GetEffectivePointerEvents(this) != NS_STYLE_POINTER_EVENTS_NONE;
   if (disp->mOpacity == 0.0 && aBuilder->IsForPainting() &&
       !aBuilder->WillComputePluginGeometry() &&
       !(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) &&
-      !nsLayoutUtils::HasAnimations(mContent, eCSSProperty_opacity) &&
+      !nsLayoutUtils::HasAnimations(this, eCSSProperty_opacity) &&
       !needEventRegions) {
     return;
   }
 
   if (disp->mWillChangeBitField != 0) {
     aBuilder->AddToWillChangeBudget(this, GetSize());
   }
 
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -2586,17 +2586,17 @@ public:
   virtual bool IsSelfEmpty() = 0;
 
   /**
    * IsGeneratedContentFrame returns whether a frame corresponds to
    * generated content
    *
    * @return whether the frame correspods to generated content
    */
-  bool IsGeneratedContentFrame() {
+  bool IsGeneratedContentFrame() const {
     return (mState & NS_FRAME_GENERATED_CONTENT) != 0;
   }
 
   /**
    * IsPseudoFrame returns whether a frame is a pseudo frame (eg an
    * anonymous table-row frame created for a CSS table-cell without an
    * enclosing table-row.
    *
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -129,25 +129,55 @@ CommonAnimationManager::NeedsRefresh() c
     if (static_cast<AnimationCollection*>(l)->mNeedsRefreshes) {
       return true;
     }
   }
   return false;
 }
 
 AnimationCollection*
-CommonAnimationManager::GetAnimationsForCompositor(nsIContent* aContent,
-                                                   nsIAtom* aElementProperty,
+CommonAnimationManager::GetAnimationCollection(const nsIFrame* aFrame)
+{
+  nsIContent* content = aFrame->GetContent();
+  if (!content) {
+    return nullptr;
+  }
+  nsIAtom* animProp;
+  if (aFrame->IsGeneratedContentFrame()) {
+    nsIFrame* parent = aFrame->GetParent();
+    if (parent->IsGeneratedContentFrame()) {
+      return nullptr;
+    }
+    nsIAtom* name = content->NodeInfo()->NameAtom();
+    if (name == nsGkAtoms::mozgeneratedcontentbefore) {
+      animProp = GetAnimationsBeforeAtom();
+    } else if (name == nsGkAtoms::mozgeneratedcontentafter) {
+      animProp = GetAnimationsAfterAtom();
+    } else {
+      return nullptr;
+    }
+    content = content->GetParent();
+    if (!content) {
+      return nullptr;
+    }
+  } else {
+    if (!content->MayHaveAnimations()) {
+      return nullptr;
+    }
+    animProp = GetAnimationsAtom();
+  }
+
+  return static_cast<AnimationCollection*>(content->GetProperty(animProp));
+}
+
+AnimationCollection*
+CommonAnimationManager::GetAnimationsForCompositor(const nsIFrame* aFrame,
                                                    nsCSSProperty aProperty)
 {
-  if (!aContent->MayHaveAnimations())
-    return nullptr;
-
-  AnimationCollection* collection =
-    static_cast<AnimationCollection*>(aContent->GetProperty(aElementProperty));
+  AnimationCollection* collection = GetAnimationCollection(aFrame);
   if (!collection ||
       !collection->HasAnimationOfProperty(aProperty) ||
       !collection->CanPerformOnCompositorThread(
         AnimationCollection::CanAnimate_AllowPartial)) {
     return nullptr;
   }
 
   // This animation can be done on the compositor.
@@ -332,21 +362,22 @@ CommonAnimationManager::GetAnimations(do
   if (!collection && aCreateIfNeeded) {
     // FIXME: Consider arena-allocating?
     collection = new AnimationCollection(aElement, propName, this);
     nsresult rv =
       aElement->SetProperty(propName, collection,
                             &AnimationCollection::PropertyDtor, false);
     if (NS_FAILED(rv)) {
       NS_WARNING("SetProperty failed");
-      delete collection;
+      // The collection must be destroyed via PropertyDtor, otherwise
+      // mCalledPropertyDtor assertion is triggered in destructor.
+      AnimationCollection::PropertyDtor(aElement, propName, collection, nullptr);
       return nullptr;
     }
-    if (propName == nsGkAtoms::animationsProperty ||
-        propName == nsGkAtoms::transitionsProperty) {
+    if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
       aElement->SetMayHaveAnimations();
     }
 
     AddElementCollection(collection);
   }
 
   return collection;
 }
@@ -572,31 +603,22 @@ AnimationCollection::IsCompositorAnimati
   void* prop = aFrame->Properties().Get(nsIFrame::RefusedAsyncAnimation());
   return bool(reinterpret_cast<intptr_t>(prop));
 }
 
 bool
 AnimationCollection::CanPerformOnCompositorThread(
   CanAnimateFlags aFlags) const
 {
-  nsIFrame* frame = nsLayoutUtils::GetStyleFrame(mElement);
-  if (!frame) {
+  dom::Element* element = GetElementToRestyle();
+  if (!element) {
     return false;
   }
-
-  if (mElementProperty != nsGkAtoms::transitionsProperty &&
-      mElementProperty != nsGkAtoms::animationsProperty) {
-    if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
-      nsCString message;
-      message.AppendLiteral("Gecko bug: Async animation of pseudoelements"
-                            " not supported.  See bug 771367 (");
-      message.Append(nsAtomCString(mElementProperty));
-      message.Append(")");
-      LogAsyncAnimationFailure(message, mElement);
-    }
+  nsIFrame* frame = nsLayoutUtils::GetStyleFrame(element);
+  if (!frame) {
     return false;
   }
 
   for (size_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
     const Animation* anim = mAnimations[animIdx];
     if (!anim->IsPlaying()) {
       continue;
     }
@@ -623,17 +645,17 @@ AnimationCollection::CanPerformOnComposi
     const KeyframeEffectReadOnly* effect = anim->GetEffect();
     MOZ_ASSERT(effect, "A playing animation should have an effect");
 
     existsProperty = existsProperty || effect->Properties().Length() > 0;
 
     for (size_t propIdx = 0, propEnd = effect->Properties().Length();
          propIdx != propEnd; ++propIdx) {
       const AnimationProperty& prop = effect->Properties()[propIdx];
-      if (!CanAnimatePropertyOnCompositor(mElement,
+      if (!CanAnimatePropertyOnCompositor(element,
                                           prop.mProperty,
                                           aFlags) ||
           IsCompositorAnimationDisabledForFrame(frame)) {
         return false;
       }
     }
   }
 
@@ -834,20 +856,25 @@ AnimationCollection::CanThrottleTransfor
   }
 
   // If this animation can cause overflow, we can throttle some of the ticks.
   if (!mStyleRuleRefreshTime.IsNull() &&
       (aTime - mStyleRuleRefreshTime) < TimeDuration::FromMilliseconds(200)) {
     return true;
   }
 
+  dom::Element* element = GetElementToRestyle();
+  if (!element) {
+    return false;
+  }
+
   // If the nearest scrollable ancestor has overflow:hidden,
   // we don't care about overflow.
   nsIScrollableFrame* scrollable = nsLayoutUtils::GetNearestScrollableFrame(
-                                     nsLayoutUtils::GetStyleFrame(mElement));
+                                     nsLayoutUtils::GetStyleFrame(element));
   if (!scrollable) {
     return true;
   }
 
   ScrollbarStyles ss = scrollable->GetScrollbarStyles();
   if (ss.mVertical == NS_STYLE_OVERFLOW_HIDDEN &&
       ss.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN &&
       scrollable->GetLogicalScrollPosition() == nsPoint(0, 0)) {
@@ -855,17 +882,21 @@ AnimationCollection::CanThrottleTransfor
   }
 
   return false;
 }
 
 bool
 AnimationCollection::CanThrottleAnimation(TimeStamp aTime)
 {
-  nsIFrame* frame = nsLayoutUtils::GetStyleFrame(mElement);
+  dom::Element* element = GetElementToRestyle();
+  if (!element) {
+    return false;
+  }
+  nsIFrame* frame = nsLayoutUtils::GetStyleFrame(element);
   if (!frame) {
     return false;
   }
 
 
   const auto& info = css::CommonAnimationManager::sLayerAnimationInfo;
   for (size_t i = 0; i < ArrayLength(info); i++) {
     auto record = info[i];
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -156,29 +156,36 @@ protected:
   virtual nsIAtom* GetAnimationsAtom() = 0;
   virtual nsIAtom* GetAnimationsBeforeAtom() = 0;
   virtual nsIAtom* GetAnimationsAfterAtom() = 0;
 
   virtual bool IsAnimationManager() {
     return false;
   }
 
+
+public:
   // Return an AnimationCollection* if we have an animation for
-  // the element aContent and pseudo-element indicator aElementProperty
-  // that can be performed on the compositor thread (as defined by 
-  // AnimationCollection::CanPerformOnCompositorThread).
+  // the frame aFrame that can be performed on the compositor thread (as
+  // defined by AnimationCollection::CanPerformOnCompositorThread).
   //
-  // Note that this does not test whether the element's layer uses
+  // Note that this does not test whether the frame's layer uses
   // off-main-thread compositing, although it does check whether
   // off-main-thread compositing is enabled as a whole.
-  static AnimationCollection*
-  GetAnimationsForCompositor(nsIContent* aContent,
-                             nsIAtom* aElementProperty,
+  AnimationCollection*
+  GetAnimationsForCompositor(const nsIFrame* aFrame,
                              nsCSSProperty aProperty);
 
+  // Given the frame aFrame with possibly animated content, finds its
+  // associated collection of animations. If it is a generated content
+  // frame, it may examine the parent frame to search for such animations.
+  AnimationCollection*
+  GetAnimationCollection(const nsIFrame* aFrame);
+
+protected:
   PRCList mElementCollections;
   nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect)
   bool mIsObservingRefreshDriver;
 };
 
 /**
  * A style rule that maps property-StyleAnimationValue pairs.
  */
--- a/layout/style/nsAnimationManager.h
+++ b/layout/style/nsAnimationManager.h
@@ -158,23 +158,16 @@ class nsAnimationManager final
   : public mozilla::css::CommonAnimationManager
 {
 public:
   explicit nsAnimationManager(nsPresContext *aPresContext)
     : mozilla::css::CommonAnimationManager(aPresContext)
   {
   }
 
-  static mozilla::AnimationCollection*
-  GetAnimationsForCompositor(nsIContent* aContent, nsCSSProperty aProperty)
-  {
-    return mozilla::css::CommonAnimationManager::GetAnimationsForCompositor(
-      aContent, nsGkAtoms::animationsProperty, aProperty);
-  }
-
   void UpdateStyleAndEvents(mozilla::AnimationCollection* aEA,
                             mozilla::TimeStamp aRefreshTime,
                             mozilla::EnsureStyleRuleFlags aFlags);
   void QueueEvents(mozilla::AnimationCollection* aEA,
                    mozilla::EventArray &aEventsToDispatch);
 
   void MaybeUpdateCascadeResults(mozilla::AnimationCollection* aCollection);
 
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -112,23 +112,16 @@ public:
   explicit nsTransitionManager(nsPresContext *aPresContext)
     : mozilla::css::CommonAnimationManager(aPresContext)
     , mInAnimationOnlyStyleUpdate(false)
   {
   }
 
   typedef mozilla::AnimationCollection AnimationCollection;
 
-  static AnimationCollection*
-  GetAnimationsForCompositor(nsIContent* aContent, nsCSSProperty aProperty)
-  {
-    return mozilla::css::CommonAnimationManager::GetAnimationsForCompositor(
-      aContent, nsGkAtoms::transitionsProperty, aProperty);
-  }
-
   /**
    * StyleContextChanged
    *
    * To be called from nsFrameManager::ReResolveStyleContext when the
    * style of an element has changed, to initiate transitions from
    * that style change.  For style contexts with :before and :after
    * pseudos, aElement is expected to be the generated before/after
    * element.
--- a/layout/style/test/animation_utils.js
+++ b/layout/style/test/animation_utils.js
@@ -399,29 +399,33 @@ const RunningOn = {
 };
 
 const ExpectComparisonTo = {
   Pass: 1,
   Fail: 2
 };
 
 (function() {
-  window.omta_todo_is = function(elem, property, expected, runningOn, desc) {
+  window.omta_todo_is = function(elem, property, expected, runningOn, desc,
+                                 pseudo) {
     return omta_is_approx(elem, property, expected, 0, runningOn, desc,
-                          ExpectComparisonTo.Fail);
+                          ExpectComparisonTo.Fail, pseudo);
   };
 
-  window.omta_is = function(elem, property, expected, runningOn, desc) {
-    return omta_is_approx(elem, property, expected, 0, runningOn, desc);
+  window.omta_is = function(elem, property, expected, runningOn, desc,
+                            pseudo) {
+    return omta_is_approx(elem, property, expected, 0, runningOn, desc,
+                          ExpectComparisonTo.Pass, pseudo);
   };
 
   // Many callers of this method will pass 'undefined' for
   // expectedComparisonResult.
   window.omta_is_approx = function(elem, property, expected, tolerance,
-                                   runningOn, desc, expectedComparisonResult) {
+                                   runningOn, desc, expectedComparisonResult,
+                                   pseudo) {
     // Check input
     const omtaProperties = [ "transform", "opacity" ];
     if (omtaProperties.indexOf(property) === -1) {
       ok(false, property + " is not an OMTA property");
       return;
     }
     var isTransform = property == "transform";
     var normalize = isTransform ? convertTo3dMatrix : parseFloat;
@@ -429,18 +433,18 @@ const ExpectComparisonTo = {
                   matricesRoughlyEqual :
                   function(a, b, error) { return Math.abs(a - b) <= error; };
     var normalizedToString = isTransform ?
                              convert3dMatrixToString :
                              JSON.stringify;
 
     // Get actual values
     var compositorStr =
-      SpecialPowers.DOMWindowUtils.getOMTAStyle(elem, property);
-    var computedStr = window.getComputedStyle(elem)[property];
+      SpecialPowers.DOMWindowUtils.getOMTAStyle(elem, property, pseudo);
+    var computedStr = window.getComputedStyle(elem, pseudo)[property];
 
     // Prepare expected value
     var expectedValue = normalize(expected);
     if (expectedValue === null) {
       ok(false, desc + ": test author should provide a valid 'expected' value" +
                 " - got " + expected.toString());
       return;
     }
--- a/layout/style/test/test_animations_omta.html
+++ b/layout/style/test/test_animations_omta.html
@@ -81,16 +81,22 @@ https://bugzilla.mozilla.org/show_bug.cg
       75%  { transform: translate(120px); animation-timing-function: linear }
       100% { transform: translate(20px); animation-timing-function: ease-out }
     }
 
     @keyframes always_fifty {
       from, to { transform: translate(50px) }
     }
 
+    #withbefore::before, #withafter::after {
+      content: "test";
+      animation: anim4 1s linear alternate 3;
+      display:block;
+    }
+
     @keyframes multiprop {
       0% {
         transform: translate(10px); opacity: 0.3;
         animation-timing-function: ease;
       }
       25% {
         opacity: 0.5;
         animation-timing-function: ease-out;
@@ -1431,18 +1437,82 @@ addAsyncAnimTest(function *() {
 
 // animation-fill-mode is tested in the tests for section (2).
 
 /*
  * css3-animations:  3.10. The 'animation' Shorthand Property
  * http://dev.w3.org/csswg/css3-animations/#the-animation-shorthand-property-
  */
 
-// (Unlike test_animations.html, pseudo-elements are not tested here since they
-//  are currently not run on the compositor thread.)
+/**
+ * Basic tests of animations on pseudo-elements
+ */
+addAsyncAnimTest(function *() {
+  new_div("");
+  listen();
+  gDiv.id = "withbefore";
+  yield waitForPaintsFlushed();
+  omta_is("transform", { ty: 0 }, RunningOn.Compositor,
+          ":before test at 0ms", "::before");
+  advance_clock(400);
+  omta_is("transform", { ty: 40 }, RunningOn.Compositor,
+          ":before test at 400ms", "::before");
+  advance_clock(800);
+  omta_is("transform", { ty: 80 }, RunningOn.Compositor,
+          ":before test at 1200ms", "::before");
+  omta_is("transform", { ty: 0 }, RunningOn.MainThread,
+          ":before animation should not affect element");
+  advance_clock(800);
+  omta_is("transform", { ty: 0 }, RunningOn.Compositor,
+          ":before test at 2000ms", "::before");
+  advance_clock(300);
+  omta_is("transform", { ty: 30 }, RunningOn.Compositor,
+          ":before test at 2300ms", "::before");
+  advance_clock(700);
+  check_events([ { type: "animationstart", animationName: "anim4",
+                   elapsedTime: 0, pseudoElement: "::before" },
+                 { type: "animationiteration", animationName: "anim4",
+                   elapsedTime: 1, pseudoElement: "::before" },
+                 { type: "animationiteration", animationName: "anim4",
+                   elapsedTime: 2, pseudoElement: "::before" },
+                 { type: "animationend", animationName: "anim4",
+                   elapsedTime: 3, pseudoElement: "::before" }]);
+  done_div();
+
+  new_div("");
+  listen();
+  gDiv.id = "withafter";
+  yield waitForPaintsFlushed();
+  omta_is("transform", { ty: 0 }, RunningOn.Compositor,
+          ":after test at 0ms", "::after");
+  advance_clock(400);
+  omta_is("transform", { ty: 40 }, RunningOn.Compositor,
+          ":after test at 400ms", "::after");
+  advance_clock(800);
+  omta_is("transform", { ty: 80 }, RunningOn.Compositor,
+          ":after test at 1200ms", "::after");
+  omta_is("transform", { ty: 0 }, RunningOn.MainThread,
+          ":before animation should not affect element");
+  advance_clock(800);
+  omta_is("transform", { ty: 0 }, RunningOn.Compositor,
+          ":after test at 2000ms", "::after");
+  advance_clock(300);
+  omta_is("transform", { ty: 30 }, RunningOn.Compositor,
+          ":after test at 2300ms", "::after");
+  advance_clock(700);
+  check_events([ { type: "animationstart", animationName: "anim4",
+                   elapsedTime: 0, pseudoElement: "::after" },
+                 { type: "animationiteration", animationName: "anim4",
+                   elapsedTime: 1, pseudoElement: "::after" },
+                 { type: "animationiteration", animationName: "anim4",
+                   elapsedTime: 2, pseudoElement: "::after" },
+                 { type: "animationend", animationName: "anim4",
+                   elapsedTime: 3, pseudoElement: "::after" }]);
+  done_div();
+});
 
 /**
  * Test handling of properties that are present in only some of the
  * keyframes.
  */
 addAsyncAnimTest(function *() {
   new_div("animation: multiprop 1s ease-in-out alternate infinite");
   yield waitForPaintsFlushed();
--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -516,18 +516,17 @@ nsMenuPopupFrame::LayoutPopup(nsBoxLayou
   if (mIsOpenChanged) {
     mIsOpenChanged = false;
 
 #ifndef MOZ_WIDGET_GTK
     // If the animate attribute is set to open, check for a transition and wait
     // for it to finish before firing the popupshown event.
     if (mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::animate,
                               nsGkAtoms::open, eCaseMatters) &&
-        nsLayoutUtils::HasCurrentAnimations(mContent,
-                                            nsGkAtoms::transitionsProperty)) {
+        nsLayoutUtils::HasCurrentTransitions(this)) {
       mPopupShownDispatcher = new nsXULPopupShownEvent(mContent, pc);
       mContent->AddSystemEventListener(NS_LITERAL_STRING("transitionend"),
                                        mPopupShownDispatcher, false, false);
       return;
     }
 #endif
 
     // If there are no transitions, fire the popupshown event right away.
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -1468,18 +1468,17 @@ nsXULPopupManager::FirePopupHidingEvent(
             (!animate.EqualsLiteral("cancel") || aIsCancel)) {
           presShell->FlushPendingNotifications(Flush_Layout);
 
           // Get the frame again in case the flush caused it to go away
           popupFrame = do_QueryFrame(aPopup->GetPrimaryFrame());
           if (!popupFrame)
             return;
 
-          if (nsLayoutUtils::HasCurrentAnimations(aPopup,
-                nsGkAtoms::transitionsProperty)) {
+          if (nsLayoutUtils::HasCurrentTransitions(popupFrame)) {
             nsRefPtr<TransitionEnder> ender = new TransitionEnder(aPopup, aDeselectMenu);
             aPopup->AddSystemEventListener(NS_LITERAL_STRING("transitionend"),
                                            ender, false, false);
             return;
           }
         }
       }
 #endif
--- a/media/mtransport/gonk_addrs.cpp
+++ b/media/mtransport/gonk_addrs.cpp
@@ -114,17 +114,17 @@ GetInterfaces(std::vector<NetworkInterfa
     aInterfaces->push_back(interface);
   }
   return NS_OK;
 }
 } // anonymous namespace
 
 int
 nr_stun_get_addrs(nr_local_addr aAddrs[], int aMaxAddrs,
-                  int aDropLoopback, int* aCount)
+                  int aDropLoopback, int aDropLinkLocal, int* aCount)
 {
   nsresult rv;
   int r;
 
   // Get network interface list.
   std::vector<NetworkInterface> interfaces;
   nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
   mozilla::SyncRunnable::DispatchToThread(
@@ -136,30 +136,29 @@ nr_stun_get_addrs(nr_local_addr aAddrs[]
   }
 
   // Translate to nr_transport_addr.
   int32_t n = 0;
   size_t num_interface = std::min(interfaces.size(), (size_t)aMaxAddrs);
   for (size_t i = 0; i < num_interface; ++i) {
     NetworkInterface &interface = interfaces[i];
     if (nr_sockaddr_to_transport_addr((sockaddr*)&(interface.addr),
-                                      sizeof(struct sockaddr_in),
                                       IPPROTO_UDP, 0, &(aAddrs[n].addr))) {
       r_log(NR_LOG_STUN, LOG_WARNING, "Problem transforming address");
       return R_FAILED;
     }
     strlcpy(aAddrs[n].addr.ifname, interface.name.c_str(),
             sizeof(aAddrs[n].addr.ifname));
     aAddrs[n].interface.type = interface.type;
     aAddrs[n].interface.estimated_speed = 0;
     n++;
   }
 
   *aCount = n;
-  r = nr_stun_remove_duplicate_addrs(aAddrs, aDropLoopback, aCount);
+  r = nr_stun_remove_duplicate_addrs(aAddrs, aDropLoopback, aDropLinkLocal, aCount);
   if (r != 0) {
     return r;
   }
 
   for (int i = 0; i < *aCount; ++i) {
     char typestr[100];
     nr_local_addr_fmt_info_string(aAddrs + i, typestr, sizeof(typestr));
     r_log(NR_LOG_STUN, LOG_DEBUG, "Address %d: %s on %s, type: %s\n",
--- a/media/mtransport/nr_socket_prsock.cpp
+++ b/media/mtransport/nr_socket_prsock.cpp
@@ -332,30 +332,21 @@ static int nr_transport_addr_to_praddr(n
 
     switch(addr->ip_version){
       case NR_IPV4:
         naddr->inet.family = PR_AF_INET;
         naddr->inet.port = addr->u.addr4.sin_port;
         naddr->inet.ip = addr->u.addr4.sin_addr.s_addr;
         break;
       case NR_IPV6:
-#if 0
         naddr->ipv6.family = PR_AF_INET6;
         naddr->ipv6.port = addr->u.addr6.sin6_port;
-#ifdef LINUX
-        memcpy(naddr->ipv6.ip._S6_un._S6_u8,
-               &addr->u.addr6.sin6_addr.__in6_u.__u6_addr8, 16);
-#else
-        memcpy(naddr->ipv6.ip._S6_un._S6_u8,
-               &addr->u.addr6.sin6_addr.__u6_addr.__u6_addr8, 16);
-#endif
-#else
-        // TODO: make IPv6 work
-        ABORT(R_INTERNAL);
-#endif
+        naddr->ipv6.flowinfo = addr->u.addr6.sin6_flowinfo;
+        memcpy(&naddr->ipv6.ip, &addr->u.addr6.sin6_addr, sizeof(in6_addr));
+        naddr->ipv6.scope_id = addr->u.addr6.sin6_scope_id;
         break;
       default:
         ABORT(R_BAD_ARGS);
     }
 
     _status = 0;
   abort:
     return(_status);
@@ -435,35 +426,37 @@ int nr_netaddr_to_transport_addr(const n
 
 int nr_praddr_to_transport_addr(const PRNetAddr *praddr,
                                 nr_transport_addr *addr, int protocol,
                                 int keep)
   {
     int _status;
     int r;
     struct sockaddr_in ip4;
+    struct sockaddr_in6 ip6;
 
     switch(praddr->raw.family) {
       case PR_AF_INET:
         ip4.sin_family = PF_INET;
         ip4.sin_addr.s_addr = praddr->inet.ip;
         ip4.sin_port = praddr->inet.port;
         if ((r = nr_sockaddr_to_transport_addr((sockaddr *)&ip4,
-                                               sizeof(ip4),
                                                protocol, keep,
                                                addr)))
           ABORT(r);
         break;
       case PR_AF_INET6:
-#if 0
-        r = nr_sockaddr_to_transport_addr((sockaddr *)&praddr->raw,
-          sizeof(struct sockaddr_in6),IPPROTO_UDP,keep,addr);
+        ip6.sin6_family = PF_INET6;
+        ip6.sin6_port = praddr->ipv6.port;
+        ip6.sin6_flowinfo = praddr->ipv6.flowinfo;
+        memcpy(&ip6.sin6_addr, &praddr->ipv6.ip, sizeof(in6_addr));
+        ip6.sin6_scope_id = praddr->ipv6.scope_id;
+        if ((r = nr_sockaddr_to_transport_addr((sockaddr *)&ip6,protocol,keep,addr)))
+          ABORT(r);
         break;
-#endif
-        ABORT(R_BAD_ARGS);
       default:
         MOZ_ASSERT(false);
         ABORT(R_BAD_ARGS);
     }
 
     _status=0;
  abort:
     return(_status);
@@ -511,24 +504,26 @@ int NrSocket::create(nr_transport_addr *
     ABORT(R_INTERNAL);
   }
 
   if((r=nr_transport_addr_to_praddr(addr, &naddr)))
     ABORT(r);
 
   switch (addr->protocol) {
     case IPPROTO_UDP:
-      if (!(fd_ = PR_NewUDPSocket())) {
-        r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket");
+      if (!(fd_ = PR_OpenUDPSocket(naddr.raw.family))) {
+        r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create UDP socket, "
+              "family=%d, err=%d", naddr.raw.family, PR_GetError());
         ABORT(R_INTERNAL);
       }
       break;
     case IPPROTO_TCP:
-      if (!(fd_ = PR_NewTCPSocket())) {
-        r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create socket");
+      if (!(fd_ = PR_OpenTCPSocket(naddr.raw.family))) {
+        r_log(LOG_GENERIC,LOG_CRIT,"Couldn't create TCP socket, "
+              "family=%d, err=%d", naddr.raw.family, PR_GetError());
         ABORT(R_INTERNAL);
       }
       // Set ReuseAddr for TCP sockets to enable having several
       // sockets bound to same local IP and port
       PRSocketOptionData opt_reuseaddr;
       opt_reuseaddr.option = PR_SockOpt_Reuseaddr;
       opt_reuseaddr.value.reuse_addr = PR_TRUE;
       status = PR_SetSocketOption(fd_, &opt_reuseaddr);
@@ -681,17 +676,18 @@ int NrSocket::sendto(const void *msg, si
   }
 
   // TODO: Convert flags?
   status = PR_SendTo(fd_, msg, len, flags, &naddr, PR_INTERVAL_NO_WAIT);
   if (status < 0 || (size_t)status != len) {
     if (PR_GetError() == PR_WOULD_BLOCK_ERROR)
       ABORT(R_WOULDBLOCK);
 
-    r_log(LOG_GENERIC, LOG_INFO, "Error in sendto: %s", to->as_string);
+    r_log(LOG_GENERIC, LOG_INFO, "Error in sendto %s: %d",
+          to->as_string, PR_GetError());
     ABORT(R_IO_ERROR);
   }
 
   _status=0;
 abort:
   return(_status);
 }
 
--- a/media/mtransport/nricectx.cpp
+++ b/media/mtransport/nricectx.cpp
@@ -375,17 +375,18 @@ void NrIceCtx::trickle_cb(void *arg, nr_
 
   s->SignalCandidate(s, candidate_str);
 }
 
 RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
                                   bool offerer,
                                   bool set_interface_priorities,
                                   bool allow_loopback,
-                                  bool tcp_enabled) {
+                                  bool tcp_enabled,
+                                  bool allow_link_local) {
 
   RefPtr<NrIceCtx> ctx = new NrIceCtx(name, offerer);
 
   // Initialize the crypto callbacks and logging stuff
   if (!initialized) {
     NR_reg_init(NR_REG_MODE_LOCAL);
     RLogRingBuffer::CreateInstance();
     nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
@@ -467,16 +468,20 @@ RefPtr<NrIceCtx> NrIceCtx::Create(const 
     NR_reg_set_int4((char *)NR_ICE_REG_ICE_TCP_LISTEN_BACKLOG,
                      ice_tcp_listen_backlog);
 
     NR_reg_set_char((char *)NR_ICE_REG_ICE_TCP_DISABLE, !tcp_enabled);
 
     if (allow_loopback) {
       NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, 1);
     }
+
+    if (allow_link_local) {
+      NR_reg_set_char((char *)NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS, 1);
+    }
   }
 
   // Create the ICE context
   int r;
 
   UINT4 flags = offerer ? NR_ICE_CTX_FLAGS_OFFERER:
       NR_ICE_CTX_FLAGS_ANSWERER;
   flags |= NR_ICE_CTX_FLAGS_AGGRESSIVE_NOMINATION;
--- a/media/mtransport/nricectx.h
+++ b/media/mtransport/nricectx.h
@@ -207,17 +207,18 @@ class NrIceCtx {
   enum Controlling { ICE_CONTROLLING,
                      ICE_CONTROLLED
   };
 
   static RefPtr<NrIceCtx> Create(const std::string& name,
                                  bool offerer,
                                  bool set_interface_priorities = true,
                                  bool allow_loopback = false,
-                                 bool tcp_enabled = true);
+                                 bool tcp_enabled = true,
+                                 bool allow_link_local = false);
 
   // Deinitialize all ICE global state. Used only for testing.
   static void internal_DeinitializeGlobal();
 
 
   nr_ice_ctx *ctx() { return ctx_; }
   nr_ice_peer_ctx *peer() { return peer_; }
 
--- a/media/mtransport/nriceresolver.cpp
+++ b/media/mtransport/nriceresolver.cpp
@@ -145,30 +145,43 @@ int NrIceResolver::resolve(void *obj,
 int NrIceResolver::resolve(nr_resolver_resource *resource,
                            int (*cb)(void *cb_arg, nr_transport_addr *addr),
                            void *cb_arg,
                            void **handle) {
   int _status;
   MOZ_ASSERT(allocated_resolvers_ > 0);
   ASSERT_ON_THREAD(sts_thread_);
   nsRefPtr<PendingResolution> pr;
+  uint32_t resolve_flags = 0;
 
   if (resource->transport_protocol != IPPROTO_UDP &&
       resource->transport_protocol != IPPROTO_TCP) {
     MOZ_MTLOG(ML_ERROR, "Only UDP and TCP are is supported.");
     ABORT(R_NOT_FOUND);
   }
   pr = new PendingResolution(sts_thread_,
                              resource->port? resource->port : 3478,
                              resource->transport_protocol ?
                              resource->transport_protocol :
                              IPPROTO_UDP,
                              cb, cb_arg);
+
+  switch(resource->address_family) {
+    case AF_INET:
+      resolve_flags |= nsIDNSService::RESOLVE_DISABLE_IPV6;
+      break;
+    case AF_INET6:
+      resolve_flags |= nsIDNSService::RESOLVE_DISABLE_IPV4;
+      break;
+    default:
+      ABORT(R_BAD_ARGS);
+  }
+
   if (NS_FAILED(dns_->AsyncResolve(nsAutoCString(resource->domain_name),
-                                   nsIDNSService::RESOLVE_DISABLE_IPV6, pr,
+                                   resolve_flags, pr,
                                    sts_thread_, getter_AddRefs(pr->request_)))) {
     MOZ_MTLOG(ML_ERROR, "AsyncResolve failed.");
     ABORT(R_NOT_FOUND);
   }
   // Because the C API offers no "finished" method to release the handle we
   // return, we cannot return the request we got from AsyncResolve directly.
   //
   // Instead, we return an addref'ed reference to PendingResolution itself,
--- a/media/mtransport/nriceresolverfake.cpp
+++ b/media/mtransport/nriceresolverfake.cpp
@@ -117,16 +117,17 @@ int NrIceResolverFake::resolve(void *obj
 
   PendingResolution *pending =
       new PendingResolution(fake,
                             resource->domain_name,
                             resource->port ? resource->port : 3478,
                             resource->transport_protocol ?
                             resource->transport_protocol :
                             IPPROTO_UDP,
+                            resource->address_family,
                             cb, cb_arg);
 
   if ((r=NR_ASYNC_TIMER_SET(fake->delay_ms_,NrIceResolverFake::resolve_cb,
                             (void *)pending, &pending->timer_handle_))) {
     delete pending;
     ABORT(r);
   }
   *handle = pending;
@@ -135,17 +136,18 @@ int NrIceResolverFake::resolve(void *obj
 abort:
   return(_status);
 }
 
 void NrIceResolverFake::resolve_cb(NR_SOCKET s, int how, void *cb_arg) {
   MOZ_ASSERT(cb_arg);
   PendingResolution *pending = static_cast<PendingResolution *>(cb_arg);
 
-  const PRNetAddr *addr=pending->resolver_->Resolve(pending->hostname_);
+  const PRNetAddr *addr=pending->resolver_->Resolve(pending->hostname_,
+                                                    pending->address_family_);
 
   if (addr) {
     nr_transport_addr transport_addr;
 
     int r = nr_praddr_to_transport_addr(addr, &transport_addr,
                                         pending->transport_, 0);
     MOZ_ASSERT(!r);
     if (r)
--- a/media/mtransport/nriceresolverfake.h
+++ b/media/mtransport/nriceresolverfake.h
@@ -58,17 +58,26 @@ typedef struct nr_resolver_resource_ nr_
 namespace mozilla {
 
 class NrIceResolverFake {
  public:
   NrIceResolverFake();
   ~NrIceResolverFake();
 
   void SetAddr(const std::string& hostname, const PRNetAddr& addr) {
-    addrs_[hostname] = addr;
+    switch (addr.raw.family) {
+      case AF_INET:
+        addrs_[hostname] = addr;
+        break;
+      case AF_INET6:
+        addrs6_[hostname] = addr;
+        break;
+      default:
+        MOZ_CRASH();
+    }
   }
 
   nr_resolver *AllocateResolver();
 
   void DestroyResolver();
 
 private:
   // Implementations of vtbl functions
@@ -78,47 +87,61 @@ private:
                      int (*cb)(void *cb_arg,
                                nr_transport_addr *addr),
                      void *cb_arg,
                      void **handle);
   static void resolve_cb(NR_SOCKET s, int how, void *cb_arg);
   static int cancel(void *obj, void *handle);
 
   // Get an address.
-  const PRNetAddr *Resolve(const std::string& hostname) {
-    if (!addrs_.count(hostname))
-      return nullptr;
+  const PRNetAddr *Resolve(const std::string& hostname, int address_family) {
+    switch (address_family) {
+      case AF_INET:
+        if (!addrs_.count(hostname))
+          return nullptr;
 
-    return &addrs_[hostname];
+        return &addrs_[hostname];
+      case AF_INET6:
+        if (!addrs6_.count(hostname))
+          return nullptr;
+
+        return &addrs6_[hostname];
+      default:
+        MOZ_CRASH();
+    }
   }
 
 
   struct PendingResolution {
     PendingResolution(NrIceResolverFake *resolver,
                       const std::string& hostname,
                       uint16_t port,
                       int transport,
+                      int address_family,
                       int (*cb)(void *cb_arg, nr_transport_addr *addr),
                       void *cb_arg) :
         resolver_(resolver),
         hostname_(hostname),
         port_(port),
         transport_(transport),
+        address_family_(address_family),
         cb_(cb), cb_arg_(cb_arg) {}
 
     NrIceResolverFake *resolver_;
     std::string hostname_;
     uint16_t port_;
     int transport_;
+    int address_family_;
     int (*cb_)(void *cb_arg, nr_transport_addr *addr);
     void *cb_arg_;
     void *timer_handle_;
   };
 
   nr_resolver_vtbl* vtbl_;
   std::map<std::string, PRNetAddr> addrs_;
+  std::map<std::string, PRNetAddr> addrs6_;
   uint32_t delay_ms_;
   int allocated_resolvers_;
 };
 
 }  // End of namespace mozilla
 
 #endif
--- a/media/mtransport/nrinterfaceprioritizer.cpp
+++ b/media/mtransport/nrinterfaceprioritizer.cpp
@@ -13,29 +13,31 @@ MOZ_MTLOG_MODULE("mtransport")
 namespace {
 
 class LocalAddress {
 public:
   LocalAddress()
     : key_(),
       is_vpn_(-1),
       estimated_speed_(-1),
-      type_preference_(-1) {}
+      type_preference_(-1),
+      ip_version_(-1) {}
 
   bool Init(const nr_local_addr& local_addr) {
     char buf[MAXIFNAME + 41];
     int r = nr_transport_addr_fmt_ifname_addr_string(&local_addr.addr, buf, sizeof(buf));
     if (r) {
       MOZ_MTLOG(ML_ERROR, "Error formatting interface address string.");
       return false;
     }
     key_ = buf;
     is_vpn_ = (local_addr.interface.type & NR_INTERFACE_TYPE_VPN) != 0 ? 1 : 0;
     estimated_speed_ = local_addr.interface.estimated_speed;
     type_preference_ = GetNetworkTypePreference(local_addr.interface.type);
+    ip_version_ = local_addr.addr.ip_version;
     return true;
   }
 
   bool operator<(const LocalAddress& rhs) const {
     // Interface that is "less" here is preferred.
     // If type preferences are different, we should simply sort by
     // |type_preference_|.
     if (type_preference_ != rhs.type_preference_) {
@@ -49,16 +51,21 @@ public:
       return is_vpn_ < rhs.is_vpn_;
     }
 
     // Compare estimated speed.
     if (estimated_speed_ != rhs.estimated_speed_) {
       return estimated_speed_ > rhs.estimated_speed_;
     }
 
+    // Prefer IPV6 over IPV4
+    if (ip_version_ != rhs.ip_version_) {
+      return ip_version_ > rhs.ip_version_;
+    }
+
     // All things above are the same, we can at least sort with key.
     return key_ < rhs.key_;
   }
 
   const std::string& GetKey() const {
     return key_;
   }
 
@@ -77,16 +84,17 @@ private:
     }
     return 4;
   }
 
   std::string key_;
   int is_vpn_;
   int estimated_speed_;
   int type_preference_;
+  int ip_version_;
 };
 
 class InterfacePrioritizer {
 public:
   InterfacePrioritizer()
     : local_addrs_(),
       preference_map_(),
       sorted_(false) {}
--- a/media/mtransport/stun_udp_socket_filter.cpp
+++ b/media/mtransport/stun_udp_socket_filter.cpp
@@ -16,52 +16,61 @@ extern "C" {
 #include "nr_socket_prsock.h"
 #if defined(MOZILLA_XPCOMRT_API)
 #include "mozilla/Module.h"
 #include "mozilla/ModuleUtils.h"
 #endif
 
 namespace {
 
-class NetAddressAdapter {
+class NetAddrCompare {
  public:
-  MOZ_IMPLICIT NetAddressAdapter(const mozilla::net::NetAddr& netaddr)
-    : addr_(ntohl(netaddr.inet.ip)),
-      port_(ntohs(netaddr.inet.port)) {
-    MOZ_ASSERT(netaddr.raw.family == AF_INET);
-  }
+   bool operator()(const mozilla::net::NetAddr& lhs,
+                   const mozilla::net::NetAddr& rhs) const {
+     if (lhs.raw.family != rhs.raw.family) {
+       return lhs.raw.family < rhs.raw.family;
+     }
 
-  bool operator<(const NetAddressAdapter& rhs) const {
-    return addr_ != rhs.addr_ ? (addr_ < rhs.addr_) : (port_ < rhs.port_);
-  }
-
-  bool operator!=(const NetAddressAdapter& rhs) const {
-    return (*this < rhs) || (rhs < *this);
-  }
-
- private:
-  const uint32_t addr_;
-  const uint16_t port_;
+     switch (lhs.raw.family) {
+       case AF_INET:
+         if (lhs.inet.port != rhs.inet.port) {
+           return lhs.inet.port < rhs.inet.port;
+         }
+         return lhs.inet.ip < rhs.inet.ip;
+       case AF_INET6:
+         if (lhs.inet6.port != rhs.inet6.port) {
+           return lhs.inet6.port < rhs.inet6.port;
+         }
+         return memcmp(&lhs.inet6.ip, &rhs.inet6.ip, sizeof(lhs.inet6.ip)) < 0;
+       default:
+         MOZ_ASSERT(false);
+     }
+     return false;
+   }
 };
 
 class PendingSTUNRequest {
  public:
-  PendingSTUNRequest(const NetAddressAdapter& netaddr, const UINT12 &id)
+  PendingSTUNRequest(const mozilla::net::NetAddr& netaddr, const UINT12 &id)
     : id_(id),
       net_addr_(netaddr),
       is_id_set_(true) {}
 
-  MOZ_IMPLICIT PendingSTUNRequest(const NetAddressAdapter& netaddr)
+  MOZ_IMPLICIT PendingSTUNRequest(const mozilla::net::NetAddr& netaddr)
     : id_(),
       net_addr_(netaddr),
       is_id_set_(false) {}
 
   bool operator<(const PendingSTUNRequest& rhs) const {
-    if (net_addr_ != rhs.net_addr_) {
-      return net_addr_ < rhs.net_addr_;
+    if (NetAddrCompare()(net_addr_, rhs.net_addr_)) {
+      return true;
+    }
+
+    if (NetAddrCompare()(rhs.net_addr_, net_addr_)) {
+      return false;
     }
 
     if (!is_id_set_ && !rhs.is_id_set_) {
       // PendingSTUNRequest can be stored to set only when it has id,
       // so comparing two PendingSTUNRequst without id is not going
       // to happen.
       MOZ_CRASH();
     }
@@ -71,17 +80,17 @@ class PendingSTUNRequest {
       return false;
     }
 
     return memcmp(id_.octet, rhs.id_.octet, sizeof(id_.octet)) < 0;
   }
 
  private:
   const UINT12 id_;
-  const NetAddressAdapter net_addr_;
+  const mozilla::net::NetAddr net_addr_;
   const bool is_id_set_;
 };
 
 class STUNUDPSocketFilter : public nsIUDPSocketFilter {
  public:
   STUNUDPSocketFilter()
     : white_list_(),
       pending_requests_() {}
@@ -96,35 +105,29 @@ class STUNUDPSocketFilter : public nsIUD
   bool filter_incoming_packet(const mozilla::net::NetAddr *remote_addr,
                               const uint8_t *data,
                               uint32_t len);
 
   bool filter_outgoing_packet(const mozilla::net::NetAddr *remote_addr,
                               const uint8_t *data,
                               uint32_t len);
 
-  std::set<NetAddressAdapter> white_list_;
+  std::set<mozilla::net::NetAddr, NetAddrCompare> white_list_;
   std::set<PendingSTUNRequest> pending_requests_;
   std::set<PendingSTUNRequest> response_allowed_;
 };
 
 NS_IMPL_ISUPPORTS(STUNUDPSocketFilter, nsIUDPSocketFilter)
 
 NS_IMETHODIMP
 STUNUDPSocketFilter::FilterPacket(const mozilla::net::NetAddr *remote_addr,
                                   const uint8_t *data,
                                   uint32_t len,
                                   int32_t direction,
                                   bool *result) {
-  // Allowing IPv4 address only.
-  if (remote_addr->raw.family != AF_INET) {
-    *result = false;
-    return NS_OK;
-  }
-
   switch (direction) {
     case nsIUDPSocketFilter::SF_INCOMING:
       *result = filter_incoming_packet(remote_addr, data, len);
       break;
     case nsIUDPSocketFilter::SF_OUTGOING:
       *result = filter_outgoing_packet(remote_addr, data, len);
       break;
     default:
--- a/media/mtransport/test/buffered_stun_socket_unittest.cpp
+++ b/media/mtransport/test/buffered_stun_socket_unittest.cpp
@@ -59,17 +59,17 @@ class BufferedStunSocketTest : public ::
     int r = nr_socket_buffered_stun_create(
         dummy->get_nr_socket(),
         kStunMessageLen,
         TURN_TCP_FRAMING,
         &test_socket_);
     ASSERT_EQ(0, r);
     dummy_ = dummy.forget();  // Now owned by test_socket_.
 
-    r = nr_ip4_str_port_to_transport_addr(
+    r = nr_str_port_to_transport_addr(
         (char *)"192.0.2.133", 3333, IPPROTO_TCP, &remote_addr_);
     ASSERT_EQ(0, r);
 
     r = nr_socket_connect(test_socket_,
                           &remote_addr_);
     ASSERT_EQ(0, r);
   }
 
@@ -179,17 +179,17 @@ TEST_F(BufferedStunSocketTest, TestSendT
   ASSERT_EQ(R_WOULDBLOCK, r);
 
   dummy_->CheckWriteBuffer(nullptr, 0);
 }
 
 TEST_F(BufferedStunSocketTest, TestSendToWrongAddr) {
   nr_transport_addr addr;
 
-  int r = nr_ip4_str_port_to_transport_addr(
+  int r = nr_str_port_to_transport_addr(
       (char *)"192.0.2.134", 3333, IPPROTO_TCP, &addr);
   ASSERT_EQ(0, r);
 
   r = nr_socket_sendto(test_socket_,
                        kStunMessage,
                        kStunMessageLen,
                        0, &addr);
   ASSERT_EQ(R_BAD_DATA, r);
--- a/media/mtransport/test/ice_unittest.cpp
+++ b/media/mtransport/test/ice_unittest.cpp
@@ -349,18 +349,18 @@ class IceTestPeer : public sigslot::has_
     SetStunServers(stun_servers);
   }
 
   void SetStunServers(const std::vector<NrIceStunServer> &servers) {
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(servers)));
   }
 
   void UseTestStunServer() {
-    SetStunServer(TestStunServer::GetInstance()->addr(),
-                  TestStunServer::GetInstance()->port());
+    SetStunServer(TestStunServer::GetInstance(AF_INET)->addr(),
+                  TestStunServer::GetInstance(AF_INET)->port());
   }
 
   void SetTurnServer(const std::string addr, uint16_t port,
                      const std::string username,
                      const std::string password,
                      const char* transport) {
     std::vector<unsigned char> password_vec(password.begin(), password.end());
     SetTurnServer(addr, port, username, password_vec, transport);
@@ -377,25 +377,25 @@ class IceTestPeer : public sigslot::has_
     turn_servers.push_back(*server);
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetTurnServers(turn_servers)));
   }
 
   void SetTurnServers(const std::vector<NrIceTurnServer> servers) {
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetTurnServers(servers)));
   }
 
-  void SetFakeResolver() {
+  void SetFakeResolver(const std::string& ip = g_stun_server_address,
+                       const std::string& fqdn = g_stun_server_hostname) {
     ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init()));
-    if (!g_stun_server_address.empty() && !g_stun_server_hostname.empty()) {
+    if (!ip.empty() && !fqdn.empty()) {
       PRNetAddr addr;
-      PRStatus status = PR_StringToNetAddr(g_stun_server_address.c_str(),
-                                            &addr);
+      PRStatus status = PR_StringToNetAddr(ip.c_str(), &addr);
       addr.inet.port = kDefaultStunServerPort;
       ASSERT_EQ(PR_SUCCESS, status);
-      fake_resolver_.SetAddr(g_stun_server_hostname, addr);
+      fake_resolver_.SetAddr(fqdn, addr);
     }
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver(
         fake_resolver_.AllocateResolver())));
   }
 
   void SetDNSResolver() {
     ASSERT_TRUE(NS_SUCCEEDED(dns_resolver_->Init()));
     ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetResolver(
@@ -1093,19 +1093,26 @@ void SchedulableTrickleCandidate::Trickl
   timer_handle_ = nullptr;
   nsresult res = peer_->TrickleCandidate_s(candidate_, stream_);
   ASSERT_TRUE(NS_SUCCEEDED(res));
 }
 
 class IceGatherTest : public ::testing::Test {
  public:
   void SetUp() {
-    test_utils->sts_target()->Dispatch(WrapRunnable(TestStunServer::GetInstance(),
-                                                    &TestStunServer::Reset),
-                                       NS_DISPATCH_SYNC);
+    test_utils->sts_target()->Dispatch(
+        WrapRunnable(TestStunServer::GetInstance(AF_INET),
+                     &TestStunServer::Reset),
+        NS_DISPATCH_SYNC);
+    if (TestStunServer::GetInstance(AF_INET6)) {
+      test_utils->sts_target()->Dispatch(
+          WrapRunnable(TestStunServer::GetInstance(AF_INET6),
+                       &TestStunServer::Reset),
+          NS_DISPATCH_SYNC);
+    }
   }
 
   void TearDown() {
     peer_ = nullptr;
 
     test_utils->sts_target()->Dispatch(WrapRunnable(this,
                                                     &IceGatherTest::TearDown_s),
                                        NS_DISPATCH_SYNC);
@@ -1130,64 +1137,100 @@ class IceGatherTest : public ::testing::
       WaitForGather(waitTime);
     }
   }
 
   void WaitForGather(unsigned int waitTime = kDefaultTimeout) {
     ASSERT_TRUE_WAIT(peer_->gathering_complete(), waitTime);
   }
 
-  void UseFakeStunUdpServerWithResponse(const std::string& fake_addr,
-                                        uint16_t fake_port) {
-    EnsurePeer();
-    TestStunServer::GetInstance()->SetResponseAddr(fake_addr, fake_port);
-    // Sets an additional stun server
-    peer_->SetStunServer(TestStunServer::GetInstance()->addr(),
-                         TestStunServer::GetInstance()->port(),
-                         kNrIceTransportUdp);
+  void AddStunServerWithResponse(
+      const std::string& fake_addr,
+      uint16_t fake_port,
+      const std::string& fqdn,
+      const std::string& proto,
+      std::vector<NrIceStunServer>* stun_servers) {
+    int family;
+    if (fake_addr.find(':') != std::string::npos) {
+      family = AF_INET6;
+    } else {
+      family = AF_INET;
+    }
+
+    std::string stun_addr;
+    uint16_t stun_port;
+    if (proto == kNrIceTransportUdp) {
+      TestStunServer::GetInstance(family)->SetResponseAddr(fake_addr,
+                                                           fake_port);
+      stun_addr = TestStunServer::GetInstance(family)->addr();
+      stun_port = TestStunServer::GetInstance(family)->port();
+    } else if (proto == kNrIceTransportTcp) {
+      TestStunTcpServer::GetInstance(family)->SetResponseAddr(fake_addr,
+                                                              fake_port);
+      stun_addr = TestStunTcpServer::GetInstance(family)->addr();
+      stun_port = TestStunTcpServer::GetInstance(family)->port();
+    } else {
+      MOZ_CRASH();
+    }
+
+    if (!fqdn.empty()) {
+      peer_->SetFakeResolver(stun_addr, fqdn);
+      stun_addr = fqdn;
+    }
+
+    stun_servers->push_back(*NrIceStunServer::Create(stun_addr,
+                                                     stun_port,
+                                                     proto.c_str()));
   }
 
-  void UseFakeStunTcpServerWithResponse(const std::string& fake_addr,
-                                        uint16_t fake_port) {
-    EnsurePeer();
-    TestStunTcpServer::GetInstance()->SetResponseAddr(fake_addr, fake_port);
-    // Sets an additional stun server
-    peer_->SetStunServer(TestStunTcpServer::GetInstance()->addr(),
-                         TestStunTcpServer::GetInstance()->port(),
-                         kNrIceTransportTcp);
-  }
-
-  void UseFakeStunUdpTcpServersWithResponse(const std::string& fake_udp_addr,
-                                            uint16_t fake_udp_port,
-                                            const std::string& fake_tcp_addr,
-                                            uint16_t fake_tcp_port) {
+  void UseFakeStunUdpServerWithResponse(
+      const std::string& fake_addr,
+      uint16_t fake_port,
+      const std::string& fqdn = std::string()) {
     EnsurePeer();
     std::vector<NrIceStunServer> stun_servers;
-
-    stun_servers.push_back(*NrIceStunServer::Create(
-        TestStunServer::GetInstance()->addr(),
-        TestStunServer::GetInstance()->port(),
-        kNrIceTransportUdp));
-    stun_servers.push_back(*NrIceStunServer::Create(
-        TestStunTcpServer::GetInstance()->addr(),
-        TestStunTcpServer::GetInstance()->port(),
-        kNrIceTransportTcp));
-
-    TestStunServer::GetInstance()->SetResponseAddr(fake_udp_addr,
-                                                   fake_udp_port);
-    TestStunTcpServer::GetInstance()->SetResponseAddr(fake_tcp_addr,
-                                                      fake_tcp_port);
-    // Sets an additional stun server
+    AddStunServerWithResponse(fake_addr, fake_port, fqdn, "udp", &stun_servers);
+    peer_->SetStunServers(stun_servers);
+  }
+
+  void UseFakeStunTcpServerWithResponse(
+      const std::string& fake_addr,
+      uint16_t fake_port,
+      const std::string& fqdn = std::string()) {
+    EnsurePeer();
+    std::vector<NrIceStunServer> stun_servers;
+    AddStunServerWithResponse(fake_addr, fake_port, fqdn, "tcp", &stun_servers);
+    peer_->SetStunServers(stun_servers);
+  }
+
+  void UseFakeStunUdpTcpServersWithResponse(
+      const std::string& fake_udp_addr,
+      uint16_t fake_udp_port,
+      const std::string& fake_tcp_addr,
+      uint16_t fake_tcp_port) {
+    EnsurePeer();
+    std::vector<NrIceStunServer> stun_servers;
+    AddStunServerWithResponse(fake_udp_addr,
+                              fake_udp_port,
+                              "", // no fqdn
+                              "udp",
+                              &stun_servers);
+    AddStunServerWithResponse(fake_tcp_addr,
+                              fake_tcp_port,
+                              "", // no fqdn
+                              "tcp",
+                              &stun_servers);
+
     peer_->SetStunServers(stun_servers);
   }
 
   void UseTestStunServer() {
-    TestStunServer::GetInstance()->Reset();
-    peer_->SetStunServer(TestStunServer::GetInstance()->addr(),
-                         TestStunServer::GetInstance()->port());
+    TestStunServer::GetInstance(AF_INET)->Reset();
+    peer_->SetStunServer(TestStunServer::GetInstance(AF_INET)->addr(),
+                         TestStunServer::GetInstance(AF_INET)->port());
   }
 
   // NB: Only does substring matching, watch out for stuff like "1.2.3.4"
   // matching "21.2.3.47". " 1.2.3.4 " should not have false positives.
   bool StreamHasMatchingCandidate(unsigned int stream,
                                   const std::string& match,
                                   const std::string& match2 = "") {
     std::vector<std::string> candidates = peer_->GetCandidates(stream);
@@ -1309,17 +1352,17 @@ class IceConnectTest : public ::testing:
     mapping_type_ = type;
   }
 
   void BlockUdp() {
     block_udp_ = true;
   }
 
   void UseTestStunServer() {
-    TestStunServer::GetInstance()->Reset();
+    TestStunServer::GetInstance(AF_INET)->Reset();
     p1_->UseTestStunServer();
     p2_->UseTestStunServer();
   }
 
   void SetTurnServer(const std::string addr, uint16_t port,
                      const std::string username,
                      const std::string password,
                      const char* transport = kNrIceTransportUdp) {
@@ -1477,18 +1520,18 @@ class PrioritizerTest : public ::testing
 
   void AddInterface(const std::string& num, int type, int estimated_speed) {
     std::string str_addr = "10.0.0." + num;
     std::string ifname = "eth" + num;
     nr_local_addr local_addr;
     local_addr.interface.type = type;
     local_addr.interface.estimated_speed = estimated_speed;
 
-    int r = nr_ip4_str_port_to_transport_addr(str_addr.c_str(), 0,
-                                              IPPROTO_UDP, &(local_addr.addr));
+    int r = nr_str_port_to_transport_addr(str_addr.c_str(), 0,
+                                          IPPROTO_UDP, &(local_addr.addr));
     ASSERT_EQ(0, r);
     strncpy(local_addr.addr.ifname, ifname.c_str(), MAXIFNAME);
 
     r = nr_interface_prioritizer_add_interface(prioritizer_, &local_addr);
     ASSERT_EQ(0, r);
     r = nr_interface_prioritizer_sort_preference(prioritizer_);
     ASSERT_EQ(0, r);
   }
@@ -1786,63 +1829,109 @@ TEST_F(IceGatherTest, VerifyTestStunServ
 
 TEST_F(IceGatherTest, VerifyTestStunTcpServer) {
   UseFakeStunTcpServerWithResponse("192.0.2.233", 3333);
   Gather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.2.233 3333 typ srflx",
     " tcptype "));
 }
 
+TEST_F(IceGatherTest, VerifyTestStunServerV6) {
+  if (!TestStunServer::GetInstance(AF_INET6)) {
+    // No V6 addresses
+    return;
+  }
+  UseFakeStunUdpServerWithResponse("beef::", 3333);
+  Gather();
+  ASSERT_TRUE(StreamHasMatchingCandidate(0, " beef:: 3333 "));
+}
+
+TEST_F(IceGatherTest, VerifyTestStunServerFQDN) {
+  UseFakeStunUdpServerWithResponse("192.0.2.133", 3333, "stun.example.com");
+  Gather();
+  ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.2.133 3333 "));
+}
+
+TEST_F(IceGatherTest, VerifyTestStunServerV6FQDN) {
+  if (!TestStunServer::GetInstance(AF_INET6)) {
+    // No V6 addresses
+    return;
+  }
+  UseFakeStunUdpServerWithResponse("beef::", 3333, "stun.example.com");
+  Gather();
+  ASSERT_TRUE(StreamHasMatchingCandidate(0, " beef:: 3333 "));
+}
+
 TEST_F(IceGatherTest, TestStunServerReturnsWildcardAddr) {
   UseFakeStunUdpServerWithResponse("0.0.0.0", 3333);
   Gather(kDefaultTimeout * 3);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 0.0.0.0 "));
 }
 
+TEST_F(IceGatherTest, TestStunServerReturnsWildcardAddrV6) {
+  if (!TestStunServer::GetInstance(AF_INET6)) {
+    // No V6 addresses
+    return;
+  }
+  UseFakeStunUdpServerWithResponse("::", 3333);
+  Gather(kDefaultTimeout * 3);
+  ASSERT_FALSE(StreamHasMatchingCandidate(0, " :: "));
+}
+
 TEST_F(IceGatherTest, TestStunServerReturnsPort0) {
   UseFakeStunUdpServerWithResponse("192.0.2.133", 0);
   Gather(kDefaultTimeout * 3);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.2.133 0 "));
 }
 
 TEST_F(IceGatherTest, TestStunServerReturnsLoopbackAddr) {
   UseFakeStunUdpServerWithResponse("127.0.0.133", 3333);
   Gather(kDefaultTimeout * 3);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 127.0.0.133 "));
 }
 
+TEST_F(IceGatherTest, TestStunServerReturnsLoopbackAddrV6) {
+  if (!TestStunServer::GetInstance(AF_INET6)) {
+    // No V6 addresses
+    return;
+  }
+  UseFakeStunUdpServerWithResponse("::1", 3333);
+  Gather(kDefaultTimeout * 3);
+  ASSERT_FALSE(StreamHasMatchingCandidate(0, " ::1 "));
+}
+
 TEST_F(IceGatherTest, TestStunServerTrickle) {
   UseFakeStunUdpServerWithResponse("192.0.2.1", 3333);
-  TestStunServer::GetInstance()->SetActive(false);
+  TestStunServer::GetInstance(AF_INET)->SetActive(false);
   Gather(0);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, "192.0.2.1"));
-  TestStunServer::GetInstance()->SetActive(true);
+  TestStunServer::GetInstance(AF_INET)->SetActive(true);
   WaitForGather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1"));
 }
 
 TEST_F(IceGatherTest, TestStunTcpServerTrickle) {
   UseFakeStunTcpServerWithResponse("192.0.3.1", 3333);
-  TestStunTcpServer::GetInstance()->SetActive(false);
+  TestStunTcpServer::GetInstance(AF_INET)->SetActive(false);
   Gather(0);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
-  TestStunTcpServer::GetInstance()->SetActive(true);
+  TestStunTcpServer::GetInstance(AF_INET)->SetActive(true);
   WaitForGather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
 }
 
 TEST_F(IceGatherTest, TestStunTcpAndUdpServerTrickle) {
   UseFakeStunUdpTcpServersWithResponse("192.0.2.1", 3333, "192.0.3.1", 3333);
-  TestStunServer::GetInstance()->SetActive(false);
-  TestStunTcpServer::GetInstance()->SetActive(false);
+  TestStunServer::GetInstance(AF_INET)->SetActive(false);
+  TestStunTcpServer::GetInstance(AF_INET)->SetActive(false);
   Gather(0);
   ASSERT_FALSE(StreamHasMatchingCandidate(0, "192.0.2.1", "UDP"));
   ASSERT_FALSE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
-  TestStunServer::GetInstance()->SetActive(true);
-  TestStunTcpServer::GetInstance()->SetActive(true);
+  TestStunServer::GetInstance(AF_INET)->SetActive(true);
+  TestStunTcpServer::GetInstance(AF_INET)->SetActive(true);
   WaitForGather();
   ASSERT_TRUE(StreamHasMatchingCandidate(0, "192.0.2.1", "UDP"));
   ASSERT_TRUE(StreamHasMatchingCandidate(0, " 192.0.3.1 ", " tcptype "));
 }
 
 TEST_F(IceConnectTest, TestGather) {
   AddStream("first", 1);
   ASSERT_TRUE(Gather());
@@ -2858,20 +2947,28 @@ int main(int argc, char **argv)
   ::testing::InitGoogleTest(&argc, argv);
 
   ::testing::TestEventListeners& listeners =
         ::testing::UnitTest::GetInstance()->listeners();
   // Adds a listener to the end.  Google Test takes the ownership.
 
   listeners.Append(new test::RingbufferDumper(test_utils));
   test_utils->sts_target()->Dispatch(
-    WrapRunnableNM(&TestStunServer::GetInstance), NS_DISPATCH_SYNC);
+      WrapRunnableNM(&TestStunServer::GetInstance, AF_INET),
+                     NS_DISPATCH_SYNC);
+  test_utils->sts_target()->Dispatch(
+    WrapRunnableNM(&TestStunServer::GetInstance, AF_INET6),
+                   NS_DISPATCH_SYNC);
 
   test_utils->sts_target()->Dispatch(
-    WrapRunnableNM(&TestStunTcpServer::GetInstance), NS_DISPATCH_SYNC);
+      WrapRunnableNM(&TestStunTcpServer::GetInstance, AF_INET),
+                     NS_DISPATCH_SYNC);
+  test_utils->sts_target()->Dispatch(
+    WrapRunnableNM(&TestStunTcpServer::GetInstance, AF_INET6),
+                   NS_DISPATCH_SYNC);
 
   int rv = RUN_ALL_TESTS();
 
   test_utils->sts_target()->Dispatch(
     WrapRunnableNM(&TestStunServer::ShutdownInstance), NS_DISPATCH_SYNC);
 
   test_utils->sts_target()->Dispatch(
     WrapRunnableNM(&TestStunTcpServer::ShutdownInstance), NS_DISPATCH_SYNC);
--- a/media/mtransport/test/multi_tcp_socket_unittest.cpp
+++ b/media/mtransport/test/multi_tcp_socket_unittest.cpp
@@ -107,17 +107,17 @@ class MultiTcpSocketTest : public ::test
           stun_host, port, kNrIceTransportTcp));
       stun_servers.push_back(*server);
 
       ASSERT_TRUE(NS_SUCCEEDED(ice_ctx_->SetStunServers(stun_servers)));
     }
 
     r = 1;
     for (int tries=10; tries && r; --tries) {
-      r = nr_ip4_str_port_to_transport_addr(
+      r = nr_str_port_to_transport_addr(
         (char *)"127.0.0.1", EnsureEphemeral(port_s++), IPPROTO_TCP, &local);
       ASSERT_EQ(0, r);
 
       r = nr_socket_multi_tcp_create(ice_ctx_->ctx(),
           &local, tcp_type, 1, use_framing, 2048, sock);
     }
 
     ASSERT_EQ(0, r);
--- a/media/mtransport/test/proxy_tunnel_socket_unittest.cpp
+++ b/media/mtransport/test/proxy_tunnel_socket_unittest.cpp
@@ -79,17 +79,17 @@ class DummyResolver {
 
   static int resolve(void *obj,
                      nr_resolver_resource *resource,
                      int (*cb)(void *cb_arg, nr_transport_addr *addr),
                      void *cb_arg,
                      void **handle) {
     nr_transport_addr addr;
 
-    nr_ip4_str_port_to_transport_addr(
+    nr_str_port_to_transport_addr(
         (char *)kProxyAddr.c_str(), kProxyPort, IPPROTO_TCP, &addr);
 
     cb(cb_arg, &addr);
     return 0;
   }
 
   static int cancel(void *obj, void *handle) {
     return 0;
@@ -115,21 +115,21 @@ class ProxyTunnelSocketTest : public ::t
     nr_proxy_tunnel_config_destroy(&config_);
   }
 
   void SetUp() {
     nsRefPtr<DummySocket> dummy(new DummySocket());
 
     nr_resolver_ = resolver_impl_.get_nr_resolver();
 
-    int r = nr_ip4_str_port_to_transport_addr(
+    int r = nr_str_port_to_transport_addr(
         (char *)kRemoteAddr.c_str(), kRemotePort, IPPROTO_TCP, &remote_addr_);
     ASSERT_EQ(0, r);
 
-    r = nr_ip4_str_port_to_transport_addr(
+    r = nr_str_port_to_transport_addr(
         (char *)kProxyAddr.c_str(), kProxyPort, IPPROTO_TCP, &proxy_addr_);
     ASSERT_EQ(0, r);
 
     nr_proxy_tunnel_config_create(&config_);
     nr_proxy_tunnel_config_set_resolver(config_, nr_resolver_);
     nr_proxy_tunnel_config_set_proxy(config_, kProxyAddr.c_str(), kProxyPort);
 
     r = nr_socket_proxy_tunnel_create(
--- a/media/mtransport/test/stunserver.cpp
+++ b/media/mtransport/test/stunserver.cpp
@@ -183,16 +183,18 @@ int nr_socket_wrapped_create(nr_socket *
 }
 
 
 // Instance static.
 // Note: Calling Create() at static init time is not going to be safe, since
 // we have no reason to expect this will be initted to a nullptr yet.
 TestStunServer* TestStunServer::instance;
 TestStunTcpServer* TestStunTcpServer::instance;
+TestStunServer* TestStunServer::instance6;
+TestStunTcpServer* TestStunTcpServer::instance6;
 uint16_t TestStunServer::instance_port = 3478;
 uint16_t TestStunTcpServer::instance_port = 3478;
 
 TestStunServer::~TestStunServer() {
   // TODO(ekr@rtfm.com): Put this on the right thread.
 
   // Unhook callback from our listen socket.
   if (listen_sock_) {
@@ -238,36 +240,49 @@ int TestStunServer::TryOpenListenSocket(
   if (nr_socket_local_create(nullptr, &addr->addr, &listen_sock_)) {
     MOZ_MTLOG(ML_ERROR, "Couldn't create listen socket");
     return R_ALREADY;
   }
 
   return 0;
 }
 
-int TestStunServer::Initialize() {
-  nr_local_addr addrs[100];
+int TestStunServer::Initialize(int address_family) {
+  static const size_t max_addrs = 100;
+  nr_local_addr addrs[max_addrs];
   int addr_ct;
   int r;
+  int i;
 
-  r = nr_stun_find_local_addresses(addrs, 100, &addr_ct);
+  r = nr_stun_find_local_addresses(addrs, max_addrs, &addr_ct);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't retrieve addresses");
     return R_INTERNAL;
   }
 
   if (addr_ct < 1) {
     MOZ_MTLOG(ML_ERROR, "No local addresses");
     return R_INTERNAL;
   }
 
+  for (i = 0; i < addr_ct; ++i) {
+    if (addrs[i].addr.addr->sa_family == address_family) {
+      break;
+    }
+  }
+
+  if (i == addr_ct) {
+    MOZ_MTLOG(ML_ERROR, "No local addresses of the configured IP version");
+    return R_INTERNAL;
+  }
+
   int tries = 100;
   while (tries--) {
-    // Bind to the first address (arbitrarily) on configured port (default 3478)
-    r = TryOpenListenSocket(&addrs[0], instance_port);
+    // Bind on configured port (default 3478)
+    r = TryOpenListenSocket(&addrs[i], instance_port);
     // We interpret R_ALREADY to mean the addr is probably in use. Try another.
     // Otherwise, it either worked or it didn't, and we check below.
     if (r != R_ALREADY) {
       break;
     }
     ++instance_port;
   }
 
@@ -286,35 +301,35 @@ int TestStunServer::Initialize() {
                                 &stun_server_);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't create STUN server");
     return R_INTERNAL;
   }
 
   // Cache the address and port.
   char addr_string[INET6_ADDRSTRLEN];
-  r = nr_transport_addr_get_addrstring(&addrs[0].addr, addr_string,
+  r = nr_transport_addr_get_addrstring(&addrs[i].addr, addr_string,
                                        sizeof(addr_string));
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Failed to convert listen addr to a string representation");
     return R_INTERNAL;
   }
 
   listen_addr_ = addr_string;
   listen_port_ = instance_port;
 
   return 0;
 }
 
-TestStunServer* TestStunServer::Create() {
+TestStunServer* TestStunServer::Create(int address_family) {
   NR_reg_init(NR_REG_MODE_LOCAL);
 
   ScopedDeletePtr<TestStunServer> server(new TestStunServer());
 
-  if (server->Initialize())
+  if (server->Initialize(address_family))
     return nullptr;
 
   NR_SOCKET fd;
   int r = nr_socket_getfd(server->listen_sock_, &fd);
   if (r) {
     MOZ_MTLOG(ML_ERROR, "Couldn't get fd");
     return nullptr;
   }
@@ -323,28 +338,39 @@ TestStunServer* TestStunServer::Create()
 
   return server.forget();
 }
 
 void TestStunServer::ConfigurePort(uint16_t port) {
   instance_port = port;
 }
 
-TestStunServer* TestStunServer::GetInstance() {
-  if (!instance)
-    instance = Create();
+TestStunServer* TestStunServer::GetInstance(int address_family) {
+  switch (address_family) {
+    case AF_INET:
+      if (!instance)
+        instance = Create(address_family);
 
-  MOZ_ASSERT(instance);
-  return instance;
+      MOZ_ASSERT(instance);
+      return instance;
+    case AF_INET6:
+      if (!instance6)
+        instance6 = Create(address_family);
+
+      return instance6;
+    default:
+      MOZ_CRASH();
+  }
 }
 
 void TestStunServer::ShutdownInstance() {
   delete instance;
-
   instance = nullptr;
+  delete instance6;
+  instance6 = nullptr;
 }
 
 
 struct DeferredStunOperation {
   DeferredStunOperation(TestStunServer *server,
                         const char *data, size_t len,
                         nr_transport_addr *addr) :
       server_(server),
@@ -448,19 +474,19 @@ nsresult TestStunServer::SetResponseAddr
 
   return NS_OK;
 }
 
 nsresult TestStunServer::SetResponseAddr(const std::string& addr,
                                          uint16_t port) {
   nr_transport_addr addr2;
 
-  int r = nr_ip4_str_port_to_transport_addr(addr.c_str(),
-                                            port, IPPROTO_UDP,
-                                            &addr2);
+  int r = nr_str_port_to_transport_addr(addr.c_str(),
+                                        port, IPPROTO_UDP,
+                                        &addr2);
   if (r)
     return NS_ERROR_FAILURE;
 
   return SetResponseAddr(&addr2);
 }
 
 void TestStunServer::Reset() {
   delay_ms_ = 0;
@@ -474,22 +500,32 @@ void TestStunServer::Reset() {
 
 
 // TestStunTcpServer
 
 void TestStunTcpServer::ConfigurePort(uint16_t port) {
   instance_port = port;
 }
 
-TestStunTcpServer* TestStunTcpServer::GetInstance() {
-  if (!instance)
-    instance = Create();
+TestStunTcpServer* TestStunTcpServer::GetInstance(int address_family) {
+  switch (address_family) {
+    case AF_INET:
+      if (!instance)
+        instance = Create(address_family);
 
-  MOZ_ASSERT(instance);
-  return instance;
+      MOZ_ASSERT(instance);
+      return instance;
+    case AF_INET6:
+      if (!instance6)
+        instance6 = Create(address_family);
+
+      return instance6;
+    default:
+      MOZ_CRASH();
+  }
 }
 
 void TestStunTcpServer::ShutdownInstance() {
   delete instance;
 
   instance = nullptr;
 }
 
@@ -518,22 +554,24 @@ int TestStunTcpServer::TryOpenListenSock
   if(nr_socket_listen(listen_sock_, 10)) {
     MOZ_MTLOG(ML_ERROR, "Couldn't listen on socket");
     return R_ALREADY;
   }
 
   return 0;
 }
 
-TestStunTcpServer* TestStunTcpServer::Create() {
+TestStunTcpServer* TestStunTcpServer::Create(int address_family) {
   NR_reg_init(NR_REG_MODE_LOCAL);
 
   ScopedDeletePtr<TestStunTcpServer> server(new TestStunTcpServer());
 
-  server->Initialize();
+  if (server->Initialize(address_family)) {
+    return nullptr;
+  }
 
   nr_socket_multi_tcp_set_readable_cb(server->listen_sock_,
     &TestStunServer::readable_cb, server.get());
 
   return server.forget();
 }
 
 TestStunTcpServer::~TestStunTcpServer() {
--- a/media/mtransport/test/stunserver.h
+++ b/media/mtransport/test/stunserver.h
@@ -19,22 +19,23 @@ typedef struct nr_socket_ nr_socket;
 typedef struct nr_local_addr_ nr_local_addr;
 
 namespace mozilla {
 
 class TestStunServer {
  public:
   // Generally, you should only call API in this class from the same thread that
   // the initial |GetInstance| call was made from.
-  static TestStunServer *GetInstance();
+  static TestStunServer *GetInstance(int address_family = AF_INET);
   static void ShutdownInstance();
   // |ConfigurePort| will only have an effect if called before the first call
   // to |GetInstance| (possibly following a |ShutdownInstance| call)
   static void ConfigurePort(uint16_t port);
-  static TestStunServer *Create();
+  // AF_INET, AF_INET6
+  static TestStunServer *Create(int address_family);
 
   virtual ~TestStunServer();
 
   void SetActive(bool active);
   void SetDelay(uint32_t delay_ms);
   void SetDropInitialPackets(uint32_t count);
   const std::string& addr() const { return listen_addr_; }
   uint16_t port() const { return listen_port_; }
@@ -54,17 +55,17 @@ class TestStunServer {
         stun_server_(nullptr),
         active_(true),
         delay_ms_(0),
         initial_ct_(0),
         response_addr_(nullptr),
         timer_handle_(nullptr) {}
 
   int SetInternalPort(nr_local_addr* addr, uint16_t port);
-  int Initialize();
+  int Initialize(int address_family);
   static void readable_cb(NR_SOCKET sock, int how, void *cb_arg);
 
  private:
   void Process(const uint8_t *msg, size_t len, nr_transport_addr *addr_in);
   virtual int TryOpenListenSocket(nr_local_addr* addr, uint16_t port);
   static void process_cb(NR_SOCKET sock, int how, void *cb_arg);
 
  protected:
@@ -77,31 +78,33 @@ class TestStunServer {
   bool active_;
   uint32_t delay_ms_;
   uint32_t initial_ct_;
   nr_transport_addr *response_addr_;
   void *timer_handle_;
   std::map<std::string, uint32_t> received_ct_;
 
   static TestStunServer* instance;
+  static TestStunServer* instance6;
   static uint16_t instance_port;
 };
 
 class TestStunTcpServer: public TestStunServer {
  public:
-  static TestStunTcpServer *GetInstance();
+  static TestStunTcpServer *GetInstance(int address_family);
   static void ShutdownInstance();
   static void ConfigurePort(uint16_t port);
   virtual ~TestStunTcpServer();
  protected:
   TestStunTcpServer()
       : ice_ctx_(nullptr) {}
 
   nsRefPtr<NrIceCtx> ice_ctx_;
  private:
   virtual int TryOpenListenSocket(nr_local_addr* addr, uint16_t port);
-  static TestStunTcpServer *Create();
+  static TestStunTcpServer *Create(int address_family);
 
   static TestStunTcpServer* instance;
+  static TestStunTcpServer* instance6;
   static uint16_t instance_port;
 };
 } // End of namespace mozilla
 #endif
--- a/media/mtransport/test/test_nr_socket_unittest.cpp
+++ b/media/mtransport/test/test_nr_socket_unittest.cpp
@@ -62,17 +62,17 @@ class TestNrSocketTest : public ::testin
   }
 
   nsRefPtr<TestNrSocket> CreateTestNrSocket_s(const char *ip_str,
                                               TestNat *nat) {
     // If no nat is supplied, we create a default NAT which is disabled. This
     // is how we simulate a non-natted socket.
     nsRefPtr<TestNrSocket> sock(new TestNrSocket(nat ? nat : new TestNat));
     nr_transport_addr address;
-    nr_ip4_str_port_to_transport_addr(ip_str, 0, IPPROTO_UDP, &address);
+    nr_str_port_to_transport_addr(ip_str, 0, IPPROTO_UDP, &address);
     int r = sock->create(&address);
     if (r) {
       return nullptr;
     }
     return sock;
   }
 
   void CreatePublicAddrs(size_t count, const char *ip_str = "127.0.0.1") {
--- a/media/mtransport/test/turn_unittest.cpp
+++ b/media/mtransport/test/turn_unittest.cpp
@@ -127,17 +127,17 @@ class TurnClient : public ::testing::Tes
           nr_socket_buffered_stun_create(real_socket_, 100000, TURN_TCP_FRAMING,
                                          &buffered_socket_);
       ASSERT_EQ(0, r);
       net_socket_ = buffered_socket_;
     } else {
       net_socket_ = real_socket_;
     }
 
-    r = nr_ip4_str_port_to_transport_addr(turn_server_.c_str(), 3478,
+    r = nr_str_port_to_transport_addr(turn_server_.c_str(), 3478,
       protocol_, &addr);
     ASSERT_EQ(0, r);
 
     std::vector<unsigned char> password_vec(
         g_turn_password.begin(), g_turn_password.end());
     Data password;
     INIT_DATA(password, &password_vec[0], password_vec.size());
     r = nr_turn_client_ctx_create("test", net_socket_,
@@ -232,20 +232,20 @@ class TurnClient : public ::testing::Tes
     ASSERT_EQ(0, target.compare(0, 4, "IP4:"));
 
     size_t offset = target.rfind(':');
     ASSERT_NE(std::string::npos, offset);
 
     std::string host = target.substr(4, offset - 4);
     std::string port = target.substr(offset + 1);
 
-    r = nr_ip4_str_port_to_transport_addr(host.c_str(),
-                                          atoi(port.c_str()),
-                                          IPPROTO_UDP,
-                                          &addr);
+    r = nr_str_port_to_transport_addr(host.c_str(),
+                                      atoi(port.c_str()),
+                                      IPPROTO_UDP,
+                                      &addr);
     ASSERT_EQ(0, r);
 
     r = nr_turn_client_ensure_perm(turn_ctx_, &addr);
     ASSERT_EQ(0, r);
   }
 
   void RequestPermission(const std::string& target) {
     RUN_ON_THREAD(test_utils->sts_target(),
@@ -319,20 +319,20 @@ class TurnClient : public ::testing::Tes
     ASSERT_EQ(0, target.compare(0, 4, "IP4:"));
 
     size_t offset = target.rfind(':');
     ASSERT_NE(std::string::npos, offset);
 
     std::string host = target.substr(4, offset - 4);
     std::string port = target.substr(offset + 1);
 
-    r = nr_ip4_str_port_to_transport_addr(host.c_str(),
-                                          atoi(port.c_str()),
-                                          IPPROTO_UDP,
-                                          &addr);
+    r = nr_str_port_to_transport_addr(host.c_str(),
+                                      atoi(port.c_str()),
+                                      IPPROTO_UDP,
+                                      &addr);
     ASSERT_EQ(0, r);
 
     unsigned char test[100];
     for (size_t i=0; i<sizeof(test); i++) {
       test[i] = i & 0xff;
     }
 
     std::cerr << "Sending test message to " << target << " ..." << std::endl;
@@ -483,33 +483,33 @@ int main(int argc, char **argv)
       g_turn_password.empty()) {
     printf(
         "Set TURN_SERVER_ADDRESS, TURN_SERVER_USER, and TURN_SERVER_PASSWORD\n"
         "environment variables to run this test\n");
     return 0;
   }
   {
     nr_transport_addr addr;
-    if (nr_ip4_str_port_to_transport_addr(g_turn_server.c_str(), 3478,
-                                          IPPROTO_UDP, &addr)) {
+    if (nr_str_port_to_transport_addr(g_turn_server.c_str(), 3478,
+                                      IPPROTO_UDP, &addr)) {
       printf("Invalid TURN_SERVER_ADDRESS \"%s\". Only IP numbers supported.\n",
              g_turn_server.c_str());
       return 0;
     }
   }
   test_utils = new MtransportTestUtils();
   NSS_NoDB_Init(nullptr);
   NSS_SetDomesticPolicy();
 
   // Set up the ICE registry, etc.
   // TODO(ekr@rtfm.com): Clean up
   std::string dummy("dummy");
   RUN_ON_THREAD(test_utils->sts_target(),
                 WrapRunnableNM(&NrIceCtx::Create,
-                               dummy, false, false, false, false),
+                               dummy, false, false, false, false, false),
                 NS_DISPATCH_SYNC);
 
   // Start the tests
   ::testing::InitGoogleTest(&argc, argv);
 
   int rv = RUN_ALL_TESTS();
   delete test_utils;
   return rv;
--- a/media/mtransport/third_party/nICEr/IMPORT_FILES
+++ b/media/mtransport/third_party/nICEr/IMPORT_FILES
@@ -32,16 +32,18 @@
                 ./src/net/transport_addr.c
                 ./src/net/transport_addr.h
                 ./src/net/transport_addr_reg.c
                 ./src/net/transport_addr_reg.h
 
                 # STUN
                 ./src/stun/addrs.c
                 ./src/stun/addrs.h
+                ./src/stun/ifaddrs-android.c
+                ./src/stun/ifaddrs-android.h
                 ./src/stun/nr_socket_turn.c
                 ./src/stun/nr_socket_turn.h
                 ./src/stun/stun.h
                 ./src/stun/stun_build.c
                 ./src/stun/stun_build.h
                 ./src/stun/stun_client_ctx.c
                 ./src/stun/stun_client_ctx.h
                 ./src/stun/stun_codec.c
--- a/media/mtransport/third_party/nICEr/nicer.gyp
+++ b/media/mtransport/third_party/nICEr/nicer.gyp
@@ -83,16 +83,18 @@
                 "./src/net/local_addr.c",
                 "./src/net/local_addr.h",
                 "./src/net/nr_interface_prioritizer.c",
                 "./src/net/nr_interface_prioritizer.h",
 
                 # STUN
                 "./src/stun/addrs.c",
                 "./src/stun/addrs.h",
+                "./src/stun/ifaddrs-android.c",
+                "./src/stun/ifaddrs-android.h",
                 "./src/stun/nr_socket_turn.c",
                 "./src/stun/nr_socket_turn.h",
                 "./src/stun/nr_socket_buffered_stun.c",
                 "./src/stun/nr_socket_buffered_stun.h",
                 "./src/stun/stun.h",
                 "./src/stun/stun_build.c",
                 "./src/stun/stun_build.h",
                 "./src/stun/stun_client_ctx.c",
--- a/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_candidate.c
@@ -59,17 +59,17 @@ static char *RCSSTRING __UNUSED__="$Id: 
 #include "ice_candidate.h"
 #include "ice_codeword.h"
 #include "ice_reg.h"
 #include "ice_util.h"
 #include "nr_socket_turn.h"
 #include "nr_socket.h"
 #include "nr_socket_multi_tcp.h"
 
-static int next_automatic_preference = 224;
+static int next_automatic_preference = 127;
 
 static int nr_ice_candidate_initialize2(nr_ice_candidate *cand);
 static int nr_ice_get_foundation(nr_ice_ctx *ctx,nr_ice_candidate *cand);
 static int nr_ice_srvrflx_start_stun(nr_ice_candidate *cand);
 static void nr_ice_srvrflx_stun_finished_cb(NR_SOCKET sock, int how, void *cb_arg);
 #ifdef USE_TURN
 static int nr_ice_start_relay_turn(nr_ice_candidate *cand);
 static void nr_ice_turn_allocated_cb(NR_SOCKET sock, int how, void *cb_arg);
@@ -465,18 +465,22 @@ int nr_ice_candidate_compute_priority(nr
             r_log(LOG_ICE,LOG_ERR,"Out of preference values. Can't assign one for interface %s",cand->base.ifname);
             ABORT(R_NOT_FOUND);
           }
           r_log(LOG_ICE,LOG_DEBUG,"Automatically assigning preference for interface %s->%d",cand->base.ifname,
             next_automatic_preference);
           if (r=NR_reg_set2_uchar(NR_ICE_REG_PREF_INTERFACE_PRFX,cand->base.ifname,next_automatic_preference)){
             ABORT(r);
           }
-          interface_preference=next_automatic_preference;
+          interface_preference=next_automatic_preference << 1;
           next_automatic_preference--;
+          if (cand->base.ip_version == NR_IPV6) {
+            /* Prefer IPV6 over IPV4 on the same interface. */
+            interface_preference += 1;
+          }
         }
         else {
           ABORT(r);
         }
       }
     }
     else {
       char key_of_interface[MAXIFNAME + 41];
@@ -545,16 +549,21 @@ int nr_ice_candidate_initialize(nr_ice_c
       case RELAYED:
         protocol=NR_RESOLVE_PROTOCOL_TURN;
         /* Fall through */
 #endif
       case SERVER_REFLEXIVE:
         cand->state=NR_ICE_CAND_STATE_INITIALIZING;
 
         if(cand->stun_server->type == NR_ICE_STUN_SERVER_TYPE_ADDR) {
+          if(cand->base.ip_version != cand->stun_server->u.addr.ip_version) {
+            r_log(LOG_ICE, LOG_INFO, "ICE-CANDIDATE(%s): Skipping srflx/relayed candidate with different IP version (%d) than STUN/TURN server (%d).", cand->label,cand->base.ip_version,cand->stun_server->u.addr.ip_version);
+            ABORT(R_NOT_FOUND); /* Same error code when DNS lookup fails */
+          }
+
           /* Just copy the address */
           if (r=nr_transport_addr_copy(&cand->stun_server_addr,
                                        &cand->stun_server->u.addr)) {
             r_log(LOG_ICE,LOG_ERR,"ICE-CANDIDATE(%s): Could not copy STUN server addr", cand->label);
             ABORT(r);
           }
 
           if(r=nr_ice_candidate_initialize2(cand))
@@ -562,16 +571,27 @@ int nr_ice_candidate_initialize(nr_ice_c
         }
         else {
           nr_resolver_resource resource;
           resource.domain_name=cand->stun_server->u.dnsname.host;
           resource.port=cand->stun_server->u.dnsname.port;
           resource.stun_turn=protocol;
           resource.transport_protocol=cand->stun_server->transport;
 
+          switch (cand->base.ip_version) {
+            case NR_IPV4:
+              resource.address_family=AF_INET;
+              break;
+            case NR_IPV6:
+              resource.address_family=AF_INET6;
+              break;
+            default:
+              ABORT(R_BAD_ARGS);
+          }
+
           /* Try to resolve */
           if(!cand->ctx->resolver) {
             r_log(LOG_ICE, LOG_ERR, "ICE-CANDIDATE(%s): Can't use DNS names without a resolver", cand->label);
             ABORT(R_BAD_ARGS);
           }
 
           if(r=nr_resolver_resolve(cand->ctx->resolver,
                                    &resource,
--- a/media/mtransport/third_party/nICEr/src/ice/ice_component.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.c
@@ -994,16 +994,19 @@ int nr_ice_component_pair_candidate(nr_i
       if (!lcand->tcp_type && pcand->tcp_type)
         continue;
       if (lcand->tcp_type == TCP_TYPE_ACTIVE && pcand->tcp_type != TCP_TYPE_PASSIVE)
         continue;
       if (lcand->tcp_type == TCP_TYPE_SO && pcand->tcp_type != TCP_TYPE_SO)
         continue;
       if (lcand->tcp_type == TCP_TYPE_PASSIVE)
         continue;
+      if(pcand->addr.ip_version != lcand->addr.ip_version)
+        continue;
+
       /*
         Two modes, depending on |pair_all_remote|
 
         1. Pair remote candidates which have not been paired
            (used in initial pairing or in processing the other side's
            trickle candidates).
         2. Pair any remote candidate (used when processing our own
            trickle candidates).
@@ -1329,8 +1332,49 @@ int nr_ice_component_insert_pair(nr_ice_
       }
     }
 
     _status=0;
   abort:
     return(_status);
   }
 
+int nr_ice_component_get_default_candidate(nr_ice_component *comp, nr_ice_candidate **candp, int ip_version)
+  {
+    int _status;
+    nr_ice_candidate *cand;
+    nr_ice_candidate *best_cand = NULL;
+
+    /* We have the component. Now find the "best" candidate, making
+       use of the fact that more "reliable" candidate types have
+       higher numbers. So, we sort by type and then priority within
+       type
+    */
+    cand=TAILQ_FIRST(&comp->candidates);
+    while(cand){
+      if (cand->state == NR_ICE_CAND_STATE_INITIALIZED &&
+          cand->addr.ip_version == ip_version) {
+        if (!best_cand) {
+          best_cand = cand;
+        }
+        else if (best_cand->type < cand->type) {
+          best_cand = cand;
+        } else if (best_cand->type == cand->type &&
+                   best_cand->priority < cand->priority) {
+          best_cand = cand;
+        }
+      }
+
+      cand=TAILQ_NEXT(cand,entry_comp);
+    }
+
+    /* No candidates */
+    if (!best_cand)
+      ABORT(R_NOT_FOUND);
+
+    *candp = best_cand;
+
+    _status=0;
+  abort:
+    return(_status);
+
+  }
+
--- a/media/mtransport/third_party/nICEr/src/ice/ice_component.h
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_component.h
@@ -88,13 +88,14 @@ int nr_ice_component_pair_candidates(nr_
 int nr_ice_component_service_pre_answer_requests(nr_ice_peer_ctx *pctx, nr_ice_component *pcomp, char *username, int *serviced);
 int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pair);
 int nr_ice_component_failed_pair(nr_ice_component *comp, nr_ice_cand_pair *pair);
 int nr_ice_component_check_if_failed(nr_ice_component *comp);
 int nr_ice_component_select_pair(nr_ice_peer_ctx *pctx, nr_ice_component *comp);
 int nr_ice_component_set_failed(nr_ice_component *comp);
 int nr_ice_component_finalize(nr_ice_component *lcomp, nr_ice_component *rcomp);
 int nr_ice_component_insert_pair(nr_ice_component *pcomp, nr_ice_cand_pair *pair);
+int nr_ice_component_get_default_candidate(nr_ice_component *comp, nr_ice_candidate **candp, int ip_version);
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
 #endif
--- a/media/mtransport/third_party/nICEr/src/ice/ice_media_stream.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_media_stream.c
@@ -218,66 +218,39 @@ int nr_ice_media_stream_get_attributes(n
           RFREE(attrs[index]);
         }
         RFREE(attrs);
       }
     }
     return(_status);
   }
 
-
 /* Get a default candidate per 4.1.4 */
 int nr_ice_media_stream_get_default_candidate(nr_ice_media_stream *stream, int component, nr_ice_candidate **candp)
   {
-    int _status;
+    int r,_status;
     nr_ice_component *comp;
-    nr_ice_candidate *cand;
-    nr_ice_candidate *best_cand = NULL;
 
     comp=STAILQ_FIRST(&stream->components);
     while(comp){
       if (comp->component_id == component)
         break;
 
       comp=STAILQ_NEXT(comp,entry);
     }
 
     if (!comp)
       ABORT(R_NOT_FOUND);
 
-    /* We have the component. Now find the "best" candidate, making
-       use of the fact that more "reliable" candidate types have
-       higher numbers. So, we sort by type and then priority within
-       type
-    */
-    cand=TAILQ_FIRST(&comp->candidates);
-    while(cand){
-      if (cand->state == NR_ICE_CAND_STATE_INITIALIZED) {
-        if (!best_cand) {
-          best_cand = cand;
-        }
-        else {
-          if (best_cand->type < cand->type) {
-            best_cand = cand;
-          } else if (best_cand->type == cand->type) {
-            if (best_cand->priority < cand->priority)
-              best_cand = cand;
-          }
-        }
-      }
-
-      cand=TAILQ_NEXT(cand,entry_comp);
+    /* If there aren't any IPV4 candidates, try IPV6 */
+    if((r=nr_ice_component_get_default_candidate(comp, candp, NR_IPV4)) &&
+       (r=nr_ice_component_get_default_candidate(comp, candp, NR_IPV6))) {
+      ABORT(r);
     }
 
-    /* No candidates */
-    if (!best_cand)
-      ABORT(R_NOT_FOUND);
-
-    *candp = best_cand;
-
     _status=0;
   abort:
     return(_status);
   }
 
 
 int nr_ice_media_stream_pair_candidates(nr_ice_peer_ctx *pctx,nr_ice_media_stream *lstream,nr_ice_media_stream *pstream)
   {
--- a/media/mtransport/third_party/nICEr/src/ice/ice_parser.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_parser.c
@@ -115,17 +115,16 @@ abort:
 int
 nr_ice_peer_candidate_from_attribute(nr_ice_ctx *ctx,char *orig,nr_ice_media_stream *stream,nr_ice_candidate **candp)
 {
     int r,_status;
     char* str = orig;
     nr_ice_candidate *cand;
     char *connection_address=0;
     unsigned int port;
-    in_addr_t addr;
     int i;
     unsigned int component_id;
     char *rel_addr=0;
     unsigned char transport;
 
     if(!(cand=RCALLOC(sizeof(nr_ice_candidate))))
         ABORT(R_NO_MEMORY);
 
@@ -207,32 +206,27 @@ nr_ice_peer_candidate_from_attribute(nr_
 
     /* Peer address/port */
     if ((r=grab_token(&str, &connection_address)))
         ABORT(r);
 
     if (*str == '\0')
         ABORT(R_BAD_DATA);
 
-    addr = inet_addr(connection_address);
-    if (addr == INADDR_NONE)
-        ABORT(R_BAD_DATA);
-
     skip_whitespace(&str);
     if (*str == '\0')
         ABORT(R_BAD_DATA);
 
     if (sscanf(str, "%u", &port) != 1)
         ABORT(R_BAD_DATA);
 
     if (port < 1 || port > 0x0FFFF)
         ABORT(R_BAD_DATA);
 
-    /* Assume v4 for now */
-    if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,transport,&cand->addr))
+    if ((r=nr_str_port_to_transport_addr(connection_address,port,transport,&cand->addr)))
       ABORT(r);
 
     skip_to_past_space(&str);
     if (*str == '\0')
         ABORT(R_BAD_DATA);
 
     /* Type */
     if (strncasecmp("typ", str, 3))
@@ -284,20 +278,16 @@ nr_ice_peer_candidate_from_attribute(nr_
             ABORT(R_BAD_DATA);
 
         if ((r=grab_token(&str, &rel_addr)))
             ABORT(r);
 
         if (*str == '\0')
             ABORT(R_BAD_DATA);
 
-        addr = inet_addr(rel_addr);
-        if (addr == INADDR_NONE)
-            ABORT(R_BAD_DATA);
-
         skip_whitespace(&str);
         if (*str == '\0')
             ABORT(R_BAD_DATA);
 
         if (strncasecmp("rport", str, 5))
               ABORT(R_BAD_DATA);
 
         fast_forward(&str, 5);
@@ -309,18 +299,17 @@ nr_ice_peer_candidate_from_attribute(nr_
             ABORT(R_BAD_DATA);
 
         if (sscanf(str, "%u", &port) != 1)
             ABORT(R_BAD_DATA);
 
         if (port < 1 || port > 0x0FFFF)
             ABORT(R_BAD_DATA);
 
-        /* Assume v4 for now */
-        if(r=nr_ip4_port_to_transport_addr(ntohl(addr),port,transport,&cand->base))
+        if ((r=nr_str_port_to_transport_addr(rel_addr,port,transport,&cand->base)))
           ABORT(r);
 
         skip_to_past_space(&str);
         /* it's expected to be at EOD at this point */
 
         break;
     default:
         ABORT(R_INTERNAL);
--- a/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c
+++ b/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c
@@ -251,17 +251,17 @@ int nr_socket_proxy_tunnel_connect(void 
 
   if ((r=nr_transport_addr_copy(&sock->remote_addr, addr))) {
     ABORT(r);
   }
 
   assert(config->proxy_host);
 
   /* Check if the proxy_host is already an IP address */
-  has_addr = !nr_ip4_str_port_to_transport_addr(config->proxy_host,
+  has_addr = !nr_str_port_to_transport_addr(config->proxy_host,
       config->proxy_port, IPPROTO_TCP, &proxy_addr);
 
   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_connect: %s", config->proxy_host);
 
   if (!has_addr && !config->resolver) {
     r_log(LOG_GENERIC,LOG_ERR,"nr_socket_proxy_tunnel_connect name resolver not configured");
     ABORT(R_NOT_FOUND);
   }
--- a/media/mtransport/third_party/nICEr/src/net/nr_resolver.h
+++ b/media/mtransport/third_party/nICEr/src/net/nr_resolver.h
@@ -41,16 +41,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 #define NR_RESOLVE_PROTOCOL_STUN 1
 #define NR_RESOLVE_PROTOCOL_TURN 2
 
 typedef struct nr_resolver_resource_ {
   char *domain_name;
   UINT2 port;
   int stun_turn;
   UCHAR transport_protocol;
+  UCHAR address_family;
 } nr_resolver_resource;
 
 typedef struct nr_resolver_vtbl_ {
   int (*destroy)(void **obj);
   int (*resolve)(void *obj,
                  nr_resolver_resource *resource,
                  int (*cb)(void *cb_arg, nr_transport_addr *addr),
                  void *cb_arg,
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr.c
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.c
@@ -95,54 +95,61 @@ int nr_transport_addr_fmt_ifname_addr_st
     int _status;
     char buffer[40];
 
     switch(addr->ip_version){
       case NR_IPV4:
         if (!inet_ntop(AF_INET, &addr->u.addr4.sin_addr,buffer,sizeof(buffer))) {
            strncpy(buffer, "[error]", len);
         }
-        snprintf(buf,len,"%s:%s",addr->ifname,buffer);
+        break;
+      case NR_IPV6:
+        if (!inet_ntop(AF_INET6, &addr->u.addr6.sin6_addr,buffer,sizeof(buffer))) {
+           strncpy(buffer, "[error]", len);
+        }
         break;
       default:
         ABORT(R_INTERNAL);
     }
+    snprintf(buf,len,"%s:%s",addr->ifname,buffer);
 
     _status=0;
   abort:
     return(_status);
   }
 
-int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int saddr_len, int protocol, int keep, nr_transport_addr *addr)
+int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int protocol, int keep, nr_transport_addr *addr)
   {
     int r,_status;
 
     if(!keep) memset(addr,0,sizeof(nr_transport_addr));
 
-    if(saddr->sa_family==PF_INET){
-      if(saddr_len != sizeof(struct sockaddr_in))
+    switch(protocol){
+      case IPPROTO_TCP:
+      case IPPROTO_UDP:
+        break;
+      default:
         ABORT(R_BAD_ARGS);
+    }
 
-      switch(protocol){
-        case IPPROTO_TCP:
-        case IPPROTO_UDP:
-          break;
-        default:
-          ABORT(R_BAD_ARGS);
-      }
+    addr->protocol=protocol;
+
+    if(saddr->sa_family==AF_INET){
       addr->ip_version=NR_IPV4;
-      addr->protocol=protocol;
 
       memcpy(&addr->u.addr4,saddr,sizeof(struct sockaddr_in));
       addr->addr=(struct sockaddr *)&addr->u.addr4;
-      addr->addr_len=saddr_len;
+      addr->addr_len=sizeof(struct sockaddr_in);
     }
-    else if(saddr->sa_family==PF_INET6){
-      /* Not implemented */
-      ABORT(R_INTERNAL);
+    else if(saddr->sa_family==AF_INET6){
+      addr->ip_version=NR_IPV6;
+
+      memcpy(&addr->u.addr6, saddr, sizeof(struct sockaddr_in6));
+      addr->addr=(struct sockaddr *)&addr->u.addr6;
+      addr->addr_len=sizeof(struct sockaddr_in6);
     }
     else
       ABORT(R_BAD_ARGS);
 
     if(r=nr_transport_addr_fmt_addr_string(addr))
       ABORT(r);
 
     _status=0;
@@ -201,26 +208,52 @@ int nr_ip4_port_to_transport_addr(UINT4 
     if(r=nr_transport_addr_fmt_addr_string(addr))
       ABORT(r);
 
     _status=0;
   abort:
     return(_status);
   }
 
-int nr_ip4_str_port_to_transport_addr(const char *ip4, UINT2 port, int protocol, nr_transport_addr *addr)
+int nr_str_port_to_transport_addr(const char *ip, UINT2 port, int protocol, nr_transport_addr *addr_out)
   {
     int r,_status;
-    in_addr_t ip_addr;
+    struct in_addr addr;
+    struct in6_addr addr6;
+
+    if (inet_pton(AF_INET, ip, &addr) == 1) {
+      if(r=nr_ip4_port_to_transport_addr(ntohl(addr.s_addr),port,protocol,addr_out))
+        ABORT(r);
+    } else if (inet_pton(AF_INET6, ip, &addr6) == 1) {
+      if(r=nr_ip6_port_to_transport_addr(&addr6,port,protocol,addr_out))
+        ABORT(r);
+    } else {
+      ABORT(R_BAD_DATA);
+    }
 
-    ip_addr=inet_addr(ip4);
-    if (ip_addr == INADDR_NONE)
-      ABORT(R_BAD_DATA);
-    /* Assume v4 for now */
-    if(r=nr_ip4_port_to_transport_addr(ntohl(ip_addr),port,protocol,addr))
+    _status=0;
+  abort:
+    return(_status);
+  }
+
+int nr_ip6_port_to_transport_addr(struct in6_addr* addr6, UINT2 port, int protocol, nr_transport_addr *addr)
+  {
+    int r,_status;
+
+    memset(addr, 0, sizeof(nr_transport_addr));
+
+    addr->ip_version=NR_IPV6;
+    addr->protocol=protocol;
+    addr->u.addr6.sin6_family=PF_INET6;
+    addr->u.addr6.sin6_port=htons(port);
+    memcpy(addr->u.addr6.sin6_addr.s6_addr, addr6->s6_addr, sizeof(addr6->s6_addr));
+    addr->addr=(struct sockaddr *)&addr->u.addr6;
+    addr->addr_len=sizeof(struct sockaddr_in6);
+
+    if(r=nr_transport_addr_fmt_addr_string(addr))
       ABORT(r);
 
     _status=0;
   abort:
     return(_status);
   }
 
 int nr_transport_addr_get_addrstring(nr_transport_addr *addr, char *str, int maxlen)
@@ -286,36 +319,16 @@ int nr_transport_addr_set_port(nr_transp
         ABORT(R_INTERNAL);
     }
 
     _status=0;
   abort:
     return(_status);
   }
 
-int nr_transport_addr_get_ip4(nr_transport_addr *addr, UINT4 *ip4p)
-  {
-    int _status;
-
-    switch(addr->ip_version){
-      case NR_IPV4:
-        *ip4p=ntohl(addr->u.addr4.sin_addr.s_addr);
-        break;
-      case NR_IPV6:
-        ABORT(R_NOT_FOUND);
-        break;
-      default:
-        ABORT(R_INTERNAL);
-    }
-
-    _status=0;
-  abort:
-    return(_status);
-  }
-
 /* memcmp() may not work if, for instance, the string or interface
    haven't been made. Hmmm.. */
 int nr_transport_addr_cmp(nr_transport_addr *addr1,nr_transport_addr *addr2,int mode)
   {
     assert(mode);
 
     if(addr1->ip_version != addr2->ip_version)
       return(1);
@@ -335,17 +348,23 @@ int nr_transport_addr_cmp(nr_transport_a
         if(addr1->u.addr4.sin_addr.s_addr != addr2->u.addr4.sin_addr.s_addr)
           return(1);
         if(mode < NR_TRANSPORT_ADDR_CMP_MODE_ALL)
           return(0);
         if(addr1->u.addr4.sin_port != addr2->u.addr4.sin_port)
           return(1);
         break;
       case NR_IPV6:
-        UNIMPLEMENTED;
+        if(memcmp(addr1->u.addr6.sin6_addr.s6_addr,addr2->u.addr6.sin6_addr.s6_addr,sizeof(struct in6_addr)))
+          return(1);
+        if(mode < NR_TRANSPORT_ADDR_CMP_MODE_ALL)
+          return(0);
+        if(addr1->u.addr6.sin6_port != addr2->u.addr6.sin6_port)
+          return(1);
+        break;
       default:
         abort();
     }
 
     return(0);
   }
 
 int nr_transport_addr_is_loopback(nr_transport_addr *addr)
@@ -358,30 +377,52 @@ int nr_transport_addr_is_loopback(nr_tra
               return 1;
             break;
           default:
             UNIMPLEMENTED;
             break;
         }
         break;
 
+      case NR_IPV6:
+        if(!memcmp(addr->u.addr6.sin6_addr.s6_addr,in6addr_loopback.s6_addr,sizeof(struct in6_addr)))
+          return(1);
+        break;
       default:
         UNIMPLEMENTED;
     }
 
     return(0);
   }
 
+int nr_transport_addr_is_link_local(nr_transport_addr *addr)
+  {
+    if(addr->ip_version == NR_IPV6){
+      UINT4* addrTop = (UINT4*)(addr->u.addr6.sin6_addr.s6_addr);
+      return ((*addrTop & htonl(0xFFC00000)) == htonl(0xFE800000));
+    } else {
+      assert(0);
+    }
+
+    return(0);
+  }
+
 int nr_transport_addr_is_wildcard(nr_transport_addr *addr)
   {
     switch(addr->ip_version){
       case NR_IPV4:
         if(addr->u.addr4.sin_addr.s_addr==INADDR_ANY)
           return(1);
         if(addr->u.addr4.sin_port==0)
           return(1);
         break;
+      case NR_IPV6:
+        if(!memcmp(addr->u.addr6.sin6_addr.s6_addr,in6addr_any.s6_addr,sizeof(struct in6_addr)))
+          return(1);
+        if(addr->u.addr6.sin6_port==0)
+          return(1);
+        break;
       default:
         UNIMPLEMENTED;
     }
 
     return(0);
   }
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr.h
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr.h
@@ -66,33 +66,34 @@ typedef struct nr_transport_addr_ {
     struct sockaddr_in6 addr6;
   } u;
   char ifname[MAXIFNAME];
   /* A string version.
      56 = 5 ("IP6:[") + 39 (ipv6 address) + 2 ("]:") + 5 (port) + 4 (/UDP) + 1 (null) */
   char as_string[56];
 } nr_transport_addr;
 
-int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int saddr_len, int protocol, int keep, nr_transport_addr *addr);
+int nr_sockaddr_to_transport_addr(struct sockaddr *saddr, int protocol, int keep, nr_transport_addr *addr);
 
 // addresses, ports in local byte order
 int nr_ip4_port_to_transport_addr(UINT4 ip4, UINT2 port, int protocol, nr_transport_addr *addr);
-int nr_ip4_str_port_to_transport_addr(const char *ip4, UINT2 port, int protocol, nr_transport_addr *addr);
+int nr_str_port_to_transport_addr(const char *ip4, UINT2 port, int protocol, nr_transport_addr *addr);
+int nr_ip6_port_to_transport_addr(struct in6_addr* addr6, UINT2 port, int protocol, nr_transport_addr *addr);
 
 int nr_transport_addr_get_addrstring(nr_transport_addr *addr, char *str, int maxlen);
 int nr_transport_addr_get_port(nr_transport_addr *addr, int *port);
-int nr_transport_addr_get_ip4(nr_transport_addr *addr, UINT4 *ip4p);
 int nr_transport_addr_cmp(nr_transport_addr *addr1,nr_transport_addr *addr2,int mode);
 #define NR_TRANSPORT_ADDR_CMP_MODE_VERSION   1
 #define NR_TRANSPORT_ADDR_CMP_MODE_PROTOCOL  2
 #define NR_TRANSPORT_ADDR_CMP_MODE_ADDR      3
 #define NR_TRANSPORT_ADDR_CMP_MODE_ALL       4
 
 int nr_transport_addr_is_wildcard(nr_transport_addr *addr);
 int nr_transport_addr_is_loopback(nr_transport_addr *addr);
+int nr_transport_addr_is_link_local(nr_transport_addr *addr);
 int nr_transport_addr_copy(nr_transport_addr *to, nr_transport_addr *from);
 int nr_transport_addr_copy_keep_ifname(nr_transport_addr *to, nr_transport_addr *from);
 int nr_transport_addr_fmt_addr_string(nr_transport_addr *addr);
 int nr_transport_addr_fmt_ifname_addr_string(const nr_transport_addr *addr, char *buf, int len);
 int nr_transport_addr_set_port(nr_transport_addr *addr, int port);
 
 #endif
 
--- a/media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c
+++ b/media/mtransport/third_party/nICEr/src/net/transport_addr_reg.c
@@ -48,16 +48,19 @@ static char *RCSSTRING __UNUSED__="$Id: 
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #endif
 #include <assert.h>
 #include "nr_api.h"
 #include "transport_addr.h"
 #include "transport_addr_reg.h"
 
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 46 /* Value used by linux/BSD */
+#endif
 
 int
 nr_reg_get_transport_addr(NR_registry prefix, int keep, nr_transport_addr *addr)
 {
     int r,_status;
     unsigned int count;
     char *address = 0;
     UINT2 port = 0;
@@ -102,17 +105,17 @@ nr_reg_get_transport_addr(NR_registry pr
         else if (!strcasecmp("udp", protocol))
             p = IPPROTO_UDP;
         else
             ABORT(R_BAD_DATA);
     }
 
     if (!keep) memset(addr, 0, sizeof(*addr));
 
-    if ((r=nr_ip4_str_port_to_transport_addr(address?address:"0.0.0.0", port, p, addr)))
+    if ((r=nr_str_port_to_transport_addr(address?address:"0.0.0.0", port, p, addr)))
         ABORT(r);
 
     if (ifname)
         strlcpy(addr->ifname, ifname, sizeof(addr->ifname));
 
     _status=0;
   abort:
     RFREE(protocol);
@@ -128,54 +131,69 @@ nr_reg_set_transport_addr(NR_registry pr
 
     if (! keep) {
         if ((r=NR_reg_del(prefix)))
             ABORT(r);
     }
 
     switch (addr->ip_version) {
     case NR_IPV4:
-        if (addr->u.addr4.sin_addr.s_addr != INADDR_ANY) {
+        if (!nr_transport_addr_is_wildcard(addr)) {
             if ((r=NR_reg_set2_string(prefix, "address", inet_ntoa(addr->u.addr4.sin_addr))))
                 ABORT(r);
         }
 
         if (addr->u.addr4.sin_port != 0) {
             if ((r=NR_reg_set2_uint2(prefix, "port", ntohs(addr->u.addr4.sin_port))))
                 ABORT(r);
         }
-
-        switch (addr->protocol) {
-        case IPPROTO_TCP:
-            if ((r=NR_reg_set2_string(prefix, "protocol", "tcp")))
-                ABORT(r);
-            break;
-        case IPPROTO_UDP:
-            if ((r=NR_reg_set2_string(prefix, "protocol", "udp")))
-                ABORT(r);
-            break;
-        default:
-            UNIMPLEMENTED;
-            break;
-        }
-
-        if (strlen(addr->ifname) > 0) {
-            if ((r=NR_reg_set2_string(prefix, "ifname", addr->ifname)))
-                ABORT(r);
-        }
         break;
 
     case NR_IPV6:
-        UNIMPLEMENTED;
+        if (!nr_transport_addr_is_wildcard(addr)) {
+          char address[INET6_ADDRSTRLEN];
+          if(!inet_ntop(AF_INET6, &addr->u.addr6.sin6_addr,address,sizeof(address))) {
+            ABORT(R_BAD_DATA);
+          }
+
+          if ((r=NR_reg_set2_string(prefix, "address", address))) {
+            ABORT(r);
+          }
+        }
+
+        if (addr->u.addr6.sin6_port != 0) {
+            if ((r=NR_reg_set2_uint2(prefix, "port", ntohs(addr->u.addr6.sin6_port))))
+                ABORT(r);
+        }
         break;
     default:
         ABORT(R_INTERNAL);
         break;
     }
 
+    /* We abort if neither NR_IPV4 or NR_IPV6 above */
+    switch (addr->protocol) {
+      case IPPROTO_TCP:
+        if ((r=NR_reg_set2_string(prefix, "protocol", "tcp")))
+          ABORT(r);
+        break;
+      case IPPROTO_UDP:
+        if ((r=NR_reg_set2_string(prefix, "protocol", "udp")))
+          ABORT(r);
+        break;
+      default:
+        UNIMPLEMENTED;
+        break;
+    }
+
+    if (strlen(addr->ifname) > 0) {
+      if ((r=NR_reg_set2_string(prefix, "ifname", addr->ifname)))
+        ABORT(r);
+    }
+
     _status=0;
   abort:
     if (_status)
         NR_reg_del(prefix);
     return _status;
 }
 
 int
--- a/media/mtransport/third_party/nICEr/src/stun/addrs.c
+++ b/media/mtransport/third_party/nICEr/src/stun/addrs.c
@@ -36,277 +36,52 @@ static char *RCSSTRING __UNUSED__="$Id: 
 #include <csi_platform.h>
 #include <assert.h>
 #include <string.h>
 
 #ifdef WIN32
 #include <winsock2.h>
 #include <iphlpapi.h>
 #include <tchar.h>
-#else   /* UNIX */
-#include <sys/param.h>
+#else   /* !WIN32 */
+
 #include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
 #ifndef ANDROID
-#include <sys/syslog.h>
+/* This works on linux and BSD, but not android */
+#include <sys/types.h> /* getifaddrs */
+#include <ifaddrs.h> /* getifaddrs */
 #else
-#include <syslog.h>
+#include "ifaddrs-android.h"
+#define getifaddrs android_getifaddrs
+#define freeifaddrs android_freeifaddrs
+#endif
+
+#ifdef LINUX
+
+#ifdef ANDROID
 /* Work around an Android NDK < r8c bug */
 #undef __unused
-#endif
-#ifndef LINUX
-#include <net/if.h>
-#if !defined(__OpenBSD__) && !defined(__NetBSD__)
-#include <net/if_var.h>
-#endif
-#include <net/if_dl.h>
-#include <net/if_types.h>
-#include <sys/sockio.h>
 #else
-#include <linux/sockios.h>
-#include <linux/if.h>
-#include <linux/kernel.h>
-#include <linux/wireless.h>
-#ifndef ANDROID
-#include <linux/ethtool.h>
-#endif
-#endif
-#include <net/route.h>
+#include <linux/if.h> /* struct ifreq, IFF_POINTTOPOINT */
+#include <linux/wireless.h> /* struct iwreq */
+#include <linux/ethtool.h> /* struct ethtool_cmd */
+#include <linux/sockios.h> /* SIOCETHTOOL */
+#endif /* ANDROID */
 
-/* IP */
-#include <netinet/in.h>
-#ifdef LINUX
-#include "sys/ioctl.h"
-#else
-#include <netinet/in_var.h>
-#endif
-#include <arpa/inet.h>
-#include <netdb.h>
-#endif  /* UNIX */
+#endif /* LINUX */
+
+#endif  /* !WIN32 */
 
 #include "stun.h"
 #include "addrs.h"
 
-
-
-#if defined(BSD) || defined(DARWIN)
-/*
- * Copyright (c) 1983, 1993
- *    The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *[3 Deleted as of 22nd July 1999; see
- *    ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change
- *    for details]
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <err.h>
-#include <sys/sysctl.h>
-
-static void stun_rt_xaddrs(caddr_t, caddr_t, struct rt_addrinfo *);
-static int stun_grab_addrs(char *name, int addrcount,
-               struct ifa_msghdr *ifam,
-               nr_local_addr addrs[], int maxaddrs, int *count);
-static int
-nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr);
-
-
-/*
- * Expand the compacted form of addresses as returned via the
- * configuration read via sysctl().
- */
-#define ROUNDUP(a) \
-    ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
-
-static void
-stun_rt_xaddrs(cp, cplim, rtinfo)
-    caddr_t cp, cplim;
-    struct rt_addrinfo *rtinfo;
-{
-    struct sockaddr *sa;
-    int i;
-
-    memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
-    for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
-        if ((rtinfo->rti_addrs & (1 << i)) == 0)
-            continue;
-        rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
-        ADVANCE(cp, sa);
-    }
-}
-
-static int
-stun_grab_addrs(char *name, int addrcount, struct ifa_msghdr *ifam, nr_local_addr addrs[], int maxaddrs, int *count)
-{
-    int r,_status;
-    int s = -1;
-    struct ifreq ifr;
-    struct rt_addrinfo info;
-    struct sockaddr_in *sin;
-
-    ifr.ifr_addr.sa_family = AF_INET;
-    strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-
-    if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0) {
-      r_log(NR_LOG_STUN, LOG_ERR, "unable to obtain addresses from socket");
-      ABORT(R_FAILED);
-    }
-
-    while (addrcount > 0) {
-        info.rti_addrs = ifam->ifam_addrs;
-
-        /* Expand the compacted addresses */
-        stun_rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam, &info);
-        addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
-        addrs[*count].interface.estimated_speed = 0;
-        /* TODO (Bug 895790) Get interface properties for Darwin */
-
-        switch (info.rti_info[RTAX_IFA]->sa_family) {
-        case AF_INET:
-            sin = (struct sockaddr_in *)info.rti_info[RTAX_IFA];
-
-            if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sin, sizeof(*sin), IPPROTO_UDP, 0, &(addrs[*count].addr))))
-                ABORT(r);
-
-            strlcpy(addrs[*count].addr.ifname, name, sizeof(addrs[*count].addr.ifname));
-
-            ++*count;
-            break;
-        case AF_INET6:
-            UNIMPLEMENTED;
-            break;
-        }
-
-        addrcount--;
-
-        if (*count >= maxaddrs) {
-            r_log(NR_LOG_STUN, LOG_WARNING, "Address list truncated at %d out of %d entries", maxaddrs, maxaddrs+addrcount);
-            break;
-        }
-
-        ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
-    }
-
-    _status = 0;
-  abort:
-    if (s != -1) close(s);
-    return _status;
-}
-
-static int
-stun_get_mib_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
-{
-    int _status;
-    char name[32];
-    int flags;
-    int addrcount;
-    struct if_msghdr *ifm, *nextifm;
-    struct ifa_msghdr *ifam;
-    struct sockaddr_dl *sdl;
-    char *buf = 0;
-    char *lim;
-    char *next;
-    size_t needed;
-    int mib[6];
-
-    *count = 0;
-
-    mib[0] = CTL_NET;
-    mib[1] = PF_ROUTE;
-    mib[2] = 0;
-    mib[3] = AF_INET;
-    mib[4] = NET_RT_IFLIST;
-    mib[5] = 0;
-
-    if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) {
-        errx(1, "iflist-sysctl-estimate");
-        ABORT(R_INTERNAL);
-    }
-
-    if ((buf = malloc(needed)) == NULL) {
-        errx(1, "malloc");
-        ABORT(R_NO_MEMORY);
-    }
-
-    if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
-        errx(1, "actual retrieval of interface table");
-        ABORT(R_INTERNAL);
-    }
-
-    lim = buf + needed;
-
-    next = buf;
-    while (next < lim) {
-        ifm = (struct if_msghdr *)next;
-
-        if (ifm->ifm_type == RTM_IFINFO) {
-            sdl = (struct sockaddr_dl *)(ifm + 1);
-            flags = ifm->ifm_flags;
-        } else {
-            r_log(NR_LOG_STUN, LOG_WARNING, "out of sync parsing NET_RT_IFLIST");
-            r_log(NR_LOG_STUN, LOG_DEBUG, "expected %d, got %d, msglen = %d, buf:%p, next:%p, lim:%p", RTM_IFINFO, ifm->ifm_type, ifm->ifm_msglen, buf, next, lim);
-            ABORT(R_FAILED);
-        }
-
-        next += ifm->ifm_msglen;
-        ifam = NULL;
-        addrcount = 0;
-        while (next < lim) {
-
-            nextifm = (struct if_msghdr *)next;
-
-            if (nextifm->ifm_type != RTM_NEWADDR)
-                break;
-
-            if (ifam == NULL)
-                ifam = (struct ifa_msghdr *)nextifm;
-
-            addrcount++;
-            next += nextifm->ifm_msglen;
-        }
-
-        if (sdl->sdl_nlen > sizeof(name) - 1) {
-            ABORT(R_INTERNAL);
-        }
-
-        memcpy(name, sdl->sdl_data, sdl->sdl_nlen);
-        name[sdl->sdl_nlen] = '\0';
-
-        stun_grab_addrs(name, addrcount, ifam, addrs, maxaddrs, count);
-    }
-
-    _status = 0;
-abort:
-    if (buf) free(buf);
-    return _status;
-}
-
-#elif defined(WIN32)
+#if defined(WIN32)
 
 #define WIN32_MAX_NUM_INTERFACES  20
 
 
 #define _NR_MAX_KEY_LENGTH 256
 #define _NR_MAX_NAME_LENGTH 512
 
 #define _ADAPTERS_BASE_REG "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
@@ -363,135 +138,16 @@ static int nr_win32_get_adapter_friendly
 
 abort:
     if (_status) {
       if (my_fn) free(my_fn);
     }
     return(_status);
 }
 
-
-static int
-stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
-{
-    int r,_status;
-    PIP_ADAPTER_INFO pAdapterInfo;
-    PIP_ADAPTER_INFO pAdapter = NULL;
-    PIP_ADDR_STRING pAddrString;
-    ULONG out_buf_len;
-    char *friendly_name=0;
-    char munged_ifname[IFNAMSIZ];
-    int n = 0;
-
-    *count = 0;
-
-    pAdapterInfo = (IP_ADAPTER_INFO *) RMALLOC(sizeof(IP_ADAPTER_INFO));
-    out_buf_len = sizeof(IP_ADAPTER_INFO);
-
-    /* First call to GetAdaptersInfo is mainly to get length */
-
-    if (GetAdaptersInfo(pAdapterInfo, &out_buf_len) == ERROR_BUFFER_OVERFLOW) {
-      RFREE(pAdapterInfo);
-      pAdapterInfo = (IP_ADAPTER_INFO *) RMALLOC(out_buf_len);
-      if (pAdapterInfo == NULL) {
-        r_log(NR_LOG_STUN, LOG_ERR, "Error allocating memory for GetAdaptersInfo output");
-        ABORT(R_NO_MEMORY);
-      }
-    }
-    if ((r = GetAdaptersInfo(pAdapterInfo, &out_buf_len)) != NO_ERROR) {
-      r_log(NR_LOG_STUN, LOG_ERR, "Got error from GetAdaptersInfo");
-      ABORT(R_INTERNAL);
-    }
-    r_log(NR_LOG_STUN, LOG_DEBUG, "Got AdaptersInfo");
-
-    pAdapter = pAdapterInfo;
-
-    while (pAdapter) {
-      char *c;
-
-      r_log(NR_LOG_STUN, LOG_DEBUG, "Adapter Name (GUID) = %s", pAdapter->AdapterName);
-      r_log(NR_LOG_STUN, LOG_DEBUG, "Adapter Description = %s", pAdapter->Description);
-
-      if (nr_win32_get_adapter_friendly_name(pAdapter->AdapterName, &friendly_name)) {
-        friendly_name = 0;
-      }
-      if (friendly_name && *friendly_name) {
-        r_log(NR_LOG_STUN, LOG_INFO, "Found adapter with friendly name: %s", friendly_name);
-        snprintf(munged_ifname, IFNAMSIZ, "%s%c", friendly_name, 0);
-        RFREE(friendly_name);
-        friendly_name = 0;
-      } else {
-        // Not all adapters follow the friendly name convention. Windows' PPTP
-        // VPN adapter puts "VPN Connection 2" in the Description field instead.
-        // Windows's renaming-logic appears to enforce uniqueness in spite of this.
-        r_log(NR_LOG_STUN, LOG_INFO, "Found adapter with description: %s", pAdapter->Description);
-        snprintf(munged_ifname, IFNAMSIZ, "%s%c", pAdapter->Description, 0);
-      }
-      /* replace spaces with underscores */
-      c = strchr(munged_ifname, ' ');
-      while (c != NULL) {
-        *c = '_';
-         c = strchr(munged_ifname, ' ');
-      }
-      c = strchr(munged_ifname, '.');
-      while (c != NULL) {
-        *c = '+';
-         c = strchr(munged_ifname, '.');
-      }
-
-      r_log(NR_LOG_STUN, LOG_INFO, "Converted ifname: %s", munged_ifname);
-
-      for (pAddrString = &(pAdapter->IpAddressList); pAddrString != NULL; pAddrString = pAddrString->Next) {
-        unsigned long this_addr = inet_addr(pAddrString->IpAddress.String);
-        nr_transport_addr *addr = &(addrs[n].addr);
-
-        if (this_addr == 0)
-          continue;
-
-        r_log(NR_LOG_STUN, LOG_INFO, "Adapter %s address: %s", munged_ifname, pAddrString->IpAddress.String);
-
-        addr->ip_version=NR_IPV4;
-        addr->protocol = IPPROTO_UDP;
-
-        addr->u.addr4.sin_family=PF_INET;
-        addr->u.addr4.sin_port=0;
-        addr->u.addr4.sin_addr.s_addr=this_addr;
-        addr->addr=(struct sockaddr *)&(addr->u.addr4);
-        addr->addr_len=sizeof(struct sockaddr_in);
-
-        strlcpy(addr->ifname, munged_ifname, sizeof(addr->ifname));
-        snprintf(addr->as_string,40,"IP4:%s:%d",
-                 inet_ntoa(addr->u.addr4.sin_addr),
-                 ntohs(addr->u.addr4.sin_port));
-
-        /* TODO: (Bug 895793) Getting interface properties for Windows */
-        addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
-        addrs[n].interface.estimated_speed = 0;
-
-        if (++n >= maxaddrs)
-          goto done;
-      }
-
-      pAdapter = pAdapter->Next;
-    }
-
-  done:
-    *count = n;
-    _status = 0;
-
-  abort:
-    RFREE(pAdapterInfo);
-    RFREE(friendly_name);
-    return _status;
-}
-
-#ifdef GET_WIN32_ADDRS_NO_WIN2K
-   /* Here's a nice way to get adapter addresses and names, but it
-    * isn't supported on Win2000.
-    */
 static int
 stun_get_win32_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
 {
     int r,_status;
     PIP_ADAPTER_ADDRESSES AdapterAddresses = NULL, tmpAddress = NULL;
     ULONG buflen;
     char munged_ifname[IFNAMSIZ];
     int n = 0;
@@ -500,31 +156,31 @@ stun_get_win32_addrs(nr_local_addr addrs
 
     if (maxaddrs <= 0)
       ABORT(R_INTERNAL);
 
     /* Call GetAdaptersAddresses() twice.  First, just to get the buf length */
 
     buflen = 0;
 
-    r = GetAdaptersAddresses(AF_INET, 0, NULL, AdapterAddresses, &buflen);
+    r = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, AdapterAddresses, &buflen);
     if (r != ERROR_BUFFER_OVERFLOW) {
       r_log(NR_LOG_STUN, LOG_ERR, "Error getting buf len from GetAdaptersAddresses()");
       ABORT(R_INTERNAL);
     }
 
     AdapterAddresses = (PIP_ADAPTER_ADDRESSES) RMALLOC(buflen);
     if (AdapterAddresses == NULL) {
       r_log(NR_LOG_STUN, LOG_ERR, "Error allocating buf for GetAdaptersAddresses()");
       ABORT(R_NO_MEMORY);
     }
 
     /* for real, this time */
 
-    r = GetAdaptersAddresses(AF_INET, 0, NULL, AdapterAddresses, &buflen);
+    r = GetAdaptersAddresses(AF_UNSPEC, 0, NULL, AdapterAddresses, &buflen);
     if (r != NO_ERROR) {
       r_log(NR_LOG_STUN, LOG_ERR, "Error getting addresses from GetAdaptersAddresses()");
       ABORT(R_INTERNAL);
     }
 
     /* Loop through the adapters */
 
     for (tmpAddress = AdapterAddresses; tmpAddress != NULL; tmpAddress = tmpAddress->Next) {
@@ -549,17 +205,17 @@ stun_get_win32_addrs(nr_local_addr addrs
       if ((tmpAddress->IfIndex != 0) || (tmpAddress->Ipv6IfIndex != 0)) {
         IP_ADAPTER_UNICAST_ADDRESS *u = 0;
 
         for (u = tmpAddress->FirstUnicastAddress; u != 0; u = u->Next) {
           SOCKET_ADDRESS *sa_addr = &u->Address;
 
           if ((sa_addr->lpSockaddr->sa_family == AF_INET) ||
               (sa_addr->lpSockaddr->sa_family == AF_INET6)) {
-            if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sa_addr->lpSockaddr, sizeof(*sa_addr->lpSockaddr), IPPROTO_UDP, 0, &(addrs[n].addr))))
+            if ((r=nr_sockaddr_to_transport_addr((struct sockaddr*)sa_addr->lpSockaddr, IPPROTO_UDP, 0, &(addrs[n].addr))))
                 ABORT(r);
           }
           else {
             r_log(NR_LOG_STUN, LOG_DEBUG, "Unrecognized sa_family for adapteraddress %s",munged_ifname);
             continue;
           }
 
           strlcpy(addrs[n].addr.ifname, munged_ifname, sizeof(addrs[n].addr.ifname));
@@ -575,141 +231,108 @@ stun_get_win32_addrs(nr_local_addr addrs
    done:
     *count = n;
     _status = 0;
 
   abort:
     RFREE(AdapterAddresses);
     return _status;
 }
-#endif  /* GET_WIN32_ADDRS_NO_WIN2K */
 
-#elif defined(__sparc__)
+#else /* WIN32 */
 
 static int
-stun_get_sparc_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
-{
-    *count = 0;
-    UNIMPLEMENTED; /*TODO !nn! - sparc */
-    return 0;
-}
-
-#else
+nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr);
 
 static int
-stun_get_siocgifconf_addrs(nr_local_addr addrs[], int maxaddrs, int *count)
+stun_getifaddrs(nr_local_addr addrs[], int maxaddrs, int *count)
 {
-   struct ifconf ifc;
-   int _status;
-   int s = socket( AF_INET, SOCK_DGRAM, 0 );
-   int len = 100 * sizeof(struct ifreq);
-   int r;
-   int e;
-   char *ptr;
-   int tl;
-   int n;
-   struct ifreq ifr2;
+  int r,_status;
+  struct ifaddrs* if_addrs_head=NULL;
+  struct ifaddrs* if_addr;
 
-   char buf[ len ];
-
-   ifc.ifc_len = len;
-   ifc.ifc_buf = buf;
-
-   e = ioctl(s,SIOCGIFCONF,&ifc);
+  *count=0;
 
-   if ( e == -1 )
-   {
-      return(R_INTERNAL);
-   }
+  if (getifaddrs(&if_addrs_head) == -1) {
+    r_log(NR_LOG_STUN, LOG_ERR, "getifaddrs error e = %d", errno);
+    ABORT(R_INTERNAL);
+  }
 
-   ptr = buf;
-   tl = ifc.ifc_len;
-   n=0;
+  if_addr = if_addrs_head;
 
-   while ( (tl > 0) && ( n < maxaddrs) )
-   {
-      struct ifreq* ifr = (struct ifreq *)ptr;
-
-#ifdef LINUX
-      int si = sizeof(struct ifreq);
-#ifndef ANDROID
-      struct ethtool_cmd ecmd;
-      struct iwreq wrq;
-#endif
-#else
-      int si = sizeof(ifr->ifr_name) + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr));
-#endif
-      tl -= si;
-      ptr += si;
+  while (if_addr && *count < maxaddrs) {
+    switch (if_addr->ifa_addr->sa_family) {
+      case AF_INET:
+      case AF_INET6:
+        if (r=nr_sockaddr_to_transport_addr(if_addr->ifa_addr, IPPROTO_UDP, 0, &(addrs[*count].addr))) {
+          r_log(NR_LOG_STUN, LOG_ERR, "nr_sockaddr_to_transport_addr error r = %d", r);
+        } else {
+#if defined(LINUX) && !defined(ANDROID)
+          struct ethtool_cmd ecmd;
+          struct ifreq ifr;
+          struct iwreq wrq;
+          int e;
+          int s = socket(AF_INET, SOCK_DGRAM, 0);
 
-      ifr2 = *ifr;
-
-      e = ioctl(s,SIOCGIFADDR,&ifr2);
-      if ( e == -1 )
-      {
-          continue;
-      }
-
-      //r_log(NR_LOG_STUN, LOG_ERR, "ioctl addr e = %d",e);
-
-      if ((r=nr_sockaddr_to_transport_addr(&ifr2.ifr_addr, sizeof(ifr2.ifr_addr), IPPROTO_UDP, 0, &(addrs[n].addr)))) {
-          r_log(NR_LOG_STUN, LOG_WARNING, "Problem transforming address");
-      }
-      else {
-          addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
-          addrs[n].interface.estimated_speed = 0;
-#if defined(LINUX) && !defined(ANDROID)
+          strncpy(ifr.ifr_name, if_addr->ifa_name, sizeof(ifr.ifr_name));
           /* TODO (Bug 896851): interface property for Android */
           /* Getting ethtool for ethernet information. */
           ecmd.cmd = ETHTOOL_GSET;
-          ifr2.ifr_data = (void*)&ecmd;
-          e = ioctl(s, SIOCETHTOOL, &ifr2);
+          /* In/out param */
+          ifr.ifr_data = (void*)&ecmd;
+
+          e = ioctl(s, SIOCETHTOOL, &ifr);
           if (e == 0)
           {
              /* For wireless network, we won't get ethtool, it's a wired
-                connection */
-             addrs[n].interface.type = NR_INTERFACE_TYPE_WIRED;
+              * connection */
+             addrs[*count].interface.type = NR_INTERFACE_TYPE_WIRED;
 #ifdef DONT_HAVE_ETHTOOL_SPEED_HI
-             addrs[n].interface.estimated_speed = ecmd.speed;
+             addrs[*count].interface.estimated_speed = ecmd.speed;
 #else
-             addrs[n].interface.estimated_speed = ((ecmd.speed_hi << 16) | ecmd.speed) * 1000;
+             addrs[*count].interface.estimated_speed = ((ecmd.speed_hi << 16) | ecmd.speed) * 1000;
 #endif
           }
 
-          strncpy(wrq.ifr_name, ifr->ifr_name, sizeof(wrq.ifr_name));
+          strncpy(wrq.ifr_name, if_addr->ifa_name, sizeof(wrq.ifr_name));
           e = ioctl(s, SIOCGIWRATE, &wrq);
           if (e == 0)
           {
-             addrs[n].interface.type = NR_INTERFACE_TYPE_WIFI;
-             addrs[n].interface.estimated_speed = wrq.u.bitrate.value / 1000;
+             addrs[*count].interface.type = NR_INTERFACE_TYPE_WIFI;
+             addrs[*count].interface.estimated_speed = wrq.u.bitrate.value / 1000;
           }
 
-          ifr2 = *ifr;
-          e = ioctl(s, SIOCGIFFLAGS, &ifr2);
-          if (e == 0)
+          if (if_addr->ifa_flags & IFF_POINTOPOINT)
           {
-             if (ifr2.ifr_flags & IFF_POINTOPOINT)
-             {
-                addrs[n].interface.type = NR_INTERFACE_TYPE_UNKNOWN | NR_INTERFACE_TYPE_VPN;
-                /* TODO (Bug 896913): find backend network type of this VPN */
-             }
+             addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN | NR_INTERFACE_TYPE_VPN;
+             /* TODO (Bug 896913): find backend network type of this VPN */
           }
+#else
+          addrs[*count].interface.type = NR_INTERFACE_TYPE_UNKNOWN;
+          addrs[*count].interface.estimated_speed = 0;
 #endif
-          strlcpy(addrs[n].addr.ifname, ifr->ifr_name, sizeof(addrs[n].addr.ifname));
-          ++n;
-      }
-   }
+          strlcpy(addrs[*count].addr.ifname, if_addr->ifa_name, sizeof(addrs[*count].addr.ifname));
+          ++(*count);
+        }
+        break;
+      default:
+        ;
+    }
 
-   close(s);
-
-   *count = n;
+    if_addr = if_addr->ifa_next;
+  }
 
-    _status = 0;
-    return _status;
+  _status=0;
+abort:
+  if (if_addrs_head) {
+    freeifaddrs(if_addrs_head);
+  }
+  return(_status);
 }
+
 #endif
 
 static int
 nr_stun_is_duplicate_addr(nr_local_addr addrs[], int count, nr_local_addr *addr)
 {
     int i;
     int different;
 
@@ -719,17 +342,17 @@ nr_stun_is_duplicate_addr(nr_local_addr 
         if (!different)
             return 1;  /* duplicate */
     }
 
     return 0;
 }
 
 int
-nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int *count)
+nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int remove_link_local, int *count)
 {
     int r, _status;
     nr_local_addr *tmp = 0;
     int i;
     int n;
 
     tmp = RMALLOC(*count * sizeof(*tmp));
     if (!tmp)
@@ -738,16 +361,21 @@ nr_stun_remove_duplicate_addrs(nr_local_
     n = 0;
     for (i = 0; i < *count; ++i) {
         if (nr_stun_is_duplicate_addr(tmp, n, &addrs[i])) {
             /* skip addrs[i], it's a duplicate */
         }
         else if (remove_loopback && nr_transport_addr_is_loopback(&addrs[i].addr)) {
             /* skip addrs[i], it's a loopback */
         }
+        else if (remove_link_local &&
+                 addrs[i].addr.ip_version == NR_IPV6 &&
+                 nr_transport_addr_is_link_local(&addrs[i].addr)) {
+            /* skip addrs[i], it's a link-local address */
+        }
         else {
             /* otherwise, copy it to the temporary array */
             if ((r=nr_local_addr_copy(&tmp[n], &addrs[i])))
                 ABORT(r);
             ++n;
         }
     }
 
@@ -763,33 +391,29 @@ nr_stun_remove_duplicate_addrs(nr_local_
   abort:
     RFREE(tmp);
     return _status;
 }
 
 #ifndef USE_PLATFORM_NR_STUN_GET_ADDRS
 
 int
-nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int drop_loopback, int *count)
+nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int drop_loopback, int drop_link_local, int *count)
 {
     int _status=0;
     int i;
     char typestr[100];
 
-#if defined(BSD) || defined(DARWIN)
-    _status = stun_get_mib_addrs(addrs, maxaddrs, count);
-#elif defined(WIN32)
+#ifdef WIN32
     _status = stun_get_win32_addrs(addrs, maxaddrs, count);
-#elif defined(__sparc__)
-    _status = stun_get_sparc_addrs(addrs, maxaddrs, count);
 #else
-    _status = stun_get_siocgifconf_addrs(addrs, maxaddrs, count);
+    _status = stun_getifaddrs(addrs, maxaddrs, count);
 #endif
 
-    nr_stun_remove_duplicate_addrs(addrs, drop_loopback, count);
+    nr_stun_remove_duplicate_addrs(addrs, drop_loopback, drop_link_local, count);
 
     for (i = 0; i < *count; ++i) {
     nr_local_addr_fmt_info_string(addrs+i,typestr,sizeof(typestr));
         r_log(NR_LOG_STUN, LOG_DEBUG, "Address %d: %s on %s, type: %s\n",
             i,addrs[i].addr.as_string,addrs[i].addr.ifname,typestr);
     }
 
     return _status;
--- a/media/mtransport/third_party/nICEr/src/stun/addrs.h
+++ b/media/mtransport/third_party/nICEr/src/stun/addrs.h
@@ -32,12 +32,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
 
 #ifndef _addrs_h_
 #define _addrs_h_
 
 #include "transport_addr.h"
 #include "local_addr.h"
 
-int nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int remove_loopback, int *count);
-int nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback,int *count);
+int nr_stun_get_addrs(nr_local_addr addrs[], int maxaddrs, int remove_loopback, int remove_link_local, int *count);
+int nr_stun_remove_duplicate_addrs(nr_local_addr addrs[], int remove_loopback, int remove_link_local, int *count);
 
 #endif
copy from media/webrtc/trunk/webrtc/base/ifaddrs-android.cc
copy to media/mtransport/third_party/nICEr/src/stun/ifaddrs-android.c
--- a/media/webrtc/trunk/webrtc/base/ifaddrs-android.cc
+++ b/media/mtransport/third_party/nICEr/src/stun/ifaddrs-android.c
@@ -1,223 +1,242 @@
 /*
- *  Copyright 2012 The WebRTC Project Authors. All rights reserved.
- *
- *  Use of this source code is governed by a BSD-style license
- *  that can be found in the LICENSE file in the root of the source
- *  tree. An additional intellectual property rights grant can be found
- *  in the file PATENTS.  All contributing project authors may
- *  be found in the AUTHORS file in the root of the source tree.
- */
+Copyright (c) 2011, The WebRTC project authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
 
-#if defined(WEBRTC_ANDROID)
-#include "webrtc/base/ifaddrs-android.h"
+  * Neither the name of Google nor the names of its contributors may
+    be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if defined(ANDROID)
+#include "ifaddrs-android.h"
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/utsname.h>
 #include <sys/ioctl.h>
 #include <netinet/in.h>
 #include <net/if.h>
 #include <unistd.h>
 #include <errno.h>
 #include <linux/netlink.h>
 #include <linux/rtnetlink.h>
 
-namespace {
-
 struct netlinkrequest {
-  nlmsghdr header;
-  ifaddrmsg msg;
+  struct nlmsghdr header;
+  struct ifaddrmsg msg;
 };
 
-const int kMaxReadSize = 4096;
-
-}  // namespace
+static const int kMaxReadSize = 4096;
 
-namespace rtc {
-
-int set_ifname(struct ifaddrs* ifaddr, int interface) {
+static int set_ifname(struct ifaddrs* ifaddr, int interface) {
   char buf[IFNAMSIZ] = {0};
   char* name = if_indextoname(interface, buf);
   if (name == NULL) {
     return -1;
   }
-  ifaddr->ifa_name = new char[strlen(name) + 1];
+  ifaddr->ifa_name = malloc(strlen(name) + 1);
   strncpy(ifaddr->ifa_name, name, strlen(name) + 1);
   return 0;
 }
 
-int set_flags(struct ifaddrs* ifaddr) {
+static int set_flags(struct ifaddrs* ifaddr) {
   int fd = socket(AF_INET, SOCK_DGRAM, 0);
   if (fd == -1) {
     return -1;
   }
-  ifreq ifr;
+  struct ifreq ifr;
   memset(&ifr, 0, sizeof(ifr));
   strncpy(ifr.ifr_name, ifaddr->ifa_name, IFNAMSIZ - 1);
   int rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
   close(fd);
   if (rc == -1) {
     return -1;
   }
   ifaddr->ifa_flags = ifr.ifr_flags;
   return 0;
 }
 
-int set_addresses(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* data,
+static int set_addresses(struct ifaddrs* ifaddr, struct ifaddrmsg* msg, void* data,
                   size_t len) {
   if (msg->ifa_family == AF_INET) {
-    sockaddr_in* sa = new sockaddr_in;
+    struct sockaddr_in* sa = malloc(sizeof(struct sockaddr_in));
+    memset(sa, 0, sizeof(struct sockaddr_in));
     sa->sin_family = AF_INET;
     memcpy(&sa->sin_addr, data, len);
-    ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
+    ifaddr->ifa_addr = (struct sockaddr*)sa;
   } else if (msg->ifa_family == AF_INET6) {
-    sockaddr_in6* sa = new sockaddr_in6;
+    struct sockaddr_in6* sa = malloc(sizeof(struct sockaddr_in6));
+    memset(sa, 0, sizeof(struct sockaddr_in6));
     sa->sin6_family = AF_INET6;
     sa->sin6_scope_id = msg->ifa_index;
     memcpy(&sa->sin6_addr, data, len);
-    ifaddr->ifa_addr = reinterpret_cast<sockaddr*>(sa);
+    ifaddr->ifa_addr = (struct sockaddr*)sa;
   } else {
     return -1;
   }
   return 0;
 }
 
-int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
+static int make_prefixes(struct ifaddrs* ifaddr, int family, int prefixlen) {
   char* prefix = NULL;
   if (family == AF_INET) {
-    sockaddr_in* mask = new sockaddr_in;
+    struct sockaddr_in* mask = malloc(sizeof(struct sockaddr_in));
+    memset(mask, 0, sizeof(struct sockaddr_in));
     mask->sin_family = AF_INET;
-    memset(&mask->sin_addr, 0, sizeof(in_addr));
-    ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
+    memset(&mask->sin_addr, 0, sizeof(struct in_addr));
+    ifaddr->ifa_netmask = (struct sockaddr*)mask;
     if (prefixlen > 32) {
       prefixlen = 32;
     }
-    prefix = reinterpret_cast<char*>(&mask->sin_addr);
+    prefix = (char*)&mask->sin_addr;
   } else if (family == AF_INET6) {
-    sockaddr_in6* mask = new sockaddr_in6;
+    struct sockaddr_in6* mask = malloc(sizeof(struct sockaddr_in6));
+    memset(mask, 0, sizeof(struct sockaddr_in6));
     mask->sin6_family = AF_INET6;
-    memset(&mask->sin6_addr, 0, sizeof(in6_addr));
-    ifaddr->ifa_netmask = reinterpret_cast<sockaddr*>(mask);
+    memset(&mask->sin6_addr, 0, sizeof(struct in6_addr));
+    ifaddr->ifa_netmask = (struct sockaddr*)mask;
     if (prefixlen > 128) {
       prefixlen = 128;
     }
-    prefix = reinterpret_cast<char*>(&mask->sin6_addr);
+    prefix = (char*)&mask->sin6_addr;
   } else {
     return -1;
   }
   for (int i = 0; i < (prefixlen / 8); i++) {
     *prefix++ = 0xFF;
   }
   char remainder = 0xff;
   remainder <<= (8 - prefixlen % 8);
   *prefix = remainder;
   return 0;
 }
 
-int populate_ifaddrs(struct ifaddrs* ifaddr, ifaddrmsg* msg, void* bytes,
+static int populate_ifaddrs(struct ifaddrs* ifaddr, struct ifaddrmsg* msg, void* bytes,
                      size_t len) {
   if (set_ifname(ifaddr, msg->ifa_index) != 0) {
     return -1;
   }
   if (set_flags(ifaddr) != 0) {
     return -1;
   }
   if (set_addresses(ifaddr, msg, bytes, len) != 0) {
     return -1;
   }
   if (make_prefixes(ifaddr, msg->ifa_family, msg->ifa_prefixlen) != 0) {
     return -1;
   }
   return 0;
 }
 
-int getifaddrs(struct ifaddrs** result) {
+int android_getifaddrs(struct ifaddrs** result) {
   int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
   if (fd < 0) {
     return -1;
   }
 
-  netlinkrequest ifaddr_request;
+  struct netlinkrequest ifaddr_request;
   memset(&ifaddr_request, 0, sizeof(ifaddr_request));
   ifaddr_request.header.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
   ifaddr_request.header.nlmsg_type = RTM_GETADDR;
-  ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(ifaddrmsg));
+  ifaddr_request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
 
   ssize_t count = send(fd, &ifaddr_request, ifaddr_request.header.nlmsg_len, 0);
-  if (static_cast<size_t>(count) != ifaddr_request.header.nlmsg_len) {
+  if ((size_t)count != ifaddr_request.header.nlmsg_len) {
     close(fd);
     return -1;
   }
   struct ifaddrs* start = NULL;
   struct ifaddrs* current = NULL;
   char buf[kMaxReadSize];
   ssize_t amount_read = recv(fd, &buf, kMaxReadSize, 0);
   while (amount_read > 0) {
-    nlmsghdr* header = reinterpret_cast<nlmsghdr*>(&buf[0]);
-    size_t header_size = static_cast<size_t>(amount_read);
+    struct nlmsghdr* header = (struct nlmsghdr*)&buf[0];
+    size_t header_size = (size_t)amount_read;
     for ( ; NLMSG_OK(header, header_size);
           header = NLMSG_NEXT(header, header_size)) {
       switch (header->nlmsg_type) {
         case NLMSG_DONE:
-          // Success. Return.
+          /* Success. Return. */
           *result = start;
           close(fd);
           return 0;
         case NLMSG_ERROR:
           close(fd);
-          freeifaddrs(start);
+          android_freeifaddrs(start);
           return -1;
         case RTM_NEWADDR: {
-          ifaddrmsg* address_msg =
-              reinterpret_cast<ifaddrmsg*>(NLMSG_DATA(header));
-          rtattr* rta = IFA_RTA(address_msg);
+          struct ifaddrmsg* address_msg =
+              (struct ifaddrmsg*)NLMSG_DATA(header);
+          struct rtattr* rta = IFA_RTA(address_msg);
           ssize_t payload_len = IFA_PAYLOAD(header);
           while (RTA_OK(rta, payload_len)) {
             if (rta->rta_type == IFA_ADDRESS) {
               int family = address_msg->ifa_family;
               if (family == AF_INET || family == AF_INET6) {
-                ifaddrs* newest = new ifaddrs;
-                memset(newest, 0, sizeof(ifaddrs));
+                struct ifaddrs* newest = malloc(sizeof(struct ifaddrs));
+                memset(newest, 0, sizeof(struct ifaddrs));
                 if (current) {
                   current->ifa_next = newest;
                 } else {
                   start = newest;
                 }
                 if (populate_ifaddrs(newest, address_msg, RTA_DATA(rta),
                                      RTA_PAYLOAD(rta)) != 0) {
-                  freeifaddrs(start);
+                  android_freeifaddrs(start);
                   *result = NULL;
                   return -1;
                 }
                 current = newest;
               }
             }
             rta = RTA_NEXT(rta, payload_len);
           }
           break;
         }
       }
     }
     amount_read = recv(fd, &buf, kMaxReadSize, 0);
   }
   close(fd);
-  freeifaddrs(start);
+  android_freeifaddrs(start);
   return -1;
 }
 
-void freeifaddrs(struct ifaddrs* addrs) {
+void android_freeifaddrs(struct ifaddrs* addrs) {
   struct ifaddrs* last = NULL;
   struct ifaddrs* cursor = addrs;
   while (cursor) {
-    delete[] cursor->ifa_name;
-    delete cursor->ifa_addr;
-    delete cursor->ifa_netmask;
+    free(cursor->ifa_name);
+    free(cursor->ifa_addr);
+    free(cursor->ifa_netmask);
     last = cursor;
     cursor = cursor->ifa_next;
-    delete last;
+    free(last);
   }
 }
 
-}  // namespace rtc
-#endif  // defined(WEBRTC_ANDROID)
+#endif  /* defined(ANDROID) */
new file mode 100644
--- /dev/null
+++ b/media/mtransport/third_party/nICEr/src/stun/ifaddrs-android.h
@@ -0,0 +1,57 @@
+/*
+Copyright (c) 2011, The WebRTC project authors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+  * Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+  * Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+  * Neither the name of Google nor the names of its contributors may
+    be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef WEBRTC_BASE_IFADDRS_ANDROID_H_
+#define WEBRTC_BASE_IFADDRS_ANDROID_H_
+
+#include <stdio.h>
+#include <sys/socket.h>
+
+/* Implementation of getifaddrs for Android.
+ * Fills out a list of ifaddr structs (see below) which contain information
+ * about every network interface available on the host.
+ * See 'man getifaddrs' on Linux or OS X (nb: it is not a POSIX function). */
+struct ifaddrs {
+  struct ifaddrs* ifa_next;
+  char* ifa_name;
+  unsigned int ifa_flags;
+  struct sockaddr* ifa_addr;
+  struct sockaddr* ifa_netmask;
+  /* Real ifaddrs has broadcast, point to point and data members.
+   * We don't need them (yet?). */
+};
+
+int android_getifaddrs(struct ifaddrs** result);
+void android_freeifaddrs(struct ifaddrs* addrs);
+
+#endif  /* WEBRTC_BASE_IFADDRS_ANDROID_H_ */
+
--- a/media/mtransport/third_party/nICEr/src/stun/stun_codec.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_codec.c
@@ -441,19 +441,25 @@ nr_stun_attr_codec_addr_encode(nr_stun_a
          || nr_stun_encode(&pad, 1               , buflen, buf, &offset)
          || nr_stun_encode(&family, 1            , buflen, buf, &offset)
          || nr_stun_encode_htons(ntohs(addr->u.addr4.sin_port), buflen, buf, &offset)
          || nr_stun_encode_htonl(ntohl(addr->u.addr4.sin_addr.s_addr), buflen, buf, &offset))
             ABORT(R_FAILED);
         break;
 
     case NR_IPV6:
-        assert(0);
-        ABORT(R_INTERNAL);
+        family = NR_STUN_IPV6_FAMILY;
+        if (nr_stun_encode_htons(20              , buflen, buf, &offset)
+         || nr_stun_encode(&pad, 1               , buflen, buf, &offset)
+         || nr_stun_encode(&family, 1            , buflen, buf, &offset)
+         || nr_stun_encode_htons(ntohs(addr->u.addr6.sin6_port), buflen, buf, &offset)
+         || nr_stun_encode(addr->u.addr6.sin6_addr.s6_addr, 16, buflen, buf, &offset))
+            ABORT(R_FAILED);
         break;
+
     default:
         assert(0);
         ABORT(R_INTERNAL);
         break;
     }
 
     *attrlen = offset - start;
 
@@ -465,16 +471,17 @@ nr_stun_attr_codec_addr_encode(nr_stun_a
 static int
 nr_stun_attr_codec_addr_decode(nr_stun_attr_info *attr_info, int attrlen, UCHAR *buf, int offset, int buflen, void *data)
 {
     int _status;
     UCHAR pad;
     UCHAR family;
     UINT2 port;
     UINT4 addr4;
+    struct in6_addr addr6;
     nr_transport_addr *result = data;
 
     if (nr_stun_decode(1, buf, buflen, &offset, &pad)
      || nr_stun_decode(1, buf, buflen, &offset, &family))
         ABORT(R_FAILED);
 
     switch (family) {
     case NR_STUN_IPV4_FAMILY:
@@ -487,27 +494,27 @@ nr_stun_attr_codec_addr_decode(nr_stun_a
          || nr_stun_decode_htonl(buf, buflen, &offset, &addr4))
             ABORT(R_FAILED);
 
         if (nr_ip4_port_to_transport_addr(addr4, port, IPPROTO_UDP, result))
             ABORT(R_FAILED);
         break;
 
     case NR_STUN_IPV6_FAMILY:
-        if (attrlen != 16) {
+        if (attrlen != 20) {
             r_log(NR_LOG_STUN, LOG_WARNING, "Illegal attribute length: %d", attrlen);
             ABORT(R_FAILED);
         }
 
-        r_log(NR_LOG_STUN, LOG_WARNING, "IPv6 not supported");
-#ifdef NDEBUG
-        ABORT(SKIP_ATTRIBUTE_DECODE);
-#else
-        UNIMPLEMENTED;
-#endif /* NDEBUG */
+        if (nr_stun_decode_htons(buf, buflen, &offset, &port)
+         || nr_stun_decode(16, buf, buflen, &offset, addr6.s6_addr))
+            ABORT(R_FAILED);
+
+        if (nr_ip6_port_to_transport_addr(&addr6, port, IPPROTO_UDP, result))
+            ABORT(R_FAILED);
         break;
 
     default:
         r_log(NR_LOG_STUN, LOG_WARNING, "Illegal address family: %d", family);
         ABORT(R_FAILED);
         break;
     }
 
@@ -1089,17 +1096,17 @@ nr_stun_attr_codec_xor_mapped_address_en
     r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);
 
     /* this needs to be the magic cookie in the header and not
      * the MAGIC_COOKIE constant because if we're talking to
      * older servers (that don't have a magic cookie) they use
      * message ID for this */
     magic_cookie = ntohl(header->magic_cookie);
 
-    nr_stun_xor_mapped_address(magic_cookie, &xor_mapped_address->unmasked, &xor_mapped_address->masked);
+    nr_stun_xor_mapped_address(magic_cookie, header->id, &xor_mapped_address->unmasked, &xor_mapped_address->masked);
 
     r_log(NR_LOG_STUN, LOG_DEBUG, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string);
 
     if (nr_stun_attr_codec_addr.encode(attr_info, &xor_mapped_address->masked, offset, buflen, buf, attrlen))
         return R_FAILED;
 
     return 0;
 }
@@ -1118,17 +1125,17 @@ nr_stun_attr_codec_xor_mapped_address_de
     r_log(NR_LOG_STUN, LOG_DEBUG, "Masked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->masked.as_string);
 
     /* this needs to be the magic cookie in the header and not
      * the MAGIC_COOKIE constant because if we're talking to
      * older servers (that don't have a magic cookie) they use
      * message ID for this */
     magic_cookie = ntohl(header->magic_cookie);
 
-    nr_stun_xor_mapped_address(magic_cookie, &xor_mapped_address->masked, &xor_mapped_address->unmasked);
+    nr_stun_xor_mapped_address(magic_cookie, header->id, &xor_mapped_address->masked, &xor_mapped_address->unmasked);
 
     r_log(NR_LOG_STUN, LOG_DEBUG, "Unmasked XOR-MAPPED-ADDRESS = %s", xor_mapped_address->unmasked.as_string);
 
     _status = 0;
   abort:
     return _status;
 }
 
--- a/media/mtransport/third_party/nICEr/src/stun/stun_reg.h
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_reg.h
@@ -40,16 +40,17 @@ extern "C" {
 #endif /* __cplusplus */
 
 #define NR_STUN_REG_PREF_CLNT_RETRANSMIT_TIMEOUT    "stun.client.retransmission_timeout"
 #define NR_STUN_REG_PREF_CLNT_RETRANSMIT_BACKOFF    "stun.client.retransmission_backoff_factor"
 #define NR_STUN_REG_PREF_CLNT_MAXIMUM_TRANSMITS     "stun.client.maximum_transmits"
 #define NR_STUN_REG_PREF_CLNT_FINAL_RETRANSMIT_BACKOFF   "stun.client.final_retransmit_backoff"
 
 #define NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS            "stun.allow_loopback"
+#define NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS     "stun.allow_link_local"
 #define NR_STUN_REG_PREF_ADDRESS_PRFX               "stun.address"
 #define NR_STUN_REG_PREF_SERVER_NAME                "stun.server.name"
 #define NR_STUN_REG_PREF_SERVER_NONCE_SIZE          "stun.server.nonce_size"
 #define NR_STUN_REG_PREF_SERVER_REALM               "stun.server.realm"
 
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
--- a/media/mtransport/third_party/nICEr/src/stun/stun_util.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_util.c
@@ -66,30 +66,48 @@ nr_stun_startup(void)
       ABORT(r);
 
    _status=0;
  abort:
    return _status;
 }
 
 int
-nr_stun_xor_mapped_address(UINT4 magicCookie, nr_transport_addr *from, nr_transport_addr *to)
+nr_stun_xor_mapped_address(UINT4 magicCookie, UINT12 transactionId, nr_transport_addr *from, nr_transport_addr *to)
 {
     int _status;
 
     switch (from->ip_version) {
     case NR_IPV4:
         nr_ip4_port_to_transport_addr(
             (ntohl(from->u.addr4.sin_addr.s_addr) ^ magicCookie),
             (ntohs(from->u.addr4.sin_port) ^ (magicCookie>>16)),
             from->protocol, to);
         break;
     case NR_IPV6:
-        assert(0);
-        ABORT(R_INTERNAL);
+        {
+          union {
+            unsigned char addr[16];
+            UINT4 addr32[4];
+          } maskedAddr;
+
+          maskedAddr.addr32[0] = htonl(magicCookie); /* Passed in host byte order */
+          memcpy(&maskedAddr.addr32[1], transactionId.octet, sizeof(transactionId));
+
+          /* We now have the mask in network byte order */
+          /* Xor the address in network byte order */
+          for (int i = 0; i < sizeof(maskedAddr); ++i) {
+            maskedAddr.addr[i] ^= from->u.addr6.sin6_addr.s6_addr[i];
+          }
+
+          nr_ip6_port_to_transport_addr(
+              (struct in6_addr*)&maskedAddr,
+              (ntohs(from->u.addr6.sin6_port) ^ (magicCookie>>16)),
+              from->protocol, to);
+        }
         break;
     default:
         assert(0);
         ABORT(R_INTERNAL);
         break;
     }
 
     _status = 0;
@@ -106,25 +124,33 @@ nr_stun_find_local_addresses(nr_local_ad
     if ((r=NR_reg_get_child_count(NR_STUN_REG_PREF_ADDRESS_PRFX, (unsigned int*)count)))
         if (r == R_NOT_FOUND)
             *count = 0;
         else
             ABORT(r);
 
     if (*count == 0) {
         char allow_loopback;
+        char allow_link_local;
 
         if ((r=NR_reg_get_char(NR_STUN_REG_PREF_ALLOW_LOOPBACK_ADDRS, &allow_loopback))) {
             if (r == R_NOT_FOUND)
                 allow_loopback = 0;
             else
                 ABORT(r);
         }
 
-        if ((r=nr_stun_get_addrs(addrs, maxaddrs, !allow_loopback, count)))
+        if ((r=NR_reg_get_char(NR_STUN_REG_PREF_ALLOW_LINK_LOCAL_ADDRS, &allow_link_local))) {
+            if (r == R_NOT_FOUND)
+                allow_link_local = 0;
+            else
+                ABORT(r);
+        }
+
+        if ((r=nr_stun_get_addrs(addrs, maxaddrs, !allow_loopback, !allow_link_local, count)))
             ABORT(r);
 
         goto done;
     }
 
     if (*count >= maxaddrs) {
         r_log(NR_LOG_STUN, LOG_INFO, "Address list truncated from %d to %d", *count, maxaddrs);
        *count = maxaddrs;
--- a/media/mtransport/third_party/nICEr/src/stun/stun_util.h
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_util.h
@@ -37,17 +37,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 
 #include "stun.h"
 #include "local_addr.h"
 
 extern int NR_LOG_STUN;
 
 int nr_stun_startup(void);
 
-int nr_stun_xor_mapped_address(UINT4 magicCookie, nr_transport_addr *from, nr_transport_addr *to);
+int nr_stun_xor_mapped_address(UINT4 magicCookie, UINT12 transactionId, nr_transport_addr *from, nr_transport_addr *to);
 
 int nr_stun_find_local_addresses(nr_local_addr addrs[], int maxaddrs, int *count);
 
 int nr_stun_different_transaction(UCHAR *msg, int len, nr_stun_message *req);
 
 char* nr_stun_msg_type(int type);
 
 int nr_random_alphanum(char *alphanum, int size);
--- a/media/mtransport/third_party/nrappkit/src/util/util.c
+++ b/media/mtransport/third_party/nrappkit/src/util/util.c
@@ -719,16 +719,41 @@ inet_ntop6(const unsigned char *src, cha
     errno = ENOSPC;
     return (NULL);
   }
   strlcpy(dst, tmp, size);
   return (dst);
 }
 #endif /* INET6 */
 
+#ifdef WIN32
+/* Not exactly, will forgive stuff like <addr>:<port> */
+int inet_pton(int af, const char *src, void *dst)
+{
+  struct sockaddr_storage ss;
+  int addrlen = sizeof(ss);
+
+  if (af != AF_INET && af != AF_INET6) {
+    return -1;
+  }
+
+  if (!WSAStringToAddressA(src, af, NULL, (struct sockaddr*)&ss, &addrlen)) {
+    if (af == AF_INET) {
+      struct sockaddr_in *in = (struct sockaddr_in*)&ss;
+      memcpy(dst, &in->sin_addr, sizeof(struct in_addr));
+    } else {
+      struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&ss;
+      memcpy(dst, &in6->sin6_addr, sizeof(struct in6_addr));
+    }
+    return 1;
+  }
+  return 0;
+}
+#endif /* WIN32 */
+
 #endif
 
 #ifdef WIN32
 #include <time.h>
 /* this is only millisecond-accurate, but that should be OK */
 
 int gettimeofday(struct timeval *tv, void *tz)
   {
--- a/media/mtransport/third_party/nrappkit/src/util/util.h
+++ b/media/mtransport/third_party/nrappkit/src/util/util.h
@@ -62,12 +62,13 @@ int nr_rm_tree(char *path);
 int nr_write_pid_file(char *pid_filename);
 
 int nr_reg_uint4_fetch_and_check(NR_registry key, UINT4 min, UINT4 max, int log_fac, int die, UINT4 *val);
 int nr_reg_uint8_fetch_and_check(NR_registry key, UINT8 min, UINT8 max, int log_fac, int die, UINT8 *val);
 
 #ifdef WIN32
 int snprintf(char *buffer, size_t n, const char *format, ...);
 const char *inet_ntop(int af, const void *src, char *dst, size_t size);
+int inet_pton(int af, const char *src, void *dst);
 #endif
 
 #endif
 
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.cpp
@@ -371,16 +371,17 @@ PeerConnectionImpl::PeerConnectionImpl(c
   , mIceConnectionState(PCImplIceConnectionState::New)
   , mIceGatheringState(PCImplIceGatheringState::New)
   , mDtlsConnected(false)
   , mWindow(nullptr)
   , mIdentity(nullptr)
   , mPrivacyRequested(false)
   , mSTSThread(nullptr)
   , mAllowIceLoopback(false)
+  , mAllowIceLinkLocal(false)
   , mMedia(nullptr)
   , mUuidGen(MakeUnique<PCUuidGenerator>())
   , mNumAudioStreams(0)
   , mNumVideoStreams(0)
   , mHaveDataStream(false)
   , mAddCandidateErrorCount(0)
   , mTrickle(true) // TODO(ekr@rtfm.com): Use pref
   , mShouldSuppressNegotiationNeeded(false)
@@ -392,16 +393,18 @@ PeerConnectionImpl::PeerConnectionImpl(c
   }
 #endif
   CSFLogInfo(logTag, "%s: PeerConnectionImpl constructor for %s",
              __FUNCTION__, mHandle.c_str());
   STAMP_TIMECARD(mTimeCard, "Constructor Completed");
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
   mAllowIceLoopback = Preferences::GetBool(
     "media.peerconnection.ice.loopback", false);
+  mAllowIceLinkLocal = Preferences::GetBool(
+    "media.peerconnection.ice.link_local", false);
 #endif
 }
 
 PeerConnectionImpl::~PeerConnectionImpl()
 {
   if (mTimeCard) {
     STAMP_TIMECARD(mTimeCard, "Destructor Invoked");
     print_timecard(mTimeCard);
@@ -727,17 +730,16 @@ PeerConnectionImpl::Initialize(PeerConne
     if (NS_FAILED(res)) {
       CSFLogError(logTag, "%s: Invalid RTCConfiguration", __FUNCTION__);
       return res;
     }
     aConfiguration = &converted;
   }
 
   mMedia = new PeerConnectionMedia(this);
-  mMedia->SetAllowIceLoopback(mAllowIceLoopback);
 
   // Connect ICE slots.
   mMedia->SignalIceGatheringStateChange.connect(
       this,
       &PeerConnectionImpl::IceGatheringStateChange);
   mMedia->SignalEndOfLocalCandidates.connect(
       this,
       &PeerConnectionImpl::EndOfLocalCandidates);
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionImpl.h
@@ -282,16 +282,21 @@ public:
   // Get the media object
   const nsRefPtr<PeerConnectionMedia>& media() const {
     PC_AUTO_ENTER_API_CALL_NO_CHECK();
     return mMedia;
   }
 
   // Configure the ability to use localhost.
   void SetAllowIceLoopback(bool val) { mAllowIceLoopback = val; }
+  bool GetAllowIceLoopback() const { return mAllowIceLoopback; }
+
+  // Configure the ability to use IPV6 link-local addresses.
+  void SetAllowIceLinkLocal(bool val) { mAllowIceLinkLocal = val; }
+  bool GetAllowIceLinkLocal() const { return mAllowIceLinkLocal; }
 
   // Handle system to allow weak references to be passed through C code
   virtual const std::string& GetHandle();
 
   // Name suitable for exposing to content
   virtual const std::string& GetName();
 
   // ICE events
@@ -734,16 +739,17 @@ private:
   nsCOMPtr<nsIEventTarget> mSTSThread;
 
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
   // DataConnection that's used to get all the DataChannels
   nsRefPtr<mozilla::DataChannelConnection> mDataConnection;
 #endif
 
   bool mAllowIceLoopback;
+  bool mAllowIceLinkLocal;
   nsRefPtr<PeerConnectionMedia> mMedia;
 
   // The JSEP negotiation session.
   mozilla::UniquePtr<PCUuidGenerator> mUuidGen;
   mozilla::UniquePtr<mozilla::JsepSession> mJsepSession;
 
 #if !defined(MOZILLA_EXTERNAL_LINKAGE)
   // Start time of ICE, used for telemetry
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -214,17 +214,16 @@ PeerConnectionMedia::ProtocolProxyQueryH
 
 NS_IMPL_ISUPPORTS(PeerConnectionMedia::ProtocolProxyQueryHandler, nsIProtocolProxyCallback)
 #endif // !defined(MOZILLA_XPCOMRT_API)
 
 PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl *parent)
     : mParent(parent),
       mParentHandle(parent->GetHandle()),
       mParentName(parent->GetName()),
-      mAllowIceLoopback(false),
       mIceCtx(nullptr),
       mDNSResolver(new NrIceResolver()),
       mUuidGen(MakeUnique<PCUuidGenerator>()),
       mMainThread(mParent->GetMainThread()),
       mSTSThread(mParent->GetSTSThread()),
       mProxyResolveCompleted(false) {
 }
 
@@ -306,18 +305,19 @@ nsresult PeerConnectionMedia::Init(const
   bool ice_tcp = false;
 #endif
 
   // TODO(ekr@rtfm.com): need some way to set not offerer later
   // Looks like a bug in the NrIceCtx API.
   mIceCtx = NrIceCtx::Create("PC:" + mParentName,
                              true, // Offerer
                              true, // Explicitly set priorities
-                             mAllowIceLoopback,
-                             ice_tcp);
+                             mParent->GetAllowIceLoopback(),
+                             ice_tcp,
+                             mParent->GetAllowIceLinkLocal());
   if(!mIceCtx) {
     CSFLogError(logTag, "%s: Failed to create Ice Context", __FUNCTION__);
     return NS_ERROR_FAILURE;
   }
 
   if (NS_FAILED(rv = mIceCtx->SetStunServers(stun_servers))) {
     CSFLogError(logTag, "%s: Failed to set stun servers", __FUNCTION__);
     return rv;
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -227,19 +227,16 @@ class PeerConnectionMedia : public sigsl
   explicit PeerConnectionMedia(PeerConnectionImpl *parent);
 
   PeerConnectionImpl* GetPC() { return mParent; }
   nsresult Init(const std::vector<NrIceStunServer>& stun_servers,
                 const std::vector<NrIceTurnServer>& turn_servers);
   // WARNING: This destroys the object!
   void SelfDestruct();
 
-  // Configure the ability to use localhost.
-  void SetAllowIceLoopback(bool val) { mAllowIceLoopback = val; }
-
   RefPtr<NrIceCtx> ice_ctx() const { return mIceCtx; }
 
   RefPtr<NrIceMediaStream> ice_media_stream(size_t i) const {
     return mIceCtx->GetStream(i);
   }
 
   size_t num_ice_media_streams() const {
     return mIceCtx->GetStreamCount();
@@ -486,19 +483,16 @@ class PeerConnectionMedia : public sigsl
   nsTArray<nsRefPtr<LocalSourceStreamInfo> > mLocalSourceStreams;
 
   // A list of streams provided by the other side
   // This is only accessed on the main thread (with one special exception)
   nsTArray<nsRefPtr<RemoteSourceStreamInfo> > mRemoteSourceStreams;
 
   std::map<size_t, std::pair<bool, RefPtr<MediaSessionConduit>>> mConduits;
 
-  // Allow loopback for ICE.
-  bool mAllowIceLoopback;
-
   // ICE objects
   RefPtr<NrIceCtx> mIceCtx;
 
   // DNS
   nsRefPtr<NrIceResolver> mDNSResolver;
 
   // Transport flows: even is RTP, odd is RTCP
   std::map<int, RefPtr<TransportFlow> > mTransportFlows;
--- a/media/webrtc/signaling/src/sdp/SdpMediaSection.h
+++ b/media/webrtc/signaling/src/sdp/SdpMediaSection.h
@@ -281,16 +281,21 @@ public:
   GetAddress() const
   {
     return mAddr;
   }
   void
   SetAddress(const std::string& address)
   {
     mAddr = address;
+    if (mAddr.find(':') != std::string::npos) {
+      mAddrType = sdp::kIPv6;
+    } else {
+      mAddrType = sdp::kIPv4;
+    }
   }
   uint8_t
   GetTtl() const
   {
     return mTtl;
   }
   uint32_t
   GetCount() const
--- a/media/webrtc/signaling/test/signaling_unittests.cpp
+++ b/media/webrtc/signaling/test/signaling_unittests.cpp
@@ -908,16 +908,17 @@ class SignalingAgent {
     mRemoteDescriptionSet(false) {
     cfg_.addStunServer(stun_addr, stun_port, kNrIceTransportUdp);
     cfg_.addStunServer(stun_addr, stun_port, kNrIceTransportTcp);
 
     PeerConnectionImpl *pcImpl =
       PeerConnectionImpl::CreatePeerConnection();
     EXPECT_TRUE(pcImpl);
     pcImpl->SetAllowIceLoopback(true);
+    pcImpl->SetAllowIceLinkLocal(true);
     pc = new PCDispatchWrapper(pcImpl);
   }
 
 
   ~SignalingAgent() {
     mozilla::SyncRunnable::DispatchToThread(gMainThread,
       WrapRunnable(this, &SignalingAgent::Close));
   }
@@ -4704,17 +4705,17 @@ int main(int argc, char **argv) {
   NSS_NoDB_Init(nullptr);
   NSS_SetDomesticPolicy();
 
   ::testing::TestEventListeners& listeners =
         ::testing::UnitTest::GetInstance()->listeners();
   // Adds a listener to the end.  Google Test takes the ownership.
   listeners.Append(new test::RingbufferDumper(test_utils));
   test_utils->sts_target()->Dispatch(
-    WrapRunnableNM(&TestStunServer::GetInstance), NS_DISPATCH_SYNC);
+    WrapRunnableNM(&TestStunServer::GetInstance, AF_INET), NS_DISPATCH_SYNC);
 
   // Set the main thread global which is this thread.
   nsIThread *thread;
   NS_GetMainThread(&thread);
   gMainThread = thread;
   MOZ_ASSERT(NS_IsMainThread());
 
   // Now create the GTest thread and run all of the tests on it
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -370,16 +370,17 @@ pref("media.getusermedia.browser.enabled
 pref("media.peerconnection.video.min_bitrate", 200);
 pref("media.peerconnection.video.start_bitrate", 300);
 pref("media.peerconnection.video.max_bitrate", 2000);
 #endif
 pref("media.navigator.permission.disabled", false);
 pref("media.peerconnection.default_iceservers", "[]");
 pref("media.peerconnection.ice.loopback", false); // Set only for testing in offline environments.
 pref("media.peerconnection.ice.tcp", false);
+pref("media.peerconnection.ice.link_local", false); // Set only for testing IPV6 in networks that don't assign IPV6 addresses
 pref("media.peerconnection.use_document_iceservers", true);
 pref("media.peerconnection.identity.enabled", true);
 pref("media.peerconnection.identity.timeout", 10000);
 pref("media.peerconnection.ice.stun_client_maximum_transmits", 7);
 pref("media.peerconnection.ice.trickle_grace_period", 5000);
 // These values (aec, agc, and noice) are from media/webrtc/trunk/webrtc/common_types.h
 // kXxxUnchanged = 0, kXxxDefault = 1, and higher values are specific to each
 // setting (for Xxx = Ec, Agc, or Ns).  Defaults are all set to kXxxDefault here.
--- a/netwerk/base/nsSocketTransport2.cpp
+++ b/netwerk/base/nsSocketTransport2.cpp
@@ -2,16 +2,17 @@
 /* vim:set ts=4 sw=4 et cindent: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsSocketTransport2.h"
 
 #include "mozilla/Attributes.h"
+#include "mozilla/Telemetry.h"
 #include "nsIOService.h"
 #include "nsStreamUtils.h"
 #include "nsNetSegmentUtils.h"
 #include "nsNetAddr.h"
 #include "nsTransportUtils.h"
 #include "nsProxyInfo.h"
 #include "nsNetCID.h"
 #include "nsNetUtil.h"
@@ -46,16 +47,21 @@
 #include <winsock2.h>
 #include <mstcpip.h>
 #elif defined(XP_UNIX)
 #include <errno.h>
 #include <netinet/tcp.h>
 #endif
 /* End keepalive config inclusions. */
 
+#define SUCCESSFUL_CONNECTING_TO_IPV4_ADDRESS 0
+#define UNSUCCESSFUL_CONNECTING_TO_IPV4_ADDRESS 1
+#define SUCCESSFUL_CONNECTING_TO_IPV6_ADDRESS 2
+#define UNSUCCESSFUL_CONNECTING_TO_IPV6_ADDRESS 3
+
 using namespace mozilla;
 using namespace mozilla::net;
 
 //-----------------------------------------------------------------------------
 
 static NS_DEFINE_CID(kSocketProviderServiceCID, NS_SOCKETPROVIDERSERVICE_CID);
 static NS_DEFINE_CID(kDNSServiceCID, NS_DNSSERVICE_CID);
 
@@ -1496,16 +1502,26 @@ nsSocketTransport::RecoverFromError()
         mCondition != NS_ERROR_PROXY_CONNECTION_REFUSED &&
         mCondition != NS_ERROR_NET_TIMEOUT &&
         mCondition != NS_ERROR_UNKNOWN_HOST &&
         mCondition != NS_ERROR_UNKNOWN_PROXY_HOST)
         return false;
 
     bool tryAgain = false;
 
+    if (mSocketTransportService->IsTelemetryEnabled()) {
+        if (mNetAddr.raw.family == AF_INET) {
+            Telemetry::Accumulate(Telemetry::IPV4_AND_IPV6_ADDRESS_CONNECTIVITY,
+                                  UNSUCCESSFUL_CONNECTING_TO_IPV4_ADDRESS);
+        } else if (mNetAddr.raw.family == AF_INET6) {
+            Telemetry::Accumulate(Telemetry::IPV4_AND_IPV6_ADDRESS_CONNECTIVITY,
+                                  UNSUCCESSFUL_CONNECTING_TO_IPV6_ADDRESS);
+        }
+    }
+
     if (mConnectionFlags & (DISABLE_IPV6 | DISABLE_IPV4) &&
         mCondition == NS_ERROR_UNKNOWN_HOST &&
         mState == STATE_RESOLVING &&
         !mProxyTransparentResolvesHost) {
         SOCKET_LOG(("  trying lookup again with both ipv4/ipv6 enabled\n"));
         mConnectionFlags &= ~(DISABLE_IPV6 | DISABLE_IPV4);
         tryAgain = true;
     }
@@ -1850,16 +1866,28 @@ nsSocketTransport::OnSocketReady(PRFileD
     }
     else if (mState == STATE_CONNECTING) {
         PRStatus status = PR_ConnectContinue(fd, outFlags);
         if (status == PR_SUCCESS) {
             //
             // we are connected!
             //
             OnSocketConnected();
+
+            if (mSocketTransportService->IsTelemetryEnabled()) {
+                if (mNetAddr.raw.family == AF_INET) {
+                    Telemetry::Accumulate(
+                        Telemetry::IPV4_AND_IPV6_ADDRESS_CONNECTIVITY,
+                        SUCCESSFUL_CONNECTING_TO_IPV4_ADDRESS);
+                } else if (mNetAddr.raw.family == AF_INET6) {
+                    Telemetry::Accumulate(
+                        Telemetry::IPV4_AND_IPV6_ADDRESS_CONNECTIVITY,
+                        SUCCESSFUL_CONNECTING_TO_IPV6_ADDRESS);
+                }
+            }
         }
         else {
             PRErrorCode code = PR_GetError();
 #if defined(TEST_CONNECT_ERRORS)
             code = RandomizeConnectError(code);
 #endif
             //
             // If the connect is still not ready, then continue polling...
--- a/netwerk/base/nsSocketTransportService2.h
+++ b/netwerk/base/nsSocketTransportService2.h
@@ -104,16 +104,18 @@ public:
     // Called by the networking dashboard on the socket thread only
     // Fills the passed array with socket information
     void GetSocketConnections(nsTArray<mozilla::net::SocketInfo> *);
     uint64_t GetSentBytes() { return mSentBytesCount; }
     uint64_t GetReceivedBytes() { return mReceivedBytesCount; }
 
     // Returns true if keepalives are enabled in prefs.
     bool IsKeepaliveEnabled() { return mKeepaliveEnabledPref; }
+
+    bool IsTelemetryEnabled() { return mTelemetryEnabledPref; }
 protected:
 
     virtual ~nsSocketTransportService();
 
 private:
 
     //-------------------------------------------------------------------------
     // misc (any thread)
--- a/security/manager/ssl/tests/unit/test_ocsp_caching.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_caching.js
@@ -1,14 +1,17 @@
 // -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
 "use strict";
 
+// Checks various aspects of the OCSP cache, mainly to to ensure we do not fetch
+// responses more than necessary.
+
 let gFetchCount = 0;
 let gGoodOCSPResponse = null;
 
 function generateGoodOCSPResponse() {
   let args = [ ["good", "localhostAndExampleCom", "unused" ] ];
   let responses = generateOCSPResponses(args, "tlsserver");
   return responses[0];
 }
@@ -79,29 +82,37 @@ function add_tests() {
   //---------------------------------------------------------------------------
 
   // Reset state
   add_test(function() { clearOCSPCache(); gFetchCount = 0; run_next_test(); });
 
   // This test assumes that OCSPStaplingServer uses the same cert for
   // ocsp-stapling-unknown.example.com and ocsp-stapling-none.example.com.
 
-  // Get an Unknown response for the *.exmaple.com cert and put it in the
+  // Get an Unknown response for the *.example.com cert and put it in the
   // OCSP cache.
   add_connection_test("ocsp-stapling-unknown.example.com",
                       SEC_ERROR_OCSP_UNKNOWN_CERT,
                       clearSessionCache);
-  add_test(function() { do_check_eq(gFetchCount, 0); run_next_test(); });
+  add_test(function() {
+    equal(gFetchCount, 0,
+          "Stapled Unknown response -> a fetch should not have been attempted");
+    run_next_test();
+  });
 
-  // A failure to retrieve an OCSP response must result in the cached Unkown
+  // A failure to retrieve an OCSP response must result in the cached Unknown
   // response being recognized and honored.
   add_connection_test("ocsp-stapling-none.example.com",
                       SEC_ERROR_OCSP_UNKNOWN_CERT,
                       clearSessionCache);
-  add_test(function() { do_check_eq(gFetchCount, 1); run_next_test(); });
+  add_test(function() {
+    equal(gFetchCount, 1,
+          "No stapled response -> a fetch should have been attempted");
+    run_next_test();
+  });
 
   // A valid Good response from the OCSP responder must override the cached
   // Unknown response.
   //
   // Note that We need to make sure that the Unknown response and the Good
   // response have different thisUpdate timestamps; otherwise, the Good
   // response will be seen as "not newer" and it won't replace the existing
   // entry.
@@ -112,46 +123,67 @@ function add_tests() {
     timer.initWithCallback(run_next_test, duration, Ci.nsITimer.TYPE_ONE_SHOT);
   });
   add_test(function() {
     gGoodOCSPResponse = generateGoodOCSPResponse();
     run_next_test();
   });
   add_connection_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
                       clearSessionCache);
-  add_test(function() { do_check_eq(gFetchCount, 2); run_next_test(); });
+  add_test(function() {
+    equal(gFetchCount, 2,
+          "Cached Unknown response, no stapled response -> a fetch should" +
+          " have been attempted");
+    run_next_test();
+  });
 
   // The Good response retrieved from the previous fetch must have replaced
   // the Unknown response in the cache, resulting in the catched Good response
   // being returned and no fetch.
   add_connection_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
                       clearSessionCache);
-  add_test(function() { do_check_eq(gFetchCount, 2); run_next_test(); });
+  add_test(function() {
+    equal(gFetchCount, 2,
+          "Cached Good response -> a fetch should not have been attempted");
+    run_next_test();
+  });
 
 
   //---------------------------------------------------------------------------
 
   // Reset state
   add_test(function() { clearOCSPCache(); gFetchCount = 0; run_next_test(); });
 
   // A failure to retrieve an OCSP response will result in an error entry being
   // added to the cache.
   add_connection_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
                       clearSessionCache);
-  add_test(function() { do_check_eq(gFetchCount, 1); run_next_test(); });
+  add_test(function() {
+    equal(gFetchCount, 1,
+          "No stapled response -> a fetch should have been attempted");
+    run_next_test();
+  });
 
   // The error entry will prevent a fetch from happening for a while.
   add_connection_test("ocsp-stapling-none.example.com", PRErrorCodeSuccess,
                       clearSessionCache);
-  add_test(function() { do_check_eq(gFetchCount, 1); run_next_test(); });
+  add_test(function() {
+    equal(gFetchCount, 1,
+          "Noted OCSP server failure -> a fetch should not have been attempted");
+    run_next_test();
+  });
 
   // The error entry must not prevent a stapled OCSP response from being
   // honored.
   add_connection_test("ocsp-stapling-revoked.example.com",
                       SEC_ERROR_REVOKED_CERTIFICATE,
                       clearSessionCache);
-  add_test(function() { do_check_eq(gFetchCount, 1); run_next_test(); });
+  add_test(function() {
+    equal(gFetchCount, 1,
+          "Stapled Revoked response -> a fetch should not have been attempted");
+    run_next_test();
+  });
 
   //---------------------------------------------------------------------------
 
   // Reset state
   add_test(function() { clearOCSPCache(); gFetchCount = 0; run_next_test(); });
 }
--- a/security/manager/ssl/tests/unit/test_ocsp_no_hsts_upgrade.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_no_hsts_upgrade.js
@@ -40,13 +40,15 @@ function run_test() {
   add_test(function () { ocspResponder.stop(run_next_test); });
 
   let SSService = Cc["@mozilla.org/ssservice;1"]
                     .getService(Ci.nsISiteSecurityService);
   let uri = Services.io.newURI("http://localhost", null, null);
   let sslStatus = new FakeSSLStatus();
   SSService.processHeader(Ci.nsISiteSecurityService.HEADER_HSTS, uri,
                           "max-age=10000", sslStatus, 0);
-  do_check_true(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
-                                       "localhost", 0));
+  ok(SSService.isSecureHost(Ci.nsISiteSecurityService.HEADER_HSTS,
+                            "localhost", 0),
+     "Domain for the OCSP AIA URI should be considered a HSTS host, otherwise" +
+     " we wouldn't be testing what we think we're testing");
 
   run_next_test();
 }
--- a/security/manager/ssl/tests/unit/test_ocsp_required.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_required.js
@@ -42,13 +42,14 @@ function run_test() {
 
 function add_tests()
 {
   add_connection_test("ocsp-stapling-none.example.com",
                       SEC_ERROR_OCSP_BAD_SIGNATURE);
   add_connection_test("ocsp-stapling-none.example.com",
                       SEC_ERROR_OCSP_BAD_SIGNATURE);
   add_test(function () {
-    do_check_eq(gOCSPRequestCount, 1);
+    equal(gOCSPRequestCount, 1,
+          "OCSP request count should be 1 due to OCSP response caching");
     gOCSPRequestCount = 0;
     run_next_test();
   });
 }
--- a/security/manager/ssl/tests/unit/test_ocsp_stapling.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_stapling.js
@@ -165,37 +165,43 @@ function add_tests(certDB, otherTestCA) 
                 SEC_ERROR_REVOKED_CERTIFICATE, true);
 }
 
 function check_ocsp_stapling_telemetry() {
   let histogram = Cc["@mozilla.org/base/telemetry;1"]
                     .getService(Ci.nsITelemetry)
                     .getHistogramById("SSL_OCSP_STAPLING")
                     .snapshot();
-  do_check_eq(histogram.counts[0], 0); // histogram bucket 0 is unused
-  do_check_eq(histogram.counts[1], 5); // 5 connections with a good response
-  do_check_eq(histogram.counts[2], 18); // 18 connections with no stapled resp.
-  do_check_eq(histogram.counts[3], 0); // 0 connections with an expired response
-  do_check_eq(histogram.counts[4], 21); // 21 connections with bad responses
+  equal(histogram.counts[0], 0,
+        "Should have 0 connections for unused histogram bucket 0");
+  equal(histogram.counts[1], 5,
+        "Actual and expected connections with a good response should match");
+  equal(histogram.counts[2], 18,
+        "Actual and expected connections with no stapled response should match");
+  equal(histogram.counts[3], 0,
+        "Actual and expected connections with an expired response should match");
+  equal(histogram.counts[4], 21,
+        "Actual and expected connections with bad responses should match");
   run_next_test();
 }
 
 function run_test() {
   do_get_profile();
 
   let certDB = Cc["@mozilla.org/security/x509certdb;1"]
                   .getService(Ci.nsIX509CertDB);
   let otherTestCAFile = do_get_file("tlsserver/other-test-ca.der", false);
   let otherTestCADER = readFile(otherTestCAFile);
   let otherTestCA = certDB.constructX509(otherTestCADER, otherTestCADER.length);
 
   let fakeOCSPResponder = new HttpServer();
   fakeOCSPResponder.registerPrefixHandler("/", function (request, response) {
     response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
-    do_check_true(gExpectOCSPRequest);
+    ok(gExpectOCSPRequest,
+       "Should be getting an OCSP request only when expected");
   });
   fakeOCSPResponder.start(8888);
 
   add_tls_server_setup("OCSPStaplingServer");
 
   add_tests(certDB, otherTestCA);
 
   add_test(function () {
--- a/security/manager/ssl/tests/unit/test_ocsp_stapling_expired.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_stapling_expired.js
@@ -16,17 +16,17 @@ function add_ocsp_test(aHost, aExpectedR
   add_connection_test(aHost, aExpectedResult,
     function() {
       clearOCSPCache();
       clearSessionCache();
       gCurrentOCSPResponse = aOCSPResponseToServe;
       gOCSPRequestCount = 0;
     },
     function() {
-      do_check_eq(gOCSPRequestCount, 1);
+      equal(gOCSPRequestCount, 1, "Should have made 1 fallback OCSP request");
     });
 }
 
 do_get_profile();
 Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
 Services.prefs.setIntPref("security.OCSP.enabled", 1);
 let args = [["good", "localhostAndExampleCom", "unused"],
              ["expiredresponse", "localhostAndExampleCom", "unused"],
@@ -153,15 +153,20 @@ function run_test() {
   run_next_test();
 }
 
 function check_ocsp_stapling_telemetry() {
   let histogram = Cc["@mozilla.org/base/telemetry;1"]
                     .getService(Ci.nsITelemetry)
                     .getHistogramById("SSL_OCSP_STAPLING")
                     .snapshot();
-  do_check_eq(histogram.counts[0], 0); // histogram bucket 0 is unused
-  do_check_eq(histogram.counts[1], 0); // 0 connections with a good response
-  do_check_eq(histogram.counts[2], 0); // 0 connections with no stapled resp.
-  do_check_eq(histogram.counts[3], 21); // 21 connections with an expired response
-  do_check_eq(histogram.counts[4], 0); // 0 connections with bad responses
+  equal(histogram.counts[0], 0,
+        "Should have 0 connections for unused histogram bucket 0");
+  equal(histogram.counts[1], 0,
+        "Actual and expected connections with a good response should match");
+  equal(histogram.counts[2], 0,
+        "Actual and expected connections with no stapled response should match");
+  equal(histogram.counts[3], 21,
+        "Actual and expected connections with an expired response should match");
+  equal(histogram.counts[4], 0,
+        "Actual and expected connections with bad responses should match");
   run_next_test();
 }
--- a/security/manager/ssl/tests/unit/test_ocsp_stapling_with_intermediate.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_stapling_with_intermediate.js
@@ -33,13 +33,13 @@ function run_test() {
 
   add_tls_server_setup("OCSPStaplingServer");
 
   add_ocsp_test("ocsp-stapling-with-intermediate.example.com",
                 PRErrorCodeSuccess);
 
   add_test(function () { ocspResponder.stop(run_next_test); });
   add_test(function() {
-    do_check_eq(gOCSPRequestCount, 0);
+    equal(gOCSPRequestCount, 0, "No OCSP requests should have been made");
     run_next_test();
   });
   run_next_test();
 }
--- a/security/manager/ssl/tests/unit/test_ocsp_timeout.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_timeout.js
@@ -65,21 +65,24 @@ function add_tests_in_mode(useHardFail) 
 
     // With OCSP hard-fail on, we timeout after 10 seconds.
     // With OCSP soft-fail, we timeout after 2 seconds.
     // Date() is not guaranteed to be monotonic, so add extra fuzz time to
     // prevent intermittent failures (this only appeared to be a problem on
     // Windows XP). See Bug 1121117.
     const FUZZ_MS = 300;
     if (useHardFail) {
-      do_check_true(timeDifference + FUZZ_MS > 10000);
+      ok(timeDifference + FUZZ_MS > 10000,
+         "Automatic OCSP timeout should be about 10s for hard-fail");
     } else {
-      do_check_true(timeDifference + FUZZ_MS > 2000);
+      ok(timeDifference + FUZZ_MS > 2000,
+         "Automatic OCSP timeout should be about 2s for soft-fail");
     }
     // Make sure we didn't wait too long.
     // (Unfortunately, we probably can't have a tight upper bound on
     // how long is too long for this test, because we might be running
     // on slow hardware.)
-    do_check_true(timeDifference < 60000);
+    ok(timeDifference < 60000,
+       "Automatic OCSP timeout shouldn't be more than 60s");
     clearOCSPCache();
     run_next_test();
   });
 }
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -2481,16 +2481,22 @@
   },
   "STS_POLL_BLOCK_TIME": {
     "expires_in_version": "never",
     "kind": "exponential",
     "high": "60000",
     "n_buckets": 1000,
     "description": "Time spend blocked on poll (ms)."
   },
+  "IPV4_AND_IPV6_ADDRESS_CONNECTIVITY": {
+    "expires_in_version": "never",
+    "kind": "enumerated",
+    "n_values": 4,
+    "description": "Count the number of 0) successful connections to an ipv4 address, 1) failed connection an ipv4 address, 2) successful connection to an ipv6 address and 3) failed connections to an ipv6 address."
+  },
   "URL_PATH_ENDS_IN_EXCLAMATION": {
     "expires_in_version": "never",
     "kind": "boolean",
     "description": "The URL path ends in !"
   },
   "URL_PATH_CONTAINS_EXCLAMATION_SLASH": {
     "expires_in_version": "never",
     "kind": "boolean",
--- a/toolkit/mozapps/installer/packager.mk
+++ b/toolkit/mozapps/installer/packager.mk
@@ -199,16 +199,16 @@ upload: checksum
 		$(UPLOAD_FILES) \
 		$(CHECKSUM_FILES)
 
 # source-package creates a source tarball from the files in MOZ_PKG_SRCDIR,
 # which is either set to a clean checkout or defaults to $topsrcdir
 source-package:
 	@echo 'Packaging source tarball...'
 	$(MKDIR) -p $(DIST)/$(PKG_SRCPACK_PATH)
-	(cd $(MOZ_PKG_SRCDIR) && $(CREATE_SOURCE_TAR) - $(DIR_TO_BE_PACKAGED)) | xz -9e > $(SOURCE_TAR)
+	(cd $(MOZ_PKG_SRCDIR) && $(CREATE_SOURCE_TAR) - ./ ) | xz -9e > $(SOURCE_TAR)
 
 hg-bundle:
 	$(MKDIR) -p $(DIST)/$(PKG_SRCPACK_PATH)
 	$(CREATE_HG_BUNDLE_CMD)
 
 source-upload:
 	$(MAKE) upload UPLOAD_FILES='$(SOURCE_UPLOAD_FILES)' CHECKSUM_FILE='$(SOURCE_CHECKSUM_FILE)'
--- a/toolkit/mozapps/installer/upload-files.mk
+++ b/toolkit/mozapps/installer/upload-files.mk
@@ -770,30 +770,30 @@ endif
 ifdef MOZ_STUB_INSTALLER
 UPLOAD_FILES += $(call QUOTED_WILDCARD,$(DIST)/$(PKG_INST_PATH)$(PKG_STUB_BASENAME).exe)
 endif
 
 ifndef MOZ_PKG_SRCDIR
 MOZ_PKG_SRCDIR = $(topsrcdir)
 endif
 
-DIR_TO_BE_PACKAGED ?= ../$(notdir $(topsrcdir))
+SRC_TAR_PREFIX = $(MOZ_APP_NAME)-$(MOZ_PKG_VERSION)
 SRC_TAR_EXCLUDE_PATHS += \
   --exclude='.hg*' \
   --exclude='CVS' \
   --exclude='.cvs*' \
   --exclude='.mozconfig*' \
   --exclude='*.pyc' \
   --exclude='$(MOZILLA_DIR)/Makefile' \
   --exclude='$(MOZILLA_DIR)/dist'
 ifdef MOZ_OBJDIR
 SRC_TAR_EXCLUDE_PATHS += --exclude='$(MOZ_OBJDIR)'
 endif
 CREATE_SOURCE_TAR = $(TAR) -c --owner=0 --group=0 --numeric-owner \
-  --mode=go-w $(SRC_TAR_EXCLUDE_PATHS) -f
+  --mode=go-w $(SRC_TAR_EXCLUDE_PATHS) --transform='s,^\./,$(SRC_TAR_PREFIX)/,' -f
 
 SOURCE_TAR = $(DIST)/$(PKG_SRCPACK_PATH)$(PKG_SRCPACK_BASENAME).tar.xz
 HG_BUNDLE_FILE = $(DIST)/$(PKG_SRCPACK_PATH)$(PKG_BUNDLE_BASENAME).bundle
 SOURCE_CHECKSUM_FILE = $(DIST)/$(PKG_SRCPACK_PATH)$(PKG_SRCPACK_BASENAME).checksums
 SOURCE_UPLOAD_FILES = $(SOURCE_TAR)
 
 HG ?= hg
 CREATE_HG_BUNDLE_CMD  = $(HG) -v -R $(topsrcdir) bundle --base null
--- a/view/nsView.cpp
+++ b/view/nsView.cpp
@@ -224,20 +224,20 @@ nsIntRect nsView::CalcWidgetBounds(nsWin
       viewBounds += nsPoint(NSIntPixelsToAppUnits(screenPoint.x, p2a),
                             NSIntPixelsToAppUnits(screenPoint.y, p2a));
     }
   }
 
   // Compute widget bounds in device pixels
   nsIntRect newBounds = viewBounds.ToNearestPixels(p2a);
 
-#ifdef XP_MACOSX
-  // cocoa rounds widget coordinates to the nearest global "display pixel"
-  // integer value. So we avoid fractional display pixel values by rounding
-  // to the nearest value that won't yield a fractional display pixel.
+#if defined(XP_MACOSX) || (MOZ_WIDGET_GTK == 3)
+  // cocoa and GTK round widget coordinates to the nearest global "display
+  // pixel" integer value. So we avoid fractional display pixel values by
+  // rounding to the nearest value that won't yield a fractional display pixel.
   nsIWidget* widget = parentWidget ? parentWidget : mWindow.get();
   uint32_t round;
   if (aType == eWindowType_popup && widget &&
       ((round = widget->RoundsWidgetCoordinatesTo()) > 1)) {
     nsIntSize pixelRoundedSize = newBounds.Size();
     // round the top left and bottom right to the nearest round pixel
     newBounds.x = NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.x, p2a) / round) * round;
     newBounds.y = NSToIntRoundUp(NSAppUnitsToDoublePixels(viewBounds.y, p2a) / round) * round;
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -6572,8 +6572,14 @@ nsWindow::SynthesizeNativeMouseScrollEve
     return NS_OK;
   }
 #endif
 
   gdk_event_put(&event);
 
   return NS_OK;
 }
+
+int32_t
+nsWindow::RoundsWidgetCoordinatesTo()
+{
+    return GdkScaleFactor();
+}
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -477,16 +477,18 @@ private:
     // nsBaseWidget
     virtual LayerManager* GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr,
                                           LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE,
                                           LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT,
                                           bool* aAllowRetaining = nullptr) override;
 
     void CleanLayerManagerRecursive();
 
+    virtual int32_t RoundsWidgetCoordinatesTo() override;
+
     /**
      * |mIMModule| takes all IME related stuff.
      *
      * This is owned by the top-level nsWindow or the topmost child
      * nsWindow embedded in a non-Gecko widget.
      *
      * The instance is created when the top level widget is created.  And when
      * the widget is destroyed, it's released.  All child windows refer its
--- a/widget/windows/nsWindow.cpp
+++ b/widget/windows/nsWindow.cpp
@@ -406,21 +406,20 @@ nsWindow::nsWindow() : nsWindowBase()
   sInstanceCount++;
 }
 
 nsWindow::~nsWindow()
 {
   mInDtor = true;
 
   // If the widget was released without calling Destroy() then the native window still
-  // exists, and we need to destroy it. This will also result in a call to OnDestroy.
-  //
-  // XXX How could this happen???
-  if (nullptr != mWnd)
-    Destroy();
+  // exists, and we need to destroy it.
+  // Destroy() will early-return if it was already called. In any case it is important
+  // to call it before destroying mPresentLock (cf. 1156182).
+  Destroy();
 
   // Free app icon resources.  This must happen after `OnDestroy` (see bug 708033).
   if (mIconSmall)
     ::DestroyIcon(mIconSmall);
 
   if (mIconBig)
     ::DestroyIcon(mIconBig);
 
--- a/xpcom/idl-parser/header.py
+++ b/xpcom/idl-parser/header.py
@@ -2,87 +2,103 @@
 # header.py - Generate C++ header files from IDL.
 #
 # 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/.
 
 """Print a C++ header file for the IDL files specified on the command line"""
 
-import sys, os.path, re, xpidl, itertools, glob
+import sys
+import os.path
+import re
+import xpidl
+import itertools
+import glob
 
 printdoccomments = False
 
 if printdoccomments:
     def printComments(fd, clist, indent):
         for c in clist:
             fd.write("%s%s\n" % (indent, c))
 else:
     def printComments(fd, clist, indent):
         pass
 
+
 def firstCap(str):
     return str[0].upper() + str[1:]
 
+
 def attributeParamName(a):
     return "a" + firstCap(a.name)
 
+
 def attributeParamNames(a):
     l = [attributeParamName(a)]
     if a.implicit_jscontext:
         l.insert(0, "cx")
     return ", ".join(l)
 
+
 def attributeNativeName(a, getter):
     binaryname = a.binaryname is not None and a.binaryname or firstCap(a.name)
     return "%s%s" % (getter and 'Get' or 'Set', binaryname)
 
+
 def attributeReturnType(a, macro):
     """macro should be NS_IMETHOD or NS_IMETHODIMP"""
     if (a.nostdcall):
         return macro == "NS_IMETHOD" and "virtual nsresult" or "nsresult"
     else:
         return macro
 
+
 def attributeParamlist(a, getter):
     l = ["%s%s" % (a.realtype.nativeType(getter and 'out' or 'in'),
                    attributeParamName(a))]
     if a.implicit_jscontext:
         l.insert(0, "JSContext* cx")
 
     return ", ".join(l)
 
+
 def attributeAsNative(a, getter):
         deprecated = a.deprecated and "NS_DEPRECATED " or ""
         params = {'deprecated': deprecated,
                   'returntype': attributeReturnType(a, 'NS_IMETHOD'),
                   'binaryname': attributeNativeName(a, getter),
                   'paramlist': attributeParamlist(a, getter)}
         return "%(deprecated)s%(returntype)s %(binaryname)s(%(paramlist)s)" % params
 
+
 def methodNativeName(m):
     return m.binaryname is not None and m.binaryname or firstCap(m.name)
 
+
 def methodReturnType(m, macro):
     """macro should be NS_IMETHOD or NS_IMETHODIMP"""
     if m.nostdcall and m.notxpcom:
         return "%s%s" % (macro == "NS_IMETHOD" and "virtual " or "",
                          m.realtype.nativeType('in').strip())
     elif m.nostdcall:
         return "%snsresult" % (macro == "NS_IMETHOD" and "virtual " or "")
     elif m.notxpcom:
         return "%s_(%s)" % (macro, m.realtype.nativeType('in').strip())
     else:
         return macro
 
+
 def methodAsNative(m):
     return "%s %s(%s)" % (methodReturnType(m, 'NS_IMETHOD'),
                           methodNativeName(m),
                           paramlistAsNative(m))
 
+
 def paramlistAsNative(m, empty='void'):
     l = [paramAsNative(p) for p in m.params]
 
     if m.implicit_jscontext:
         l.append("JSContext* cx")
 
     if m.optional_argc:
         l.append('uint8_t _argc')
@@ -95,20 +111,22 @@ def paramlistAsNative(m, empty='void'):
                                            location=None,
                                            realtype=m.realtype)))
 
     if len(l) == 0:
         return empty
 
     return ", ".join(l)
 
+
 def paramAsNative(p):
     return "%s%s" % (p.nativeType(),
                      p.name)
 
+
 def paramlistNames(m):
     names = [p.name for p in m.params]
 
     if m.implicit_jscontext:
         names.append('cx')
 
     if m.optional_argc:
         names.append('_argc')
@@ -152,20 +170,22 @@ header_end = """/* For IDL files that do
 footer = """
 #endif /* __gen_%(basename)s_h__ */
 """
 
 forward_decl = """class %(name)s; /* forward declaration */
 
 """
 
+
 def idl_basename(f):
     """returns the base name of a file with the last extension stripped"""
     return os.path.basename(f).rpartition('.')[0]
 
+
 def print_header(idl, fd, filename):
     fd.write(header % {'filename': filename,
                        'basename': idl_basename(filename)})
 
     foundinc = False
     for inc in idl.includes():
         if not foundinc:
             foundinc = True
@@ -181,17 +201,18 @@ def print_header(idl, fd, filename):
             if attr.infallible:
                 fd.write(infallible_includes)
                 break
 
     fd.write('\n')
     fd.write(header_end)
 
     for p in idl.productions:
-        if p.kind == 'include': continue
+        if p.kind == 'include':
+            continue
         if p.kind == 'cdata':
             fd.write(p.data)
             continue
 
         if p.kind == 'forward':
             fd.write(forward_decl % {'name': p.name})
             continue
         if p.kind == 'interface':
@@ -216,17 +237,17 @@ iface_header = r"""
 
 uuid_decoder = re.compile(r"""(?P<m0>[a-f0-9]{8})-
                               (?P<m1>[a-f0-9]{4})-
                               (?P<m2>[a-f0-9]{4})-
                               (?P<m3>[a-f0-9]{4})-
                               (?P<m4>[a-f0-9]{12})$""", re.X)
 
 iface_prolog = """ {
- public: 
+ public:
 
   NS_DECLARE_STATIC_IID_ACCESSOR(%(defname)s_IID)
 
 """
 
 iface_epilog = """};
 
   NS_DEFINE_STATIC_IID_ACCESSOR(%(name)s, %(defname)s_IID)
@@ -297,16 +318,17 @@ attr_infallible_tmpl = """\
   {
     %(realtype)sresult;
     mozilla::DebugOnly<nsresult> rv = %(nativename)s(%(argnames)s&result);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
     return result;
   }
 """
 
+
 def write_interface(iface, fd):
     if iface.namemap is None:
         raise Exception("Interface was not resolved.")
 
     def write_const_decls(g):
         fd.write("  enum {\n")
         enums = []
         for c in g:
@@ -320,21 +342,21 @@ def write_interface(iface, fd):
         fd.write(",\n".join(enums))
         fd.write("\n  };\n\n")
 
     def write_method_decl(m):
         printComments(fd, m.doccomments, '  ')
 
         fd.write("  /* %s */\n" % m.toIDL())
         fd.write("  %s = 0;\n\n" % methodAsNative(m))
-                                                                           
+
     def write_attr_decl(a):
         printComments(fd, a.doccomments, '  ')
 
-        fd.write("  /* %s */\n" % a.toIDL());
+        fd.write("  /* %s */\n" % a.toIDL())
 
         fd.write("  %s = 0;\n" % attributeAsNative(a, True))
         if a.infallible:
             fd.write(attr_infallible_tmpl %
                      {'realtype': a.realtype.nativeType('in'),
                       'nativename': attributeNativeName(a, getter=True),
                       'args': '' if not a.implicit_jscontext else 'JSContext* cx',
                       'argnames': '' if not a.implicit_jscontext else 'cx, '})
@@ -379,17 +401,17 @@ def write_interface(iface, fd):
         fd.write("MOZ_DEPRECATED ")
     fd.write(iface.name)
     if iface.base:
         fd.write(" : public %s" % iface.base)
     fd.write(iface_prolog % names)
 
     for key, group in itertools.groupby(iface.members, key=type):
         if key == xpidl.ConstMember:
-            write_const_decls(group) # iterator of all the consts
+            write_const_decls(group)  # iterator of all the consts
         else:
             for member in group:
                 if key == xpidl.Attribute:
                     write_attr_decl(member)
                 elif key == xpidl.Method:
                     write_method_decl(member)
                 elif key == xpidl.CDATA:
                     fd.write(" %s" % member.data)
@@ -405,22 +427,22 @@ def write_interface(iface, fd):
             fd.write("\\\n  %s override; " % attributeAsNative(member, True))
             if not member.readonly:
                 fd.write("\\\n  %s override; " % attributeAsNative(member, False))
         elif isinstance(member, xpidl.Method):
             fd.write("\\\n  %s override; " % methodAsNative(member))
     if len(iface.members) == 0:
         fd.write('\\\n  /* no methods! */')
     elif not member.kind in ('attribute', 'method'):
-       fd.write('\\')
+        fd.write('\\')
 
     fd.write(iface_forward % names)
 
     def emitTemplate(forward_infallible, tmpl, tmpl_notxpcom=None):
-        if tmpl_notxpcom == None:
+        if tmpl_notxpcom is None:
             tmpl_notxpcom = tmpl
         for member in iface.members:
             if isinstance(member, xpidl.Attribute):
                 if forward_infallible and member.infallible:
                     fd.write("\\\n  using %s::%s; " % (iface.name, attributeNativeName(member, True)))
                 fd.write(tmpl % {'asNative': attributeAsNative(member, True),
                                  'nativeName': attributeNativeName(member, True),
                                  'paramList': attributeParamNames(member)})
@@ -452,17 +474,18 @@ def write_interface(iface, fd):
     # implement them.
     emitTemplate(False,
                  "\\\n  %(asNative)s override { return !_to ? NS_ERROR_NULL_POINTER : _to->%(nativeName)s(%(paramList)s); } ",
                  "\\\n  %(asNative)s override; ")
 
     fd.write(iface_template_prolog % names)
 
     for member in iface.members:
-        if isinstance(member, xpidl.ConstMember) or isinstance(member, xpidl.CDATA): continue
+        if isinstance(member, xpidl.ConstMember) or isinstance(member, xpidl.CDATA):
+            continue
         fd.write("/* %s */\n" % member.toIDL())
         if isinstance(member, xpidl.Attribute):
             fd.write(example_tmpl % {'implclass': implclass,
                                      'returntype': attributeReturnType(member, 'NS_IMETHODIMP'),
                                      'nativeName': attributeNativeName(member, True),
                                      'paramList': attributeParamlist(member, True)})
             if not member.readonly:
                 fd.write(example_tmpl % {'implclass': implclass,
--- a/xpcom/idl-parser/runtests.py
+++ b/xpcom/idl-parser/runtests.py
@@ -4,20 +4,21 @@
 # http://creativecommons.org/publicdomain/zero/1.0/
 #
 # Unit tests for xpidl.py
 
 import mozunit
 import unittest
 import xpidl
 
+
 class TestParser(unittest.TestCase):
     def setUp(self):
         self.p = xpidl.IDLParser()
-    
+
     def testEmpty(self):
         i = self.p.parse("", filename='f')
         self.assertTrue(isinstance(i, xpidl.IDL))
         self.assertEqual([], i.productions)
 
     def testForwardInterface(self):
         i = self.p.parse("interface foo;", filename='f')
         self.assertTrue(isinstance(i, xpidl.IDL))
--- a/xpcom/idl-parser/typelib.py
+++ b/xpcom/idl-parser/typelib.py
@@ -4,17 +4,18 @@
 # 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/.
 
 """Generate an XPIDL typelib for the IDL files specified on the command line"""
 
 import os
 import sys
-import xpidl, xpt
+import xpidl
+import xpt
 
 # A map of xpidl.py types to xpt.py types
 TypeMap = {
     # nsresult is not strictly an xpidl.py type, but it's useful here
     'nsresult':           xpt.Type.Tags.uint32,
     # builtins
     'boolean':            xpt.Type.Tags.boolean,
     'void':               xpt.Type.Tags.void,
@@ -42,38 +43,40 @@ TypeMap = {
     'nsid':               xpt.Type.Tags.nsIID,
     'domstring':          xpt.Type.Tags.DOMString,
     'astring':            xpt.Type.Tags.AString,
     'utf8string':         xpt.Type.Tags.UTF8String,
     'cstring':            xpt.Type.Tags.CString,
     'jsval':              xpt.Type.Tags.jsval
 }
 
+
 # XXXkhuey dipper types should go away (bug 677784)
 def isDipperType(type):
     return type == xpt.Type.Tags.DOMString or type == xpt.Type.Tags.AString or type == xpt.Type.Tags.CString or type == xpt.Type.Tags.UTF8String
 
+
 def build_interface(iface, ifaces):
     def get_type(type, calltype, iid_is=None, size_is=None):
         """ Return the appropriate xpt.Type object for this param """
 
         while isinstance(type, xpidl.Typedef):
             type = type.realtype
 
         if isinstance(type, xpidl.Builtin):
-            if type.name == 'string' and size_is != None:
-                  return xpt.StringWithSizeType(size_is, size_is)
-            elif type.name == 'wstring' and size_is != None:
-                  return xpt.WideStringWithSizeType(size_is, size_is)
+            if type.name == 'string' and size_is is not None:
+                return xpt.StringWithSizeType(size_is, size_is)
+            elif type.name == 'wstring' and size_is is not None:
+                return xpt.WideStringWithSizeType(size_is, size_is)
             else:
-                  tag = TypeMap[type.name]
-                  isPtr = (tag == xpt.Type.Tags.char_ptr or tag == xpt.Type.Tags.wchar_t_ptr)
-                  return xpt.SimpleType(tag,
-                                        pointer=isPtr,
-                                        reference=False)
+                tag = TypeMap[type.name]
+                isPtr = (tag == xpt.Type.Tags.char_ptr or tag == xpt.Type.Tags.wchar_t_ptr)
+                return xpt.SimpleType(tag,
+                                      pointer=isPtr,
+                                      reference=False)
 
         if isinstance(type, xpidl.Array):
             # NB: For an Array<T> we pass down the iid_is to get the type of T.
             #     This allows Arrays of InterfaceIs types to work.
             return xpt.ArrayType(get_type(type.type, calltype, iid_is), size_is,
                                  #XXXkhuey length_is duplicates size_is (bug 677788),
                                  size_is)
 
@@ -92,17 +95,17 @@ def build_interface(iface, ifaces):
         if isinstance(type, xpidl.Native):
             if type.specialtype:
                 # XXXkhuey jsval is marked differently in the typelib and in the headers :-(
                 isPtr = (type.isPtr(calltype) or type.isRef(calltype)) and not type.specialtype == 'jsval'
                 isRef = type.isRef(calltype) and not type.specialtype == 'jsval'
                 return xpt.SimpleType(TypeMap[type.specialtype],
                                       pointer=isPtr,
                                       reference=isRef)
-            elif iid_is != None:
+            elif iid_is is not None:
                 return xpt.InterfaceIsType(iid_is)
             else:
                 # void ptr
                 return xpt.SimpleType(TypeMap['void'],
                                       pointer=True,
                                       reference=False)
 
         raise Exception("Unknown type!")
@@ -230,16 +233,17 @@ def build_interface(iface, ifaces):
 
     return xpt.Interface(iface.name, iface.attributes.uuid, methods=methods,
                          constants=consts, resolved=True, parent=parent,
                          scriptable=iface.attributes.scriptable,
                          function=iface.attributes.function,
                          builtinclass=iface.attributes.builtinclass,
                          main_process_scriptable_only=iface.attributes.main_process_scriptable_only)
 
+
 def write_typelib(idl, fd, filename):
     """ Generate the typelib. """
 
     # We only care about interfaces
     ifaces = []
     for p in idl.productions:
         if p.kind == 'interface':
             ifaces.append(build_interface(p, ifaces))
--- a/xpcom/idl-parser/xpidl.py
+++ b/xpcom/idl-parser/xpidl.py
@@ -2,18 +2,21 @@
 # xpidl.py - A parser for cross-platform IDL (XPIDL) files.
 #
 # 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/.
 
 """A parser for cross-platform IDL (XPIDL) files."""
 
-import sys, os.path, re
-from ply import lex, yacc
+import sys
+import os.path
+import re
+from ply import lex
+from ply import yacc
 
 """A type conforms to the following pattern:
 
     def isScriptable(self):
         'returns True or False'
 
     def nativeType(self, calltype):
         'returns a string representation of the native type
@@ -22,31 +25,33 @@ from ply import lex, yacc
 Interface members const/method/attribute conform to the following pattern:
 
     name = 'string'
 
     def toIDL(self):
         'returns the member signature as IDL'
 """
 
+
 def attlistToIDL(attlist):
     if len(attlist) == 0:
         return ''
 
     attlist = list(attlist)
-    attlist.sort(cmp=lambda a,b: cmp(a[0], b[0]))
+    attlist.sort(cmp=lambda a, b: cmp(a[0], b[0]))
 
     return '[%s] ' % ','.join(["%s%s" % (name, value is not None and '(%s)' % value or '')
                               for name, value, aloc in attlist])
 
 _paramsHardcode = {
     2: ('array', 'shared', 'iid_is', 'size_is', 'retval'),
     3: ('array', 'size_is', 'const'),
 }
 
+
 def paramAttlistToIDL(attlist):
     if len(attlist) == 0:
         return ''
 
     # Hack alert: g_hash_table_foreach is pretty much unimitatable... hardcode
     # quirk
     attlist = list(attlist)
     sorted = []
@@ -61,39 +66,43 @@ def paramAttlistToIDL(attlist):
 
                 i += 1
 
     sorted.extend(attlist)
 
     return '[%s] ' % ', '.join(["%s%s" % (name, value is not None and ' (%s)' % value or '')
                                 for name, value, aloc in sorted])
 
+
 def unaliasType(t):
     while t.kind == 'typedef':
         t = t.realtype
     assert t is not None
     return t
 
+
 def getBuiltinOrNativeTypeName(t):
     t = unaliasType(t)
     if t.kind == 'builtin':
         return t.name
     elif t.kind == 'native':
         assert t.specialtype is not None
         return '[%s]' % t.specialtype
     else:
         return None
 
+
 class BuiltinLocation(object):
     def get(self):
         return "<builtin type>"
 
     def __str__(self):
         return self.get()
 
+
 class Builtin(object):
     kind = 'builtin'
     location = BuiltinLocation
 
     def __init__(self, name, nativename, signed=False, maybeConst=False):
         self.name = name
         self.nativename = nativename
         self.signed = signed
@@ -134,28 +143,29 @@ builtinNames = [
     Builtin('wchar', 'char16_t', False, False),
     Builtin('wstring', 'char16_t *', False, False),
 ]
 
 builtinMap = {}
 for b in builtinNames:
     builtinMap[b.name] = b
 
+
 class Location(object):
     _line = None
 
     def __init__(self, lexer, lineno, lexpos):
         self._lineno = lineno
         self._lexpos = lexpos
         self._lexdata = lexer.lexdata
         self._file = getattr(lexer, 'filename', "<unknown>")
 
     def __eq__(self, other):
-        return self._lexpos == other._lexpos and \
-               self._file == other._file
+        return (self._lexpos == other._lexpos and
+                self._file == other._file)
 
     def resolve(self):
         if self._line:
             return
 
         startofline = self._lexdata.rfind('\n', 0, self._lexpos) + 1
         endofline = self._lexdata.find('\n', self._lexpos, self._lexpos + 80)
         self._line = self._lexdata[startofline:endofline]
@@ -173,16 +183,17 @@ class Location(object):
         self.resolve()
         return "%s line %s:%s" % (self._file, self._lineno, self._colno)
 
     def __str__(self):
         self.resolve()
         return "%s line %s:%s\n%s\n%s" % (self._file, self._lineno, self._colno,
                                           self._line, self.pointerline())
 
+
 class NameMap(object):
     """Map of name -> object. Each object must have a .name and .location property.
     Setting the same name twice throws an error."""
     def __init__(self):
         self._d = {}
 
     def __getitem__(self, key):
         if key in builtinMap:
@@ -197,42 +208,45 @@ class NameMap(object):
 
     def set(self, object):
         if object.name in builtinMap:
             raise IDLError("name '%s' is a builtin and cannot be redeclared" % (object.name), object.location)
         if object.name.startswith("_"):
             object.name = object.name[1:]
         if object.name in self._d:
             old = self._d[object.name]
-            if old == object: return
+            if old == object:
+                return
             if isinstance(old, Forward) and isinstance(object, Interface):
                 self._d[object.name] = object
             elif isinstance(old, Interface) and isinstance(object, Forward):
                 pass
             else:
                 raise IDLError("name '%s' specified twice. Previous location: %s" % (object.name, self._d[object.name].location), object.location)
         else:
             self._d[object.name] = object
 
     def get(self, id, location):
         try:
             return self[id]
         except KeyError:
             raise IDLError("Name '%s' not found", location)
 
+
 class IDLError(Exception):
     def __init__(self, message, location, warning=False):
         self.message = message
         self.location = location
         self.warning = warning
 
     def __str__(self):
         return "%s: %s, %s" % (self.warning and 'warning' or 'error',
                                self.message, self.location)
 
+
 class Include(object):
     kind = 'include'
 
     def __init__(self, filename, location):
         self.filename = filename
         self.location = location
 
     def __str__(self):
@@ -240,27 +254,29 @@ class Include(object):
 
     def resolve(self, parent):
         def incfiles():
             yield self.filename
             for dir in parent.incdirs:
                 yield os.path.join(dir, self.filename)
 
         for file in incfiles():
-            if not os.path.exists(file): continue
+            if not os.path.exists(file):
+                continue
 
             self.IDL = parent.parser.parse(open(file).read(), filename=file)
             self.IDL.resolve(parent.incdirs, parent.parser)
             for type in self.IDL.getNames():
                 parent.setName(type)
             parent.deps.extend(self.IDL.deps)
             return
 
         raise IDLError("File '%s' not found" % self.filename, self.location)
 
+
 class IDL(object):
     def __init__(self, productions):
         self.productions = productions
         self.deps = []
 
     def setName(self, object):
         self.namemap.set(object)
 
@@ -292,16 +308,17 @@ class IDL(object):
                 yield p
 
     def needsJSTypes(self):
         for p in self.productions:
             if p.kind == 'interface' and p.needsJSTypes():
                 return True
         return False
 
+
 class CDATA(object):
     kind = 'cdata'
     _re = re.compile(r'\n+')
 
     def __init__(self, data, location):
         self.data = self._re.sub('\n', data)
         self.location = location
 
@@ -309,16 +326,17 @@ class CDATA(object):
         pass
 
     def __str__(self):
         return "cdata: %s\n\t%r\n" % (self.location.get(), self.data)
 
     def count(self):
         return 0
 
+
 class Typedef(object):
     kind = 'typedef'
 
     def __init__(self, type, name, location, doccomments):
         self.type = type
         self.name = name
         self.location = location
         self.doccomments = doccomments
@@ -335,33 +353,35 @@ class Typedef(object):
 
     def nativeType(self, calltype):
         return "%s %s" % (self.name,
                           calltype != 'in' and '*' or '')
 
     def __str__(self):
         return "typedef %s %s\n" % (self.type, self.name)
 
+
 class Forward(object):
     kind = 'forward'
 
     def __init__(self, name, location, doccomments):
         self.name = name
         self.location = location
         self.doccomments = doccomments
 
     def __eq__(self, other):
         return other.kind == 'forward' and other.name == self.name
 
     def resolve(self, parent):
         # Hack alert: if an identifier is already present, move the doccomments
         # forward.
         if parent.hasName(self.name):
             for i in xrange(0, len(parent.productions)):
-                if parent.productions[i] is self: break
+                if parent.productions[i] is self:
+                    break
             for i in xrange(i + 1, len(parent.productions)):
                 if hasattr(parent.productions[i], 'doccomments'):
                     parent.productions[i].doccomments[0:0] = self.doccomments
                     break
 
         parent.setName(self)
 
     def isScriptable(self):
@@ -369,16 +389,17 @@ class Forward(object):
 
     def nativeType(self, calltype):
         return "%s %s" % (self.name,
                           calltype != 'in' and '* *' or '*')
 
     def __str__(self):
         return "forward-declared %s\n" % self.name
 
+
 class Native(object):
     kind = 'native'
 
     modifier = None
     specialtype = None
 
     specialtypes = {
         'nsid': None,
@@ -406,20 +427,20 @@ class Native(object):
                     raise IDLError("More than one special type", aloc)
                 self.specialtype = name
                 if self.specialtypes[name] is not None:
                     self.nativename = self.specialtypes[name]
             else:
                 raise IDLError("Unexpected attribute", aloc)
 
     def __eq__(self, other):
-        return self.name == other.name and \
-               self.nativename == other.nativename and \
-               self.modifier == other.modifier and \
-               self.specialtype == other.specialtype
+        return (self.name == other.name and
+                self.nativename == other.nativename and
+                self.modifier == other.modifier and
+                self.specialtype == other.specialtype)
 
     def resolve(self, parent):
         parent.setName(self)
 
     def isScriptable(self):
         if self.specialtype is None:
             return False
 
@@ -454,16 +475,17 @@ class Native(object):
             m = '*' + ((self.modifier == 'ptr' and calltype != 'in') and '*' or '')
         else:
             m = calltype != 'in' and '*' or ''
         return "%s%s %s" % (const and 'const ' or '', self.nativename, m)
 
     def __str__(self):
         return "native %s(%s)\n" % (self.name, self.nativename)
 
+
 class Interface(object):
     kind = 'interface'
 
     def __init__(self, name, attlist, base, members, location, doccomments):
         self.name = name
         self.attributes = InterfaceAttributes(attlist, location)
         self.base = base
         self.members = members
@@ -515,18 +537,17 @@ class Interface(object):
         for member in self.members:
             member.resolve(self)
 
         # The number 250 is NOT arbitrary; this number is the maximum number of
         # stub entries defined in xpcom/reflect/xptcall/genstubs.pl
         # Do not increase this value without increasing the number in that
         # location, or you WILL cause otherwise unknown problems!
         if self.countEntries() > 250 and not self.attributes.builtinclass:
-            raise IDLError("interface '%s' has too many entries" % self.name,
-                self.location)
+            raise IDLError("interface '%s' has too many entries" % self.name, self.location)
 
     def isScriptable(self):
         # NOTE: this is not whether *this* interface is scriptable... it's
         # whether, when used as a type, it's scriptable, which is true of all
         # interfaces.
         return True
 
     def nativeType(self, calltype, const=False):
@@ -547,17 +568,17 @@ class Interface(object):
         return "".join(l)
 
     def getConst(self, name, location):
         # The constant may be in a base class
         iface = self
         while name not in iface.namemap and iface is not None:
             iface = self.idl.getName(self.base, self.location)
         if iface is None:
-            raise IDLError("cannot find symbol '%s'" % name, c.location)
+            raise IDLError("cannot find symbol '%s'" % name)
         c = iface.namemap.get(name, location)
         if c.kind != 'const':
             raise IDLError("symbol '%s' is not a constant", c.location)
 
         return c.getValue()
 
     def needsJSTypes(self):
         for m in self.members:
@@ -570,16 +591,17 @@ class Interface(object):
     def countEntries(self):
         ''' Returns the number of entries in the vtable for this interface. '''
         total = sum(member.count() for member in self.members)
         if self.base is not None:
             realbase = self.idl.getName(self.base, self.location)
             total += realbase.countEntries()
         return total
 
+
 class InterfaceAttributes(object):
     uuid = None
     scriptable = False
     builtinclass = False
     function = False
     deprecated = False
     noscript = False
     main_process_scriptable_only = False
@@ -647,18 +669,20 @@ class InterfaceAttributes(object):
         if self.builtinclass:
             l.append("\tbuiltinclass\n")
         if self.function:
             l.append("\tfunction\n")
         if self.main_process_scriptable_only:
             l.append("\tmain_process_scriptable_only\n")
         return "".join(l)
 
+
 class ConstMember(object):
     kind = 'const'
+
     def __init__(self, type, name, value, location, doccomments):
         self.type = type
         self.name = name
         self.value = value
         self.location = location
         self.doccomments = doccomments
 
     def resolve(self, parent):
@@ -676,16 +700,17 @@ class ConstMember(object):
         return self.value(self.iface)
 
     def __str__(self):
         return "\tconst %s %s = %s\n" % (self.type, self.name, self.getValue())
 
     def count(self):
         return 0
 
+
 class Attribute(object):
     kind = 'attribute'
     noscript = False
     readonly = False
     implicit_jscontext = False
     nostdcall = False
     binaryname = None
     null = None
@@ -710,30 +735,30 @@ class Attribute(object):
                 self.binaryname = value
                 continue
 
             if name == 'Null':
                 if value is None:
                     raise IDLError("'Null' attribute requires a value", aloc)
                 if readonly:
                     raise IDLError("'Null' attribute only makes sense for setters",
-                                   aloc);
+                                   aloc)
                 if value not in ('Empty', 'Null', 'Stringify'):
                     raise IDLError("'Null' attribute value must be 'Empty', 'Null' or 'Stringify'",
-                                   aloc);
+                                   aloc)
                 self.null = value
             elif name == 'Undefined':
                 if value is None:
                     raise IDLError("'Undefined' attribute requires a value", aloc)
                 if readonly:
                     raise IDLError("'Undefined' attribute only makes sense for setters",
-                                   aloc);
+                                   aloc)
                 if value not in ('Empty', 'Null'):
                     raise IDLError("'Undefined' attribute value must be 'Empty' or 'Null'",
-                                   aloc);
+                                   aloc)
                 self.undefined = value
             else:
                 if value is not None:
                     raise IDLError("Unexpected attribute value", aloc)
 
                 if name == 'noscript':
                     self.noscript = True
                 elif name == 'implicit_jscontext':
@@ -746,49 +771,50 @@ class Attribute(object):
                     self.infallible = True
                 else:
                     raise IDLError("Unexpected attribute '%s'" % name, aloc)
 
     def resolve(self, iface):
         self.iface = iface
         self.realtype = iface.idl.getName(self.type, self.location)
         if (self.null is not None and
-            getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
+                getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
             raise IDLError("'Null' attribute can only be used on DOMString",
                            self.location)
         if (self.undefined is not None and
-            getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
+                getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
             raise IDLError("'Undefined' attribute can only be used on DOMString",
                            self.location)
         if self.infallible and not self.realtype.kind == 'builtin':
             raise IDLError('[infallible] only works on builtin types '
                            '(numbers, booleans, and raw char types)',
                            self.location)
         if self.infallible and not iface.attributes.builtinclass:
             raise IDLError('[infallible] attributes are only allowed on '
                            '[builtinclass] interfaces',
                            self.location)
 
-
     def toIDL(self):
         attribs = attlistToIDL(self.attlist)
         readonly = self.readonly and 'readonly ' or ''
         return "%s%sattribute %s %s;" % (attribs, readonly, self.type, self.name)
 
     def isScriptable(self):
-        if not self.iface.attributes.scriptable: return False
+        if not self.iface.attributes.scriptable:
+            return False
         return not self.noscript
 
     def __str__(self):
         return "\t%sattribute %s %s\n" % (self.readonly and 'readonly ' or '',
                                           self.type, self.name)
 
     def count(self):
         return self.readonly and 1 or 2
 
+
 class Method(object):
     kind = 'method'
     noscript = False
     notxpcom = False
     binaryname = None
     implicit_jscontext = False
     nostdcall = False
     optional_argc = False
@@ -848,17 +874,18 @@ class Method(object):
                     if p.size_is == size_param.name:
                         found_size_param = True
                         if getBuiltinOrNativeTypeName(size_param.realtype) != 'unsigned long':
                             raise IDLError("is_size parameter must have type 'unsigned long'", self.location)
                 if not found_size_param:
                     raise IDLError("could not find is_size parameter '%s'" % p.size_is, self.location)
 
     def isScriptable(self):
-        if not self.iface.attributes.scriptable: return False
+        if not self.iface.attributes.scriptable:
+            return False
         return not (self.noscript or self.notxpcom)
 
     def __str__(self):
         return "\t%s %s(%s)\n" % (self.type, self.name, ", ".join([p.name for p in self.params]))
 
     def toIDL(self):
         if len(self.raises):
             raises = ' raises (%s)' % ','.join(self.raises)
@@ -881,16 +908,17 @@ class Method(object):
             t = p.realtype
             if isinstance(t, Native) and t.specialtype == "jsval":
                 return True
         return False
 
     def count(self):
         return 1
 
+
 class Param(object):
     size_is = None
     iid_is = None
     const = False
     array = False
     retval = False
     shared = False
     optional = False
@@ -915,24 +943,24 @@ class Param(object):
                 if value is None:
                     raise IDLError("'iid_is' must specify a parameter", aloc)
                 self.iid_is = value
             elif name == 'Null':
                 if value is None:
                     raise IDLError("'Null' must specify a parameter", aloc)
                 if value not in ('Empty', 'Null', 'Stringify'):
                     raise IDLError("'Null' parameter value must be 'Empty', 'Null', or 'Stringify'",
-                                   aloc);
+                                   aloc)
                 self.null = value
             elif name == 'Undefined':
                 if value is None:
                     raise IDLError("'Undefined' must specify a parameter", aloc)
                 if value not in ('Empty', 'Null'):
                     raise IDLError("'Undefined' parameter value must be 'Empty' or 'Null'",
-                                   aloc);
+                                   aloc)
                 self.undefined = value
             else:
                 if value is not None:
                     raise IDLError("Unexpected value for attribute '%s'" % name,
                                    aloc)
 
                 if name == 'const':
                     self.const = True
@@ -947,53 +975,57 @@ class Param(object):
                 else:
                     raise IDLError("Unexpected attribute '%s'" % name, aloc)
 
     def resolve(self, method):
         self.realtype = method.iface.idl.getName(self.type, self.location)
         if self.array:
             self.realtype = Array(self.realtype)
         if (self.null is not None and
-            getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
+                getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
             raise IDLError("'Null' attribute can only be used on DOMString",
                            self.location)
         if (self.undefined is not None and
-            getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
+                getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
             raise IDLError("'Undefined' attribute can only be used on DOMString",
                            self.location)
 
     def nativeType(self):
         kwargs = {}
-        if self.shared: kwargs['shared'] = True
-        if self.const: kwargs['const'] = True
+        if self.shared:
+            kwargs['shared'] = True
+        if self.const:
+            kwargs['const'] = True
 
         try:
             return self.realtype.nativeType(self.paramtype, **kwargs)
         except IDLError, e:
             raise IDLError(e.message, self.location)
         except TypeError, e:
             raise IDLError("Unexpected parameter attribute", self.location)
 
     def toIDL(self):
         return "%s%s %s %s" % (paramAttlistToIDL(self.attlist),
                                self.paramtype,
                                self.type,
                                self.name)
 
+
 class Array(object):
     def __init__(self, basetype):
         self.type = basetype
 
     def isScriptable(self):
         return self.type.isScriptable()
 
     def nativeType(self, calltype, const=False):
         return "%s%s*" % (const and 'const ' or '',
                           self.type.nativeType(calltype))
 
+
 class IDLParser(object):
     keywords = {
         'const': 'CONST',
         'interface': 'INTERFACE',
         'in': 'IN',
         'inout': 'INOUT',
         'out': 'OUT',
         'attribute': 'ATTRIBUTE',
@@ -1021,17 +1053,17 @@ class IDLParser(object):
         ('nativeid', 'exclusive'),
     )
 
     hexchar = r'[a-fA-F0-9]'
 
     t_NUMBER = r'-?\d+'
     t_HEXNUM = r'0x%s+' % hexchar
     t_LSHIFT = r'<<'
-    t_RSHIFT=  r'>>'
+    t_RSHIFT = r'>>'
 
     literals = '"(){}[],;:=|+-*'
 
     t_ignore = ' \t'
 
     def t_multilinecomment(self, t):
         r'/\*(?s).*?\*/'
         t.lexer.lineno += t.value.count('\n')