| // Copyright 2017 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. |
| |
| #ifndef CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_H_ |
| #define CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_H_ |
| |
| #include <map> |
| #include <memory> |
| #include <utility> |
| |
| #include "base/callback.h" |
| #include "base/containers/flat_set.h" |
| #include "base/files/file_path.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/sequenced_task_runner.h" |
| #include "base/time/clock.h" |
| #include "base/time/time.h" |
| #include "chrome/browser/media/webrtc/webrtc_event_log_manager_common.h" |
| #include "chrome/browser/media/webrtc/webrtc_event_log_manager_local.h" |
| #include "chrome/browser/media/webrtc/webrtc_event_log_manager_remote.h" |
| #include "components/prefs/pref_change_registrar.h" |
| #include "content/public/browser/render_process_host_observer.h" |
| #include "content/public/browser/webrtc_event_logger.h" |
| |
| namespace content { |
| class BrowserContext; |
| class NetworkConnectionTracker; |
| }; |
| |
| // This is a singleton class running in the browser UI thread (ownership of |
| // the only instance lies in BrowserContext). It is in charge of writing WebRTC |
| // event logs to temporary files, then uploading those files to remote servers, |
| // as well as of writing the logs to files which were manually indicated by the |
| // user from the WebRTCIntenals. (A log may simulatenously be written to both, |
| // either, or none.) |
| // The only instance of this class is owned by BrowserProcessImpl. It is |
| // destroyed from ~BrowserProcessImpl(), at which point any tasks posted to the |
| // internal SequencedTaskRunner, or coming from another thread, would no longer |
| // execute. |
| class WebRtcEventLogManager final : public content::RenderProcessHostObserver, |
| public content::WebRtcEventLogger, |
| public WebRtcLocalEventLogsObserver, |
| public WebRtcRemoteEventLogsObserver { |
| public: |
| using BrowserContextId = WebRtcEventLogPeerConnectionKey::BrowserContextId; |
| |
| // To turn WebRTC on and off, we go through PeerConnectionTrackerProxy. In |
| // order to make this toggling easily testable, PeerConnectionTrackerProxyImpl |
| // will send real messages to PeerConnectionTracker, whereas |
| // PeerConnectionTrackerProxyForTesting will be a mock that just makes sure |
| // the correct messages were attempted to be sent. |
| class PeerConnectionTrackerProxy { |
| public: |
| virtual ~PeerConnectionTrackerProxy() = default; |
| virtual void SetWebRtcEventLoggingState( |
| const WebRtcEventLogPeerConnectionKey& key, |
| bool event_logging_enabled) = 0; |
| }; |
| |
| // Ensures that no previous instantiation of the class was performed, then |
| // instantiates the class and returns the object (ownership is transfered to |
| // the caller). Subsequent calls to GetInstance() will return this object, |
| // until it is destructed, at which pointer nullptr will be returned by |
| // subsequent calls. |
| static std::unique_ptr<WebRtcEventLogManager> CreateSingletonInstance(); |
| |
| // Returns the object previously constructed using CreateSingletonInstance(), |
| // if it was constructed and was not yet destroyed; nullptr otherwise. |
| static WebRtcEventLogManager* GetInstance(); |
| |
| ~WebRtcEventLogManager() override; |
| |
| void EnableForBrowserContext(content::BrowserContext* browser_context, |
| base::OnceClosure reply); |
| |
| void DisableForBrowserContext(content::BrowserContext* browser_context, |
| base::OnceClosure reply); |
| |
| void PeerConnectionAdded(int render_process_id, |
| int lid, // Renderer-local PeerConnection ID. |
| const std::string& peer_connection_id, |
| base::OnceCallback<void(bool)> reply) override; |
| |
| void PeerConnectionRemoved(int render_process_id, |
| int lid, // Renderer-local PeerConnection ID. |
| base::OnceCallback<void(bool)> reply) override; |
| |
| // From the logger's perspective, we treat stopping a peer connection the |
| // same as we do its removal. Should a stopped peer connection be later |
| // removed, the removal callback will assume the value |false|. |
| void PeerConnectionStopped(int render_process_id, |
| int lid, // Renderer-local PeerConnection ID. |
| base::OnceCallback<void(bool)> reply) override; |
| |
| // The file's actual path is derived from |base_path| by adding a timestamp, |
| // the render process ID and the PeerConnection's local ID. |
| void EnableLocalLogging(const base::FilePath& base_path, |
| base::OnceCallback<void(bool)> reply) override; |
| void EnableLocalLogging(const base::FilePath& base_path, |
| size_t max_file_size_bytes, |
| base::OnceCallback<void(bool)> reply); |
| |
| void DisableLocalLogging(base::OnceCallback<void(bool)> reply) override; |
| |
| void OnWebRtcEventLogWrite( |
| int render_process_id, |
| int lid, // Renderer-local PeerConnection ID. |
| const std::string& message, |
| base::OnceCallback<void(std::pair<bool, bool>)> reply) override; |
| |
| // Start logging a peer connection's WebRTC events to a file, which will |
| // later be uploaded to a remote server. If a reply is provided, it will be |
| // posted back to BrowserThread::UI with the log-identifier (if successful) |
| // of the created log or (if unsuccessful) the error message. |
| // See the comment in WebRtcRemoteEventLogManager::StartRemoteLogging for |
| // more details. |
| void StartRemoteLogging( |
| int render_process_id, |
| const std::string& peer_connection_id, |
| size_t max_file_size_bytes, |
| base::OnceCallback<void(bool, const std::string&, const std::string&)> |
| reply); |
| |
| // Clear WebRTC event logs associated with a given browser context, in a given |
| // time range (|delete_begin| inclusive, |delete_end| exclusive), then |
| // post |reply| back to the thread from which the method was originally |
| // invoked (which can be any thread). |
| void ClearCacheForBrowserContext( |
| const content::BrowserContext* browser_context, |
| const base::Time& delete_begin, |
| const base::Time& delete_end, |
| base::OnceClosure reply); |
| |
| // Set (or unset) an observer that will be informed whenever a local log file |
| // is started/stopped. The observer needs to be able to either run from |
| // anywhere. If you need the code to run on specific runners or queues, have |
| // the observer post them there. |
| // If a reply callback is given, it will be posted back to BrowserThread::UI |
| // after the observer has been set. |
| void SetLocalLogsObserver(WebRtcLocalEventLogsObserver* observer, |
| base::OnceClosure reply); |
| |
| // Set (or unset) an observer that will be informed whenever a remote log file |
| // is started/stopped. Note that this refers to writing these files to disk, |
| // not for uploading them to the server. |
| // The observer needs to be able to either run from anywhere. If you need the |
| // code to run on specific runners or queues, have the observer post |
| // them there. |
| // If a reply callback is given, it will be posted back to BrowserThread::UI |
| // after the observer has been set. |
| void SetRemoteLogsObserver(WebRtcRemoteEventLogsObserver* observer, |
| base::OnceClosure reply); |
| |
| private: |
| friend class SigninManagerAndroidTest; |
| friend class WebRtcEventLogManagerTestBase; |
| friend class WebRTCInternalsIntegrationBrowserTest; |
| |
| using PeerConnectionKey = WebRtcEventLogPeerConnectionKey; |
| |
| // This bitmap allows us to track for which clients (local/remote logging) |
| // we have turned WebRTC event logging on for a given peer connection, so that |
| // we may turn it off only when the last client no longer needs it. |
| enum LoggingTarget : unsigned int { |
| kLocalLogging = 1 << 0, |
| kRemoteLogging = 1 << 1 |
| }; |
| using LoggingTargetBitmap = std::underlying_type<LoggingTarget>::type; |
| |
| WebRtcEventLogManager(); |
| |
| bool IsRemoteLoggingAllowedForBrowserContext( |
| content::BrowserContext* browser_context) const; |
| |
| // Determines the exact subclass of LogFileWriter::Factory to be used for |
| // producing remote-bound logs. |
| std::unique_ptr<LogFileWriter::Factory> CreateRemoteLogFileWriterFactory(); |
| |
| // RenderProcessHostObserver implementation. |
| void RenderProcessExited( |
| content::RenderProcessHost* host, |
| const content::ChildProcessTerminationInfo& info) override; |
| void RenderProcessHostDestroyed(content::RenderProcessHost* host) override; |
| |
| // RenderProcessExited() and RenderProcessHostDestroyed() treated similarly |
| // by this function. |
| void RenderProcessHostExitedDestroyed(content::RenderProcessHost* host); |
| |
| // WebRtcLocalEventLogsObserver implementation: |
| void OnLocalLogStarted(PeerConnectionKey peer_connection, |
| const base::FilePath& file_path) override; |
| void OnLocalLogStopped(PeerConnectionKey peer_connection) override; |
| |
| // WebRtcRemoteEventLogsObserver implementation: |
| void OnRemoteLogStarted(PeerConnectionKey key, |
| const base::FilePath& file_path) override; |
| void OnRemoteLogStopped(PeerConnectionKey key) override; |
| |
| void OnLoggingTargetStarted(LoggingTarget target, PeerConnectionKey key); |
| void OnLoggingTargetStopped(LoggingTarget target, PeerConnectionKey key); |
| |
| void StartListeningForPrefChangeForBrowserContext( |
| content::BrowserContext* browser_context); |
| void StopListeningForPrefChangeForBrowserContext( |
| content::BrowserContext* browser_context); |
| |
| void OnPrefChange(content::BrowserContext* browser_context); |
| |
| // network_connection_tracker() is not available during instantiation; |
| // we get it when the first profile is loaded, which is also the earliest |
| // time when it could be needed. |
| // The LogFileWriter::Factory is similarly deferred, but for a different |
| // reason - it makes it easier to allow unit tests to inject their own. |
| // OnFirstBrowserContextLoaded() is on the UI thread. |
| // OnFirstBrowserContextLoadedInternal() is the task sent to |task_runner_|. |
| void OnFirstBrowserContextLoaded(); |
| void OnFirstBrowserContextLoadedInternal( |
| network::NetworkConnectionTracker* network_connection_tracker, |
| std::unique_ptr<LogFileWriter::Factory> log_file_writer_factory); |
| |
| void EnableRemoteBoundLoggingForBrowserContext( |
| BrowserContextId browser_context_id, |
| const base::FilePath& browser_context_dir, |
| base::OnceClosure reply); |
| |
| void DisableRemoteBoundLoggingForBrowserContext( |
| BrowserContextId browser_context_id, |
| base::OnceClosure reply); |
| |
| void RemovePendingRemoteBoundLogsForNotEnabledBrowserContext( |
| BrowserContextId browser_context_id, |
| const base::FilePath& browser_context_dir, |
| base::OnceClosure reply); |
| |
| void PeerConnectionAddedInternal(PeerConnectionKey key, |
| const std::string& peer_connection_id, |
| base::OnceCallback<void(bool)> reply); |
| void PeerConnectionRemovedInternal(PeerConnectionKey key, |
| base::OnceCallback<void(bool)> reply); |
| |
| void EnableLocalLoggingInternal(const base::FilePath& base_path, |
| size_t max_file_size_bytes, |
| base::OnceCallback<void(bool)> reply); |
| void DisableLocalLoggingInternal(base::OnceCallback<void(bool)> reply); |
| |
| void OnWebRtcEventLogWriteInternal( |
| PeerConnectionKey key, |
| const std::string& message, |
| base::OnceCallback<void(std::pair<bool, bool>)> reply); |
| |
| void StartRemoteLoggingInternal( |
| int render_process_id, |
| BrowserContextId browser_context_id, |
| const std::string& peer_connection_id, |
| const base::FilePath& browser_context_dir, |
| size_t max_file_size_bytes, |
| base::OnceCallback<void(bool, const std::string&, const std::string&)> |
| reply); |
| |
| void ClearCacheForBrowserContextInternal(BrowserContextId browser_context_id, |
| const base::Time& delete_begin, |
| const base::Time& delete_end); |
| |
| void RenderProcessExitedInternal(int render_process_id); |
| |
| void SetLocalLogsObserverInternal(WebRtcLocalEventLogsObserver* observer, |
| base::OnceClosure reply); |
| |
| void SetRemoteLogsObserverInternal(WebRtcRemoteEventLogsObserver* observer, |
| base::OnceClosure reply); |
| |
| // Injects a fake clock, to be used by tests. For example, this could be |
| // used to inject a frozen clock, thereby allowing unit tests to know what a |
| // local log's filename would end up being. |
| void SetClockForTesting(base::Clock* clock, base::OnceClosure reply); |
| |
| // Injects a PeerConnectionTrackerProxy for testing. The normal tracker proxy |
| // is used to communicate back to WebRTC whether event logging is desired for |
| // a given peer connection. Using this function, those indications can be |
| // intercepted by a unit test. |
| void SetPeerConnectionTrackerProxyForTesting( |
| std::unique_ptr<PeerConnectionTrackerProxy> pc_tracker_proxy, |
| base::OnceClosure reply); |
| |
| // Injects a fake uploader, to be used by unit tests. |
| void SetWebRtcEventLogUploaderFactoryForTesting( |
| std::unique_ptr<WebRtcEventLogUploader::Factory> uploader_factory, |
| base::OnceClosure reply); |
| |
| // Sets a LogFileWriter factory for remote-bound files. |
| // Only usable in tests. |
| // Must be called before the first browser context is enabled. |
| // Effective immediately. |
| void SetRemoteLogFileWriterFactoryForTesting( |
| std::unique_ptr<LogFileWriter::Factory> factory); |
| |
| // It is not always feasible to check in unit tests that uploads do not occur |
| // at a certain time, because that's (sometimes) racy with the event that |
| // suppresses the upload. We therefore allow unit tests to glimpse into the |
| // black box and verify that the box is aware that it should not upload. |
| void UploadConditionsHoldForTesting(base::OnceCallback<void(bool)> callback); |
| |
| // This allows unit tests that do not wish to change the task runner to still |
| // check when certain operations are finished. |
| // TODO(crbug.com/775415): Remove this and use PostNullTaskForTesting instead. |
| scoped_refptr<base::SequencedTaskRunner>& GetTaskRunnerForTesting(); |
| |
| void PostNullTaskForTesting(base::OnceClosure reply); |
| |
| // Documented in WebRtcRemoteEventLogManager. |
| void ShutDownForTesting(base::OnceClosure reply); |
| |
| static WebRtcEventLogManager* g_webrtc_event_log_manager; |
| |
| // The main logic will run sequentially on this runner, on which blocking |
| // tasks are allowed. |
| scoped_refptr<base::SequencedTaskRunner> task_runner_; |
| |
| // Indicates whether remote-bound logging is generally allowed, although |
| // possibly not for all profiles. This makes it possible for remote-bound to |
| // be disabled through Finch. |
| // TODO(crbug.com/775415): Remove this kill-switch. |
| const bool remote_logging_feature_enabled_; |
| |
| // Observer which will be informed whenever a local log file is started or |
| // stopped. Its callbacks are called synchronously from |task_runner_|, |
| // so the observer needs to be able to either run from any (sequenced) runner. |
| WebRtcLocalEventLogsObserver* local_logs_observer_; |
| |
| // Observer which will be informed whenever a remote log file is started or |
| // stopped. Its callbacks are called synchronously from |task_runner_|, |
| // so the observer needs to be able to either run from any (sequenced) runner. |
| WebRtcRemoteEventLogsObserver* remote_logs_observer_; |
| |
| // Manages local-bound logs - logs stored on the local filesystem when |
| // logging has been explicitly enabled by the user. |
| WebRtcLocalEventLogManager local_logs_manager_; |
| |
| // Manages remote-bound logs - logs which will be sent to a remote server. |
| // This is only possible when the appropriate Chrome policy is configured. |
| WebRtcRemoteEventLogManager remote_logs_manager_; |
| |
| // Each loaded BrowserContext is mapped to a PrefChangeRegistrar, which keeps |
| // us informed about preference changes, thereby allowing as to support |
| // dynamic refresh. |
| std::map<BrowserContextId, PrefChangeRegistrar> pref_change_registrars_; |
| |
| // This keeps track of which peer connections have event logging turned on |
| // in WebRTC, and for which client(s). |
| std::map<PeerConnectionKey, LoggingTargetBitmap> |
| peer_connections_with_event_logging_enabled_in_webrtc_; |
| |
| // The set of RenderProcessHosts with which the manager is registered for |
| // observation. Allows us to register for each RPH only once, and get notified |
| // when it exits (cleanly or due to a crash). |
| // This object is only to be accessed on the UI thread. |
| base::flat_set<content::RenderProcessHost*> observed_render_process_hosts_; |
| |
| // In production, this holds a small object that just tells WebRTC (via |
| // PeerConnectionTracker) to start/stop producing event logs for a specific |
| // peer connection. In (relevant) unit tests, a mock will be injected. |
| std::unique_ptr<PeerConnectionTrackerProxy> pc_tracker_proxy_; |
| |
| // The globals network_connection_tracker() and system_request_context() are |
| // sent down to |remote_logs_manager_| with the first enabled browser context. |
| // This member must only be accessed on the UI thread. |
| bool first_browser_context_initializations_done_; |
| |
| // May only be set for tests, in which case, it will be passed to |
| // |remote_logs_manager_| when (and if) produced. |
| std::unique_ptr<LogFileWriter::Factory> |
| remote_log_file_writer_factory_for_testing_; |
| |
| DISALLOW_COPY_AND_ASSIGN(WebRtcEventLogManager); |
| }; |
| |
| #endif // CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_H_ |