1 // Copyright 2017 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_H_
6 #define CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_H_
7 
8 #include <map>
9 #include <memory>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/callback.h"
14 #include "base/containers/flat_set.h"
15 #include "base/files/file_path.h"
16 #include "base/memory/scoped_refptr.h"
17 #include "base/time/clock.h"
18 #include "base/time/time.h"
19 #include "base/updateable_sequenced_task_runner.h"
20 #include "chrome/browser/media/webrtc/webrtc_event_log_manager_common.h"
21 #include "chrome/browser/media/webrtc/webrtc_event_log_manager_local.h"
22 #include "chrome/browser/media/webrtc/webrtc_event_log_manager_remote.h"
23 #include "components/prefs/pref_change_registrar.h"
24 #include "components/upload_list/upload_list.h"
25 #include "content/public/browser/render_process_host_observer.h"
26 #include "content/public/browser/webrtc_event_logger.h"
27 
28 class WebRTCInternalsIntegrationBrowserTest;
29 
30 namespace content {
31 class BrowserContext;
32 class NetworkConnectionTracker;
33 }  // namespace content
34 
35 namespace webrtc_event_logging {
36 
37 // This is a singleton class running in the browser UI thread (ownership of
38 // the only instance lies in BrowserContext). It is in charge of writing WebRTC
39 // event logs to temporary files, then uploading those files to remote servers,
40 // as well as of writing the logs to files which were manually indicated by the
41 // user from the WebRTCIntenals. (A log may simulatenously be written to both,
42 // either, or none.)
43 // The only instance of this class is owned by BrowserProcessImpl. It is
44 // destroyed from ~BrowserProcessImpl(), at which point any tasks posted to the
45 // internal SequencedTaskRunner, or coming from another thread, would no longer
46 // execute.
47 class WebRtcEventLogManager final : public content::RenderProcessHostObserver,
48                                     public content::WebRtcEventLogger,
49                                     public WebRtcLocalEventLogsObserver,
50                                     public WebRtcRemoteEventLogsObserver {
51  public:
52   using BrowserContextId = WebRtcEventLogPeerConnectionKey::BrowserContextId;
53 
54   // To turn WebRTC on and off, we go through PeerConnectionTrackerProxy. In
55   // order to make this toggling easily testable, PeerConnectionTrackerProxyImpl
56   // will send real messages to PeerConnectionTracker, whereas
57   // PeerConnectionTrackerProxyForTesting will be a mock that just makes sure
58   // the correct messages were attempted to be sent.
59   class PeerConnectionTrackerProxy {
60    public:
61     virtual ~PeerConnectionTrackerProxy() = default;
62 
63     virtual void EnableWebRtcEventLogging(
64         const WebRtcEventLogPeerConnectionKey& key,
65         int output_period_ms) = 0;
66 
67     virtual void DisableWebRtcEventLogging(
68         const WebRtcEventLogPeerConnectionKey& key) = 0;
69   };
70 
71   // Ensures that no previous instantiation of the class was performed, then
72   // instantiates the class and returns the object (ownership is transfered to
73   // the caller). Subsequent calls to GetInstance() will return this object,
74   // until it is destructed, at which pointer nullptr will be returned by
75   // subsequent calls.
76   static std::unique_ptr<WebRtcEventLogManager> CreateSingletonInstance();
77 
78   // Returns the object previously constructed using CreateSingletonInstance(),
79   // if it was constructed and was not yet destroyed; nullptr otherwise.
80   static WebRtcEventLogManager* GetInstance();
81 
82   // Given a BrowserContext, return the path to the directory where its
83   // remote-bound event logs are kept.
84   // Since incognito sessions don't have such a directory, an empty
85   // base::FilePath will be returned for them.
86   static base::FilePath GetRemoteBoundWebRtcEventLogsDir(
87       content::BrowserContext* browser_context);
88 
89   ~WebRtcEventLogManager() override;
90 
91   void EnableForBrowserContext(content::BrowserContext* browser_context,
92                                base::OnceClosure reply);
93 
94   void DisableForBrowserContext(content::BrowserContext* browser_context,
95                                 base::OnceClosure reply);
96 
97   void PeerConnectionAdded(int render_process_id,
98                            int lid,  // Renderer-local PeerConnection ID.
99                            base::OnceCallback<void(bool)> reply) override;
100 
101   void PeerConnectionRemoved(int render_process_id,
102                              int lid,  // Renderer-local PeerConnection ID.
103                              base::OnceCallback<void(bool)> reply) override;
104 
105   // From the logger's perspective, we treat stopping a peer connection the
106   // same as we do its removal. Should a stopped peer connection be later
107   // removed, the removal callback will assume the value |false|.
108   void PeerConnectionStopped(int render_process_id,
109                              int lid,  // Renderer-local PeerConnection ID.
110                              base::OnceCallback<void(bool)> reply) override;
111 
112   void PeerConnectionSessionIdSet(
113       int render_process_id,
114       int lid,
115       const std::string& session_id,
116       base::OnceCallback<void(bool)> reply) override;
117 
118   // The file's actual path is derived from |base_path| by adding a timestamp,
119   // the render process ID and the PeerConnection's local ID.
120   void EnableLocalLogging(const base::FilePath& base_path,
121                           base::OnceCallback<void(bool)> reply) override;
122   void EnableLocalLogging(const base::FilePath& base_path,
123                           size_t max_file_size_bytes,
124                           base::OnceCallback<void(bool)> reply);
125 
126   void DisableLocalLogging(base::OnceCallback<void(bool)> reply) override;
127 
128   void OnWebRtcEventLogWrite(
129       int render_process_id,
130       int lid,  // Renderer-local PeerConnection ID.
131       const std::string& message,
132       base::OnceCallback<void(std::pair<bool, bool>)> reply) override;
133 
134   // Start logging a peer connection's WebRTC events to a file, which will
135   // later be uploaded to a remote server. If a reply is provided, it will be
136   // posted back to BrowserThread::UI with the log-identifier (if successful)
137   // of the created log or (if unsuccessful) the error message.
138   // See the comment in  WebRtcRemoteEventLogManager::StartRemoteLogging for
139   // more details.
140   void StartRemoteLogging(
141       int render_process_id,
142       const std::string& session_id,
143       size_t max_file_size_bytes,
144       int output_period_ms,
145       size_t web_app_id,
146       base::OnceCallback<void(bool, const std::string&, const std::string&)>
147           reply);
148 
149   // Clear WebRTC event logs associated with a given browser context, in a given
150   // time range (|delete_begin| inclusive, |delete_end| exclusive), then
151   // post |reply| back to the thread from which the method was originally
152   // invoked (which can be any thread).
153   void ClearCacheForBrowserContext(
154       const content::BrowserContext* browser_context,
155       const base::Time& delete_begin,
156       const base::Time& delete_end,
157       base::OnceClosure reply);
158 
159   // Get the logging history (relevant only to remote-bound logs). This includes
160   // information such as when logs were captured, when they were uploaded,
161   // and what their ID in the remote server was.
162   // Must be called on the UI thread.
163   // The results to the query are posted using |reply| back to the UI thread.
164   // If |browser_context_id| is not the ID a profile for which remote-bound
165   // logging is enabled, an empty list is returned.
166   // The returned vector is sorted by capture time in ascending order.
167   void GetHistory(
168       BrowserContextId browser_context_id,
169       base::OnceCallback<void(const std::vector<UploadList::UploadInfo>&)>
170           reply);
171 
172   // Set (or unset) an observer that will be informed whenever a local log file
173   // is started/stopped. The observer needs to be able to either run from
174   // anywhere. If you need the code to run on specific runners or queues, have
175   // the observer post them there.
176   // If a reply callback is given, it will be posted back to BrowserThread::UI
177   // after the observer has been set.
178   void SetLocalLogsObserver(WebRtcLocalEventLogsObserver* observer,
179                             base::OnceClosure reply);
180 
181   // Set (or unset) an observer that will be informed whenever a remote log file
182   // is started/stopped. Note that this refers to writing these files to disk,
183   // not for uploading them to the server.
184   // The observer needs to be able to either run from anywhere. If you need the
185   // code to run on specific runners or queues, have the observer post
186   // them there.
187   // If a reply callback is given, it will be posted back to BrowserThread::UI
188   // after the observer has been set.
189   void SetRemoteLogsObserver(WebRtcRemoteEventLogsObserver* observer,
190                              base::OnceClosure reply);
191 
192  private:
193   friend class WebRtcEventLogManagerTestBase;
194   friend class ::WebRTCInternalsIntegrationBrowserTest;
195 
196   using PeerConnectionKey = WebRtcEventLogPeerConnectionKey;
197 
198   // This bitmap allows us to track for which clients (local/remote logging)
199   // we have turned WebRTC event logging on for a given peer connection, so that
200   // we may turn it off only when the last client no longer needs it.
201   enum LoggingTarget : unsigned int {
202     kLocalLogging = 1 << 0,
203     kRemoteLogging = 1 << 1
204   };
205   using LoggingTargetBitmap = std::underlying_type<LoggingTarget>::type;
206 
207   WebRtcEventLogManager();
208 
209   bool IsRemoteLoggingAllowedForBrowserContext(
210       content::BrowserContext* browser_context) const;
211 
212   // Determines the exact subclass of LogFileWriter::Factory to be used for
213   // producing remote-bound logs.
214   std::unique_ptr<LogFileWriter::Factory> CreateRemoteLogFileWriterFactory();
215 
216   // RenderProcessHostObserver implementation.
217   void RenderProcessExited(
218       content::RenderProcessHost* host,
219       const content::ChildProcessTerminationInfo& info) override;
220   void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
221 
222   // RenderProcessExited() and RenderProcessHostDestroyed() treated similarly
223   // by this function.
224   void RenderProcessHostExitedDestroyed(content::RenderProcessHost* host);
225 
226   // WebRtcLocalEventLogsObserver implementation:
227   void OnLocalLogStarted(PeerConnectionKey peer_connection,
228                          const base::FilePath& file_path) override;
229   void OnLocalLogStopped(PeerConnectionKey peer_connection) override;
230 
231   // WebRtcRemoteEventLogsObserver implementation:
232   void OnRemoteLogStarted(PeerConnectionKey key,
233                           const base::FilePath& file_path,
234                           int output_period_ms) override;
235   void OnRemoteLogStopped(PeerConnectionKey key) override;
236 
237   void OnLoggingTargetStarted(LoggingTarget target,
238                               PeerConnectionKey key,
239                               int output_period_ms);
240   void OnLoggingTargetStopped(LoggingTarget target, PeerConnectionKey key);
241 
242   void StartListeningForPrefChangeForBrowserContext(
243       content::BrowserContext* browser_context);
244   void StopListeningForPrefChangeForBrowserContext(
245       content::BrowserContext* browser_context);
246 
247   void OnPrefChange(content::BrowserContext* browser_context);
248 
249   // network_connection_tracker() is not available during instantiation;
250   // we get it when the first profile is loaded, which is also the earliest
251   // time when it could be needed.
252   // The LogFileWriter::Factory is similarly deferred, but for a different
253   // reason - it makes it easier to allow unit tests to inject their own.
254   // OnFirstBrowserContextLoaded() is on the UI thread.
255   // OnFirstBrowserContextLoadedInternal() is the task sent to |task_runner_|.
256   void OnFirstBrowserContextLoaded();
257   void OnFirstBrowserContextLoadedInternal(
258       network::NetworkConnectionTracker* network_connection_tracker,
259       std::unique_ptr<LogFileWriter::Factory> log_file_writer_factory);
260 
261   void EnableRemoteBoundLoggingForBrowserContext(
262       BrowserContextId browser_context_id,
263       const base::FilePath& browser_context_dir,
264       base::OnceClosure reply);
265 
266   void DisableRemoteBoundLoggingForBrowserContext(
267       BrowserContextId browser_context_id,
268       base::OnceClosure reply);
269 
270   void RemovePendingRemoteBoundLogsForNotEnabledBrowserContext(
271       BrowserContextId browser_context_id,
272       const base::FilePath& browser_context_dir,
273       base::OnceClosure reply);
274 
275   void PeerConnectionAddedInternal(PeerConnectionKey key,
276                                    base::OnceCallback<void(bool)> reply);
277   void PeerConnectionRemovedInternal(PeerConnectionKey key,
278                                      base::OnceCallback<void(bool)> reply);
279 
280   void PeerConnectionSessionIdSetInternal(PeerConnectionKey key,
281                                           const std::string& session_id,
282                                           base::OnceCallback<void(bool)> reply);
283 
284   void EnableLocalLoggingInternal(const base::FilePath& base_path,
285                                   size_t max_file_size_bytes,
286                                   base::OnceCallback<void(bool)> reply);
287   void DisableLocalLoggingInternal(base::OnceCallback<void(bool)> reply);
288 
289   void OnWebRtcEventLogWriteInternal(
290       PeerConnectionKey key,
291       const std::string& message,
292       base::OnceCallback<void(std::pair<bool, bool>)> reply);
293 
294   void StartRemoteLoggingInternal(
295       int render_process_id,
296       BrowserContextId browser_context_id,
297       const std::string& session_id,
298       const base::FilePath& browser_context_dir,
299       size_t max_file_size_bytes,
300       int output_period_ms,
301       size_t web_app_id,
302       base::OnceCallback<void(bool, const std::string&, const std::string&)>
303           reply);
304 
305   void ClearCacheForBrowserContextInternal(BrowserContextId browser_context_id,
306                                            const base::Time& delete_begin,
307                                            const base::Time& delete_end);
308 
309   void OnClearCacheForBrowserContextDoneInternal(base::OnceClosure reply);
310 
311   void GetHistoryInternal(
312       BrowserContextId browser_context_id,
313       base::OnceCallback<void(const std::vector<UploadList::UploadInfo>&)>
314           reply);
315 
316   void RenderProcessExitedInternal(int render_process_id);
317 
318   void SetLocalLogsObserverInternal(WebRtcLocalEventLogsObserver* observer,
319                                     base::OnceClosure reply);
320 
321   void SetRemoteLogsObserverInternal(WebRtcRemoteEventLogsObserver* observer,
322                                      base::OnceClosure reply);
323 
324   // Injects a fake clock, to be used by tests. For example, this could be
325   // used to inject a frozen clock, thereby allowing unit tests to know what a
326   // local log's filename would end up being.
327   void SetClockForTesting(base::Clock* clock, base::OnceClosure reply);
328 
329   // Injects a PeerConnectionTrackerProxy for testing. The normal tracker proxy
330   // is used to communicate back to WebRTC whether event logging is desired for
331   // a given peer connection. Using this function, those indications can be
332   // intercepted by a unit test.
333   void SetPeerConnectionTrackerProxyForTesting(
334       std::unique_ptr<PeerConnectionTrackerProxy> pc_tracker_proxy,
335       base::OnceClosure reply);
336 
337   // Injects a fake uploader, to be used by unit tests.
338   void SetWebRtcEventLogUploaderFactoryForTesting(
339       std::unique_ptr<WebRtcEventLogUploader::Factory> uploader_factory,
340       base::OnceClosure reply);
341 
342   // Sets a LogFileWriter factory for remote-bound files.
343   // Only usable in tests.
344   // Must be called before the first browser context is enabled.
345   // Effective immediately.
346   void SetRemoteLogFileWriterFactoryForTesting(
347       std::unique_ptr<LogFileWriter::Factory> factory);
348 
349   // It is not always feasible to check in unit tests that uploads do not occur
350   // at a certain time, because that's (sometimes) racy with the event that
351   // suppresses the upload. We therefore allow unit tests to glimpse into the
352   // black box and verify that the box is aware that it should not upload.
353   void UploadConditionsHoldForTesting(base::OnceCallback<void(bool)> callback);
354 
355   // This allows unit tests that do not wish to change the task runner to still
356   // check when certain operations are finished.
357   // TODO(crbug.com/775415): Remove this and use PostNullTaskForTesting instead.
358   scoped_refptr<base::SequencedTaskRunner> GetTaskRunnerForTesting();
359 
360   void PostNullTaskForTesting(base::OnceClosure reply);
361 
362   // Documented in WebRtcRemoteEventLogManager.
363   void ShutDownForTesting(base::OnceClosure reply);
364 
365   static WebRtcEventLogManager* g_webrtc_event_log_manager;
366 
367   // The main logic will run sequentially on this runner, on which blocking
368   // tasks are allowed.
369   scoped_refptr<base::UpdateableSequencedTaskRunner> task_runner_;
370 
371   // The number of user-blocking tasks.
372   // The priority of |task_runner_| is increased to USER_BLOCKING when this is
373   // non-zero, and reduced to BEST_EFFORT when zero.
374   // This object is only to be accessed on the UI thread.
375   size_t num_user_blocking_tasks_;
376 
377   // Indicates whether remote-bound logging is generally allowed, although
378   // possibly not for all profiles. This makes it possible for remote-bound to
379   // be disabled through Finch.
380   // TODO(crbug.com/775415): Remove this kill-switch.
381   const bool remote_logging_feature_enabled_;
382 
383   // Observer which will be informed whenever a local log file is started or
384   // stopped. Its callbacks are called synchronously from |task_runner_|,
385   // so the observer needs to be able to either run from any (sequenced) runner.
386   WebRtcLocalEventLogsObserver* local_logs_observer_;
387 
388   // Observer which will be informed whenever a remote log file is started or
389   // stopped. Its callbacks are called synchronously from |task_runner_|,
390   // so the observer needs to be able to either run from any (sequenced) runner.
391   WebRtcRemoteEventLogsObserver* remote_logs_observer_;
392 
393   // Manages local-bound logs - logs stored on the local filesystem when
394   // logging has been explicitly enabled by the user.
395   WebRtcLocalEventLogManager local_logs_manager_;
396 
397   // Manages remote-bound logs - logs which will be sent to a remote server.
398   // This is only possible when the appropriate Chrome policy is configured.
399   WebRtcRemoteEventLogManager remote_logs_manager_;
400 
401   // Each loaded BrowserContext is mapped to a PrefChangeRegistrar, which keeps
402   // us informed about preference changes, thereby allowing as to support
403   // dynamic refresh.
404   std::map<BrowserContextId, PrefChangeRegistrar> pref_change_registrars_;
405 
406   // This keeps track of which peer connections have event logging turned on
407   // in WebRTC, and for which client(s).
408   std::map<PeerConnectionKey, LoggingTargetBitmap>
409       peer_connections_with_event_logging_enabled_in_webrtc_;
410 
411   // The set of RenderProcessHosts with which the manager is registered for
412   // observation. Allows us to register for each RPH only once, and get notified
413   // when it exits (cleanly or due to a crash).
414   // This object is only to be accessed on the UI thread.
415   base::flat_set<content::RenderProcessHost*> observed_render_process_hosts_;
416 
417   // In production, this holds a small object that just tells WebRTC (via
418   // PeerConnectionTracker) to start/stop producing event logs for a specific
419   // peer connection. In (relevant) unit tests, a mock will be injected.
420   std::unique_ptr<PeerConnectionTrackerProxy> pc_tracker_proxy_;
421 
422   // The globals network_connection_tracker() and system_request_context() are
423   // sent down to |remote_logs_manager_| with the first enabled browser context.
424   // This member must only be accessed on the UI thread.
425   bool first_browser_context_initializations_done_;
426 
427   // May only be set for tests, in which case, it will be passed to
428   // |remote_logs_manager_| when (and if) produced.
429   std::unique_ptr<LogFileWriter::Factory>
430       remote_log_file_writer_factory_for_testing_;
431 
432   DISALLOW_COPY_AND_ASSIGN(WebRtcEventLogManager);
433 };
434 
435 }  // namespace webrtc_event_logging
436 
437 #endif  // CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_H_
438