| // Copyright 2018 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CRASH_REPORTER_CRASH_SENDER_UTIL_H_ |
| #define CRASH_REPORTER_CRASH_SENDER_UTIL_H_ |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/files/file.h> |
| #include <base/files/file_path.h> |
| #include <base/optional.h> |
| #include <base/time/clock.h> |
| #include <base/time/time.h> |
| #include <base/values.h> |
| #include <brillo/http/http_form_data.h> |
| #include <gtest/gtest_prod.h> // for FRIEND_TEST |
| #include <metrics/metrics_library.h> |
| #include <session_manager/dbus-proxies.h> |
| #include <shill/dbus-proxies.h> |
| |
| #include "crash-reporter/crash_sender_base.h" |
| |
| namespace util { |
| |
| // Maximum crashes to send per 24 hours. |
| constexpr int kMaxCrashRate = 32; |
| |
| // Maximum bytes of crash reports to send per 24 hours. Note that "whichever |
| // comes last" maximum with kMaxCrashRate; that is, we'll always send 32 crashes |
| // per 24 hours, even if that exceeds 24MB, and we'll always send 24MB per 24 |
| // hours, even if that exceeds 32 crashes. |
| constexpr int kMaxCrashBytes = 24 * 1024 * 1024; |
| |
| // Maximum time to sleep before attempting to send a crash report. This value is |
| // inclusive as an upper bound, thus 0 means a crash report can be sent |
| // immediately. |
| constexpr int kMaxSpreadTimeInSeconds = 600; |
| |
| // Parsed command line flags. |
| struct CommandLineFlags { |
| base::TimeDelta max_spread_time; |
| std::string crash_directory; |
| bool ignore_rate_limits = false; |
| bool ignore_hold_off_time = false; |
| bool allow_dev_sending = false; |
| bool ignore_pause_file = false; |
| bool test_mode = false; |
| bool upload_old_reports = false; |
| }; |
| |
| // Represents a metadata file name, and its parsed metadata. |
| typedef std::pair<base::FilePath, CrashInfo> MetaFile; |
| |
| // Parses the command line, and handles the command line flags. |
| // |
| // On error, the process exits as a failure with an error message for the |
| // first-encountered error. |
| void ParseCommandLine(int argc, |
| const char* const* argv, |
| CommandLineFlags* flags); |
| |
| // Returns true if the marker file exists indicating we should pause sending. |
| // This can be overridden with a command line flag to the program. |
| bool DoesPauseFileExist(); |
| |
| // Gets the base part of a crash report file, such as name.01234.5678.9012 from |
| // name.01234.5678.9012.meta or name.01234.5678.9012.log.tar.xz. We make sure |
| // "name" is sanitized in CrashCollector::Sanitize to not include any periods. |
| // The directory part will be preserved. |
| base::FilePath GetBasePartOfCrashFile(const base::FilePath& file_name); |
| |
| // Removes orphaned files in |crash_dir|, that are files 24 hours old or older, |
| // without corresponding meta file. |
| void RemoveOrphanedCrashFiles(const base::FilePath& crash_dir); |
| |
| // Sort the vector of crash reports so that the report we want to send first |
| // is at the front of the vector. |
| void SortReports(std::vector<MetaFile>* reports); |
| |
| // Returns the list of meta data files (files with ".meta" suffix), sorted by |
| // the timestamp in the old-to-new order. |
| std::vector<base::FilePath> GetMetaFiles(const base::FilePath& crash_dir); |
| |
| // Returns true if the metadata indicates that the crash was already uploaded. |
| bool IsAlreadyUploaded(const base::FilePath& meta_file); |
| |
| // Returns true if the given timestamp file is new enough, indicating that there |
| // was a recent attempt to send a crash report. |
| bool IsTimestampNewEnough(const base::FilePath& timestamp_file); |
| |
| // Returns true if sending a crash report now does not exceed |max_crash_rate| |
| // crashes and |max_crash_bytes| bytes per 24 hours. |
| // |
| // |timestamps_dir| contains the state files indicating how many sends have |
| // happened and how big they were. |
| bool IsBelowRate(const base::FilePath& timestamps_dir, |
| int max_crash_rate, |
| int max_crash_bytes); |
| |
| // Records a crash send attempt so that IsBelowRate knows about it. |
| // |timestamps_dir| should be the same directory passed to IsBelowRate(). |
| // |bytes| is the number of bytes sent over the network. |
| void RecordSendAttempt(const base::FilePath& timestamps_dir, int bytes); |
| |
| // A helper class for sending crashes. The behaviors can be customized with |
| // Options class for unit testing. |
| // |
| // Crash reports will be sent even when the device is on a mobile data |
| // connection (see crbug.com/185110 for discussion). |
| class Sender : public SenderBase { |
| public: |
| struct Options : SenderBase::Options { |
| // Shill FlimFlam Manager proxy interface for determining network state. |
| org::chromium::flimflam::ManagerProxyInterface* shill_proxy = nullptr; |
| |
| // Maximum crashes to send per 24 hours. (We'll send more if still below |
| // max_crash_bytes.) |
| int max_crash_rate = kMaxCrashRate; |
| |
| // Maximum bytes we will upload per 24 hours. (We'll send more if still |
| // below max_crash_rate.) |
| int max_crash_bytes = kMaxCrashBytes; |
| |
| // Maximum time to sleep before attempting to send. |
| base::TimeDelta max_spread_time; |
| |
| // Boundary to use in the form data. |
| std::string form_data_boundary; |
| |
| // If true, we will ignore other checks when deciding if we should write to |
| // the Chrome uploads.log file. |
| bool always_write_uploads_log = false; |
| |
| // If true, we allow sending crash reports for unofficial test images and |
| // the reports are uploaded to a staging crash server instead. |
| bool allow_dev_sending = false; |
| |
| // If true, just log the kTestModeSuccessful message if the crash report |
| // looks legible instead of actually uploading it. |
| bool test_mode = false; |
| |
| // If true, ignore timestamp check and upload old reports. |
| bool upload_old_reports = false; |
| }; |
| |
| Sender(std::unique_ptr<MetricsLibraryInterface> metrics_lib, |
| std::unique_ptr<base::Clock> clock, |
| const Options& options); |
| |
| // Chooses an action to take for the crash report associated with the given |
| // meta file, and reports the reason. The crash information will be stored in |
| // |info| for reuse. |
| SenderBase::Action ChooseAction(const base::FilePath& meta_file, |
| std::string* reason, |
| CrashInfo* info); |
| |
| // Removes invalid files in |crash_dir|, that are unknown, corrupted, or |
| // invalid in other ways, and picks crash reports that should be sent to the |
| // server. The meta files of the latter will be stored in |to_send|. |
| void RemoveAndPickCrashFiles(const base::FilePath& directory, |
| std::vector<MetaFile>* reports_to_send); |
| |
| // Sends each crash in |crash_meta_files|, in multiple steps: |
| // |
| // For each meta file: |
| // - Sleeps to avoid overloading the network |
| // - Checks if the device enters guest mode, and stops if entered. |
| // - Enforces the rate limit per 24 hours. |
| // - Removes crash files that are successfully uploaded. |
| // |total_sleep_time|: if nonnull, set to the total amount of time sleeping. |
| void SendCrashes(const std::vector<MetaFile>& crash_meta_files, |
| base::TimeDelta* total_sleep_time); |
| |
| // Given the |details| for a crash, creates a brillo::http::FormData object |
| // which will have all of the fields for submission to the crash server |
| // populated. Returns a nullptr if there were critical errors in populating |
| // the data. This also logs out all of the details during the process. On |
| // success, |product_name_out| is also set to the product name (it's not |
| // possible to extract data from the returned FormData object in a |
| // non-destructive manner). |
| std::unique_ptr<brillo::http::FormData> CreateCrashFormData( |
| const CrashDetails& details, std::string* product_name_out); |
| |
| private: |
| friend class IsNetworkOnlineTest; |
| FRIEND_TEST(CrashSenderUtilTest, RemoveReportFiles); |
| FRIEND_TEST(CrashSenderUtilTest, FailRemoveReportFilesSendsMetric); |
| |
| // Removes report files associated with the given meta file. |
| // More specifically, if "foo.meta" is given, "foo.*" will be removed. |
| void RemoveReportFiles(const base::FilePath& meta_file); |
| |
| // Send the specified reason for removing a crash to UMA. |
| void RecordCrashRemoveReason(SenderBase::CrashRemoveReason reason) override; |
| |
| // Creates a JSON entity with the required fields for uploads.log file. |
| std::unique_ptr<base::Value> CreateJsonEntity(const std::string& report_id, |
| const std::string& product_name, |
| const CrashDetails& details); |
| |
| // Requests to send a crash report represented with the given crash details. |
| bool RequestToSendCrash(const CrashDetails& details); |
| |
| // Returns true if we have consent to send crashes to Google. |
| bool HasCrashUploadingConsent(); |
| |
| // Is this a "safe" device coredump, from an allowlist of driver names |
| // for devices whose device coredump does not contain PII? |
| bool IsSafeDeviceCoredump(const CrashInfo& info); |
| |
| // Checks if we have an online connection state so we can try sending crash |
| // reports. |
| bool IsNetworkOnline(); |
| |
| std::unique_ptr<MetricsLibraryInterface> metrics_lib_; |
| std::unique_ptr<org::chromium::flimflam::ManagerProxyInterface> shill_proxy_; |
| std::vector<std::string> proxy_servers_; |
| std::string form_data_boundary_; |
| bool always_write_uploads_log_; |
| const int max_crash_rate_; |
| const int max_crash_bytes_; |
| const base::TimeDelta max_spread_time_; |
| bool allow_dev_sending_; |
| const bool test_mode_; |
| const bool upload_old_reports_; |
| |
| DISALLOW_COPY_AND_ASSIGN(Sender); |
| }; |
| |
| } // namespace util |
| |
| #endif // CRASH_REPORTER_CRASH_SENDER_UTIL_H_ |