mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-25 22:30:49 +08:00
[ios] Add an optional upload complete observation callback to the in-process handler
Breakpad offers a callback when uploads complete: https://source.chromium.org/chromium/chromium/src/+/main:third_party/breakpad/breakpad/src/client/ios/BreakpadController.h;l=103;drc=1fc9cc0d0e1dfafb8d29dba8d01f09587d870026 This adds an equivalent observation callback to Crashpad on iOS which is invoked each time an upload attempt completes (whether it succeeds or fails). I couldn't find any existing unit tests for the upload thread, but I tested this manually by integrating it into a client. Please let me know the best way to test this. Change-Id: I17822af5e63c8634484606a6470ce83b2c385676 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3852399 Reviewed-by: Justin Cohen <justincohen@chromium.org> Commit-Queue: Justin Cohen <justincohen@chromium.org> Reviewed-by: Robert Sesek <rsesek@chromium.org>
This commit is contained in:
parent
6278690abe
commit
ca3cf2f4e3
@ -15,6 +15,7 @@
|
||||
#ifndef CRASHPAD_CLIENT_CRASHPAD_CLIENT_H_
|
||||
#define CRASHPAD_CLIENT_CRASHPAD_CLIENT_H_
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
@ -461,6 +462,17 @@ class CrashpadClient {
|
||||
// BUILDFLAG(IS_CHROMEOS) || DOXYGEN
|
||||
|
||||
#if BUILDFLAG(IS_IOS) || DOXYGEN
|
||||
//! \brief Observation callback invoked each time this object finishes
|
||||
//! processing and attempting to upload on-disk crash reports (whether or
|
||||
//! not the uploads succeeded).
|
||||
//!
|
||||
//! This callback is copied into this object. Any references or pointers
|
||||
//! inside must outlive this object.
|
||||
//!
|
||||
//! The callback might be invoked on a background thread, so clients must
|
||||
//! synchronize appropriately.
|
||||
using ProcessPendingReportsObservationCallback = std::function<void()>;
|
||||
|
||||
//! \brief Configures the process to direct its crashes to the iOS in-process
|
||||
//! Crashpad handler.
|
||||
//!
|
||||
@ -469,11 +481,16 @@ class CrashpadClient {
|
||||
//! \param[in] database The path to a Crashpad database.
|
||||
//! \param[in] url The URL of an upload server.
|
||||
//! \param[in] annotations Process annotations to set in each crash report.
|
||||
//! \param[in] callback Optional callback invoked zero or more times
|
||||
//! on a background thread each time the handler finishes
|
||||
//! processing and attempting to upload on-disk crash reports.
|
||||
//! If this callback is empty, it is not invoked.
|
||||
//! \return `true` on success, `false` on failure with a message logged.
|
||||
static bool StartCrashpadInProcessHandler(
|
||||
const base::FilePath& database,
|
||||
const std::string& url,
|
||||
const std::map<std::string, std::string>& annotations);
|
||||
const std::map<std::string, std::string>& annotations,
|
||||
ProcessPendingReportsObservationCallback callback);
|
||||
|
||||
//! \brief Requests that the handler convert intermediate dumps into
|
||||
//! minidumps and trigger an upload if possible.
|
||||
|
@ -72,11 +72,14 @@ class CrashHandler : public Thread,
|
||||
instance_ = nullptr;
|
||||
}
|
||||
|
||||
bool Initialize(const base::FilePath& database,
|
||||
const std::string& url,
|
||||
const std::map<std::string, std::string>& annotations) {
|
||||
bool Initialize(
|
||||
const base::FilePath& database,
|
||||
const std::string& url,
|
||||
const std::map<std::string, std::string>& annotations,
|
||||
internal::InProcessHandler::ProcessPendingReportsObservationCallback
|
||||
callback) {
|
||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||
if (!in_process_handler_.Initialize(database, url, annotations) ||
|
||||
if (!in_process_handler_.Initialize(database, url, annotations, callback) ||
|
||||
!InstallMachExceptionHandler() ||
|
||||
// xnu turns hardware faults into Mach exceptions, so the only signal
|
||||
// left to register is SIGABRT, which never starts off as a hardware
|
||||
@ -411,10 +414,11 @@ CrashpadClient::~CrashpadClient() {}
|
||||
bool CrashpadClient::StartCrashpadInProcessHandler(
|
||||
const base::FilePath& database,
|
||||
const std::string& url,
|
||||
const std::map<std::string, std::string>& annotations) {
|
||||
const std::map<std::string, std::string>& annotations,
|
||||
ProcessPendingReportsObservationCallback callback) {
|
||||
CrashHandler* crash_handler = CrashHandler::Get();
|
||||
DCHECK(crash_handler);
|
||||
return crash_handler->Initialize(database, url, annotations);
|
||||
return crash_handler->Initialize(database, url, annotations, callback);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -37,7 +37,10 @@ class CrashpadIOSClient : public PlatformTest {
|
||||
|
||||
void SetUp() override {
|
||||
ASSERT_TRUE(client_.StartCrashpadInProcessHandler(
|
||||
base::FilePath(database_dir.path()), "", {}));
|
||||
base::FilePath(database_dir.path()),
|
||||
"",
|
||||
{},
|
||||
CrashpadClient::ProcessPendingReportsObservationCallback()));
|
||||
database_ = CrashReportDatabase::Initialize(database_dir.path());
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,8 @@ InProcessHandler::~InProcessHandler() {
|
||||
bool InProcessHandler::Initialize(
|
||||
const base::FilePath& database,
|
||||
const std::string& url,
|
||||
const std::map<std::string, std::string>& annotations) {
|
||||
const std::map<std::string, std::string>& annotations,
|
||||
ProcessPendingReportsObservationCallback callback) {
|
||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||
annotations_ = annotations;
|
||||
database_ = CrashReportDatabase::Initialize(database);
|
||||
@ -92,7 +93,7 @@ bool InProcessHandler::Initialize(
|
||||
upload_thread_options.identify_client_via_url = true;
|
||||
|
||||
upload_thread_.reset(new CrashReportUploadThread(
|
||||
database_.get(), url, upload_thread_options));
|
||||
database_.get(), url, upload_thread_options, callback));
|
||||
}
|
||||
|
||||
if (!CreateDirectory(database))
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -42,6 +43,17 @@ class InProcessHandler {
|
||||
InProcessHandler(const InProcessHandler&) = delete;
|
||||
InProcessHandler& operator=(const InProcessHandler&) = delete;
|
||||
|
||||
//! \brief Observation callback invoked each time this object finishes
|
||||
//! processing and attempting to upload on-disk crash reports (whether or
|
||||
//! not the uploads succeeded).
|
||||
//!
|
||||
//! This callback is copied into this object. Any references or pointers
|
||||
//! inside must outlive this object.
|
||||
//!
|
||||
//! The callback might be invoked on a background thread, so clients must
|
||||
//! synchronize appropriately.
|
||||
using ProcessPendingReportsObservationCallback = std::function<void()>;
|
||||
|
||||
//! \brief Initializes the in-process handler.
|
||||
//!
|
||||
//! This method must be called only once, and must be successfully called
|
||||
@ -50,11 +62,16 @@ class InProcessHandler {
|
||||
//! \param[in] database The path to a Crashpad database.
|
||||
//! \param[in] url The URL of an upload server.
|
||||
//! \param[in] annotations Process annotations to set in each crash report.
|
||||
//! \param[in] callback Optional callback invoked zero or more times
|
||||
//! on a background thread each time this object finishes
|
||||
//! processing and attempting to upload on-disk crash reports.
|
||||
//! \return `true` if a handler to a pending intermediate dump could be
|
||||
//! opened.
|
||||
bool Initialize(const base::FilePath& database,
|
||||
const std::string& url,
|
||||
const std::map<std::string, std::string>& annotations);
|
||||
const std::map<std::string, std::string>& annotations,
|
||||
ProcessPendingReportsObservationCallback callback =
|
||||
ProcessPendingReportsObservationCallback());
|
||||
|
||||
//! \brief Generate an intermediate dump from a signal handler exception.
|
||||
//! Writes the dump with the cached writer does not allow concurrent
|
||||
|
@ -63,12 +63,36 @@ const int kRetryWorkIntervalSeconds = 15 * 60;
|
||||
const int kRetryAttempts = 5;
|
||||
#endif
|
||||
|
||||
// Wraps a reference to a no-args function (which can be empty). When this
|
||||
// object goes out of scope, invokes the function if it is non-empty.
|
||||
//
|
||||
// The lifetime of the function must outlive the lifetime of this object.
|
||||
class ScopedFunctionInvoker final {
|
||||
public:
|
||||
ScopedFunctionInvoker(const std::function<void()>& function)
|
||||
: function_(function) {}
|
||||
ScopedFunctionInvoker(const ScopedFunctionInvoker&) = delete;
|
||||
ScopedFunctionInvoker& operator=(const ScopedFunctionInvoker&) = delete;
|
||||
|
||||
~ScopedFunctionInvoker() {
|
||||
if (function_) {
|
||||
function_();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const std::function<void()>& function_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
CrashReportUploadThread::CrashReportUploadThread(CrashReportDatabase* database,
|
||||
const std::string& url,
|
||||
const Options& options)
|
||||
CrashReportUploadThread::CrashReportUploadThread(
|
||||
CrashReportDatabase* database,
|
||||
const std::string& url,
|
||||
const Options& options,
|
||||
ProcessPendingReportsObservationCallback callback)
|
||||
: options_(options),
|
||||
callback_(callback),
|
||||
url_(url),
|
||||
// When watching for pending reports, check every 15 minutes, even in the
|
||||
// absence of a signal from the handler thread. This allows for failed
|
||||
@ -105,6 +129,10 @@ void CrashReportUploadThread::ProcessPendingReports() {
|
||||
internal::ScopedBackgroundTask scoper("CrashReportUploadThread");
|
||||
#endif // BUILDFLAG(IS_IOS)
|
||||
|
||||
// If callback_ is non-empty, invoke it when this function returns after
|
||||
// uploads complete (regardless of whether or not that succeeded).
|
||||
ScopedFunctionInvoker scoped_function_invoker(callback_);
|
||||
|
||||
std::vector<UUID> known_report_uuids = known_pending_report_uuids_.Drain();
|
||||
for (const UUID& report_uuid : known_report_uuids) {
|
||||
CrashReportDatabase::Report report;
|
||||
|
@ -15,6 +15,7 @@
|
||||
#ifndef CRASHPAD_HANDLER_CRASH_REPORT_UPLOAD_THREAD_H_
|
||||
#define CRASHPAD_HANDLER_CRASH_REPORT_UPLOAD_THREAD_H_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
@ -63,14 +64,30 @@ class CrashReportUploadThread : public WorkerThread::Delegate,
|
||||
bool watch_pending_reports;
|
||||
};
|
||||
|
||||
//! \brief Observation callback invoked each time the in-process handler
|
||||
//! finishes processing and attempting to upload on-disk crash reports
|
||||
//! (whether or not the uploads succeeded).
|
||||
//!
|
||||
//! This callback is copied into this object. Any references or pointers
|
||||
//! inside must outlive this object.
|
||||
//!
|
||||
//! The callback might be invoked on a background thread, so clients must
|
||||
//! synchronize appropriately.
|
||||
using ProcessPendingReportsObservationCallback = std::function<void()>;
|
||||
|
||||
//! \brief Constructs a new object.
|
||||
//!
|
||||
//! \param[in] database The database to upload crash reports from.
|
||||
//! \param[in] url The URL of the server to upload crash reports to.
|
||||
//! \param[in] options Options for the report uploads.
|
||||
//! \param[in] callback Optional callback invoked zero or more times
|
||||
//! on a background thread each time the this object finishes
|
||||
//! processing and attempting to upload on-disk crash reports.
|
||||
//! If this callback is empty, it is not invoked.
|
||||
CrashReportUploadThread(CrashReportDatabase* database,
|
||||
const std::string& url,
|
||||
const Options& options);
|
||||
const Options& options,
|
||||
ProcessPendingReportsObservationCallback callback);
|
||||
|
||||
CrashReportUploadThread(const CrashReportUploadThread&) = delete;
|
||||
CrashReportUploadThread& operator=(const CrashReportUploadThread&) = delete;
|
||||
@ -207,6 +224,7 @@ class CrashReportUploadThread : public WorkerThread::Delegate,
|
||||
#endif
|
||||
|
||||
const Options options_;
|
||||
const ProcessPendingReportsObservationCallback callback_;
|
||||
const std::string url_;
|
||||
WorkerThread thread_;
|
||||
ThreadSafeVector<UUID> known_pending_report_uuids_;
|
||||
|
@ -1029,7 +1029,10 @@ int HandlerMain(int argc,
|
||||
upload_thread_options.watch_pending_reports = options.periodic_tasks;
|
||||
|
||||
upload_thread.Reset(new CrashReportUploadThread(
|
||||
database.get(), options.url, upload_thread_options));
|
||||
database.get(),
|
||||
options.url,
|
||||
upload_thread_options,
|
||||
CrashReportUploadThread::ProcessPendingReportsObservationCallback()));
|
||||
upload_thread.Get()->Start();
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,11 @@ UIWindow* GetAnyWindow() {
|
||||
{"crashpad", "no"}};
|
||||
}
|
||||
if (client_.StartCrashpadInProcessHandler(
|
||||
GetDatabaseDir(), "", annotations)) {
|
||||
GetDatabaseDir(),
|
||||
"",
|
||||
annotations,
|
||||
crashpad::CrashpadClient::
|
||||
ProcessPendingReportsObservationCallback())) {
|
||||
client_.ProcessIntermediateDumps();
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user