Bug 1513057 - P2: Setup crash reporter on socket process r=dragana,mayhemer
authorKershaw Chang <kershaw@mozilla.com>
Fri, 11 Jan 2019 18:48:25 +0000
changeset 453537 ba234cd899206aa59916f03d7742893f775a3a99
parent 453536 696250a73120f4f407988ee499c6c5398816cdaa
child 453538 7c4eddc3a80db9c9166d84314bd7a35629868857
push id35360
push usernbeleuzu@mozilla.com
push dateSat, 12 Jan 2019 09:39:47 +0000
treeherdermozilla-central@cb35977ae7a4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdragana, mayhemer
bugs1513057
milestone66.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
Bug 1513057 - P2: Setup crash reporter on socket process r=dragana,mayhemer This patch is quite straightforward. Just add socket process support. Differential Revision: https://phabricator.services.mozilla.com/D14151
netwerk/ipc/PSocketProcess.ipdl
netwerk/ipc/SocketProcessChild.cpp
netwerk/ipc/SocketProcessParent.cpp
netwerk/ipc/SocketProcessParent.h
toolkit/components/crashes/CrashManager.jsm
toolkit/components/crashes/CrashService.js
toolkit/components/crashes/tests/xpcshell/test_crash_manager.js
toolkit/components/crashes/tests/xpcshell/test_crash_store.js
toolkit/components/telemetry/Histograms.json
--- a/netwerk/ipc/PSocketProcess.ipdl
+++ b/netwerk/ipc/PSocketProcess.ipdl
@@ -1,18 +1,23 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
 
 include PrefsTypes;
 
+using mozilla::dom::NativeThreadId from "mozilla/dom/TabMessageUtils.h";
+
 namespace mozilla {
 namespace net {
 
 protocol PSocketProcess
 {
+parent:
+  async InitCrashReporter(Shmem shmem, NativeThreadId threadId);
+
 child:
   async PreferenceUpdate(Pref pref);
 };
 
 } // namespace net
 } // namespace mozilla
--- a/netwerk/ipc/SocketProcessChild.cpp
+++ b/netwerk/ipc/SocketProcessChild.cpp
@@ -3,16 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SocketProcessChild.h"
 #include "SocketProcessLogging.h"
 
 #include "base/task.h"
 #include "mozilla/Assertions.h"
