Index: chromecast/crash/minidump_writer.cc |
diff --git a/chromecast/crash/minidump_writer.cc b/chromecast/crash/minidump_writer.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8e2a3c281da0191bc132e5dd51ebf232497e4726 |
--- /dev/null |
+++ b/chromecast/crash/minidump_writer.cc |
@@ -0,0 +1,151 @@ |
+// 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/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/dump_info.h" |
+#include "chromecast/crash/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() { |
+ // 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()) { |
+ 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 |