Merge inbound to mozilla-central. a=merge
authorAndreea Pavel <apavel@mozilla.com>
Fri, 26 Jan 2018 19:48:13 +0200
changeset 455965 8275c46e2880469ebb154f6b0c49bb1a97630757
parent 455959 831d2c0e7bf95bba7f8a2ae4c3a85cf05e565e5b (current diff)
parent 455964 933304b9909eaae1eb75a43dd8ea00babcc82ebe (diff)
child 455966 149128f5d22647741a5a191da141578d7f561d5d
child 455976 046b8dbedde98697d0d2bb29f760b3116ffe85ee
child 456053 1ee8edcdd50daaec5fd6c61dd1fd5c2548c5043f
push id1683
push usersfraser@mozilla.com
push dateThu, 26 Apr 2018 16:43:40 +0000
treeherdermozilla-release@5af6cb21869d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
mobile/android/base/moz.build
--- a/editor/libeditor/HTMLEditor.h
+++ b/editor/libeditor/HTMLEditor.h
@@ -467,17 +467,17 @@ public:
    */
   nsresult OnMouseMove(nsIDOMMouseEvent* aMouseEvent);
 
   /**
    * Modifies the table containing the selection according to the
    * activation of an inline table editing UI element
    * @param aUIAnonymousElement [IN] the inline table editing UI element
    */
