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..5f4016e1c4efc11efee47fb3453cce86e68da7fc |
--- /dev/null |
+++ b/chromecast/crash/linux/minidump_writer.cc |
@@ -0,0 +1,135 @@ |
+// 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 "base/bind.h" |
+#include "base/files/file_util.h" |
+#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"; |
+ |
+const int kDefaultDumpIntervalHours = 24; |
+const int kDefaultMaxDumps = 5; |
+const int kDefaultMaxRecentDumps = 5; |
+ |
+// Fork and run dumpstate, saving results to minidump_name + ".txt.gz". |
+int 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; |
+} |
+ |
+} // namespace |
+ |
+MinidumpWriter::MinidumpWriter(MinidumpGenerator* minidump_generator, |
+ const std::string& minidump_filename, |
+ const MinidumpParams& params, |
+ const DumpStateCallback& dump_state_cb) |
+ : minidump_generator_(minidump_generator), |
+ minidump_path_(minidump_filename), |
+ params_(params), |
+ max_dumps_(kDefaultMaxDumps), |
+ dump_interval_(base::TimeDelta::FromHours(kDefaultDumpIntervalHours)), |
+ max_recent_dumps_(kDefaultMaxRecentDumps), |
+ dump_state_cb_(dump_state_cb) { |
+} |
+ |
+MinidumpWriter::MinidumpWriter(MinidumpGenerator* minidump_generator, |
+ const std::string& minidump_filename, |
+ const MinidumpParams& params) |
+ : MinidumpWriter(minidump_generator, |
+ minidump_filename, |
+ params, |
+ base::Bind(&DumpState)) { |
+} |
+ |
+MinidumpWriter::~MinidumpWriter() { |
+} |
+ |
+int MinidumpWriter::DoWork() { |
+ // If path is not absolute, append it to |dump_path_|. |
+ if (!minidump_path_.value().empty() && minidump_path_.value()[0] != '/') |
+ minidump_path_ = dump_path_.Append(minidump_path_); |
+ |
+ // The path should be a file in the |dump_path_| directory. |
+ if (dump_path_ != minidump_path_.DirName()) { |
+ LOG(INFO) << "The absolute path: " << minidump_path_.value() << " is not" |
+ << "in the correct directory: " << dump_path_.value(); |
+ return -1; |
+ } |
+ |
+ // Query if we are able to write another minidump. |
+ if (!CanWriteDump()) { |
+ LOG(INFO) << "Skipping writing of dump due to limits"; |
+ return -1; |
+ } |
+ |
+ // Generate a minidump at the specified |minidump_path_|. |
+ if (!minidump_generator_->Generate(minidump_path_.value())) { |
+ LOG(ERROR) << "Generate minidump failed " << minidump_path_.value(); |
+ return -1; |
+ } |
+ |
+ // Run the dumpstate callback. |
+ DCHECK(!dump_state_cb_.is_null()); |
+ if (dump_state_cb_.Run(minidump_path_.value()) < 0) { |
+ LOG(ERROR) << "DumpState callback failed."; |
+ return -1; |
+ } |
+ |
+ // Add this entry to the lockfile. |
+ const DumpInfo info(minidump_path_.value(), |
+ minidump_path_.value() + kDumpStateSuffix, |
+ time(NULL), |
+ params_); |
+ if (AddEntryToLockFile(info) < 0) { |
+ LOG(ERROR) << "lockfile logging failed"; |
+ return -1; |
+ } |
+ |
+ return 0; |
+} |
+ |
+bool MinidumpWriter::CanWriteDump() { |
+ const auto& dumps = GetDumpMetadata(); |
+ |
+ // If no more dumps can be written, return false. |
+ if (static_cast<int>(dumps.size()) >= max_dumps_) |
+ return false; |
+ |
+ // If too many dumps have been written recently, return false. |
+ time_t cur_time = time(0); |
+ int recent_dumps = 0; |
+ for (auto dump : dumps) { |
+ if (difftime(cur_time, dump->dump_time()) <= dump_interval_.InSecondsF()) { |
+ if (++recent_dumps >= max_recent_dumps_) |
+ return false; |
+ } |
+ } |
+ |
+ return true; |
+} |
+ |
+} // namespace crash_manager |