blob: 492d466239d1ad35410bf4fe8608f6ee9e8df21e [file] [log] [blame]
// 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.
#include "client/prune_crash_reports.h"
#include <sys/stat.h>
#include <stdint.h>
#include <algorithm>
#include <vector>
#include "base/logging.h"
#include "base/notreached.h"
#include "build/build_config.h"
namespace crashpad {
size_t PruneCrashReportDatabase(CrashReportDatabase* database,
PruneCondition* condition) {
std::vector<CrashReportDatabase::Report> all_reports;
CrashReportDatabase::OperationStatus status;
status = database->GetPendingReports(&all_reports);
if (status != CrashReportDatabase::kNoError) {
LOG(ERROR) << "PruneCrashReportDatabase: Failed to get pending reports";
return 0;
}
std::vector<CrashReportDatabase::Report> completed_reports;
status = database->GetCompletedReports(&completed_reports);
if (status != CrashReportDatabase::kNoError) {
LOG(ERROR) << "PruneCrashReportDatabase: Failed to get completed reports";
return 0;
}
all_reports.insert(all_reports.end(), completed_reports.begin(),
completed_reports.end());
std::sort(all_reports.begin(), all_reports.end(),
[](const CrashReportDatabase::Report& lhs,
const CrashReportDatabase::Report& rhs) {
return lhs.creation_time > rhs.creation_time;
});
size_t num_pruned = 0;
for (const auto& report : all_reports) {
if (condition->ShouldPruneReport(report)) {
status = database->DeleteReport(report.uuid);
if (status != CrashReportDatabase::kNoError) {
LOG(ERROR) << "Database Pruning: Failed to remove report "
<< report.uuid.ToString();
} else {
num_pruned++;
}
}
}
return num_pruned;
// TODO(rsesek): For databases that do not use a directory structure, it is
// possible for the metadata sidecar to become corrupted and thus leave
// orphaned crash report files on-disk. https://crashpad.chromium.org/bug/66
}
// static
std::unique_ptr<PruneCondition> PruneCondition::GetDefault() {
// DatabaseSizePruneCondition must be the LHS so that it is always evaluated,
// due to the short-circuting behavior of BinaryPruneCondition.
return std::make_unique<BinaryPruneCondition>(
BinaryPruneCondition::OR,
new DatabaseSizePruneCondition(1024 * 128),
new AgePruneCondition(365));
}
static const time_t kSecondsInDay = 60 * 60 * 24;
AgePruneCondition::AgePruneCondition(int max_age_in_days)
: oldest_report_time_(
((time(nullptr) - (max_age_in_days * kSecondsInDay))
/ kSecondsInDay) * kSecondsInDay) {}
AgePruneCondition::~AgePruneCondition() {}
bool AgePruneCondition::ShouldPruneReport(
const CrashReportDatabase::Report& report) {
return report.creation_time < oldest_report_time_;
}
DatabaseSizePruneCondition::DatabaseSizePruneCondition(size_t max_size_in_kb)
: max_size_in_kb_(max_size_in_kb), measured_size_in_kb_(0) {}
DatabaseSizePruneCondition::~DatabaseSizePruneCondition() {}
bool DatabaseSizePruneCondition::ShouldPruneReport(
const CrashReportDatabase::Report& report) {
// Round up fractional KB to the next 1-KB boundary.
measured_size_in_kb_ +=
static_cast<size_t>((report.total_size + 1023) / 1024);
return measured_size_in_kb_ > max_size_in_kb_;
}
BinaryPruneCondition::BinaryPruneCondition(
Operator op, PruneCondition* lhs, PruneCondition* rhs)
: op_(op), lhs_(lhs), rhs_(rhs) {}
BinaryPruneCondition::~BinaryPruneCondition() {}
bool BinaryPruneCondition::ShouldPruneReport(
const CrashReportDatabase::Report& report) {
switch (op_) {
case AND:
return lhs_->ShouldPruneReport(report) && rhs_->ShouldPruneReport(report);
case OR:
return lhs_->ShouldPruneReport(report) || rhs_->ShouldPruneReport(report);
default:
NOTREACHED();
return false;
}
}
} // namespace crashpad