commit
f54506acc0
12 changed files with 155 additions and 61 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -6,6 +6,7 @@
|
||||||
/vendor/brightray/vendor/download/
|
/vendor/brightray/vendor/download/
|
||||||
/vendor/python_26/
|
/vendor/python_26/
|
||||||
/vendor/npm/
|
/vendor/npm/
|
||||||
|
/vendor/.gclient
|
||||||
node_modules/
|
node_modules/
|
||||||
*.xcodeproj
|
*.xcodeproj
|
||||||
*.swp
|
*.swp
|
||||||
|
|
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -13,3 +13,6 @@
|
||||||
[submodule "vendor/native_mate"]
|
[submodule "vendor/native_mate"]
|
||||||
path = vendor/native_mate
|
path = vendor/native_mate
|
||||||
url = https://github.com/zcbenz/native-mate.git
|
url = https://github.com/zcbenz/native-mate.git
|
||||||
|
[submodule "vendor/crashpad"]
|
||||||
|
path = vendor/crashpad
|
||||||
|
url = https://github.com/atom/crashpad.git
|
||||||
|
|
6
atom.gyp
6
atom.gyp
|
@ -275,7 +275,8 @@
|
||||||
}], # OS=="win"
|
}], # OS=="win"
|
||||||
['OS=="mac"', {
|
['OS=="mac"', {
|
||||||
'dependencies': [
|
'dependencies': [
|
||||||
'vendor/breakpad/breakpad.gyp:breakpad',
|
'vendor/crashpad/client/client.gyp:crashpad_client',
|
||||||
|
'vendor/crashpad/handler/handler.gyp:crashpad_handler',
|
||||||
],
|
],
|
||||||
}], # OS=="mac"
|
}], # OS=="mac"
|
||||||
['OS=="linux"', {
|
['OS=="linux"', {
|
||||||
|
@ -430,8 +431,7 @@
|
||||||
{
|
{
|
||||||
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Resources',
|
'destination': '<(PRODUCT_DIR)/<(product_name) Framework.framework/Versions/A/Resources',
|
||||||
'files': [
|
'files': [
|
||||||
'<(PRODUCT_DIR)/Inspector',
|
'<(PRODUCT_DIR)/crashpad_handler',
|
||||||
'<(PRODUCT_DIR)/crash_report_sender.app',
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include "atom/common/node_includes.h"
|
#include "atom/common/node_includes.h"
|
||||||
|
|
||||||
|
using crash_reporter::CrashReporter;
|
||||||
|
|
||||||
namespace mate {
|
namespace mate {
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
@ -31,17 +33,30 @@ struct Converter<std::map<std::string, std::string> > {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct Converter<CrashReporter::UploadReportResult> {
|
||||||
|
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
|
||||||
|
const CrashReporter::UploadReportResult& reports) {
|
||||||
|
mate::Dictionary dict(isolate, v8::Object::New(isolate));
|
||||||
|
dict.Set("date", v8::Date::New(isolate, reports.first*1000.0));
|
||||||
|
dict.Set("id", reports.second);
|
||||||
|
return dict.GetHandle();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace mate
|
} // namespace mate
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
|
||||||
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
void Initialize(v8::Local<v8::Object> exports, v8::Local<v8::Value> unused,
|
||||||
v8::Local<v8::Context> context, void* priv) {
|
v8::Local<v8::Context> context, void* priv) {
|
||||||
using crash_reporter::CrashReporter;
|
|
||||||
mate::Dictionary dict(context->GetIsolate(), exports);
|
mate::Dictionary dict(context->GetIsolate(), exports);
|
||||||
|
auto report = base::Unretained(CrashReporter::GetInstance());
|
||||||
dict.SetMethod("start",
|
dict.SetMethod("start",
|
||||||
base::Bind(&CrashReporter::Start,
|
base::Bind(&CrashReporter::Start, report));
|
||||||
base::Unretained(CrashReporter::GetInstance())));
|
dict.SetMethod("_getUploadedReports",
|
||||||
|
base::Bind(&CrashReporter::GetUploadedReports, report));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -41,6 +41,10 @@ class CrashReporter
|
||||||
start()
|
start()
|
||||||
|
|
||||||
getLastCrashReport: ->
|
getLastCrashReport: ->
|
||||||
|
if process.platform is 'darwin'
|
||||||
|
reports = binding._getUploadedReports()
|
||||||
|
return if reports.length > 0 then reports[0] else null
|
||||||
|
|
||||||
tmpdir =
|
tmpdir =
|
||||||
if process.platform is 'win32'
|
if process.platform is 'win32'
|
||||||
os.tmpdir()
|
os.tmpdir()
|
||||||
|
|
|
@ -39,4 +39,9 @@ void CrashReporter::SetUploadParameters(const StringMap& parameters) {
|
||||||
SetUploadParameters();
|
SetUploadParameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<CrashReporter::UploadReportResult>
|
||||||
|
CrashReporter::GetUploadedReports() {
|
||||||
|
return std::vector<CrashReporter::UploadReportResult>();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace crash_reporter
|
} // namespace crash_reporter
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "base/basictypes.h"
|
#include "base/basictypes.h"
|
||||||
|
|
||||||
|
@ -15,6 +17,7 @@ namespace crash_reporter {
|
||||||
class CrashReporter {
|
class CrashReporter {
|
||||||
public:
|
public:
|
||||||
typedef std::map<std::string, std::string> StringMap;
|
typedef std::map<std::string, std::string> StringMap;
|
||||||
|
typedef std::pair<int, std::string> UploadReportResult; // upload-date, id
|
||||||
|
|
||||||
static CrashReporter* GetInstance();
|
static CrashReporter* GetInstance();
|
||||||
|
|
||||||
|
@ -25,6 +28,8 @@ class CrashReporter {
|
||||||
bool skip_system_crash_handler,
|
bool skip_system_crash_handler,
|
||||||
const StringMap& extra_parameters);
|
const StringMap& extra_parameters);
|
||||||
|
|
||||||
|
virtual std::vector<CrashReporter::UploadReportResult> GetUploadedReports();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CrashReporter();
|
CrashReporter();
|
||||||
virtual ~CrashReporter();
|
virtual ~CrashReporter();
|
||||||
|
|
|
@ -6,13 +6,20 @@
|
||||||
#define ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_MAC_H_
|
#define ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_MAC_H_
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "atom/common/crash_reporter/crash_reporter.h"
|
#include "atom/common/crash_reporter/crash_reporter.h"
|
||||||
#include "base/compiler_specific.h"
|
#include "base/compiler_specific.h"
|
||||||
#import "vendor/breakpad/src/client/mac/Framework/Breakpad.h"
|
#include "base/memory/scoped_ptr.h"
|
||||||
|
#include "base/strings/string_piece.h"
|
||||||
|
#include "vendor/crashpad/client/simple_string_dictionary.h"
|
||||||
|
|
||||||
template <typename T> struct DefaultSingletonTraits;
|
template <typename T> struct DefaultSingletonTraits;
|
||||||
|
|
||||||
|
namespace crashpad {
|
||||||
|
class CrashReportDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
namespace crash_reporter {
|
namespace crash_reporter {
|
||||||
|
|
||||||
class CrashReporterMac : public CrashReporter {
|
class CrashReporterMac : public CrashReporter {
|
||||||
|
@ -33,7 +40,14 @@ class CrashReporterMac : public CrashReporter {
|
||||||
CrashReporterMac();
|
CrashReporterMac();
|
||||||
virtual ~CrashReporterMac();
|
virtual ~CrashReporterMac();
|
||||||
|
|
||||||
BreakpadRef breakpad_;
|
void SetUploadsEnabled(bool enable_uploads);
|
||||||
|
void SetCrashKeyValue(const base::StringPiece& key,
|
||||||
|
const base::StringPiece& value);
|
||||||
|
|
||||||
|
std::vector<UploadReportResult> GetUploadedReports() override;
|
||||||
|
|
||||||
|
scoped_ptr<crashpad::SimpleStringDictionary> simple_string_dictionary_;
|
||||||
|
scoped_ptr<crashpad::CrashReportDatabase> crash_report_database_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(CrashReporterMac);
|
DISALLOW_COPY_AND_ASSIGN(CrashReporterMac);
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,20 +4,24 @@
|
||||||
|
|
||||||
#include "atom/common/crash_reporter/crash_reporter_mac.h"
|
#include "atom/common/crash_reporter/crash_reporter_mac.h"
|
||||||
|
|
||||||
|
#include "base/files/file_path.h"
|
||||||
|
#include "base/mac/bundle_locations.h"
|
||||||
#include "base/mac/mac_util.h"
|
#include "base/mac/mac_util.h"
|
||||||
#include "base/memory/singleton.h"
|
#include "base/memory/singleton.h"
|
||||||
|
#include "base/strings/string_piece.h"
|
||||||
|
#include "base/strings/stringprintf.h"
|
||||||
#include "base/strings/sys_string_conversions.h"
|
#include "base/strings/sys_string_conversions.h"
|
||||||
#import "vendor/breakpad/src/client/apple/Framework/BreakpadDefines.h"
|
#include "vendor/crashpad/client/crash_report_database.h"
|
||||||
|
#include "vendor/crashpad/client/crashpad_client.h"
|
||||||
|
#include "vendor/crashpad/client/crashpad_info.h"
|
||||||
|
#include "vendor/crashpad/client/settings.h"
|
||||||
|
|
||||||
namespace crash_reporter {
|
namespace crash_reporter {
|
||||||
|
|
||||||
CrashReporterMac::CrashReporterMac()
|
CrashReporterMac::CrashReporterMac() {
|
||||||
: breakpad_(NULL) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CrashReporterMac::~CrashReporterMac() {
|
CrashReporterMac::~CrashReporterMac() {
|
||||||
if (breakpad_ != NULL)
|
|
||||||
BreakpadRelease(breakpad_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CrashReporterMac::InitBreakpad(const std::string& product_name,
|
void CrashReporterMac::InitBreakpad(const std::string& product_name,
|
||||||
|
@ -26,54 +30,50 @@ void CrashReporterMac::InitBreakpad(const std::string& product_name,
|
||||||
const std::string& submit_url,
|
const std::string& submit_url,
|
||||||
bool auto_submit,
|
bool auto_submit,
|
||||||
bool skip_system_crash_handler) {
|
bool skip_system_crash_handler) {
|
||||||
if (breakpad_ != NULL)
|
// check whether crashpad has been initilized.
|
||||||
BreakpadRelease(breakpad_);
|
// Only need to initilize once.
|
||||||
|
if (simple_string_dictionary_)
|
||||||
NSMutableDictionary* parameters =
|
|
||||||
[NSMutableDictionary dictionaryWithCapacity:4];
|
|
||||||
|
|
||||||
[parameters setValue:@ATOM_PRODUCT_NAME
|
|
||||||
forKey:@BREAKPAD_PRODUCT];
|
|
||||||
[parameters setValue:base::SysUTF8ToNSString(product_name)
|
|
||||||
forKey:@BREAKPAD_PRODUCT_DISPLAY];
|
|
||||||
[parameters setValue:base::SysUTF8ToNSString(version)
|
|
||||||
forKey:@BREAKPAD_VERSION];
|
|
||||||
[parameters setValue:base::SysUTF8ToNSString(company_name)
|
|
||||||
forKey:@BREAKPAD_VENDOR];
|
|
||||||
[parameters setValue:base::SysUTF8ToNSString(submit_url)
|
|
||||||
forKey:@BREAKPAD_URL];
|
|
||||||
[parameters setValue:(auto_submit ? @"YES" : @"NO")
|
|
||||||
forKey:@BREAKPAD_SKIP_CONFIRM];
|
|
||||||
[parameters setValue:(skip_system_crash_handler ? @"YES" : @"NO")
|
|
||||||
forKey:@BREAKPAD_SEND_AND_EXIT];
|
|
||||||
|
|
||||||
// Report all crashes (important for testing the crash reporter).
|
|
||||||
[parameters setValue:@"0" forKey:@BREAKPAD_REPORT_INTERVAL];
|
|
||||||
|
|
||||||
// Put dump files under "/tmp/ProductName Crashes".
|
|
||||||
std::string dump_dir = "/tmp/" + product_name + " Crashes";
|
|
||||||
[parameters setValue:base::SysUTF8ToNSString(dump_dir)
|
|
||||||
forKey:@BREAKPAD_DUMP_DIRECTORY];
|
|
||||||
|
|
||||||
// Temporarily run Breakpad in-process on 10.10 and later because APIs that
|
|
||||||
// it depends on got broken (http://crbug.com/386208).
|
|
||||||
// This can catch crashes in the browser process only.
|
|
||||||
if (base::mac::IsOSYosemiteOrLater()) {
|
|
||||||
[parameters setObject:[NSNumber numberWithBool:YES]
|
|
||||||
forKey:@BREAKPAD_IN_PROCESS];
|
|
||||||
}
|
|
||||||
|
|
||||||
breakpad_ = BreakpadCreate(parameters);
|
|
||||||
if (!breakpad_) {
|
|
||||||
LOG(ERROR) << "Failed to initialize breakpad";
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
std::string dump_dir = "/tmp/" + product_name + " Crashes";
|
||||||
|
base::FilePath database_path(dump_dir);
|
||||||
|
if (is_browser_) {
|
||||||
|
@autoreleasepool {
|
||||||
|
base::FilePath framework_bundle_path = base::mac::FrameworkBundlePath();
|
||||||
|
base::FilePath handler_path =
|
||||||
|
framework_bundle_path.Append("Resources").Append("crashpad_handler");
|
||||||
|
|
||||||
|
crashpad::CrashpadClient crashpad_client;
|
||||||
|
if (crashpad_client.StartHandler(handler_path, database_path,
|
||||||
|
submit_url,
|
||||||
|
StringMap(),
|
||||||
|
std::vector<std::string>())) {
|
||||||
|
crashpad_client.UseHandler();
|
||||||
|
}
|
||||||
|
} // @autoreleasepool
|
||||||
}
|
}
|
||||||
|
|
||||||
for (StringMap::const_iterator iter = upload_parameters_.begin();
|
crashpad::CrashpadInfo* crashpad_info =
|
||||||
iter != upload_parameters_.end(); ++iter) {
|
crashpad::CrashpadInfo::GetCrashpadInfo();
|
||||||
BreakpadAddUploadParameter(breakpad_,
|
if (skip_system_crash_handler) {
|
||||||
base::SysUTF8ToNSString(iter->first),
|
crashpad_info->set_system_crash_reporter_forwarding(
|
||||||
base::SysUTF8ToNSString(iter->second));
|
crashpad::TriState::kDisabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
simple_string_dictionary_.reset(new crashpad::SimpleStringDictionary());
|
||||||
|
crashpad_info->set_simple_annotations(simple_string_dictionary_.get());
|
||||||
|
|
||||||
|
SetCrashKeyValue("prod", ATOM_PRODUCT_NAME);
|
||||||
|
SetCrashKeyValue("process_type", is_browser_ ? "browser" : "renderer");
|
||||||
|
SetCrashKeyValue("ver", version);
|
||||||
|
|
||||||
|
for (const auto& upload_parameter: upload_parameters_) {
|
||||||
|
SetCrashKeyValue(upload_parameter.first, upload_parameter.second);
|
||||||
|
}
|
||||||
|
if (is_browser_) {
|
||||||
|
crash_report_database_ = crashpad::CrashReportDatabase::Initialize(
|
||||||
|
database_path);
|
||||||
|
SetUploadsEnabled(auto_submit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +81,48 @@ void CrashReporterMac::SetUploadParameters() {
|
||||||
upload_parameters_["platform"] = "darwin";
|
upload_parameters_["platform"] = "darwin";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CrashReporterMac::SetUploadsEnabled(bool enable_uploads) {
|
||||||
|
if (crash_report_database_) {
|
||||||
|
crashpad::Settings* settings = crash_report_database_->GetSettings();
|
||||||
|
settings->SetUploadsEnabled(enable_uploads);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashReporterMac::SetCrashKeyValue(const base::StringPiece& key,
|
||||||
|
const base::StringPiece& value) {
|
||||||
|
simple_string_dictionary_->SetKeyValue(key.data(), value.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<CrashReporter::UploadReportResult>
|
||||||
|
CrashReporterMac::GetUploadedReports() {
|
||||||
|
std::vector<CrashReporter::UploadReportResult> uploaded_reports;
|
||||||
|
|
||||||
|
if (!crash_report_database_) {
|
||||||
|
return uploaded_reports;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<crashpad::CrashReportDatabase::Report> completed_reports;
|
||||||
|
crashpad::CrashReportDatabase::OperationStatus status =
|
||||||
|
crash_report_database_->GetCompletedReports(&completed_reports);
|
||||||
|
if (status != crashpad::CrashReportDatabase::kNoError) {
|
||||||
|
return uploaded_reports;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const crashpad::CrashReportDatabase::Report& completed_report :
|
||||||
|
completed_reports) {
|
||||||
|
if (completed_report.uploaded) {
|
||||||
|
uploaded_reports.push_back(
|
||||||
|
UploadReportResult(static_cast<int>(completed_report.creation_time),
|
||||||
|
completed_report.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sort_by_time = [](const UploadReportResult& a,
|
||||||
|
const UploadReportResult& b) {return a.first >= b.first;};
|
||||||
|
std::sort(uploaded_reports.begin(), uploaded_reports.end(), sort_by_time);
|
||||||
|
return uploaded_reports;
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
CrashReporterMac* CrashReporterMac::GetInstance() {
|
CrashReporterMac* CrashReporterMac::GetInstance() {
|
||||||
return Singleton<CrashReporterMac>::get();
|
return Singleton<CrashReporterMac>::get();
|
||||||
|
|
|
@ -27,6 +27,11 @@ crashReporter.start({
|
||||||
* Only string properties are send correctly.
|
* Only string properties are send correctly.
|
||||||
* Nested objects are not supported.
|
* Nested objects are not supported.
|
||||||
|
|
||||||
|
**Note:** On OS X, electron uses a new `crashpad` client, which is different
|
||||||
|
with the `breakpad` on Windows and Linux. To enable crash collection feature,
|
||||||
|
you are required to call `crashReporter.start` API to initiliaze `crashpad` in
|
||||||
|
main process, even you only collect crash report in renderer process.
|
||||||
|
|
||||||
## crashReporter.getLastCrashReport()
|
## crashReporter.getLastCrashReport()
|
||||||
|
|
||||||
Returns the date and ID of last crash report, when there was no crash report
|
Returns the date and ID of last crash report, when there was no crash report
|
||||||
|
|
|
@ -5,12 +5,10 @@ url = require 'url'
|
||||||
remote = require 'remote'
|
remote = require 'remote'
|
||||||
formidable = require 'formidable'
|
formidable = require 'formidable'
|
||||||
|
|
||||||
|
crashReporter = remote.require 'crash-reporter'
|
||||||
BrowserWindow = remote.require 'browser-window'
|
BrowserWindow = remote.require 'browser-window'
|
||||||
|
|
||||||
describe 'crash-reporter module', ->
|
describe 'crash-reporter module', ->
|
||||||
# We have trouble makeing crash reporter work on Yosemite.
|
|
||||||
return if process.platform is 'darwin'
|
|
||||||
|
|
||||||
fixtures = path.resolve __dirname, 'fixtures'
|
fixtures = path.resolve __dirname, 'fixtures'
|
||||||
|
|
||||||
w = null
|
w = null
|
||||||
|
@ -47,4 +45,5 @@ describe 'crash-reporter module', ->
|
||||||
protocol: 'file'
|
protocol: 'file'
|
||||||
pathname: path.join fixtures, 'api', 'crash.html'
|
pathname: path.join fixtures, 'api', 'crash.html'
|
||||||
search: "?port=#{port}"
|
search: "?port=#{port}"
|
||||||
|
crashReporter.start {'submitUrl': 'http://127.0.0.1:' + port}
|
||||||
w.loadUrl url
|
w.loadUrl url
|
||||||
|
|
1
vendor/crashpad
vendored
Submodule
1
vendor/crashpad
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit e6a0d433b0ee399eecce2bef671794771052ffdb
|
Loading…
Reference in a new issue