2015-01-26 15:59:01 -05:00
|
|
|
|
// Copyright 2015 The Crashpad Authors. All rights reserved.
|
|
|
|
|
//
|
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
|
|
#ifndef CRASHPAD_CLIENT_CRASH_REPORT_DATABASE_H_
|
|
|
|
|
#define CRASHPAD_CLIENT_CRASH_REPORT_DATABASE_H_
|
|
|
|
|
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
2016-04-25 12:13:07 -07:00
|
|
|
|
#include <memory>
|
2015-01-26 15:59:01 -05:00
|
|
|
|
#include <string>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
#include "base/files/file_path.h"
|
2016-01-06 12:22:50 -05:00
|
|
|
|
#include "base/macros.h"
|
2015-01-26 15:59:01 -05:00
|
|
|
|
#include "util/file/file_io.h"
|
2016-09-26 15:06:19 -07:00
|
|
|
|
#include "util/misc/metrics.h"
|
2015-01-26 15:59:01 -05:00
|
|
|
|
#include "util/misc/uuid.h"
|
|
|
|
|
|
|
|
|
|
namespace crashpad {
|
|
|
|
|
|
2015-03-09 18:47:52 -04:00
|
|
|
|
class Settings;
|
|
|
|
|
|
2015-01-26 15:59:01 -05:00
|
|
|
|
//! \brief An interface for managing a collection of crash report files and
|
|
|
|
|
//! metadata associated with the crash reports.
|
|
|
|
|
//!
|
|
|
|
|
//! All Report objects that are returned by this class are logically const.
|
|
|
|
|
//! They are snapshots of the database at the time the query was run, and the
|
|
|
|
|
//! data returned is liable to change after the query is executed.
|
|
|
|
|
//!
|
|
|
|
|
//! The lifecycle of a crash report has three stages:
|
|
|
|
|
//!
|
|
|
|
|
//! 1. New: A crash report is created with PrepareNewCrashReport(), the
|
|
|
|
|
//! the client then writes the report, and then calls
|
|
|
|
|
//! FinishedWritingCrashReport() to make the report Pending.
|
|
|
|
|
//! 2. Pending: The report has been written but has not been locally
|
2016-08-24 15:37:46 -04:00
|
|
|
|
//! processed, or it was has been brought back from 'Completed' state by
|
|
|
|
|
//! user request.
|
2015-01-26 15:59:01 -05:00
|
|
|
|
//! 3. Completed: The report has been locally processed, either by uploading
|
|
|
|
|
//! it to a collection server and calling RecordUploadAttempt(), or by
|
|
|
|
|
//! calling SkipReportUpload().
|
|
|
|
|
class CrashReportDatabase {
|
|
|
|
|
public:
|
|
|
|
|
//! \brief A crash report record.
|
|
|
|
|
//!
|
|
|
|
|
//! This represents the metadata for a crash report, as well as the location
|
|
|
|
|
//! of the report itself. A CrashReportDatabase maintains at least this
|
|
|
|
|
//! information.
|
|
|
|
|
struct Report {
|
|
|
|
|
Report();
|
|
|
|
|
|
|
|
|
|
//! A unique identifier by which this report will always be known to the
|
|
|
|
|
//! database.
|
|
|
|
|
UUID uuid;
|
|
|
|
|
|
|
|
|
|
//! The current location of the crash report on the client’s filesystem.
|
|
|
|
|
//! The location of a crash report may change over time, so the UUID should
|
|
|
|
|
//! be used as the canonical identifier.
|
|
|
|
|
base::FilePath file_path;
|
|
|
|
|
|
|
|
|
|
//! An identifier issued to this crash report by a collection server.
|
|
|
|
|
std::string id;
|
|
|
|
|
|
|
|
|
|
//! The time at which the report was generated.
|
|
|
|
|
time_t creation_time;
|
|
|
|
|
|
|
|
|
|
//! Whether this crash report was successfully uploaded to a collection
|
|
|
|
|
//! server.
|
|
|
|
|
bool uploaded;
|
|
|
|
|
|
|
|
|
|
//! The last timestamp at which an attempt was made to submit this crash
|
|
|
|
|
//! report to a collection server. If this is zero, then the report has
|
|
|
|
|
//! never been uploaded. If #uploaded is true, then this timestamp is the
|
|
|
|
|
//! time at which the report was uploaded, and no other attempts to upload
|
|
|
|
|
//! this report will be made.
|
|
|
|
|
time_t last_upload_attempt_time;
|
|
|
|
|
|
|
|
|
|
//! The number of times an attempt was made to submit this report to
|
|
|
|
|
//! a collection server. If this is more than zero, then
|
|
|
|
|
//! #last_upload_attempt_time will be set to the timestamp of the most
|
|
|
|
|
//! recent attempt.
|
|
|
|
|
int upload_attempts;
|
2016-08-24 15:37:46 -04:00
|
|
|
|
|
|
|
|
|
//! Whether this crash report was explicitly requested by user to be
|
|
|
|
|
//! uploaded. This can be true only if report is in the 'pending' state.
|
|
|
|
|
bool upload_explicitly_requested;
|
2015-01-26 15:59:01 -05:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//! \brief A crash report that is in the process of being written.
|
|
|
|
|
//!
|
|
|
|
|
//! An instance of this struct should be created via PrepareNewCrashReport()
|
|
|
|
|
//! and destroyed with FinishedWritingCrashReport().
|
|
|
|
|
struct NewReport {
|
|
|
|
|
//! The file handle to which the report should be written.
|
|
|
|
|
FileHandle handle;
|
|
|
|
|
|
2015-03-13 13:00:56 -04:00
|
|
|
|
//! A unique identifier by which this report will always be known to the
|
|
|
|
|
//! database.
|
|
|
|
|
UUID uuid;
|
|
|
|
|
|
2015-01-26 15:59:01 -05:00
|
|
|
|
//! The path to the crash report being written.
|
|
|
|
|
base::FilePath path;
|
|
|
|
|
};
|
|
|
|
|
|
2015-04-03 18:57:01 -04:00
|
|
|
|
//! \brief A scoper to cleanly handle the interface requirement imposed by
|
|
|
|
|
//! PrepareNewCrashReport().
|
|
|
|
|
//!
|
|
|
|
|
//! Calls ErrorWritingCrashReport() upon destruction unless disarmed by
|
|
|
|
|
//! calling Disarm(). Armed upon construction.
|
|
|
|
|
class CallErrorWritingCrashReport {
|
|
|
|
|
public:
|
|
|
|
|
//! \brief Arms the object to call ErrorWritingCrashReport() on \a database
|
|
|
|
|
//! with an argument of \a new_report on destruction.
|
|
|
|
|
CallErrorWritingCrashReport(CrashReportDatabase* database,
|
|
|
|
|
NewReport* new_report);
|
|
|
|
|
|
|
|
|
|
//! \brief Calls ErrorWritingCrashReport() if the object is armed.
|
|
|
|
|
~CallErrorWritingCrashReport();
|
|
|
|
|
|
|
|
|
|
//! \brief Disarms the object so that CallErrorWritingCrashReport() will not
|
|
|
|
|
//! be called upon destruction.
|
|
|
|
|
void Disarm();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
CrashReportDatabase* database_; // weak
|
|
|
|
|
NewReport* new_report_; // weak
|
|
|
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(CallErrorWritingCrashReport);
|
|
|
|
|
};
|
|
|
|
|
|
2015-01-26 15:59:01 -05:00
|
|
|
|
//! \brief The result code for operations performed on a database.
|
|
|
|
|
enum OperationStatus {
|
|
|
|
|
//! \brief No error occurred.
|
|
|
|
|
kNoError = 0,
|
|
|
|
|
|
|
|
|
|
//! \brief The report that was requested could not be located.
|
2017-04-13 10:12:28 -04:00
|
|
|
|
//!
|
|
|
|
|
//! This may occur when the report is present in the database but not in a
|
|
|
|
|
//! state appropriate for the requested operation, for example, if
|
|
|
|
|
//! GetReportForUploading() is called to obtain report that’s already in the
|
|
|
|
|
//! completed state.
|
2015-01-26 15:59:01 -05:00
|
|
|
|
kReportNotFound,
|
|
|
|
|
|
|
|
|
|
//! \brief An error occured while performing a file operation on a crash
|
|
|
|
|
//! report.
|
|
|
|
|
//!
|
|
|
|
|
//! A database is responsible for managing both the metadata about a report
|
|
|
|
|
//! and the actual crash report itself. This error is returned when an
|
|
|
|
|
//! error occurred when managing the report file. Additional information
|
|
|
|
|
//! will be logged.
|
|
|
|
|
kFileSystemError,
|
|
|
|
|
|
2015-03-10 12:22:31 -04:00
|
|
|
|
//! \brief An error occured while recording metadata for a crash report or
|
|
|
|
|
//! database-wide settings.
|
2015-01-26 15:59:01 -05:00
|
|
|
|
//!
|
|
|
|
|
//! A database is responsible for managing both the metadata about a report
|
|
|
|
|
//! and the actual crash report itself. This error is returned when an
|
2015-03-10 12:22:31 -04:00
|
|
|
|
//! error occurred when managing the metadata about a crash report or
|
|
|
|
|
//! database-wide settings. Additional information will be logged.
|
2015-01-26 15:59:01 -05:00
|
|
|
|
kDatabaseError,
|
|
|
|
|
|
|
|
|
|
//! \brief The operation could not be completed because a concurrent
|
|
|
|
|
//! operation affecting the report is occurring.
|
|
|
|
|
kBusyError,
|
2016-08-24 15:37:46 -04:00
|
|
|
|
|
|
|
|
|
//! \brief The report cannot be uploaded by user request as it has already
|
|
|
|
|
//! been uploaded.
|
|
|
|
|
kCannotRequestUpload,
|
2015-01-26 15:59:01 -05:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
virtual ~CrashReportDatabase() {}
|
|
|
|
|
|
2015-10-08 13:10:02 -04:00
|
|
|
|
//! \brief Opens a database of crash reports, possibly creating it.
|
2015-01-26 15:59:01 -05:00
|
|
|
|
//!
|
2015-10-08 13:10:02 -04:00
|
|
|
|
//! \param[in] path A path to the database to be created or opened. If the
|
|
|
|
|
//! database does not yet exist, it will be created if possible. Note that
|
|
|
|
|
//! for databases implemented as directory structures, existence refers
|
|
|
|
|
//! solely to the outermost directory.
|
2015-01-26 15:59:01 -05:00
|
|
|
|
//!
|
|
|
|
|
//! \return A database object on success, `nullptr` on failure with an error
|
|
|
|
|
//! logged.
|
2015-10-08 13:10:02 -04:00
|
|
|
|
//!
|
|
|
|
|
//! \sa InitializeWithoutCreating
|
2016-04-25 12:13:07 -07:00
|
|
|
|
static std::unique_ptr<CrashReportDatabase> Initialize(
|
|
|
|
|
const base::FilePath& path);
|
2015-01-26 15:59:01 -05:00
|
|
|
|
|
2015-10-08 13:10:02 -04:00
|
|
|
|
//! \brief Opens an existing database of crash reports.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[in] path A path to the database to be opened. If the database does
|
|
|
|
|
//! not yet exist, it will not be created. Note that for databases
|
|
|
|
|
//! implemented as directory structures, existence refers solely to the
|
|
|
|
|
//! outermost directory. On such databases, as long as the outermost
|
|
|
|
|
//! directory is present, this method will create the inner structure.
|
|
|
|
|
//!
|
|
|
|
|
//! \return A database object on success, `nullptr` on failure with an error
|
|
|
|
|
//! logged.
|
|
|
|
|
//!
|
|
|
|
|
//! \sa Initialize
|
2016-04-25 12:13:07 -07:00
|
|
|
|
static std::unique_ptr<CrashReportDatabase> InitializeWithoutCreating(
|
2015-10-08 13:10:02 -04:00
|
|
|
|
const base::FilePath& path);
|
|
|
|
|
|
2015-03-09 18:47:52 -04:00
|
|
|
|
//! \brief Returns the Settings object for this database.
|
|
|
|
|
//!
|
|
|
|
|
//! \return A weak pointer to the Settings object, which is owned by the
|
|
|
|
|
//! database.
|
|
|
|
|
virtual Settings* GetSettings() = 0;
|
|
|
|
|
|
2015-01-26 15:59:01 -05:00
|
|
|
|
//! \brief Creates a record of a new crash report.
|
|
|
|
|
//!
|
|
|
|
|
//! Callers can then write the crash report using the file handle provided.
|
2015-04-03 18:57:01 -04:00
|
|
|
|
//! The caller does not own the new crash report record or its file handle,
|
|
|
|
|
//! both of which must be explicitly disposed of by calling
|
2015-02-04 16:33:15 -05:00
|
|
|
|
//! FinishedWritingCrashReport() or ErrorWritingCrashReport().
|
2015-01-26 15:59:01 -05:00
|
|
|
|
//!
|
2015-04-03 18:57:01 -04:00
|
|
|
|
//! To arrange to call ErrorWritingCrashReport() during any early return, use
|
|
|
|
|
//! CallErrorWritingCrashReport.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[out] report A NewReport object containing a file handle to which
|
|
|
|
|
//! the crash report data should be written. Only valid if this returns
|
|
|
|
|
//! #kNoError. The caller must not delete the NewReport object or close
|
|
|
|
|
//! the file handle within.
|
2015-01-26 15:59:01 -05:00
|
|
|
|
//!
|
|
|
|
|
//! \return The operation status code.
|
|
|
|
|
virtual OperationStatus PrepareNewCrashReport(NewReport** report) = 0;
|
|
|
|
|
|
|
|
|
|
//! \brief Informs the database that a crash report has been written.
|
|
|
|
|
//!
|
|
|
|
|
//! After calling this method, the database is permitted to move and rename
|
2015-02-04 16:33:15 -05:00
|
|
|
|
//! the file at NewReport::path.
|
2015-01-26 15:59:01 -05:00
|
|
|
|
//!
|
2015-04-03 18:57:01 -04:00
|
|
|
|
//! \param[in] report A NewReport obtained with PrepareNewCrashReport(). The
|
|
|
|
|
//! NewReport object and file handle within will be invalidated as part of
|
|
|
|
|
//! this call.
|
2015-01-26 15:59:01 -05:00
|
|
|
|
//! \param[out] uuid The UUID of this crash report.
|
|
|
|
|
//!
|
|
|
|
|
//! \return The operation status code.
|
|
|
|
|
virtual OperationStatus FinishedWritingCrashReport(NewReport* report,
|
|
|
|
|
UUID* uuid) = 0;
|
|
|
|
|
|
2015-02-04 16:33:15 -05:00
|
|
|
|
//! \brief Informs the database that an error occurred while attempting to
|
|
|
|
|
//! write a crash report, and that any resources associated with it should
|
|
|
|
|
//! be cleaned up.
|
|
|
|
|
//!
|
|
|
|
|
//! After calling this method, the database is permitted to remove the file at
|
|
|
|
|
//! NewReport::path.
|
|
|
|
|
//!
|
2015-04-03 18:57:01 -04:00
|
|
|
|
//! \param[in] report A NewReport obtained with PrepareNewCrashReport(). The
|
|
|
|
|
//! NewReport object and file handle within will be invalidated as part of
|
|
|
|
|
//! this call.
|
2015-02-04 16:33:15 -05:00
|
|
|
|
//!
|
|
|
|
|
//! \return The operation status code.
|
|
|
|
|
virtual OperationStatus ErrorWritingCrashReport(NewReport* report) = 0;
|
|
|
|
|
|
2015-01-26 15:59:01 -05:00
|
|
|
|
//! \brief Returns the crash report record for the unique identifier.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[in] uuid The crash report record unique identifier.
|
|
|
|
|
//! \param[out] report A crash report record. Only valid if this returns
|
|
|
|
|
//! #kNoError.
|
|
|
|
|
//!
|
|
|
|
|
//! \return The operation status code.
|
|
|
|
|
virtual OperationStatus LookUpCrashReport(const UUID& uuid,
|
|
|
|
|
Report* report) = 0;
|
|
|
|
|
|
|
|
|
|
//! \brief Returns a list of crash report records that have not been uploaded.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[out] reports A list of crash report record objects. This must be
|
|
|
|
|
//! empty on entry. Only valid if this returns #kNoError.
|
|
|
|
|
//!
|
|
|
|
|
//! \return The operation status code.
|
2015-03-06 18:43:28 -05:00
|
|
|
|
virtual OperationStatus GetPendingReports(std::vector<Report>* reports) = 0;
|
2015-01-26 15:59:01 -05:00
|
|
|
|
|
|
|
|
|
//! \brief Returns a list of crash report records that have been completed,
|
|
|
|
|
//! either by being uploaded or by skipping upload.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[out] reports A list of crash report record objects. This must be
|
|
|
|
|
//! empty on entry. Only valid if this returns #kNoError.
|
|
|
|
|
//!
|
|
|
|
|
//! \return The operation status code.
|
2015-03-06 18:43:28 -05:00
|
|
|
|
virtual OperationStatus GetCompletedReports(std::vector<Report>* reports) = 0;
|
2015-01-26 15:59:01 -05:00
|
|
|
|
|
|
|
|
|
//! \brief Obtains a report object for uploading to a collection server.
|
|
|
|
|
//!
|
|
|
|
|
//! The file at Report::file_path should be uploaded by the caller, and then
|
|
|
|
|
//! the returned Report object must be disposed of via a call to
|
|
|
|
|
//! RecordUploadAttempt().
|
|
|
|
|
//!
|
|
|
|
|
//! A subsequent call to this method with the same \a uuid is illegal until
|
|
|
|
|
//! RecordUploadAttempt() has been called.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[in] uuid The unique identifier for the crash report record.
|
|
|
|
|
//! \param[out] report A crash report record for the report to be uploaded.
|
|
|
|
|
//! The caller does not own this object. Only valid if this returns
|
|
|
|
|
//! #kNoError.
|
|
|
|
|
//!
|
|
|
|
|
//! \return The operation status code.
|
|
|
|
|
virtual OperationStatus GetReportForUploading(const UUID& uuid,
|
|
|
|
|
const Report** report) = 0;
|
|
|
|
|
|
|
|
|
|
//! \brief Adjusts a crash report record’s metadata to account for an upload
|
2015-03-10 12:22:31 -04:00
|
|
|
|
//! attempt, and updates the last upload attempt time as returned by
|
|
|
|
|
//! Settings::GetLastUploadAttemptTime().
|
2015-01-26 15:59:01 -05:00
|
|
|
|
//!
|
|
|
|
|
//! After calling this method, the database is permitted to move and rename
|
|
|
|
|
//! the file at Report::file_path.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[in] report The report object obtained from
|
|
|
|
|
//! GetReportForUploading(). This object is invalidated after this call.
|
|
|
|
|
//! \param[in] successful Whether the upload attempt was successful.
|
|
|
|
|
//! \param[in] id The identifier assigned to this crash report by the
|
|
|
|
|
//! collection server. Must be empty if \a successful is `false`; may be
|
|
|
|
|
//! empty if it is `true`.
|
|
|
|
|
//!
|
|
|
|
|
//! \return The operation status code.
|
|
|
|
|
virtual OperationStatus RecordUploadAttempt(const Report* report,
|
|
|
|
|
bool successful,
|
|
|
|
|
const std::string& id) = 0;
|
|
|
|
|
|
|
|
|
|
//! \brief Moves a report from the pending state to the completed state, but
|
|
|
|
|
//! without the report being uploaded.
|
|
|
|
|
//!
|
|
|
|
|
//! This can be used if the user has disabled crash report collection, but
|
|
|
|
|
//! crash generation is still enabled in the product.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[in] uuid The unique identifier for the crash report record.
|
2016-09-26 15:06:19 -07:00
|
|
|
|
//! \param[in] reason The reason the report upload is being skipped for
|
|
|
|
|
//! metrics tracking purposes.
|
2015-01-26 15:59:01 -05:00
|
|
|
|
//!
|
|
|
|
|
//! \return The operation status code.
|
2016-09-26 15:06:19 -07:00
|
|
|
|
virtual OperationStatus SkipReportUpload(
|
|
|
|
|
const UUID& uuid,
|
|
|
|
|
Metrics::CrashSkippedReason reason) = 0;
|
2015-01-26 15:59:01 -05:00
|
|
|
|
|
2015-10-07 17:01:47 -04:00
|
|
|
|
//! \brief Deletes a crash report file and its associated metadata.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[in] uuid The UUID of the report to delete.
|
|
|
|
|
//!
|
|
|
|
|
//! \return The operation status code.
|
|
|
|
|
virtual OperationStatus DeleteReport(const UUID& uuid) = 0;
|
|
|
|
|
|
2016-08-24 15:37:46 -04:00
|
|
|
|
//! \brief Marks a crash report as explicitly requested to be uploaded by the
|
|
|
|
|
//! user and moves it to 'pending' state.
|
|
|
|
|
//!
|
|
|
|
|
//! \param[in] uuid The unique identifier for the crash report record.
|
|
|
|
|
//!
|
|
|
|
|
//! \return The operation status code.
|
|
|
|
|
virtual OperationStatus RequestUpload(const UUID& uuid) = 0;
|
|
|
|
|
|
2015-01-26 15:59:01 -05:00
|
|
|
|
protected:
|
|
|
|
|
CrashReportDatabase() {}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(CrashReportDatabase);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace crashpad
|
|
|
|
|
|
|
|
|
|
#endif // CRASHPAD_CLIENT_CRASH_REPORT_DATABASE_H_
|