+#include "mozilla/ipc/CrashReporterClient.h"
 #include "mozilla/ipc/ProcessChild.h"
 #include "mozilla/Preferences.h"
 #include "nsDebugImpl.h"
 #include "nsThreadManager.h"
 #include "ProcessUtils.h"
 
 namespace mozilla {
 namespace net {
@@ -45,28 +46,32 @@ bool SocketProcessChild::Init(base::Proc
   // versions.
   MessageChannel* channel = GetIPCChannel();
   if (channel && !channel->SendBuildIDsMatchMessage(aParentBuildID)) {
     // We need to quit this process if the buildID doesn't match the parent's.
     // This can occur when an update occurred in the background.
     ProcessChild::QuickExit();
   }
 
+  // Init crash reporter support.
+  CrashReporterClient::InitSingleton(this);
+
   SetThisProcessName("Socket Process");
   return true;
 }
 
 void SocketProcessChild::ActorDestroy(ActorDestroyReason aWhy) {
   LOG(("SocketProcessChild::ActorDestroy\n"));
 
   if (AbnormalShutdown == aWhy) {
     NS_WARNING("Shutting down Socket process early due to a crash!");
     ProcessChild::QuickExit();
   }
 
+  CrashReporterClient::DestroySingleton();
   XRE_ShutdownChildProcess();
 }
 
 void SocketProcessChild::CleanUp() {
   LOG(("SocketProcessChild::CleanUp\n"));
 
   NS_ShutdownXPCOM(nullptr);
 }
--- a/netwerk/ipc/SocketProcessParent.cpp
+++ b/netwerk/ipc/SocketProcessParent.cpp
@@ -1,32 +1,48 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
 
 #include "SocketProcessParent.h"
+
 #include "SocketProcessHost.h"
-#include "mozilla/Move.h"
+#include "mozilla/ipc/CrashReporterHost.h"
 
 namespace mozilla {
 namespace net {
 
 SocketProcessParent::SocketProcessParent(SocketProcessHost* aHost)
     : mHost(aHost) {
   MOZ_ASSERT(mHost);
 
   MOZ_COUNT_CTOR(SocketProcessParent);
 }
 
 SocketProcessParent::~SocketProcessParent() {
   MOZ_COUNT_DTOR(SocketProcessParent);
 }
 
+mozilla::ipc::IPCResult SocketProcessParent::RecvInitCrashReporter(
+    Shmem&& aShmem, const NativeThreadId& aThreadId) {
+  mCrashReporter = MakeUnique<CrashReporterHost>(GeckoProcessType_Content,
+                                                 aShmem, aThreadId);
+
+  return IPC_OK();
+}
+
 void SocketProcessParent::ActorDestroy(ActorDestroyReason aWhy) {
+  if (aWhy == AbnormalShutdown) {
+    if (mCrashReporter) {
+      mCrashReporter->GenerateCrashReport(OtherPid());
+      mCrashReporter = nullptr;
+    }
+  }
+
   if (mHost) {
     mHost->OnChannelClosed();
   }
 }
 
 // To ensure that IPDL is finished before SocketParent gets deleted.
 class DeferredDeleteSocketProcessParent : public Runnable {
  public:
--- a/netwerk/ipc/SocketProcessParent.h
+++ b/netwerk/ipc/SocketProcessParent.h
@@ -5,33 +5,42 @@
 
 #ifndef mozilla_net_SocketProcessParent_h
 #define mozilla_net_SocketProcessParent_h
 
 #include "mozilla/UniquePtr.h"
 #include "mozilla/net/PSocketProcessParent.h"
 
 namespace mozilla {
+
+namespace ipc {
+class CrashReporterHost;
+}  // namespace ipc
+
 namespace net {
 
 class SocketProcessHost;
 
 // IPC actor of socket process in parent process. This is allocated and managed
 // by SocketProcessHost.
 class SocketProcessParent final : public PSocketProcessParent {
  public:
   friend class SocketProcessHost;
 
   explicit SocketProcessParent(SocketProcessHost* aHost);
   ~SocketProcessParent();
 
+  mozilla::ipc::IPCResult RecvInitCrashReporter(
+      Shmem&& aShmem, const NativeThreadId& aThreadId) override;
+
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
  private:
   SocketProcessHost* mHost;
+  UniquePtr<ipc::CrashReporterHost> mCrashReporter;
 
   static void Destroy(UniquePtr<SocketProcessParent>&& aParent);
 };
 
 }  // namespace net
 }  // namespace mozilla
 
 #endif  // mozilla_net_SocketProcessParent_h
--- a/toolkit/components/crashes/CrashManager.jsm
+++ b/toolkit/components/crashes/CrashManager.jsm
@@ -175,16 +175,19 @@ this.CrashManager.prototype = Object.fre
   PROCESS_TYPE_GMPLUGIN: "gmplugin",
 
   // A crash in the GPU process.
   PROCESS_TYPE_GPU: "gpu",
 
   // A crash in the RDD process.
   PROCESS_TYPE_RDD: "rdd",
 
+  // A crash in the socket process.
+  PROCESS_TYPE_SOCKET: "socket",
+
   // A real crash.
   CRASH_TYPE_CRASH: "crash",
 
   // A hang.
   CRASH_TYPE_HANG: "hang",
 
   // Submission result values.
   SUBMISSION_RESULT_OK: "ok",
@@ -459,17 +462,18 @@ this.CrashManager.prototype = Object.fre
       if (deferred) {
         this._crashPromises.delete(id);
         deferred.resolve();
       }
 
       // Send a telemetry ping for each non-main process crash
       if (processType === this.PROCESS_TYPE_CONTENT ||
           processType === this.PROCESS_TYPE_GPU ||
-          processType === this.PROCESS_TYPE_RDD) {
+          processType === this.PROCESS_TYPE_RDD ||
+          processType === this.PROCESS_TYPE_SOCKET) {
         this._sendCrashPing(id, processType, date, metadata);
       }
     })();
 
     return promise;
   },
 
   /**
--- a/toolkit/components/crashes/CrashService.js
+++ b/toolkit/components/crashes/CrashService.js
@@ -177,16 +177,19 @@ CrashService.prototype = Object.freeze({
       processType = Services.crashmanager.PROCESS_TYPE_GMPLUGIN;
       break;
     case Ci.nsICrashService.PROCESS_TYPE_GPU:
       processType = Services.crashmanager.PROCESS_TYPE_GPU;
       break;
     case Ci.nsICrashService.PROCESS_TYPE_RDD:
       processType = Services.crashmanager.PROCESS_TYPE_RDD;
       break;
+    case Ci.nsICrashService.PROCESS_TYPE_SOCKET:
+      processType = Services.crashmanager.PROCESS_TYPE_SOCKET;
+      break;
     case Ci.nsICrashService.PROCESS_TYPE_IPDLUNITTEST:
       // We'll never send crash reports for this type of process.
       return;
     default:
       throw new Error("Unrecognized PROCESS_TYPE: " + processType);
     }
 
     let allThreads = false;
--- a/toolkit/components/crashes/tests/xpcshell/test_crash_manager.js
+++ b/toolkit/components/crashes/tests/xpcshell/test_crash_manager.js
@@ -391,24 +391,26 @@ add_task(async function test_addCrash() 
   await m.addCrash(m.PROCESS_TYPE_PLUGIN, m.CRASH_TYPE_HANG,
                    "plugin-hang", DUMMY_DATE);
   await m.addCrash(m.PROCESS_TYPE_GMPLUGIN, m.CRASH_TYPE_CRASH,
                    "gmplugin-crash", DUMMY_DATE);
   await m.addCrash(m.PROCESS_TYPE_GPU, m.CRASH_TYPE_CRASH,
                    "gpu-crash", DUMMY_DATE);
   await m.addCrash(m.PROCESS_TYPE_RDD, m.CRASH_TYPE_CRASH,
                    "rdd-crash", DUMMY_DATE);
+  await m.addCrash(m.PROCESS_TYPE_SOCKET, m.CRASH_TYPE_CRASH,
+                   "socket-crash", DUMMY_DATE);
 
   await m.addCrash(m.PROCESS_TYPE_MAIN, m.CRASH_TYPE_CRASH,
                    "changing-item", DUMMY_DATE);
   await m.addCrash(m.PROCESS_TYPE_CONTENT, m.CRASH_TYPE_HANG,
                    "changing-item", DUMMY_DATE_2);
 
   crashes = await m.getCrashes();
-  Assert.equal(crashes.length, 10);
+  Assert.equal(crashes.length, 11);
 
   let map = new Map(crashes.map(crash => [crash.id, crash]));
 
   let crash = map.get("main-crash");
   Assert.ok(!!crash);
   Assert.equal(crash.crashDate, DUMMY_DATE);
   Assert.equal(crash.type, m.PROCESS_TYPE_MAIN + "-" + m.CRASH_TYPE_CRASH);
   Assert.ok(crash.isOfType(m.PROCESS_TYPE_MAIN, m.CRASH_TYPE_CRASH));
@@ -456,29 +458,36 @@ add_task(async function test_addCrash() 
   Assert.ok(crash.isOfType(m.PROCESS_TYPE_GPU, m.CRASH_TYPE_CRASH));
 
   crash = map.get("rdd-crash");
   Assert.ok(!!crash);
   Assert.equal(crash.crashDate, DUMMY_DATE);
   Assert.equal(crash.type, m.PROCESS_TYPE_RDD + "-" + m.CRASH_TYPE_CRASH);
   Assert.ok(crash.isOfType(m.PROCESS_TYPE_RDD, m.CRASH_TYPE_CRASH));
 
+  crash = map.get("socket-crash");
+  Assert.ok(!!crash);
+  Assert.equal(crash.crashDate, DUMMY_DATE);
+  Assert.equal(crash.type, m.PROCESS_TYPE_SOCKET + "-" + m.CRASH_TYPE_CRASH);
+  Assert.ok(crash.isOfType(m.PROCESS_TYPE_SOCKET, m.CRASH_TYPE_CRASH));
+
   crash = map.get("changing-item");
   Assert.ok(!!crash);
   Assert.equal(crash.crashDate, DUMMY_DATE_2);
   Assert.equal(crash.type, m.PROCESS_TYPE_CONTENT + "-" + m.CRASH_TYPE_HANG);
   Assert.ok(crash.isOfType(m.PROCESS_TYPE_CONTENT, m.CRASH_TYPE_HANG));
 });
 
 add_task(async function test_child_process_crash_ping() {
   let m = await getManager();
   const EXPECTED_PROCESSES = [
     m.PROCESS_TYPE_CONTENT,
     m.PROCESS_TYPE_GPU,
     m.PROCESS_TYPE_RDD,
+    m.PROCESS_TYPE_SOCKET,
   ];
 
   const UNEXPECTED_PROCESSES = [
     m.PROCESS_TYPE_PLUGIN,
     m.PROCESS_TYPE_GMPLUGIN,
     null,
     12, // non-string process type
   ];
--- a/toolkit/components/crashes/tests/xpcshell/test_crash_store.js
+++ b/toolkit/components/crashes/tests/xpcshell/test_crash_store.js
@@ -18,16 +18,17 @@ DUMMY_DATE_2.setMilliseconds(0);
 
 const {
   PROCESS_TYPE_MAIN,
   PROCESS_TYPE_CONTENT,
   PROCESS_TYPE_PLUGIN,
   PROCESS_TYPE_GMPLUGIN,
   PROCESS_TYPE_GPU,
   PROCESS_TYPE_RDD,
+  PROCESS_TYPE_SOCKET,
   CRASH_TYPE_CRASH,
   CRASH_TYPE_HANG,
   SUBMISSION_RESULT_OK,
   SUBMISSION_RESULT_FAILED,
 } = CrashManager.prototype;
 
 var STORE_DIR_COUNT = 0;
 
@@ -376,41 +377,69 @@ add_task(async function test_add_rdd_cra
     s.addCrash(PROCESS_TYPE_RDD, CRASH_TYPE_CRASH, "id1", new Date())
   );
   Assert.equal(s.crashesCount, 2);
 
   let crashes = s.getCrashesOfType(PROCESS_TYPE_RDD, CRASH_TYPE_CRASH);
   Assert.equal(crashes.length, 2);
 });
 
+add_task(async function test_add_socket_crash() {
+  let s = await getStore();
+
+  Assert.ok(
+    s.addCrash(PROCESS_TYPE_SOCKET, CRASH_TYPE_CRASH, "id1", new Date())
+  );
+  Assert.equal(s.crashesCount, 1);
+
+  let c = s.crashes[0];
+  Assert.ok(c.crashDate);
+  Assert.equal(c.type, PROCESS_TYPE_SOCKET + "-" + CRASH_TYPE_CRASH);
+  Assert.ok(c.isOfType(PROCESS_TYPE_SOCKET, CRASH_TYPE_CRASH));
+
+  Assert.ok(
+    s.addCrash(PROCESS_TYPE_SOCKET, CRASH_TYPE_CRASH, "id2", new Date())
+  );
+  Assert.equal(s.crashesCount, 2);
+
+  Assert.ok(
+    s.addCrash(PROCESS_TYPE_SOCKET, CRASH_TYPE_CRASH, "id1", new Date())
+  );
+  Assert.equal(s.crashesCount, 2);
+
+  let crashes = s.getCrashesOfType(PROCESS_TYPE_SOCKET, CRASH_TYPE_CRASH);
+  Assert.equal(crashes.length, 2);
+});
+
 add_task(async function test_add_mixed_types() {
   let s = await getStore();
 
   Assert.ok(
     s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH, "mcrash", new Date()) &&
     s.addCrash(PROCESS_TYPE_MAIN, CRASH_TYPE_HANG, "mhang", new Date()) &&
     s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_CRASH, "ccrash", new Date()) &&
     s.addCrash(PROCESS_TYPE_CONTENT, CRASH_TYPE_HANG, "chang", new Date()) &&
     s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_CRASH, "pcrash", new Date()) &&
     s.addCrash(PROCESS_TYPE_PLUGIN, CRASH_TYPE_HANG, "phang", new Date()) &&
     s.addCrash(PROCESS_TYPE_GMPLUGIN, CRASH_TYPE_CRASH, "gmpcrash", new Date()) &&
     s.addCrash(PROCESS_TYPE_GPU, CRASH_TYPE_CRASH, "gpucrash", new Date()) &&
-    s.addCrash(PROCESS_TYPE_RDD, CRASH_TYPE_CRASH, "rddcrash", new Date())
+    s.addCrash(PROCESS_TYPE_RDD, CRASH_TYPE_CRASH, "rddcrash", new Date()) &&
+    s.addCrash(PROCESS_TYPE_SOCKET, CRASH_TYPE_CRASH, "socketcrash", new Date())
   );
 
-  Assert.equal(s.crashesCount, 9);
+  Assert.equal(s.crashesCount, 10);
 
   await s.save();
 
   s._data.crashes.clear();
   Assert.equal(s.crashesCount, 0);
 
   await s.load();
 
-  Assert.equal(s.crashesCount, 9);
+  Assert.equal(s.crashesCount, 10);
 
   let crashes = s.getCrashesOfType(PROCESS_TYPE_MAIN, CRASH_TYPE_CRASH);
   Assert.equal(crashes.length, 1);
   crashes = s.getCrashesOfType(PROCESS_TYPE_MAIN, CRASH_TYPE_HANG);
   Assert.equal(crashes.length, 1);
   crashes = s.getCrashesOfType(PROCESS_TYPE_CONTENT, CRASH_TYPE_CRASH);
   Assert.equal(crashes.length, 1);
   crashes = s.getCrashesOfType(PROCESS_TYPE_CONTENT, CRASH_TYPE_HANG);
@@ -420,16 +449,18 @@ add_task(async function test_add_mixed_t
   crashes = s.getCrashesOfType(PROCESS_TYPE_PLUGIN, CRASH_TYPE_HANG);
   Assert.equal(crashes.length, 1);
   crashes = s.getCrashesOfType(PROCESS_TYPE_GMPLUGIN, CRASH_TYPE_CRASH);
   Assert.equal(crashes.length, 1);
   crashes = s.getCrashesOfType(PROCESS_TYPE_GPU, CRASH_TYPE_CRASH);
   Assert.equal(crashes.length, 1);
   crashes = s.getCrashesOfType(PROCESS_TYPE_RDD, CRASH_TYPE_CRASH);
   Assert.equal(crashes.length, 1);
+  crashes = s.getCrashesOfType(PROCESS_TYPE_SOCKET, CRASH_TYPE_CRASH);
+  Assert.equal(crashes.length, 1);
 });
 
 // Crashes added beyond the high water mark behave properly.
 add_task(async function test_high_water() {
   let s = await getStore();
 
   let d1 = new Date(2014, 0, 1, 0, 0, 0);
   let d2 = new Date(2014, 0, 2, 0, 0, 0);
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -11624,17 +11624,19 @@
       "content-hang",
       "plugin-crash",
       "plugin-hang",
       "gmplugin-crash",
       "gmplugin-hang",
       "gpu-crash",
       "gpu-hang",
       "rdd-crash",
-      "rdd-hang"
+      "rdd-hang",
+      "socket-crash",
+      "socket-hang"
     ],
     "releaseChannelCollection": "opt-out",
     "description": "An attempt to submit a crash. Keyed on the CrashManager Crash.type."
   },
   "PROCESS_CRASH_SUBMIT_SUCCESS": {
     "record_in_processes": ["main", "content"],
     "expires_in_version": "never",
     "kind": "boolean",