Bug 1513057 - P2: Setup crash reporter on socket process r=dragana,mayhemer
☠☠ backed out by 3f76ed638d83 ☠ ☠
authorKershaw Chang <kershaw@mozilla.com>
Fri, 11 Jan 2019 13:26:56 +0000
changeset 510575 edbda5ee5fd53f9ba0ab75477f08c7b29088eca1
parent 510574 c900ac2519f5007a28b201bbc00a95873ac38f9c
child 510576 a81f83df08d50ced7d669958f9a06f52b087a5fc
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [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
ipc/glue/CrashReporterHost.cpp
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/nsICrashService.idl
toolkit/components/crashes/tests/xpcshell/test_crash_manager.js
toolkit/components/crashes/tests/xpcshell/test_crash_store.js
toolkit/components/telemetry/Histograms.json
--- a/ipc/glue/CrashReporterHost.cpp
+++ b/ipc/glue/CrashReporterHost.cpp
@@ -31,19 +31,21 @@ static_assert(nsICrashService::PROCESS_T
 static_assert(nsICrashService::PROCESS_TYPE_GMPLUGIN == (int)GeckoProcessType_GMPlugin,
               "GeckoProcessType enum is out of sync with nsICrashService!");
 static_assert(nsICrashService::PROCESS_TYPE_GPU == (int)GeckoProcessType_GPU,
               "GeckoProcessType enum is out of sync with nsICrashService!");
 static_assert(nsICrashService::PROCESS_TYPE_VR == (int)GeckoProcessType_VR,
               "GeckoProcessType enum is out of sync with nsICrashService!");
 static_assert(nsICrashService::PROCESS_TYPE_RDD == (int)GeckoProcessType_RDD,
               "GeckoProcessType enum is out of sync with nsICrashService!");
+static_assert(nsICrashService::PROCESS_TYPE_SOCKET == (int)GeckoProcessType_Socket,
+              "GeckoProcessType enum is out of sync with nsICrashService!");
 // Add new static asserts here if you add more process types.
 // Update this static assert as well.
-static_assert(nsICrashService::PROCESS_TYPE_RDD + 1 == (int)GeckoProcessType_End,
+static_assert(nsICrashService::PROCESS_TYPE_SOCKET + 1 == (int)GeckoProcessType_End,
               "GeckoProcessType enum is out of sync with nsICrashService!");
 
 
 namespace mozilla {
 namespace ipc {
 
 CrashReporterHost::CrashReporterHost(GeckoProcessType aProcessType,
                                      const Shmem& aShmem,
--- 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/nsICrashService.idl
+++ b/toolkit/components/crashes/nsICrashService.idl
@@ -24,13 +24,14 @@ interface nsICrashService : nsISupports
   const long PROCESS_TYPE_MAIN = 0;
   const long PROCESS_TYPE_PLUGIN = 1;
   const long PROCESS_TYPE_CONTENT = 2;
   const long PROCESS_TYPE_IPDLUNITTEST = 3;
   const long PROCESS_TYPE_GMPLUGIN = 4;
   const long PROCESS_TYPE_GPU = 5;
   const long PROCESS_TYPE_VR = 6;
   const long PROCESS_TYPE_RDD = 7;
+  const long PROCESS_TYPE_SOCKET = 8;
   // New process types should be added at the end of the above list.
 
   const long CRASH_TYPE_CRASH = 0;
   const long CRASH_TYPE_HANG = 1;
 };
--- 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",