| Index: chromecast/crash/linux/minidump_writer.cc
|
| diff --git a/chromecast/crash/linux/minidump_writer.cc b/chromecast/crash/linux/minidump_writer.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5d41e9316ce5560086611c15f0e795e0bbe4c112
|
| --- /dev/null
|
| +++ b/chromecast/crash/linux/minidump_writer.cc
|
| @@ -0,0 +1,153 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chromecast/crash/linux/minidump_writer.h"
|
| +
|
| +#include <cerrno>
|
| +#include <cstdlib>
|
| +#include <cstring>
|
| +#include <fstream>
|
| +
|
| +#include "base/logging.h"
|
| +#include "chromecast/base/path_utils.h"
|
| +#include "chromecast/base/process_utils.h"
|
| +#include "chromecast/crash/linux/dump_info.h"
|
| +#include "chromecast/crash/linux/minidump_generator.h"
|
| +
|
| +namespace chromecast {
|
| +
|
| +namespace {
|
| +
|
| +const char kDumpStateSuffix[] = ".txt.gz";
|
| +
|
| +} // namespace
|
| +
|
| +// static
|
| +int MinidumpWriter::DumpState(const std::string& minidump_name) {
|
| + std::vector<std::string> argv;
|
| + argv.push_back(GetBinPathASCII("dumpstate").value());
|
| + argv.push_back("-w");
|
| + argv.push_back("crash-request");
|
| + argv.push_back("-z");
|
| + argv.push_back("-o");
|
| + argv.push_back(
|
| + minidump_name); // dumpstate appends ".txt.gz" to the filename.
|
| +
|
| + std::string log;
|
| + if (!chromecast::GetAppOutput(argv, &log)) {
|
| + LOG(ERROR) << "failed to execute dumpstate";
|
| + return -1;
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +MinidumpWriter::MinidumpWriter(MinidumpGenerator* minidump_generator,
|
| + const std::string& minidump_path,
|
| + const MinidumpParams& params)
|
| + : minidump_generator_(minidump_generator),
|
| + minidump_path_(minidump_path),
|
| + params_(params) {
|
| + max_dumps_ = 5;
|
| + dump_interval_ = 86400;
|
| + max_recent_dumps_ = 5;
|
| + max_total_size_ = 500 * 1024 * 1024;
|
| +}
|
| +
|
| +int MinidumpWriter::DoWork() {
|
| + size_t separator_idx = minidump_path_.find_last_of('/');
|
| + if (separator_idx != std::string::npos) {
|
| + // absolute
|
| + if (dump_path_.compare(minidump_path_.substr(0, separator_idx))) {
|
| + LOG(INFO) << "Given path " << minidump_path_
|
| + << " does not match dump_path " << dump_path_;
|
| + return -1;
|
| + }
|
| + } else {
|
| + // relative
|
| + LOG(ERROR) << "Given path is not absolute";
|
| + return -1;
|
| + }
|
| +
|
| + if (!CanWriteDump()) {
|
| + LOG(INFO) << "Skipping writing of dump due to limits";
|
| + return -1;
|
| + }
|
| +
|
| + if (!minidump_generator_->Generate(minidump_path_)) {
|
| + LOG(ERROR) << "Generate minidump failed " << minidump_path_;
|
| + return -1;
|
| + }
|
| +
|
| + // write the log
|
| + if (DumpState(minidump_path_) < 0) {
|
| + LOG(ERROR) << "Could not dump system log";
|
| + }
|
| +
|
| + // dumpstate appends .txt.gz to the minidump filename, so maintain this as the
|
| + // log name.
|
| + std::string log_str = minidump_path_ + kDumpStateSuffix;
|
| +
|
| + // make a new record in the lock file.
|
| + if (LogLockFile(log_str) < 0) {
|
| + LOG(ERROR) << "lockfile logging failed";
|
| + return -1;
|
| + }
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +bool MinidumpWriter::CanWriteDump() const {
|
| + // Get the current time
|
| + time_t cur_time = time(0);
|
| +
|
| + // Note: since flock is an advisory lock only, it is fine to open the
|
| + // lockfile again by ifstream. We are guaranteed no race conditions
|
| + // because this code is only called upon successful flock.
|
| + std::ifstream in(lockfile_path_.c_str());
|
| + if (!in.is_open()) {
|
| + LOG(ERROR) << "Lockfile: " << lockfile_path_
|
| + << " did not open: " << strerror(errno);
|
| + return false;
|
| + }
|
| +
|
| + std::string record;
|
| + int num_dumps = 0;
|
| + int num_recent_dumps = 0;
|
| + while (std::getline(in, record)) {
|
| + const DumpInfo info(record);
|
| + if (info.valid()) {
|
| + // manual upload entries don't count
|
| + if (info.crashed_process_dump().length() > 0) {
|
| + num_dumps++;
|
| + if (difftime(cur_time, info.dump_time()) <= dump_interval_) {
|
| + num_recent_dumps++;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + in.close();
|
| +
|
| + if (num_dumps >= max_dumps_ || num_recent_dumps >= max_recent_dumps_) {
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +int MinidumpWriter::LogLockFile(const std::string& logfile) {
|
| + // Get the current time
|
| + time_t cur_time = time(NULL);
|
| + const DumpInfo info(minidump_path_, logfile, cur_time, params_);
|
| + if (info.valid()) {
|
| + std::ofstream out(lockfile_path_.c_str(), std::ios::app);
|
| + out << info.entry();
|
| + return 0;
|
| + } else {
|
| + LOG(ERROR) << "entry DumpInfo construction failed";
|
| + return -1;
|
| + }
|
| +}
|
| +
|
| +} // namespace crash_manager
|
|
|