Add CrashReportDatabase::ErrorWritingCrashReport().

A crash handler needs a way to clean up after itself it it calls
CrashReportDatabase::PrepareCrashReport() to begin writing a new crash
report, but then encounters an error that renders the crash report
unusable. The new ErrorWritingCrashReport() method allows it to
communicate to the database that a previously-prepared crash report
should be removed without ever being promoted to a completed report
pending upload.

TEST=client_test CrashReportDatabaseTest.ErrorWritingCrashReport
R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/904533002
This commit is contained in:
Mark Mentovai 2015-02-04 16:33:15 -05:00
parent 2289339777
commit 5d0050dee7
3 changed files with 46 additions and 2 deletions

View File

@ -145,7 +145,7 @@ class CrashReportDatabase {
//!
//! Callers can then write the crash report using the file handle provided.
//! The caller does not own this handle, and it must be explicitly closed with
//! FinishedWritingCrashReport().
//! FinishedWritingCrashReport() or ErrorWritingCrashReport().
//!
//! \param[out] report A file handle to which the crash report data should be
//! written. Only valid if this returns #kNoError. The caller must not
@ -157,7 +157,7 @@ class CrashReportDatabase {
//! \brief Informs the database that a crash report has been written.
//!
//! After calling this method, the database is permitted to move and rename
//! the file at Report::file_path.
//! the file at NewReport::path.
//!
//! \param[in] report A handle obtained with PrepareNewCrashReport(). The
//! handle will be invalidated as part of this call.
@ -167,6 +167,19 @@ class CrashReportDatabase {
virtual OperationStatus FinishedWritingCrashReport(NewReport* report,
UUID* uuid) = 0;
//! \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.
//!
//! \param[in] report A handle obtained with PrepareNewCrashReport(). The
//! handle will be invalidated as part of this call.
//!
//! \return The operation status code.
virtual OperationStatus ErrorWritingCrashReport(NewReport* report) = 0;
//! \brief Returns the crash report record for the unique identifier.
//!
//! \param[in] uuid The crash report record unique identifier.

View File

@ -109,6 +109,7 @@ class CrashReportDatabaseMac : public CrashReportDatabase {
OperationStatus PrepareNewCrashReport(NewReport** report) override;
OperationStatus FinishedWritingCrashReport(NewReport* report,
UUID* uuid) override;
OperationStatus ErrorWritingCrashReport(NewReport* report) override;
OperationStatus LookUpCrashReport(const UUID& uuid,
Report* report) override;
OperationStatus GetPendingReports(
@ -279,6 +280,24 @@ CrashReportDatabaseMac::FinishedWritingCrashReport(NewReport* report,
return kNoError;
}
CrashReportDatabase::OperationStatus
CrashReportDatabaseMac::ErrorWritingCrashReport(NewReport* report) {
// Takes ownership of the |handle| and the O_EXLOCK.
base::ScopedFD lock(report->handle);
// Take ownership of the report.
scoped_ptr<NewReport> scoped_report(report);
// Remove the file that the report would have been written to had no error
// occurred.
if (unlink(report->path.value().c_str()) != 0) {
PLOG(ERROR) << "unlink " << report->path.value();
return kFileSystemError;
}
return kNoError;
}
CrashReportDatabase::OperationStatus
CrashReportDatabaseMac::LookUpCrashReport(const UUID& uuid,
CrashReportDatabase::Report* report) {

View File

@ -133,6 +133,7 @@ TEST_F(CrashReportDatabaseTest, NewCrashReport) {
CrashReportDatabase::NewReport* new_report;
EXPECT_EQ(CrashReportDatabase::kNoError,
db()->PrepareNewCrashReport(&new_report));
EXPECT_TRUE(FileExistsAtPath(new_report->path)) << new_report->path.value();
UUID uuid;
EXPECT_EQ(CrashReportDatabase::kNoError,
db()->FinishedWritingCrashReport(new_report, &uuid));
@ -154,6 +155,17 @@ TEST_F(CrashReportDatabaseTest, NewCrashReport) {
EXPECT_TRUE(reports.empty());
}
TEST_F(CrashReportDatabaseTest, ErrorWritingCrashReport) {
CrashReportDatabase::NewReport* new_report;
EXPECT_EQ(CrashReportDatabase::kNoError,
db()->PrepareNewCrashReport(&new_report));
base::FilePath new_report_path = new_report->path;
EXPECT_TRUE(FileExistsAtPath(new_report_path)) << new_report_path.value();
EXPECT_EQ(CrashReportDatabase::kNoError,
db()->ErrorWritingCrashReport(new_report));
EXPECT_FALSE(FileExistsAtPath(new_report_path)) << new_report_path.value();
}
TEST_F(CrashReportDatabaseTest, LookUpCrashReport) {
UUID uuid;