-  nsresult DoInlineTableEditingAction(Element& aUIAnonymousElement);
+  nsresult DoInlineTableEditingAction(const Element& aUIAnonymousElement);
 
 protected:
   class BlobReader final : public nsIEditorBlobListener
   {
   public:
     BlobReader(dom::BlobImpl* aBlob, HTMLEditor* aHTMLEditor,
                bool aIsSafe, nsIDOMDocument* aSourceDoc,
                nsIDOMNode* aDestinationNode, int32_t aDestOffset,
--- a/editor/libeditor/HTMLInlineTableEditor.cpp
+++ b/editor/libeditor/HTMLInlineTableEditor.cpp
@@ -118,17 +118,17 @@ HTMLEditor::HideInlineTableEditingUI()
   DeleteRefToAnonymousNode(Move(mAddRowBeforeButton), ps);
   DeleteRefToAnonymousNode(Move(mRemoveRowButton), ps);
   DeleteRefToAnonymousNode(Move(mAddRowAfterButton), ps);
 
   return NS_OK;
 }
 
 nsresult
-HTMLEditor::DoInlineTableEditingAction(Element& aElement)
+HTMLEditor::DoInlineTableEditingAction(const Element& aElement)
 {
   nsAutoString anonclass;
   aElement.GetAttr(kNameSpaceID_None, nsGkAtoms::_moz_anonclass, anonclass);
 
   if (!StringBeginsWith(anonclass, NS_LITERAL_STRING("mozTable"))) {
     return NS_OK;
   }
 
--- a/mobile/android/base/java/org/mozilla/gecko/CrashReporter.java
+++ b/mobile/android/base/java/org/mozilla/gecko/CrashReporter.java
@@ -1,15 +1,16 @@
 /* -*- Mode: Java; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Map;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.FileWriter;
@@ -22,16 +23,21 @@ import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLDecoder;
 import java.nio.channels.Channels;
 import java.nio.channels.FileChannel;
 import java.security.MessageDigest;
 import java.util.zip.GZIPOutputStream;
 
 import org.mozilla.gecko.AppConstants.Versions;
+import org.mozilla.gecko.GeckoProfile;
+import org.mozilla.gecko.telemetry.pingbuilders.TelemetryCrashPingBuilder;
+import org.mozilla.gecko.telemetry.TelemetryDispatcher;
+import org.mozilla.gecko.util.INIParser;
+import org.mozilla.gecko.util.INISection;
 import org.mozilla.gecko.util.ProxySelector;
 
 import android.annotation.SuppressLint;
 import android.app.AlertDialog;
 import android.app.ProgressDialog;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -116,16 +122,17 @@ public class CrashReporter extends AppCo
             }
         } catch (Exception e) {
             Log.e(LOGTAG, "exception while closing progress dialog: ", e);
         }
         super.finish();
     }
 
     @Override
+    @SuppressLint("WrongThread") // We don't have a worker thread for the TelemetryDispatcher
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         // mHandler is created here so runnables can be run on the main thread
         mHandler = new Handler();
         setContentView(R.layout.crash_reporter);
         mProgressDialog = new ProgressDialog(this);
         mProgressDialog.setMessage(getString(R.string.sending_crash_report));
 
@@ -143,16 +150,40 @@ public class CrashReporter extends AppCo
         File extrasFile = new File(passedMinidumpPath.replaceAll("\\.dmp", ".extra"));
         mPendingExtrasFile = new File(pendingDir, extrasFile.getName());
         moveFile(extrasFile, mPendingExtrasFile);
 
         computeMinidumpHash(mPendingExtrasFile, mPendingMinidumpFile);
         mExtrasStringMap = new HashMap<String, String>();
         readStringsFromFile(mPendingExtrasFile.getPath(), mExtrasStringMap);
 
+        try {
+            // Find the profile name and path. Since we don't have any other way of getting it within
+            // this context we extract it from the crash dump path.
+            final File profileDir = passedMinidumpFile.getParentFile().getParentFile();
+            final String profileName = getProfileName(profileDir);
+
+            if (profileName != null) {
+                // Extract the crash dump ID and telemetry client ID, we need profile access for the latter.
+                final String passedMinidumpName = passedMinidumpFile.getName();
+                // Strip the .dmp suffix from the minidump name to obtain the crash ID.
+                final String crashId = passedMinidumpName.substring(0, passedMinidumpName.length() - 4);
+                final GeckoProfile profile = GeckoProfile.get(this, profileName, profileDir);
+                final String clientId = profile.getClientId();
+
+                // Assemble and send the crash ping
+                final TelemetryCrashPingBuilder pingBuilder =
+                    new TelemetryCrashPingBuilder(crashId, clientId, mExtrasStringMap);
+                final TelemetryDispatcher dispatcher = new TelemetryDispatcher(profileDir.getPath(), profileName);
+                dispatcher.queuePingForUpload(this, pingBuilder);
+            }
+        } catch (GeckoProfileDirectories.NoMozillaDirectoryException | IOException e) {
+            Log.e(LOGTAG, "Cannot send the crash ping: ", e);
+        }
+
         // Notify GeckoApp that we've crashed, so it can react appropriately during the next start.
         try {
             File crashFlag = new File(GeckoProfileDirectories.getMozillaDirectory(this), "CRASHED");
             crashFlag.createNewFile();
         } catch (GeckoProfileDirectories.NoMozillaDirectoryException | IOException e) {
             Log.e(LOGTAG, "Cannot set crash flag: ", e);
         }
 
@@ -269,16 +300,39 @@ public class CrashReporter extends AppCo
         backgroundSendReport();
     }
 
     public void onRestartClick(View v) {  // bound via crash_reporter.xml
         doRestart();
         backgroundSendReport();
     }
 
+    private String getProfileName(File profileDir) throws GeckoProfileDirectories.NoMozillaDirectoryException {
+        final File mozillaDir = GeckoProfileDirectories.getMozillaDirectory(this);
+        final INIParser parser = GeckoProfileDirectories.getProfilesINI(mozillaDir);
+        String profileName = null;
+
+        if (parser.getSections() != null) {
+            for (Enumeration<INISection> e = parser.getSections().elements(); e.hasMoreElements(); ) {
+                final INISection section = e.nextElement();
+                final String path = section.getStringProperty("Path");
+                final boolean isRelative = (section.getIntProperty("IsRelative") == 1);
+
+                if ((isRelative && path.equals(profileDir.getName())) ||
+                    path.equals(profileDir.getPath())) {
+                    profileName = section.getStringProperty("Name");
+                    break;
+                }
+            }
+        }
+
+        return profileName;
+    }
+
+
     private void computeMinidumpHash(File extraFile, File minidump) {
         try {
             FileInputStream stream = new FileInputStream(minidump);
             MessageDigest md = MessageDigest.getInstance("SHA-256");
 
             try {
                 byte[] buffer = new byte[4096];
                 int readBytes;
--- a/mobile/android/base/java/org/mozilla/gecko/telemetry/TelemetryDispatcher.java
+++ b/mobile/android/base/java/org/mozilla/gecko/telemetry/TelemetryDispatcher.java
@@ -5,16 +5,17 @@
  */
 
 package org.mozilla.gecko.telemetry;
 
 import android.content.Context;
 import android.support.annotation.WorkerThread;
 import android.util.Log;
 import org.mozilla.gecko.telemetry.pingbuilders.TelemetryCorePingBuilder;
+import org.mozilla.gecko.telemetry.pingbuilders.TelemetryCrashPingBuilder;
 import org.mozilla.gecko.telemetry.schedulers.TelemetryUploadScheduler;
 import org.mozilla.gecko.telemetry.schedulers.TelemetryUploadAllPingsImmediatelyScheduler;
 import org.mozilla.gecko.telemetry.stores.TelemetryJSONFilePingStore;
 import org.mozilla.gecko.telemetry.stores.TelemetryPingStore;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import java.io.File;
 import java.io.IOException;
@@ -50,29 +51,32 @@ import java.io.IOException;
  *   6) In Fennec, where you want to store a ping and attempt upload, create a PingBuilder and
  * pass it to the new queuePingForUpload method.
  */
 public class TelemetryDispatcher {
     private static final String LOGTAG = "Gecko" + TelemetryDispatcher.class.getSimpleName();
 
     private static final String STORE_CONTAINER_DIR_NAME = "telemetry_java";
     private static final String CORE_STORE_DIR_NAME = "core";
+    private static final String CRASH_STORE_DIR_NAME = "crash";
 
     private final TelemetryJSONFilePingStore coreStore;
+    private final TelemetryJSONFilePingStore crashStore;
 
     private final TelemetryUploadAllPingsImmediatelyScheduler uploadAllPingsImmediatelyScheduler;
 
     @WorkerThread // via TelemetryJSONFilePingStore
     public TelemetryDispatcher(final String profilePath, final String profileName) {
         final String storePath = profilePath + File.separator + STORE_CONTAINER_DIR_NAME;
 
         // There are measurements in the core ping (e.g. seq #) that would ideally be atomically updated
         // when the ping is stored. However, for simplicity, we use the json store and accept the possible
         // loss of data (see bug 1243585 comment 16+ for more).
         coreStore = new TelemetryJSONFilePingStore(new File(storePath, CORE_STORE_DIR_NAME), profileName);
+        crashStore = new TelemetryJSONFilePingStore(new File(storePath, CRASH_STORE_DIR_NAME), profileName);
 
         uploadAllPingsImmediatelyScheduler = new TelemetryUploadAllPingsImmediatelyScheduler();
     }
 
     private void queuePingForUpload(final Context context, final TelemetryOutgoingPing ping, final TelemetryPingStore store,
                                     final TelemetryUploadScheduler scheduler) {
         final QueuePingRunnable runnable = new QueuePingRunnable(context, ping, store, scheduler);
         ThreadUtils.postToBackgroundThread(runnable); // TODO: Investigate how busy this thread is. See if we want another.
@@ -81,16 +85,24 @@ public class TelemetryDispatcher {
     /**
      * Queues the given ping for upload and potentially schedules upload. This method can be called from any thread.
      */
     public void queuePingForUpload(final Context context, final TelemetryCorePingBuilder pingBuilder) {
         final TelemetryOutgoingPing ping = pingBuilder.build();
         queuePingForUpload(context, ping, coreStore, uploadAllPingsImmediatelyScheduler);
     }
 
+    /**
+     * Queues the given crash ping for upload and potentially schedules upload. This method can be called from any thread.
+     */
+    public void queuePingForUpload(final Context context, final TelemetryCrashPingBuilder pingBuilder) {
+        final TelemetryOutgoingPing ping = pingBuilder.build();
+        queuePingForUpload(context, ping, crashStore, uploadAllPingsImmediatelyScheduler);
+    }
+
     /* package-private */ static class QueuePingRunnable implements Runnable {
         private final Context applicationContext;
         private final TelemetryOutgoingPing ping;
         private final TelemetryPingStore store;
         private final TelemetryUploadScheduler scheduler;
 
         /* package-private */ QueuePingRunnable(final Context context, final TelemetryOutgoingPing ping, final TelemetryPingStore store,
                                                 final TelemetryUploadScheduler scheduler) {
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCrashPingBuilder.java
@@ -0,0 +1,224 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+package org.mozilla.gecko.telemetry.pingbuilders;
+
+import android.util.Log;
+
+import org.mozilla.gecko.sync.ExtendedJSONObject;
+import org.mozilla.gecko.sync.NonObjectJSONException;
+import org.mozilla.gecko.util.StringUtils;
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map.Entry;
+import java.util.TimeZone;
+
+/**
+ * Builds a {@link TelemetryOutgoingPing} representing a crash ping.
+ *
+ * See https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/telemetry/data/crash-ping.html
+ * for details on the crash ping.
+ */
+public class TelemetryCrashPingBuilder extends TelemetryPingBuilder {
+    private static final String LOGTAG = "GeckoTelemetryCrashPingBuilder";
+
+    private static final int PING_VERSION = 1;
+
+    private static final String ISO8601_DATE = "yyyy-MM-dd";
+    private static final String ISO8601_DATE_HOURS = "yyyy-MM-dd'T'HH':00:00.000Z'";
+
+    // The following list should be kept in sync with the one in CrashManager.jsm
+    private static final String[] ANNOTATION_WHITELIST = {
+        "AsyncShutdownTimeout",
+        "AvailablePageFile",
+        "AvailablePhysicalMemory",
+        "AvailableVirtualMemory",
+        "BlockedDllList",
+        "BlocklistInitFailed",
+        "BuildID",
+        "ContainsMemoryReport",
+        "CrashTime",
+        "EventLoopNestingLevel",
+        "ipc_channel_error",
+        "IsGarbageCollecting",
+        "MozCrashReason",
+        "OOMAllocationSize",
+        "ProductID",
+        "ProductName",
+        "ReleaseChannel",
+        "RemoteType",
+        "SecondsSinceLastCrash",
+        "ShutdownProgress",
+        "StartupCrash",
+        "SystemMemoryUsePercentage",
+        "TextureUsage",
+        "TotalPageFile",
+        "TotalPhysicalMemory",
+        "TotalVirtualMemory",
+        "UptimeTS",
+        "User32BeforeBlocklist",
+        "Version",
+    };
+
+    public TelemetryCrashPingBuilder(String crashId, String clientId, HashMap<String, String> annotations) {
+        super(TelemetryPingBuilder.UNIFIED_TELEMETRY_VERSION);
+
+        payload.put("type", "crash");
+        payload.put("id", docID);
+        payload.put("version", TelemetryPingBuilder.UNIFIED_TELEMETRY_VERSION);
+        payload.put("creationDate", currentDate(ISO8601_DATE_HOURS));
+        payload.put("clientId", clientId);
+
+        // Parse the telemetry environment and extract relevant fields from it
+        ExtendedJSONObject env = null;
+        String architecture = null;
+        String xpcomAbi = null;
+
+        try {
+            env = new ExtendedJSONObject(annotations.get("TelemetryEnvironment"));
+            final ExtendedJSONObject build = env.getObject("build");
+
+            if (build != null) {
+                architecture = build.getString("architecture");
+                xpcomAbi = build.getString("xpcomAbi");
+            }
+        } catch (NonObjectJSONException | IOException e) {
+            Log.w(LOGTAG, "Couldn't parse the telemetry environment, the ping will be incomplete");
+        }
+
+        if (env != null) {
+            payload.put("environment", env);
+        }
+
+        payload.put("payload", createPayloadNode(crashId, annotations));
+        payload.put("application", createApplicationNode(annotations, architecture, xpcomAbi));
+    }
+
+    /**
+     * Return the current date as a string in the specified format.
+     *
+     * @param format The date format, the following constants are provided:
+     * ISO8601_DATE - the ISO 8601 date format, YYYY-MM-DD
+     * ISO8601_DATE_HOURS - the ISO 8601 full date format, YYYY-MM-DDTHH:00:00.000Z
+     * @returns The formatted date as a string
+     */
+    private static String currentDate(String format) {
+        TimeZone tz = TimeZone.getTimeZone("UTC");
+        DateFormat df = new SimpleDateFormat(format);
+        df.setTimeZone(tz);
+
+        return df.format(new Date());
+    }
+
+    /**
+     * Creates the ping's "payload" node which contains most of the information
+     * about the crash and the "metadata" sub-node holding various annotations.
+     *
+     * @param crashId The UUID identifying the crash
+     * @param annotations A map holding the crash annotations
+     * @returns A JSON object representing the ping's payload node
+     */
+    private static ExtendedJSONObject createPayloadNode(String crashId, HashMap<String, String> annotations) {
+        ExtendedJSONObject node = new ExtendedJSONObject();
+
+        node.put("sessionId", annotations.get("TelemetrySessionId"));
+        node.put("version", PING_VERSION);
+        node.put("crashDate", currentDate(ISO8601_DATE));
+        node.put("crashTime", currentDate(ISO8601_DATE_HOURS));
+        node.put("hasCrashEnvironment", true);
+        node.put("crashId", crashId);
+        node.put("minidumpSha256Hash", annotations.get("MinidumpSha256Hash"));
+        node.put("processType", "main");
+
+        try {
+            final ExtendedJSONObject stackTraces = new ExtendedJSONObject(annotations.get("StackTraces"));
+            node.put("stackTraces", stackTraces);
+        } catch (NonObjectJSONException | IOException e) {
+            Log.w(LOGTAG, "Couldn't parse the stack traces, the ping will be incomplete");
+        }
+
+        // Assemble the payload metadata
+        node.put("metadata", createMetadataNode(annotations));
+
+        return node;
+    }
+
+    /**
+     * Creates the ping's "metadata" node which is nested under the "payload" one. This node
+     * contains all the non-PII annotations found in the crash dump.
+     *
+     * @param annotations A map holding the crash annotations
+     * @returns A JSON object representing the ping's metadata node
+     */
+    private static ExtendedJSONObject createMetadataNode(HashMap<String, String> annotations) {
+        ExtendedJSONObject node = new ExtendedJSONObject();
+
+        for (Entry<String, String> pair : annotations.entrySet()) {
+            if (Arrays.binarySearch(ANNOTATION_WHITELIST, pair.getKey()) >= 0) {
+                node.put(pair.getKey(), pair.getValue());
+            }
+        }
+
+        return node;
+    }
+
+    /**
+     * Creates the ping's "application" node. This contains version and build information about the
+     * crashed application.
+     *
+     * @param annotations A map holding the crash annotations
+     * @param architecture The platform architecture
+     * @param xpcomAbi The XPCOM ABI version
+     * @returns A JSON object representing the ping's application node
+     */
+    private static ExtendedJSONObject createApplicationNode(HashMap<String, String> annotations,
+                                                            String architecture, String xpcomAbi) {
+        ExtendedJSONObject node = new ExtendedJSONObject();
+        final String version = annotations.get("Version");
+
+        node.put("vendor", annotations.get("Vendor"));
+        node.put("name", annotations.get("ProductName"));
+        node.put("buildId", annotations.get("BuildID"));
+        node.put("displayVersion", version);
+        node.put("platformVersion", version);
+        node.put("version", version);
+        node.put("channel", annotations.get("ReleaseChannel"));
+
+        if (architecture != null) {
+            node.put("architecture", architecture);
+        }
+
+        if (xpcomAbi != null) {
+            node.put("xpcomAbi", xpcomAbi);
+        }
+
+        return node;
+    }
+
+    @Override
+    public String getDocType() {
+        return "crash";
+    }
+
+    @Override
+    public String[] getMandatoryFields() {
+        return new String[] {
+            "application",
+            "clientId",
+            "creationDate",
+            "environment",
+            "id",
+            "payload",
+            "type",
+            "version",
+        };
+    }
+}
--- a/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryPingBuilder.java
+++ b/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryPingBuilder.java
@@ -20,23 +20,33 @@ import java.util.UUID;
  * This base class handles the common ping operations under the hood:
  *   * Validating mandatory fields
  *   * Forming the server url
  */
 abstract class TelemetryPingBuilder {
     // In the server url, the initial path directly after the "scheme://host:port/"
     private static final String SERVER_INITIAL_PATH = "submit/telemetry";
 
+    // By default Fennec ping's use the old telemetry version, this can be overridden
+    private static final int DEFAULT_TELEMETRY_VERSION = 1;
+
+    // Unified telemetry is version 4
+    public static final int UNIFIED_TELEMETRY_VERSION = 4;
+
     private final String serverPath;
     protected final ExtendedJSONObject payload;
     protected final String docID;
 
     public TelemetryPingBuilder() {
+        this(DEFAULT_TELEMETRY_VERSION);
+    }
+
+    public TelemetryPingBuilder(int version) {
         docID = UUID.randomUUID().toString();
-        serverPath = getTelemetryServerPath(getDocType(), docID);
+        serverPath = getTelemetryServerPath(getDocType(), docID, version);
         payload = new ExtendedJSONObject();
     }
 
     /**
      * @return the name of the ping (e.g. "core")
      */
     public abstract String getDocType();
 
@@ -61,27 +71,30 @@ abstract class TelemetryPingBuilder {
         }
     }
 
     /**
      * Returns a url of the format:
      *   http://hostname/submit/telemetry/docId/docType/appName/appVersion/appUpdateChannel/appBuildID
      *
      * @param docType The name of the ping (e.g. "main")
+     * @param docID A UUID that identifies the ping
+     * @param version The ping format version
      * @return a url at which to POST the telemetry data to
      */
-    private static String getTelemetryServerPath(final String docType, final String docID) {
+    private static String getTelemetryServerPath(final String docType, final String docID, int version) {
         final String appName = AppConstants.MOZ_APP_BASENAME;
         final String appVersion = AppConstants.MOZ_APP_VERSION;
         final String appUpdateChannel = AppConstants.MOZ_UPDATE_CHANNEL;
         final String appBuildId = AppConstants.MOZ_APP_BUILDID;
 
         // The compiler will optimize a single String concatenation into a StringBuilder statement.
         // If you change this `return`, be sure to keep it as a single statement to keep it optimized!
         return SERVER_INITIAL_PATH + '/' +
                 docID + '/' +
                 docType + '/' +
                 appName + '/' +
                 appVersion + '/' +
                 appUpdateChannel + '/' +
-                appBuildId;
+                appBuildId +
+                (version == UNIFIED_TELEMETRY_VERSION ? "?v=4" : "");
     }
 }
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -872,16 +872,17 @@ gbjar.sources += ['java/org/mozilla/geck
     'tabs/TabsPanel.java',
     'tabs/TabsPanelThumbnailView.java',
     'tabs/TabsTouchHelperCallback.java',
     'Telemetry.java',
     'telemetry/measurements/CampaignIdMeasurements.java',
     'telemetry/measurements/SearchCountMeasurements.java',
     'telemetry/measurements/SessionMeasurements.java',
     'telemetry/pingbuilders/TelemetryCorePingBuilder.java',
+    'telemetry/pingbuilders/TelemetryCrashPingBuilder.java',
     'telemetry/pingbuilders/TelemetryLocalPingBuilder.java',
     'telemetry/pingbuilders/TelemetryPingBuilder.java',
     'telemetry/pingbuilders/TelemetrySyncEventPingBuilder.java',
     'telemetry/pingbuilders/TelemetrySyncPingBuilder.java',
     'telemetry/pingbuilders/TelemetrySyncPingBundleBuilder.java',
     'telemetry/schedulers/TelemetryUploadAllPingsImmediatelyScheduler.java',
     'telemetry/schedulers/TelemetryUploadScheduler.java',
     'telemetry/stores/TelemetryJSONFilePingStore.java',
--- a/old-configure.in
+++ b/old-configure.in
@@ -4080,132 +4080,108 @@ dnl ====================================
 AC_SUBST(MOZ_LINUX_32_SSE2_STARTUP_ERROR)
 
 dnl ========================================================
 dnl Check for pixman and cairo
 dnl ========================================================
 
 MOZ_TREE_CAIRO=1
 MOZ_ARG_ENABLE_BOOL(system-cairo,
-[  --enable-system-cairo   Use system cairo (located with pkgconfig)],
-MOZ_TREE_CAIRO=,
+[ --enable-system-cairo  Obsolete: do not use this option],
+AC_MSG_ERROR(--enable-system-cairo is not supported),
 MOZ_TREE_CAIRO=1 )
 
 MOZ_TREE_PIXMAN=1
 MOZ_ARG_ENABLE_BOOL(system-pixman,
 [ --enable-system-pixman Use system pixman (located with pkgconfig)],
 MOZ_TREE_PIXMAN=,
 MOZ_TREE_PIXMAN=force,
 MOZ_TREE_PIXMAN=1 )
 
-# System cairo depends on system pixman
-if test "$MOZ_TREE_PIXMAN" = "force"; then
-    if test -z "$MOZ_TREE_CAIRO"; then
-        AC_MSG_ERROR([--disable-system-pixman is incompatible with --enable-system-cairo.])
-    else
-        MOZ_TREE_PIXMAN=1
-    fi
-elif test -z "$MOZ_TREE_CAIRO"; then
-    MOZ_TREE_PIXMAN=
-fi
-
 if test "$MOZ_TREE_PIXMAN"; then
     AC_DEFINE(MOZ_TREE_PIXMAN)
 else
     PKG_CHECK_MODULES(MOZ_PIXMAN, pixman-1 >= 0.19.2)
 fi
 
-if test "$MOZ_TREE_CAIRO"; then
-    MOZ_CAIRO_CFLAGS="-I${DIST}/include/cairo"
-    AC_DEFINE(MOZ_TREE_CAIRO)
-
-    if test "$OS_ARCH" = "WINNT"; then
-        # For now we assume that we will have a uint64_t available through
-        # one of the above headers or mozstdint.h.
-        AC_DEFINE(HAVE_UINT64_T)
-    fi
-
-    # Define macros for cairo-features.h
-    TEE_SURFACE_FEATURE="#define CAIRO_HAS_TEE_SURFACE 1"
-    if test "$MOZ_X11"; then
-        XLIB_SURFACE_FEATURE="#define CAIRO_HAS_XLIB_SURFACE 1"
-        XLIB_XRENDER_SURFACE_FEATURE="#define CAIRO_HAS_XLIB_XRENDER_SURFACE 1"
-        PS_SURFACE_FEATURE="#define CAIRO_HAS_PS_SURFACE 1"
-    fi
-    if test "$_HAVE_FREETYPE2"; then
-        FT_FONT_FEATURE="#define CAIRO_HAS_FT_FONT 1"
-        MOZ_ENABLE_CAIRO_FT=1
-        CAIRO_FT_CFLAGS="$FT2_CFLAGS"
+MOZ_CAIRO_CFLAGS="-I${DIST}/include/cairo"
+AC_DEFINE(MOZ_TREE_CAIRO)
+
+if test "$OS_ARCH" = "WINNT"; then
+    # For now we assume that we will have a uint64_t available through
+    # one of the above headers or mozstdint.h.
+    AC_DEFINE(HAVE_UINT64_T)
+fi
+
+# Define macros for cairo-features.h
+TEE_SURFACE_FEATURE="#define CAIRO_HAS_TEE_SURFACE 1"
+if test "$MOZ_X11"; then
+    XLIB_SURFACE_FEATURE="#define CAIRO_HAS_XLIB_SURFACE 1"
+    XLIB_XRENDER_SURFACE_FEATURE="#define CAIRO_HAS_XLIB_XRENDER_SURFACE 1"
+    PS_SURFACE_FEATURE="#define CAIRO_HAS_PS_SURFACE 1"
+fi
+if test "$_HAVE_FREETYPE2"; then
+    FT_FONT_FEATURE="#define CAIRO_HAS_FT_FONT 1"
+    MOZ_ENABLE_CAIRO_FT=1
+    CAIRO_FT_CFLAGS="$FT2_CFLAGS"
+fi
+
+case "$MOZ_WIDGET_TOOLKIT" in
+  cocoa | uikit)
+    QUARTZ_SURFACE_FEATURE="#define CAIRO_HAS_QUARTZ_SURFACE 1"
+    QUARTZ_IMAGE_SURFACE_FEATURE="#define CAIRO_HAS_QUARTZ_IMAGE_SURFACE 1"
+    QUARTZ_FONT_FEATURE="#define CAIRO_HAS_QUARTZ_FONT 1"
+    ;;
+  windows)
+    WIN32_D2D_SURFACE_FEATURE="#define CAIRO_HAS_D2D_SURFACE 1"
+    WIN32_DWRITE_FONT_FEATURE="#define CAIRO_HAS_DWRITE_FONT 1"
+    WIN32_FONT_FEATURE="#define CAIRO_HAS_WIN32_FONT 1"
+    WIN32_SURFACE_FEATURE="#define CAIRO_HAS_WIN32_SURFACE 1"
+    MOZ_ENABLE_D2D_SURFACE=1
+
+    if test "$COMPILE_ENVIRONMENT"; then
+
+      dnl D3D10 Layers depend on D2D Surfaces.
+      if test -n "$WIN32_D2D_SURFACE_FEATURE"; then
+        MOZ_CHECK_HEADER(d3d10.h, MOZ_ENABLE_D3D10_LAYER=1)
+      fi
     fi
-
-    case "$MOZ_WIDGET_TOOLKIT" in
-      cocoa | uikit)
-        QUARTZ_SURFACE_FEATURE="#define CAIRO_HAS_QUARTZ_SURFACE 1"
-        QUARTZ_IMAGE_SURFACE_FEATURE="#define CAIRO_HAS_QUARTZ_IMAGE_SURFACE 1"
-        QUARTZ_FONT_FEATURE="#define CAIRO_HAS_QUARTZ_FONT 1"
-        ;;
-      windows)
-        WIN32_D2D_SURFACE_FEATURE="#define CAIRO_HAS_D2D_SURFACE 1"
-        WIN32_DWRITE_FONT_FEATURE="#define CAIRO_HAS_DWRITE_FONT 1"
-        WIN32_FONT_FEATURE="#define CAIRO_HAS_WIN32_FONT 1"
-        WIN32_SURFACE_FEATURE="#define CAIRO_HAS_WIN32_SURFACE 1"
-        MOZ_ENABLE_D2D_SURFACE=1
-
-        if test "$COMPILE_ENVIRONMENT"; then
-
-          dnl D3D10 Layers depend on D2D Surfaces.
-          if test -n "$WIN32_D2D_SURFACE_FEATURE"; then
-            MOZ_CHECK_HEADER(d3d10.h, MOZ_ENABLE_D3D10_LAYER=1)
-          fi
-        fi
-        ;;
-    esac
-    if test "$USE_FC_FREETYPE"; then
-        FC_FONT_FEATURE="#define CAIRO_HAS_FC_FONT 1"
-    fi
-    AC_SUBST(MOZ_ENABLE_CAIRO_FT)
-    AC_SUBST(MOZ_ENABLE_D2D_SURFACE)
-    AC_SUBST(MOZ_ENABLE_D3D10_LAYER)
-
-    AC_SUBST(PS_SURFACE_FEATURE)
-    AC_SUBST(SVG_SURFACE_FEATURE)
-    AC_SUBST(XLIB_SURFACE_FEATURE)
-    AC_SUBST(XLIB_XRENDER_SURFACE_FEATURE)
-    AC_SUBST(QUARTZ_SURFACE_FEATURE)
-    AC_SUBST(QUARTZ_IMAGE_SURFACE_FEATURE)
-    AC_SUBST(WIN32_SURFACE_FEATURE)
-    AC_SUBST(OS2_SURFACE_FEATURE)
-    AC_SUBST(DIRECTFB_SURFACE_FEATURE)
-    AC_SUBST(FT_FONT_FEATURE)
-    AC_SUBST(FC_FONT_FEATURE)
-    AC_SUBST(WIN32_FONT_FEATURE)
-    AC_SUBST(WIN32_DWRITE_FONT_FEATURE)
-    AC_SUBST(WIN32_D2D_SURFACE_FEATURE)
-    AC_SUBST(QUARTZ_FONT_FEATURE)
-    AC_SUBST(PNG_FUNCTIONS_FEATURE)
-    AC_SUBST(QT_SURFACE_FEATURE)
-    AC_SUBST(TEE_SURFACE_FEATURE)
-
-    if test "$MOZ_X11"; then
-        MOZ_CAIRO_OSLIBS="$MOZ_CAIRO_OSLIBS $XLDFLAGS -lXrender"
-    fi
-
-    CAIRO_FEATURES_H=gfx/cairo/cairo/src/cairo-features.h
-else
-    PKG_CHECK_MODULES(CAIRO, cairo >= $CAIRO_VERSION)
-    MOZ_CAIRO_CFLAGS="$CAIRO_CFLAGS"
-    MOZ_CAIRO_LIBS="$CAIRO_LIBS"
-    PKG_CHECK_MODULES(CAIRO_TEE, cairo-tee >= $CAIRO_VERSION)
-    if test "$MOZ_X11"; then
-        PKG_CHECK_MODULES(CAIRO_XRENDER, cairo-xlib-xrender >= $CAIRO_VERSION)
-        MOZ_CAIRO_LIBS="$MOZ_CAIRO_LIBS $XLDFLAGS $CAIRO_XRENDER_LIBS"
-        MOZ_CAIRO_OSLIBS="$MOZ_CAIRO_LIBS"
-        MOZ_CAIRO_CFLAGS="$MOZ_CAIRO_CFLAGS $CAIRO_XRENDER_CFLAGS"
-    fi
+    ;;
+esac
+if test "$USE_FC_FREETYPE"; then
+    FC_FONT_FEATURE="#define CAIRO_HAS_FC_FONT 1"
 fi
+AC_SUBST(MOZ_ENABLE_CAIRO_FT)
+AC_SUBST(MOZ_ENABLE_D2D_SURFACE)
+AC_SUBST(MOZ_ENABLE_D3D10_LAYER)
+
+AC_SUBST(PS_SURFACE_FEATURE)
+AC_SUBST(SVG_SURFACE_FEATURE)
+AC_SUBST(XLIB_SURFACE_FEATURE)
+AC_SUBST(XLIB_XRENDER_SURFACE_FEATURE)
+AC_SUBST(QUARTZ_SURFACE_FEATURE)
+AC_SUBST(QUARTZ_IMAGE_SURFACE_FEATURE)
+AC_SUBST(WIN32_SURFACE_FEATURE)
+AC_SUBST(OS2_SURFACE_FEATURE)
+AC_SUBST(DIRECTFB_SURFACE_FEATURE)
+AC_SUBST(FT_FONT_FEATURE)
+AC_SUBST(FC_FONT_FEATURE)
+AC_SUBST(WIN32_FONT_FEATURE)
+AC_SUBST(WIN32_DWRITE_FONT_FEATURE)
+AC_SUBST(WIN32_D2D_SURFACE_FEATURE)
+AC_SUBST(QUARTZ_FONT_FEATURE)
+AC_SUBST(PNG_FUNCTIONS_FEATURE)
+AC_SUBST(QT_SURFACE_FEATURE)
+AC_SUBST(TEE_SURFACE_FEATURE)
+
+if test "$MOZ_X11"; then
+    MOZ_CAIRO_OSLIBS="$MOZ_CAIRO_OSLIBS $XLDFLAGS -lXrender"
+fi
+
+CAIRO_FEATURES_H=gfx/cairo/cairo/src/cairo-features.h
 
 case "$MOZ_WIDGET_TOOLKIT" in
 android)
     TK_CFLAGS="$MOZ_CAIRO_CFLAGS $MOZ_PIXMAN_CFLAGS"
     TK_LIBS="$MOZ_CAIRO_LIBS $MOZ_PIXMAN_LIBS"
     ;;
 esac
 
--- a/uriloader/exthandler/win/nsOSHelperAppService.cpp
+++ b/uriloader/exthandler/win/nsOSHelperAppService.cpp
@@ -23,18 +23,16 @@
 
 // shellapi.h is needed to build with WIN32_LEAN_AND_MEAN
 #include <shellapi.h>
 #include <shlwapi.h>
 
 #define LOG(args) MOZ_LOG(mLog, mozilla::LogLevel::Debug, args)
 
 // helper methods: forward declarations...
-static nsresult GetExtensionFrom4xRegistryInfo(const nsACString& aMimeType, 
-                                               nsString& aFileExtension);
 static nsresult GetExtensionFromWindowsMimeDatabase(const nsACString& aMimeType,
                                                     nsString& aFileExtension);
 
 nsOSHelperAppService::nsOSHelperAppService() : 
   nsExternalHelperAppService()
   , mAppAssoc(nullptr)
 {
   CoInitialize(nullptr);
@@ -71,55 +69,16 @@ static nsresult GetExtensionFromWindowsM
                              nsIWindowsRegKey::ACCESS_QUERY_VALUE);
   
   if (NS_SUCCEEDED(rv))
      regKey->ReadStringValue(NS_LITERAL_STRING("Extension"), aFileExtension);
 
   return NS_OK;
 }
 
-// We have a serious problem!! I have this content type and the windows registry only gives me
-// helper apps based on extension. Right now, we really don't have a good place to go for 
-// trying to figure out the extension for a particular mime type....One short term hack is to look
-// this information in 4.x (it's stored in the windows regsitry). 
-static nsresult GetExtensionFrom4xRegistryInfo(const nsACString& aMimeType,
-                                               nsString& aFileExtension)
-{
-  nsCOMPtr<nsIWindowsRegKey> regKey = 
-    do_CreateInstance("@mozilla.org/windows-registry-key;1");
-  if (!regKey) 
-    return NS_ERROR_NOT_AVAILABLE;
-
-  nsresult rv = regKey->
-    Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
-         NS_LITERAL_STRING("Software\\Netscape\\Netscape Navigator\\Suffixes"),
-         nsIWindowsRegKey::ACCESS_QUERY_VALUE);
-  if (NS_FAILED(rv))
-    return NS_ERROR_NOT_AVAILABLE;
-   
-  rv = regKey->ReadStringValue(NS_ConvertASCIItoUTF16(aMimeType),
-                               aFileExtension);
-  if (NS_FAILED(rv))
-    return NS_OK;
-
-  aFileExtension.Insert(char16_t('.'), 0);
-      
-  // this may be a comma separated list of extensions...just take the 
-  // first one for now...
-
-  int32_t pos = aFileExtension.FindChar(char16_t(','));
-  if (pos > 0) {
-    // we have a comma separated list of types...
-    // truncate everything after the first comma (including the comma)
-    aFileExtension.Truncate(pos); 
-  }
-   
-  return NS_OK;
-}
-
 nsresult nsOSHelperAppService::OSProtocolHandlerExists(const char * aProtocolScheme, bool * aHandlerExists)
 {
   // look up the protocol scheme in the windows registry....if we find a match then we have a handler for it...
   *aHandlerExists = false;
   if (aProtocolScheme && *aProtocolScheme)
   {
     // Vista: use new application association interface
     if (mAppAssoc) {
@@ -491,24 +450,19 @@ already_AddRefed<nsIMIMEInfo> nsOSHelper
    * 120327, comment 271 for why this is needed.  Not even sure we
    * want to remove this once we have fixed all this stuff to work
    * right; any info we get from the OS on this type is pretty much
    * useless....
    * We'll do extension-based lookup for this type later in this function.
    */
   if (!aMIMEType.IsEmpty() &&
       !aMIMEType.LowerCaseEqualsLiteral(APPLICATION_OCTET_STREAM)) {
-    // (1) try to use the windows mime database to see if there is a mapping to a file extension
-    // (2) try to see if we have some left over 4.x registry info we can peek at...
+    // try to use the windows mime database to see if there is a mapping to a file extension
     GetExtensionFromWindowsMimeDatabase(aMIMEType, fileExtension);
     LOG(("Windows mime database: extension '%s'\n", fileExtension.get()));
-    if (fileExtension.IsEmpty()) {
-      GetExtensionFrom4xRegistryInfo(aMIMEType, fileExtension);
-      LOG(("4.x Registry: extension '%s'\n", fileExtension.get()));
-    }
   }
   // If we found an extension for the type, do the lookup
   RefPtr<nsMIMEInfoWin> mi;
   if (!fileExtension.IsEmpty())
     mi = GetByExtension(fileExtension, flatType.get());
   LOG(("Extension lookup on '%s' found: 0x%p\n", fileExtension.get(), mi.get()));
 
   bool hasDefault = false;