Browse Source

fix: send guid with linux crashes (#24898)

trop[bot] 4 years ago
parent
commit
8dc38cb973

+ 39 - 0
shell/browser/api/electron_api_crash_reporter.cc

@@ -40,7 +40,11 @@
 #endif
 
 #if defined(OS_LINUX)
+#include "base/containers/span.h"
+#include "base/files/file_util.h"
+#include "base/guid.h"
 #include "components/crash/core/app/breakpad_linux.h"
+#include "components/crash/core/common/crash_keys.h"
 #include "v8/include/v8-wasm-trap-handler-posix.h"
 #include "v8/include/v8.h"
 #endif
@@ -81,6 +85,40 @@ bool IsCrashReporterEnabled() {
 const std::map<std::string, std::string>& GetGlobalCrashKeys() {
   return GetGlobalCrashKeysMutable();
 }
+
+base::FilePath GetClientIdPath() {
+  base::FilePath path;
+  base::PathService::Get(electron::DIR_CRASH_DUMPS, &path);
+  return path.Append("client_id");
+}
+
+std::string ReadClientId() {
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  std::string client_id;
+  // "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".length == 36
+  if (!base::ReadFileToStringWithMaxSize(GetClientIdPath(), &client_id, 36) ||
+      client_id.size() != 36)
+    return std::string();
+  return client_id;
+}
+
+void WriteClientId(const std::string& client_id) {
+  DCHECK_EQ(client_id.size(), 36u);
+  base::ThreadRestrictions::ScopedAllowIO allow_io;
+  base::WriteFile(GetClientIdPath(), client_id.data(), client_id.size());
+}
+
+std::string GetClientId() {
+  static base::NoDestructor<std::string> client_id;
+  if (!client_id->empty())
+    return *client_id;
+  *client_id = ReadClientId();
+  if (client_id->empty()) {
+    *client_id = base::GenerateGUID();
+    WriteClientId(*client_id);
+  }
+  return *client_id;
+}
 #endif
 
 void Start(const std::string& submit_url,
@@ -107,6 +145,7 @@ void Start(const std::string& submit_url,
           ? "node"
           : command_line->GetSwitchValueASCII(::switches::kProcessType);
 #if defined(OS_LINUX)
+  ::crash_keys::SetMetricsClientIdFromGUID(GetClientId());
   auto& global_crash_keys = GetGlobalCrashKeysMutable();
   for (const auto& pair : global_extra) {
     global_crash_keys[pair.first] = pair.second;

+ 1 - 0
shell/browser/api/electron_api_crash_reporter.h

@@ -19,6 +19,7 @@ bool IsCrashReporterEnabled();
 
 #if defined(OS_LINUX)
 const std::map<std::string, std::string>& GetGlobalCrashKeys();
+std::string GetClientId();
 #endif
 
 // JS bindings API; exposed publicly because it's also called from node_main.cc

+ 4 - 2
shell/browser/electron_browser_client.cc

@@ -725,8 +725,10 @@ void ElectronBrowserClient::AppendExtraCommandLineSwitches(
   bool enable_crash_reporter = false;
   enable_crash_reporter = breakpad::IsCrashReporterEnabled();
   if (enable_crash_reporter) {
-    command_line->AppendSwitch(::switches::kEnableCrashReporter);
-    std::string switch_value;
+    std::string switch_value =
+        api::crash_reporter::GetClientId() + ",no_channel";
+    command_line->AppendSwitchASCII(::switches::kEnableCrashReporter,
+                                    switch_value);
     for (const auto& pair : api::crash_reporter::GetGlobalCrashKeys()) {
       if (!switch_value.empty())
         switch_value += ",";

+ 30 - 0
spec-main/api-crash-reporter-spec.ts

@@ -33,6 +33,7 @@ type CrashInfo = {
   _productName: string
   _version: string
   upload_file_minidump: Buffer // eslint-disable-line camelcase
+  guid: string
   mainProcessSpecific: 'mps' | undefined
   rendererSpecific: 'rs' | undefined
   globalParam: 'globalValue' | undefined
@@ -229,6 +230,35 @@ ifdescribe(!isLinuxOnArm && !process.mas && !process.env.DISABLE_CRASH_REPORTER_
       expect(crash.rendererSpecific).to.be.undefined();
     });
 
+    describe('with guid', () => {
+      for (const processType of ['main', 'renderer', 'sandboxed-renderer']) {
+        it(`when ${processType} crashes`, async () => {
+          const { port, waitForCrash } = await startServer();
+          runCrashApp(processType, port);
+          const crash = await waitForCrash();
+          expect(crash.guid).to.be.a('string');
+        });
+      }
+
+      it('is a consistent id', async () => {
+        let crash1Guid;
+        let crash2Guid;
+        {
+          const { port, waitForCrash } = await startServer();
+          runCrashApp('main', port);
+          const crash = await waitForCrash();
+          crash1Guid = crash.guid;
+        }
+        {
+          const { port, waitForCrash } = await startServer();
+          runCrashApp('main', port);
+          const crash = await waitForCrash();
+          crash2Guid = crash.guid;
+        }
+        expect(crash2Guid).to.equal(crash1Guid);
+      });
+    });
+
     describe('with extra parameters', () => {
       it('when renderer crashes', async () => {
         const { port, waitForCrash } = await startServer();