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