1 // Copyright 2018 The Chromium Authors. All rights reserved. 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 CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_REMOTE_H_ 6 #define CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_REMOTE_H_ 7 8 #include <map> 9 #include <set> 10 #include <string> 11 #include <vector> 12 13 #include "base/memory/weak_ptr.h" 14 #include "base/optional.h" 15 #include "base/sequenced_task_runner.h" 16 #include "base/time/time.h" 17 #include "chrome/browser/media/webrtc/webrtc_event_log_history.h" 18 #include "chrome/browser/media/webrtc/webrtc_event_log_manager_common.h" 19 #include "chrome/browser/media/webrtc/webrtc_event_log_uploader.h" 20 #include "components/upload_list/upload_list.h" 21 #include "services/network/public/cpp/network_connection_tracker.h" 22 23 namespace webrtc_event_logging { 24 25 class WebRtcRemoteEventLogManager final 26 : public network::NetworkConnectionTracker::NetworkConnectionObserver { 27 using BrowserContextId = WebRtcEventLogPeerConnectionKey::BrowserContextId; 28 using LogFilesMap = 29 std::map<WebRtcEventLogPeerConnectionKey, std::unique_ptr<LogFileWriter>>; 30 using PeerConnectionKey = WebRtcEventLogPeerConnectionKey; 31 32 public: 33 WebRtcRemoteEventLogManager( 34 WebRtcRemoteEventLogsObserver* observer, 35 scoped_refptr<base::SequencedTaskRunner> task_runner); 36 ~WebRtcRemoteEventLogManager() override; 37 38 // Sets a network::NetworkConnectionTracker which will be used to track 39 // network connectivity. 40 // Must not be called more than once. 41 // Must be called before any call to EnableForBrowserContext(). 42 void SetNetworkConnectionTracker( 43 network::NetworkConnectionTracker* network_connection_tracker); 44 45 // Sets a LogFileWriter factory. 46 // Must not be called more than once. 47 // Must be called before any call to EnableForBrowserContext(). 48 void SetLogFileWriterFactory( 49 std::unique_ptr<LogFileWriter::Factory> log_file_writer_factory); 50 51 // Enables remote-bound logging for a given BrowserContext. Logs stored during 52 // previous sessions become eligible for upload, and recording of new logs for 53 // peer connections associated with this BrowserContext, in the 54 // BrowserContext's user-data directory, becomes possible. 55 // This method would typically be called when a BrowserContext is initialized. 56 // Enabling for the same BrowserContext twice in a row, without disabling 57 // in between, is an error. 58 void EnableForBrowserContext(BrowserContextId browser_context_id, 59 const base::FilePath& browser_context_dir); 60 61 // Disables remote-bound logging for a given BrowserContext. Pending logs from 62 // earlier (while it was enabled) may no longer be uploaded, additional 63 // logs will not be created, and any active uploads associated with the 64 // BrowserContext will be cancelled. 65 // Disabling for a BrowserContext which was not enabled is not an error, 66 // because the caller is not required to know whether a previous call 67 // to EnableForBrowserContext() was successful. 68 void DisableForBrowserContext(BrowserContextId browser_context_id); 69 70 // Called to inform |this| of peer connections being added/removed. 71 // This information is used to: 72 // 1. Make decisions about when to upload previously finished logs. 73 // 2. When a peer connection is removed, if it was being logged, its log 74 // changes from ACTIVE to PENDING. 75 // The return value of both methods indicates only the consistency of the 76 // information with previously received information (e.g. can't remove a 77 // peer connection that was never added, etc.). 78 bool PeerConnectionAdded(const PeerConnectionKey& key); 79 bool PeerConnectionRemoved(const PeerConnectionKey& key); 80 81 // Called to inform |this| that a peer connection has been associated 82 // with |session_id|. After this, it is possible to refer to that peer 83 // connection using StartRemoteLogging() by providing |session_id|. 84 bool PeerConnectionSessionIdSet(const PeerConnectionKey& key, 85 const std::string& session_id); 86 87 // Attempt to start logging the WebRTC events of an active peer connection. 88 // Logging is subject to several restrictions: 89 // 1. May not log more than kMaxNumberActiveRemoteWebRtcEventLogFiles logs 90 // at the same time. 91 // 2. Each browser context may have only kMaxPendingLogFilesPerBrowserContext 92 // pending logs. Since active logs later become pending logs, it is also 93 // forbidden to start a remote-bound log that would, once completed, become 94 // a pending log that would exceed that limit. 95 // 3. The maximum file size must be sensible. 96 // 97 // If all of the restrictions were observed, and if a file was successfully 98 // created, true will be returned. 99 // 100 // If the call succeeds, the log's identifier will be written to |log_id|. 101 // The log identifier is exactly 32 uppercase ASCII characters from the 102 // ranges 0-9 and A-F. 103 // 104 // The log's filename will also incorporate |web_app_id|. 105 // |web_app_id| must be between 1 and 99 (inclusive); error otherwise. 106 // 107 // If the call fails, an error message is written to |error_message|. 108 // The error message will be specific to the failure (as opposed to a generic 109 // one) is produced only if that error message is useful for the caller: 110 // * Bad parameters. 111 // * Function called at a time when the caller could know it would fail, 112 // such as for a peer connection that was already logged. 113 // We intentionally avoid giving specific errors in some cases, so as 114 // to avoid leaking information such as having too many active and/or 115 // pending logs. 116 bool StartRemoteLogging(int render_process_id, 117 BrowserContextId browser_context_id, 118 const std::string& session_id, 119 const base::FilePath& browser_context_dir, 120 size_t max_file_size_bytes, 121 int output_period_ms, 122 size_t web_app_id, 123 std::string* log_id, 124 std::string* error_message); 125 126 // If an active remote-bound log exists for the given peer connection, this 127 // will append |message| to that log. 128 // If writing |message| to the log would exceed the log's maximum allowed 129 // size, the write is disallowed and the file is closed instead (and changes 130 // from ACTIVE to PENDING). 131 // If the log file's capacity is exhausted as a result of this function call, 132 // or if a write error occurs, the file is closed, and the remote-bound log 133 // changes from ACTIVE to PENDING. 134 // True is returned if and only if |message| was written in its entirety to 135 // an active log. 136 bool EventLogWrite(const PeerConnectionKey& key, const std::string& message); 137 138 // Clear PENDING WebRTC event logs associated with a given browser context, 139 // in a given time range, then post |reply| back to the thread from which 140 // the method was originally invoked (which can be any thread). 141 // Log files currently being written are *not* interrupted. 142 // Active uploads *are* interrupted. 143 void ClearCacheForBrowserContext(BrowserContextId browser_context_id, 144 const base::Time& delete_begin, 145 const base::Time& delete_end); 146 147 // See documentation of same method in WebRtcEventLogManager for details. 148 void GetHistory( 149 BrowserContextId browser_context_id, 150 base::OnceCallback<void(const std::vector<UploadList::UploadInfo>&)> 151 reply); 152 153 // Works on not-enabled BrowserContext-s, which means the logs are never made 154 // eligible for upload. Useful when a BrowserContext is loaded which in 155 // the past had remote-logging enabled, but no longer does. 156 void RemovePendingLogsForNotEnabledBrowserContext( 157 BrowserContextId browser_context_id, 158 const base::FilePath& browser_context_dir); 159 160 // An implicit PeerConnectionRemoved() on all of the peer connections that 161 // were associated with the renderer process. 162 void RenderProcessHostExitedDestroyed(int render_process_id); 163 164 // network::NetworkConnectionTracker::NetworkConnectionObserver implementation 165 void OnConnectionChanged(network::mojom::ConnectionType type) override; 166 167 // Unit tests may use this to inject null uploaders, or ones which are 168 // directly controlled by the unit test (succeed or fail according to the 169 // test's needs). 170 // Note that for simplicity's sake, this may be called from outside the 171 // task queue on which this object lives (WebRtcEventLogManager::task_queue_). 172 // Therefore, if a test calls this, it should call it before it initializes 173 // any BrowserContext with pending log files in its directory. 174 void SetWebRtcEventLogUploaderFactoryForTesting( 175 std::unique_ptr<WebRtcEventLogUploader::Factory> uploader_factory); 176 177 // Exposes UploadConditionsHold() to unit tests. See WebRtcEventLogManager's 178 // documentation for the rationale. 179 void UploadConditionsHoldForTesting(base::OnceCallback<void(bool)> callback); 180 181 // In production code, |task_runner_| stops running tasks as part of Chrome's 182 // shut-down process, before |this| is torn down. In unit tests, this is 183 // not the case. 184 void ShutDownForTesting(base::OnceClosure reply); 185 186 private: 187 using PeerConnectionMap = std::map<PeerConnectionKey, std::string>; 188 189 // Validates log parameters. 190 // If valid, returns true. Otherwise, false, and |error_message| gets 191 // a relevant error. 192 bool AreLogParametersValid(size_t max_file_size_bytes, 193 int output_period_ms, 194 size_t web_app_id, 195 std::string* error_message) const; 196 197 // Checks whether a browser context has already been enabled via a call to 198 // EnableForBrowserContext(), and not yet disabled using a call to 199 // DisableForBrowserContext(). 200 bool BrowserContextEnabled(BrowserContextId browser_context_id) const; 201 202 // Closes an active log file. 203 // If |make_pending| is true, closing the file changes its state from ACTIVE 204 // to PENDING. If |make_pending| is false, or if the file couldn't be closed 205 // correctly, the file will be deleted. 206 // Returns an iterator to the next ACTIVE file. 207 LogFilesMap::iterator CloseLogFile(LogFilesMap::iterator it, 208 bool make_pending); 209 210 // Attempts to create the directory where we'll write the logs, if it does 211 // not already exist. Returns true if the directory exists (either it already 212 // existed, or it was successfully created). 213 bool MaybeCreateLogsDirectory(const base::FilePath& remote_bound_logs_dir); 214 215 // Scans the user data directory associated with the BrowserContext 216 // associated with the given BrowserContextId remote-bound logs that were 217 // created during previous Chrome sessions and for history files, 218 // then process them (discard expired files, etc.) 219 void LoadLogsDirectory(BrowserContextId browser_context_id, 220 const base::FilePath& remote_bound_logs_dir); 221 222 // Loads the pending log file whose path is |path|, into the BrowserContext 223 // indicated by |browser_context_id|. Note that the contents of the file are 224 // note read by this method. 225 // Returns true if the file was loaded correctly, and should be kept on disk; 226 // false if the file was not loaded (e.g. incomplete or expired), and needs 227 // to be deleted. 228 bool LoadPendingLogInfo(BrowserContextId browser_context_id, 229 const base::FilePath& path, 230 base::Time last_modified); 231 232 // Loads a history file. Returns a WebRtcEventLogHistoryFileReader if the 233 // file was loaded correctly, and should be kept on disk; nullptr otherwise, 234 // signaling that the file should be deleted. 235 // |prune_begin| and |prune_end| define a time range where, if the log falls 236 // within the range, it will not be loaded. 237 std::unique_ptr<WebRtcEventLogHistoryFileReader> LoadHistoryFile( 238 BrowserContextId browser_context_id, 239 const base::FilePath& path, 240 const base::Time& prune_begin, 241 const base::Time& prune_end); 242 243 // Deletes any history logs associated with |browser_context_id| captured or 244 // uploaded between |prune_begin| and |prune_end|, inclusive, then returns a 245 // set of readers for the remaining (meaning not-pruned) history files. 246 std::set<WebRtcEventLogHistoryFileReader> 247 PruneAndLoadHistoryFilesForBrowserContext( 248 const base::Time& prune_begin, 249 const base::Time& prune_end, 250 BrowserContextId browser_context_id); 251 252 // Attempts the creation of a locally stored file into which a remote-bound 253 // log may be written. The log-identifier is returned if successful, the empty 254 // string otherwise. 255 bool StartWritingLog(const PeerConnectionKey& key, 256 const base::FilePath& browser_context_dir, 257 size_t max_file_size_bytes, 258 int output_period_ms, 259 size_t web_app_id, 260 std::string* log_id_out, 261 std::string* error_message_out); 262 263 // Checks if the referenced peer connection has an associated active 264 // remote-bound log. If it does, the log is changed from ACTIVE to PENDING. 265 void MaybeStopRemoteLogging(const PeerConnectionKey& key); 266 267 // Get rid of pending logs whose age exceeds our retention policy. 268 // On the one hand, we want to remove expired files as soon as possible, but 269 // on the other hand, we don't want to waste CPU by checking this too often. 270 // Therefore, we prune pending files: 271 // 1. When a new BrowserContext is initalized, thereby also pruning the 272 // pending logs contributed by that BrowserContext. 273 // 2. Before initiating a new upload, thereby avoiding uploading a file that 274 // has just now expired. 275 // 3. On infrequent events - peer connection addition/removal, but NOT 276 // on something that could potentially be frequent, such as EventLogWrite. 277 // Note that the last modification date of a file, which is the value measured 278 // against for retention, is only read from disk once per file, meaning 279 // this check is not too expensive. 280 // If a |browser_context_id| is provided, logs are only pruned for it. 281 void PrunePendingLogs( 282 base::Optional<BrowserContextId> browser_context_id = base::nullopt); 283 284 // PrunePendingLogs() and schedule the next proactive pending logs prune. 285 void RecurringlyPrunePendingLogs(); 286 287 // Removes expired history files. 288 // Since these are small, and since looking for them is not as cheap as 289 // looking for pending logs, we do not make an effort to remove them as 290 // soon as possible. 291 void PruneHistoryFiles(); 292 293 // PruneHistoryFiles() and schedule the next proactive history files prune. 294 void RecurringlyPruneHistoryFiles(); 295 296 // Cancels and deletes active logs which match the given filter criteria, as 297 // described by MatchesFilter's documentation. 298 // This method not trigger any pending logs to be uploaded, allowing it to 299 // be safely used in a context that clears browsing data. 300 void MaybeCancelActiveLogs(const base::Time& delete_begin, 301 const base::Time& delete_end, 302 BrowserContextId browser_context_id); 303 304 // Removes pending logs files which match the given filter criteria, as 305 // described by MatchesFilter's documentation. 306 // This method not trigger any pending logs to be uploaded, allowing it to 307 // be safely used in a context that clears browsing data. 308 void MaybeRemovePendingLogs( 309 const base::Time& delete_begin, 310 const base::Time& delete_end, 311 base::Optional<BrowserContextId> browser_context_id, 312 bool is_cache_clear); 313 314 // Remove all history files associated with |browser_context_id| which were 315 // either captured or uploaded between |delete_begin| and |delete_end|. 316 // This method not trigger any pending logs to be uploaded, allowing it to 317 // be safely used in a context that clears browsing data. 318 void MaybeRemoveHistoryFiles(const base::Time& delete_begin, 319 const base::Time& delete_end, 320 BrowserContextId browser_context_id); 321 322 // If the currently uploaded file matches the given filter criteria, as 323 // described by MatchesFilter's documentation, the upload will be 324 // cancelled, and the log file deleted. If this happens, the next pending log 325 // file will be considered for upload. 326 // This method is used to ensure that clearing of browsing data by the user 327 // does not leave the currently-uploaded file on disk, even for the duration 328 // of the upload. 329 // This method not trigger any pending logs to be uploaded, allowing it to 330 // be safely used in a context that clears browsing data. 331 void MaybeCancelUpload(const base::Time& delete_begin, 332 const base::Time& delete_end, 333 BrowserContextId browser_context_id); 334 335 // Checks whether a log file matches a range and (potentially) BrowserContext: 336 // * A file matches if its last modification date was at or later than 337 // |filter_range_begin|, and earlier than |filter_range_end|. 338 // * If a null time-point is given as either |filter_range_begin| or 339 // |filter_range_end|, it is treated as "beginning-of-time" or 340 // "end-of-time", respectively. 341 // * If |filter_browser_context_id| is set, only log files associated with it 342 // can match the filter. 343 bool MatchesFilter(BrowserContextId log_browser_context_id, 344 const base::Time& log_last_modification, 345 base::Optional<BrowserContextId> filter_browser_context_id, 346 const base::Time& filter_range_begin, 347 const base::Time& filter_range_end) const; 348 349 // Return |true| if and only if we can start another active log (with respect 350 // to limitations on the numbers active and pending logs). 351 bool AdditionalActiveLogAllowed(BrowserContextId browser_context_id) const; 352 353 // Uploading suppressed while active peer connections exist (unless 354 // suppression) is turned off from the command line. 355 bool UploadSuppressed() const; 356 357 // Check whether all the conditions necessary for uploading log files are 358 // currently satisfied. 359 // 1. There may be no active peer connections which might be adversely 360 // affected by the bandwidth consumption of the upload. 361 // 2. Chrome has a network connection, and that conneciton is either a wired 362 // one, or WiFi. (That is, not 3G, etc.) 363 // 3. Naturally, a file pending upload must exist. 364 bool UploadConditionsHold() const; 365 366 // When the conditions necessary for uploading first hold, schedule a delayed 367 // task to upload (MaybeStartUploading). If they ever stop holding, void it. 368 void ManageUploadSchedule(); 369 370 // Posted as a delayed task by ManageUploadSchedule. If not voided until 371 // executed, will initiate an upload of the next log file. 372 void MaybeStartUploading(); 373 374 // Callback for the success/failure of an upload. 375 // When an upload is complete, it might be time to upload the next file. 376 // Note: |log_file| and |upload_successful| are ignored in production; they 377 // are used in unit tests, so we keep them here to make things simpler, so 378 // that this method would match WebRtcEventLogUploader::UploadResultCallback 379 // without adaptation. 380 void OnWebRtcEventLogUploadComplete(const base::FilePath& log_file, 381 bool upload_successful); 382 383 // Given a renderer process ID and peer connection's session ID, find the 384 // peer connection to which they refer. 385 bool FindPeerConnection(int render_process_id, 386 const std::string& session_id, 387 PeerConnectionKey* key) const; 388 389 // Find the next peer connection in a map to which the renderer process ID 390 // and session ID refer. 391 // This helper allows FindPeerConnection() to DCHECK on uniqueness of the ID 392 // without descending down a recursive rabbit hole. 393 PeerConnectionMap::const_iterator FindNextPeerConnection( 394 PeerConnectionMap::const_iterator begin, 395 int render_process_id, 396 const std::string& session_id) const; 397 398 // Normally, uploading is suppressed while there are active peer connections. 399 // This may be disabled from the command line. 400 const bool upload_suppression_disabled_; 401 402 // The conditions for upload must hold for this much time, uninterrupted, 403 // before an upload may be initiated. 404 const base::TimeDelta upload_delay_; 405 406 // If non-zero, every |proactive_pending_logs_prune_delta_|, pending logs 407 // will be pruned. This avoids them staying around on disk for longer than 408 // their expiration if no event occurs which triggers reactive pruning. 409 const base::TimeDelta proactive_pending_logs_prune_delta_; 410 411 // Proactive pruning, if enabled, starts with the first enabled browser 412 // context. To avoid unnecessary complexity, if that browser context is 413 // disabled, proactive pruning is not disabled. 414 bool proactive_prune_scheduling_started_; 415 416 // This is used to inform WebRtcEventLogManager when remote-bound logging 417 // of a peer connection starts/stops, which allows WebRtcEventLogManager to 418 // decide when to ask WebRTC to start/stop sending event logs. 419 WebRtcRemoteEventLogsObserver* const observer_; 420 421 // The IDs of the BrowserContexts for which logging is enabled, mapped to 422 // the directory where each BrowserContext's remote-bound logs are stored. 423 std::map<BrowserContextId, base::FilePath> enabled_browser_contexts_; 424 425 // Currently active peer connections, mapped to their session IDs (once the 426 // session ID is set). 427 // PeerConnections which have been closed are not considered active, 428 // regardless of whether they have been torn down. 429 PeerConnectionMap active_peer_connections_; 430 431 // Creates LogFileWriter instances (compressed/uncompressed, etc.). 432 std::unique_ptr<LogFileWriter::Factory> log_file_writer_factory_; 433 434 // Remote-bound logs which we're currently in the process of writing to disk. 435 LogFilesMap active_logs_; 436 437 // Remote-bound logs which have been written to disk before (either during 438 // this Chrome session or during an earlier one), and which are no waiting to 439 // be uploaded. 440 std::set<WebRtcLogFileInfo> pending_logs_; 441 442 // Null if no ongoing upload, or an uploader which owns a file, and is 443 // currently busy uploading it to a remote server. 444 std::unique_ptr<WebRtcEventLogUploader> uploader_; 445 446 // The path to the file which is currently being uploaded. 447 // Used to ensure a callback from the uploader refers to the current 448 // file, rather than a second callback from the previously uploaded file, 449 // e.g. when when Cancel() is called right after the upload finishes. 450 base::FilePath currently_uploaded_file_; 451 452 // Provides notifications of network changes. 453 network::NetworkConnectionTracker* network_connection_tracker_; 454 455 // Whether the network we are currently connected to, if any, is one over 456 // which we may upload. 457 bool uploading_supported_for_connection_type_; 458 459 // If the conditions for initiating an upload do not hold, this will be 460 // set to an empty base::TimeTicks. 461 // If the conditions were found to hold, this will record the time when they 462 // started holding. (It will be set back to 0 if they ever cease holding.) 463 base::TimeTicks time_when_upload_conditions_met_; 464 465 // This is a vehicle for DCHECKs to ensure code sanity. It counts the number 466 // of scheduled tasks of MaybeStartUploading(), and proves that we never 467 // end up with a scheduled upload that never occurs. 468 size_t scheduled_upload_tasks_; 469 470 // Producer of uploader objects. (In unit tests, this would create 471 // null-implementation uploaders, or uploaders whose behavior is controlled 472 // by the unit test.) 473 std::unique_ptr<WebRtcEventLogUploader::Factory> uploader_factory_; 474 475 // |this| is created and destroyed on the UI thread, but operates on the 476 // following IO-capable sequenced task runner. 477 scoped_refptr<base::SequencedTaskRunner> task_runner_; 478 479 // Weak pointer factory. Only expected to be useful for unit tests, because 480 // in production, |task_runner_| is stopped during shut-down, so tasks will 481 // either find the pointer to be valid, or not run because the runner has 482 // already been stopped. 483 // Note that the unique_ptr is used just to make it clearer that ownership is 484 // here. In reality, this is never auto-destroyed; see destructor for details. 485 std::unique_ptr<base::WeakPtrFactory<WebRtcRemoteEventLogManager>> 486 weak_ptr_factory_; 487 488 DISALLOW_COPY_AND_ASSIGN(WebRtcRemoteEventLogManager); 489 }; 490 491 } // namespace webrtc_event_logging 492 493 #endif // CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_REMOTE_H_ 494