blob: 93ca39cc89df8475005aa94427aeaf39b6fbdeef [file] [log] [blame]
// Copyright (c) 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 CONTENT_BROWSER_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_H_
#define CONTENT_BROWSER_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_H_
#include <map>
#include <memory>
#include <type_traits>
#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/optional.h"
#include "base/sequenced_task_runner.h"
#include "base/time/clock.h"
#include "content/browser/webrtc/webrtc_event_log_manager_common.h"
#include "content/browser/webrtc/webrtc_local_event_log_manager.h"
#include "content/browser/webrtc/webrtc_remote_event_log_manager.h"
#include "content/common/content_export.h"
#include "content/public/browser/render_process_host_observer.h"
namespace content {
class BrowserContext;
// 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.)
class CONTENT_EXPORT WebRtcEventLogManager
: public RenderProcessHostObserver,
public WebRtcLocalEventLogsObserver,
public WebRtcRemoteEventLogsObserver {
public:
using BrowserContextId = WebRtcRemoteEventLogManager::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(WebRtcEventLogPeerConnectionKey key,
bool event_logging_enabled) = 0;
};
// Translate a BrowserContext into an ID, allowing associating PeerConnections
// with it while making sure that its methods would never be called outside
// of the UI thread.
static BrowserContextId GetBrowserContextId(
const BrowserContext* browser_context);
// Ensures that no previous instantiation of the class was performed, then
// instantiates the class and returns the object. Subsequent calls to
// GetInstance() will return this object.
static WebRtcEventLogManager* CreateSingletonInstance();
// Returns the object previously constructed using CreateSingletonInstance().
// Can be null in tests.
static WebRtcEventLogManager* GetInstance();
~WebRtcEventLogManager() override;
// Enables WebRTC event logging for a given BrowserContext:
// * Pending logs from previous sessions become eligible to be uploaded.
// * New logs for active peer connections *may* be recorded. (This does *not*
// start logging; it just makes it possible.)
// This function would typically be called during a BrowserContext's
// initialization.
// This function must not be called for an off-the-records BrowserContext.
// Local-logging is not associated with BrowserContexts, and is allowed even
// if EnableForBrowserContext is not called. That is, even for incognito mode.
void EnableForBrowserContext(const BrowserContext* browser_context,
base::OnceClosure reply = base::OnceClosure());
// Disables WebRTC event logging for a given BrowserContext. New remote-bound
// WebRTC event logs will no longer be created for this BrowserContext.
// This would typically be called when a BrowserContext is destroyed, so it
// receives the ID instead of a pointer to the BrowserContext itself, to
// ensure that it would not call any virtual functions during destruction.
void DisableForBrowserContext(BrowserContextId browser_context_id,
base::OnceClosure reply = base::OnceClosure());
// Call this to let the manager know when a PeerConnection was created.
// If a reply callback is given, it will be posted back to BrowserThread::UI,
// with true if and only if the operation was successful (failure is only
// possible if a peer connection with this exact key was previously added,
// but not removed).
void PeerConnectionAdded(
int render_process_id,
int lid, // Renderer-local PeerConnection ID.
base::OnceCallback<void(bool)> reply = base::OnceCallback<void(bool)>());
// Call this to let the manager know when a PeerConnection was closed.
// If a reply callback is given, it will be posted back to BrowserThread::UI,
// with true if and only if the operation was successful (failure is only
// possible if a peer connection with this key was not previously added,
// or if it has since already been removed).
void PeerConnectionRemoved(
int render_process_id,
int lid, // Renderer-local PeerConnection ID.
base::OnceCallback<void(bool)> reply = base::OnceCallback<void(bool)>());
// Enable local logging of RTC events.
// Local logging is distinguished from remote logging, in that local logs are
// kept in response to explicit user input, are saved to a specific location,
// and are never removed by Chrome.
// The file's actual path is derived from |base_path| by adding a timestamp,
// the render process ID and the PeerConnection's local ID.
// If a reply callback is given, it will be posted back to BrowserThread::UI,
// with true if and only if local logging was *not* already on.
// Note #1: An illegal file path, or one where we don't have the necessary
// permissions, does not cause a |false| reply, since even when we have the
// permissions, we're not guaranteed to keep them, and some files might be
// legal while others aren't due to additional restrictions (number of files,
// length of filename, etc.).
// Note #2: If the number of currently active peer connections exceeds the
// maximum number of local log files, there is no guarantee about which PCs
// will get a local log file associated (specifically, we do *not* guarantee
// it would be either the oldest or the newest).
void EnableLocalLogging(
const base::FilePath& base_path,
size_t max_file_size_bytes = kDefaultMaxLocalLogFileSizeBytes,
base::OnceCallback<void(bool)> reply = base::OnceCallback<void(bool)>());
// Disable local logging of RTC events.
// Any active local logs are stopped. Peer connections added after this call
// will not get a local log associated with them.
void DisableLocalLogging(
base::OnceCallback<void(bool)> reply = base::OnceCallback<void(bool)>());
// Start logging the 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 return value provided by
// WebRtcRemoteEventLogManager::StartRemoteLogging - see the comment there
// for more details.
// TODO(eladalon): Add support for injecting metadata through this call.
// https://crbug.com/775415
void StartRemoteLogging(
int render_process_id,
int lid, // Renderer-local PeerConnection ID.
size_t max_file_size_bytes,
base::OnceCallback<void(bool)> reply = base::OnceCallback<void(bool)>());
// Called when a new log fragment is sent from the renderer. This will
// potentially be written to a local WebRTC event log, a log destined for
// upload, or both.
// If a reply callback is given, it will be posted back to BrowserThread::UI
// with a pair of bools, the first bool associated with local logging and the
// second bool associated with remote-bound logging. Each bool assumes the
// value true if and only if the message was written in its entirety into
// a local/remote-bound log file.
void OnWebRtcEventLogWrite(
int render_process_id,
int lid, // Renderer-local PeerConnection ID.
const std::string& message,
base::OnceCallback<void(std::pair<bool, bool>)> reply =
base::OnceCallback<void(std::pair<bool, bool>)>());
// 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 = base::OnceClosure());
// 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 = base::OnceClosure());
protected:
friend class WebRtcEventLogManagerTest; // Unit tests inject a frozen clock.
WebRtcEventLogManager();
// This can be used by unit tests to ensure that they would run synchronously.
void SetTaskRunnerForTesting(
const scoped_refptr<base::SequencedTaskRunner>& task_runner);
// This allows unit tests that do not wish to change the task runner to still
// check when certain operations are finished.
scoped_refptr<base::SequencedTaskRunner>& GetTaskRunnerForTesting();
private:
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;
static WebRtcEventLogManager* g_webrtc_event_log_manager;
// RenderProcessHostObserver implementation.
void RenderProcessExited(RenderProcessHost* host,
base::TerminationStatus status,
int exit_code) override;
void RenderProcessHostDestroyed(RenderProcessHost* host) override;
// RenderProcessExited() and RenderProcessHostDestroyed() treated similarly
// by this function.
void RenderProcessHostExitedDestroyed(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 EnableForBrowserContextInternal(
BrowserContextId browser_context_id,
const base::FilePath& browser_context_dir,
base::OnceClosure reply);
void DisableForBrowserContextInternal(BrowserContextId browser_context_id,
base::OnceClosure reply);
void PeerConnectionAddedInternal(int render_process_id,
int lid,
base::OnceCallback<void(bool)> reply);
void PeerConnectionRemovedInternal(int render_process_id,
int lid,
BrowserContextId browser_context_id,
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 StartRemoteLoggingInternal(
int render_process_id,
int lid, // Renderer-local PeerConnection ID.
base::Optional<BrowserContextId> browser_context_id,
const base::FilePath& browser_context_dir,
size_t max_file_size_bytes,
base::OnceCallback<void(bool)> reply);
void OnWebRtcEventLogWriteInternal(
int render_process_id,
int lid, // Renderer-local PeerConnection ID.
bool remote_logging_allowed,
const std::string& message,
base::OnceCallback<void(std::pair<bool, bool>)> reply);
void RenderProcessExitedInternal(int render_process_id);
void SetLocalLogsObserverInternal(WebRtcLocalEventLogsObserver* observer,
base::OnceClosure reply);
void SetRemoteLogsObserverInternal(WebRtcRemoteEventLogsObserver* observer,
base::OnceClosure reply);
// Methods for injecting testing utilities in place of actual implementations.
// Because these are only intended for testing, we perform these changes
// asynchronously, trusting the unit tests to do so carefully enough.
void SetClockForTesting(base::Clock* clock);
void SetPeerConnectionTrackerProxyForTesting(
std::unique_ptr<PeerConnectionTrackerProxy> pc_tracker_proxy);
void SetWebRtcEventLogUploaderFactoryForTesting(
std::unique_ptr<WebRtcEventLogUploader::Factory> uploader_factory);
// 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.
WebRtcRemoteEventLogManager remote_logs_manager_;
// 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_;
// 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<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 main logic will run sequentially on this runner, on which blocking
// tasks are allowed.
scoped_refptr<base::SequencedTaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(WebRtcEventLogManager);
};
} // namespace content
#endif // CONTENT_BROWSER_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_H_