1 // Copyright 2014 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef COMPONENTS_METRICS_UNSENT_LOG_STORE_H_ 6 #define COMPONENTS_METRICS_UNSENT_LOG_STORE_H_ 7 8 #include <stddef.h> 9 10 #include <memory> 11 #include <string> 12 #include <vector> 13 14 #include "base/gtest_prod_util.h" 15 #include "base/logging.h" 16 #include "base/memory/raw_ptr.h" 17 #include "base/metrics/histogram_base.h" 18 #include "base/strings/string_piece.h" 19 #include "base/values.h" 20 #include "components/metrics/log_store.h" 21 #include "components/metrics/metrics_log.h" 22 #include "components/metrics/metrics_logs_event_manager.h" 23 #include "third_party/abseil-cpp/absl/types/optional.h" 24 25 class PrefService; 26 27 namespace metrics { 28 29 class UnsentLogStoreMetrics; 30 31 // Maintains a list of unsent logs that are written and restored from disk. 32 class UnsentLogStore : public LogStore { 33 public: 34 // Constructs an UnsentLogStore that stores data in |local_state| under the 35 // preference |log_data_pref_name|. 36 // Calling code is responsible for ensuring that the lifetime of |local_state| 37 // is longer than the lifetime of UnsentLogStore. 38 // 39 // The optional |metadata_pref_name| is the preference that is used to store 40 // the unsent logs info while the unset logs are persisted. That info will be 41 // recorded as UMA metrics in next browser startup. 42 // 43 // When saving logs to disk, stores either the first |min_log_count| logs, or 44 // at least |min_log_bytes| bytes of logs, whichever is greater. 45 // 46 // If the optional |max_log_size| parameter is non-zero, all logs larger than 47 // that limit will be skipped when writing to disk. 48 // 49 // |signing_key| is used to produce an HMAC-SHA256 signature of the logged 50 // data, which will be uploaded with the log and used to validate data 51 // integrity. 52 // 53 // |logs_event_manager| is used to notify observers of log events. Can be set 54 // to null if observing the events is not necessary. 55 UnsentLogStore(std::unique_ptr<UnsentLogStoreMetrics> metrics, 56 PrefService* local_state, 57 const char* log_data_pref_name, 58 const char* metadata_pref_name, 59 size_t min_log_count, 60 size_t min_log_bytes, 61 size_t max_log_size, 62 const std::string& signing_key, 63 MetricsLogsEventManager* logs_event_manager); 64 65 UnsentLogStore(const UnsentLogStore&) = delete; 66 UnsentLogStore& operator=(const UnsentLogStore&) = delete; 67 68 ~UnsentLogStore() override; 69 70 struct LogInfo { 71 LogInfo(); 72 73 LogInfo(const LogInfo&) = delete; 74 LogInfo& operator=(const LogInfo&) = delete; 75 76 ~LogInfo(); 77 78 // Initializes the members based on uncompressed |log_data|, 79 // |log_timestamp|, and |signing_key|. |log_data| is the uncompressed 80 // serialized log protobuf. A hash and a signature are computed from 81 // |log_data|. The signature is produced using |signing_key|. |log_data| 82 // will be compressed and stored in |compressed_log_data|. |log_timestamp| 83 // is stored as is. |log_metadata| is any optional metadata that will be 84 // attached to the log. 85 // TODO(crbug/1052796): Make this a ctor instead. 86 void Init(const std::string& log_data, 87 const std::string& log_timestamp, 88 const std::string& signing_key, 89 const LogMetadata& log_metadata); 90 91 // Same as above, but the |timestamp| field will be filled with the current 92 // time. 93 // TODO(crbug/1052796): Make this a ctor instead. 94 void Init(const std::string& log_data, 95 const std::string& signing_key, 96 const LogMetadata& log_metadata); 97 98 // Compressed log data - a serialized protobuf that's been gzipped. 99 std::string compressed_log_data; 100 101 // The SHA1 hash of the log. Computed in Init and stored to catch errors 102 // from memory corruption. 103 std::string hash; 104 105 // The HMAC-SHA256 signature of the log, used to validate the log came from 106 // Chrome. It's computed in Init and stored, instead of computed on demand, 107 // to catch errors from memory corruption. 108 std::string signature; 109 110 // The timestamp of when the log was created as a time_t value. 111 std::string timestamp; 112 113 // Properties of the log. 114 LogMetadata log_metadata; 115 }; 116 117 // LogStore: 118 bool has_unsent_logs() const override; 119 bool has_staged_log() const override; 120 const std::string& staged_log() const override; 121 const std::string& staged_log_hash() const override; 122 const std::string& staged_log_signature() const override; 123 absl::optional<uint64_t> staged_log_user_id() const override; 124 void StageNextLog() override; 125 void DiscardStagedLog(base::StringPiece reason = "") override; 126 void MarkStagedLogAsSent() override; 127 void TrimAndPersistUnsentLogs(bool overwrite_in_memory_store) override; 128 void LoadPersistedUnsentLogs() override; 129 130 // Adds a log to the list. |log_metadata| refers to metadata associated with 131 // the log. Before being stored, the data will be compressed, and a hash and 132 // signature will be computed. 133 // TODO(crbug/1052796): Remove this function, and use StoreLogInfo() 134 // everywhere instead. 135 void StoreLog(const std::string& log_data, 136 const LogMetadata& log_metadata, 137 MetricsLogsEventManager::CreateReason reason); 138 139 // Adds a log to the list, represented by a LogInfo object. This is useful 140 // if the LogInfo instance needs to be created outside the main thread 141 // (since creating a LogInfo from log data requires heavy work). Note that we 142 // also pass the size of the log data before being compressed. This is simply 143 // for calculating and emitting some metrics, and is otherwise unused. 144 void StoreLogInfo(std::unique_ptr<LogInfo> log_info, 145 size_t uncompressed_log_size, 146 MetricsLogsEventManager::CreateReason reason); 147 148 // Gets log data at the given index in the list. 149 const std::string& GetLogAtIndex(size_t index); 150 151 // Replaces the compressed log at |index| in the store with given log data and 152 // |log_metadata| reusing the same timestamp. 153 std::string ReplaceLogAtIndex(size_t index, 154 const std::string& new_log_data, 155 const LogMetadata& log_metadata); 156 157 // Deletes all logs, in memory and on disk. 158 void Purge(); 159 160 // Sets |logs_event_manager_|. 161 void SetLogsEventManager(MetricsLogsEventManager* logs_event_manager); 162 163 // Returns the timestamp of the element in the front of the list. 164 const std::string& staged_log_timestamp() const; 165 166 // The number of elements currently stored. size()167 size_t size() const { return list_.size(); } 168 169 // The signing key used to compute the signature for a log. signing_key()170 const std::string& signing_key() const { return signing_key_; } 171 172 // Returns |logs_event_manager_|. GetLogsEventManagerForTesting()173 MetricsLogsEventManager* GetLogsEventManagerForTesting() const { 174 return logs_event_manager_; 175 } 176 177 // Computes the HMAC for |log_data| using the |signing_key| and returns a bool 178 // indicating whether the signing succeeded. The returned HMAC is written to 179 // the |signature|. 180 static bool ComputeHMACForLog(const std::string& log_data, 181 const std::string& signing_key, 182 std::string* signature); 183 184 private: 185 FRIEND_TEST_ALL_PREFIXES(UnsentLogStoreTest, UnsentLogMetadataMetrics); 186 187 // Reads the list of logs from |list|. 188 void ReadLogsFromPrefList(const base::Value::List& list); 189 190 // Writes the unsent log info to the |metadata_pref_name_| preference. 191 void WriteToMetricsPref(base::HistogramBase::Count unsent_samples_count, 192 base::HistogramBase::Count sent_samples_count, 193 size_t persisted_size) const; 194 195 // Records the info in |metadata_pref_name_| as UMA metrics. 196 void RecordMetaDataMetrics(); 197 198 // Wrapper functions for the notify functions of |logs_event_manager_|. 199 void NotifyLogCreated(const LogInfo& info, 200 MetricsLogsEventManager::CreateReason reason); 201 void NotifyLogsCreated(base::span<std::unique_ptr<LogInfo>> logs, 202 MetricsLogsEventManager::CreateReason reason); 203 void NotifyLogEvent(MetricsLogsEventManager::LogEvent event, 204 base::StringPiece log_hash, 205 base::StringPiece message = ""); 206 void NotifyLogsEvent(base::span<std::unique_ptr<LogInfo>> logs, 207 MetricsLogsEventManager::LogEvent event, 208 base::StringPiece message = ""); 209 210 // An object for recording UMA metrics. 211 std::unique_ptr<UnsentLogStoreMetrics> metrics_; 212 213 // A weak pointer to the PrefService object to read and write the preference 214 // from. Calling code should ensure this object continues to exist for the 215 // lifetime of the UnsentLogStore object. 216 raw_ptr<PrefService> local_state_; 217 218 // The name of the preference to serialize logs to/from. 219 const char* log_data_pref_name_; 220 221 // The name of the preference to store the unsent logs info, it could be 222 // nullptr if the metadata isn't desired. 223 const char* metadata_pref_name_; 224 225 // We will keep at least this |min_log_count_| logs or |min_log_bytes_| bytes 226 // of logs, whichever is greater, when trimming logs. These apply after 227 // skipping logs greater than |max_log_size_|. 228 const size_t min_log_count_; 229 const size_t min_log_bytes_; 230 231 // Logs greater than this size will not be written to disk. 232 const size_t max_log_size_; 233 234 // Used to create a signature of log data, in order to verify reported data is 235 // authentic. 236 const std::string signing_key_; 237 238 // Event manager to notify observers of log events. 239 raw_ptr<MetricsLogsEventManager> logs_event_manager_; 240 241 // A list of all of the stored logs, stored with SHA1 hashes to check for 242 // corruption while they are stored in memory. 243 std::vector<std::unique_ptr<LogInfo>> list_; 244 245 // The index and type of the log staged for upload. If nothing has been 246 // staged, the index will be -1. 247 int staged_log_index_; 248 249 // The total number of samples that have been sent from this LogStore. 250 base::HistogramBase::Count total_samples_sent_ = 0; 251 }; 252 253 } // namespace metrics 254 255 #endif // COMPONENTS_METRICS_UNSENT_LOG_STORE_H_ 256