chromium/chrome/browser/media/webrtc/webrtc_event_log_manager_common.h

// Copyright 2017 The Chromium Authors
// 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_COMMON_H_
#define CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_COMMON_H_

#include <memory>
#include <optional>
#include <string>

#include "base/files/file_path.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "ipc/ipc_message.h"

class Profile;

namespace content {
class BrowserContext;
}  // namespace content

namespace webrtc_event_logging {

// This file is intended for:
// 1. Code shared between WebRtcEventLogManager, WebRtcLocalEventLogManager
//    and WebRtcRemoteEventLogManager.
// 2. Code specific to either of the above classes, but which also needs
//    to be seen by unit tests (such as constants).

extern const size_t kWebRtcEventLogManagerUnlimitedFileSize;

extern const size_t kDefaultMaxLocalLogFileSizeBytes;
extern const size_t kMaxNumberLocalWebRtcEventLogFiles;

extern const size_t kMaxRemoteLogFileSizeBytes;

extern const int kMaxOutputPeriodMs;

// Maximum size for a response from Crash, which is the upload ID.
extern const size_t kWebRtcEventLogMaxUploadIdBytes;

// The number of digits required to encode a remote-bound log ID.
extern const size_t kWebRtcEventLogIdLength;

// Min/max legal web-app IDs.
extern const size_t kMinWebRtcEventLogWebAppId;
extern const size_t kMaxWebRtcEventLogWebAppId;

// Sentinel value, guaranteed not to fall inside the range of min-max valid IDs.
extern const size_t kInvalidWebRtcEventLogWebAppId;

// Limit over the number of concurrently active (currently being written to
// disk) remote-bound log files. This limits IO operations, and so it is
// applied globally (all browser contexts are limited together).
extern const size_t kMaxActiveRemoteBoundWebRtcEventLogs;

// Limit over the number of pending logs (logs stored on disk and awaiting to
// be uploaded to a remote server). This limit avoids excessive storage. If a
// user chooses to have multiple profiles (and hence browser contexts) on a
// system, it is assumed that the user has enough storage to accommodate
// the increased storage consumption that comes with it. Therefore, this
// limit is applied per browser context.
extern const size_t kMaxPendingRemoteBoundWebRtcEventLogs;

// Max number of history files that may be kept; after this number is exceeded,
// the oldest logs should be pruned.
extern const size_t kMaxWebRtcEventLogHistoryFiles;

// Overhead incurred by GZIP due to its header and footer.
extern const size_t kGzipOverheadBytes;

// Remote-bound log files' names will be of the format:
// [prefix]_[web_app_id]_[log_id].[ext]
// Where:
// * |prefix| is equal to kRemoteBoundWebRtcEventLogFileNamePrefix.
// * |web_app_id| is a number between kMinWebRtcEventLogWebAppId and
//   kMaxWebRtcEventLogWebAppId, with zero padding.
// * |log_id| is composed of 32 random characters from '0'-'9' and 'A'-'F'.
// * |ext| is the extension determined by the used LogCompressor::Factory,
//   which will be either kWebRtcEventLogUncompressedExtension or
//   kWebRtcEventLogGzippedExtension.
extern const char kRemoteBoundWebRtcEventLogFileNamePrefix[];
extern const base::FilePath::CharType kWebRtcEventLogUncompressedExtension[];
extern const base::FilePath::CharType kWebRtcEventLogGzippedExtension[];

// Logs themselves are kept on disk for kRemoteBoundWebRtcEventLogsMaxRetention,
// or until uploaded. Smaller history files are kept for a longer time, allowing
// Chrome to display on chrome://webrtc-logs/ that these files were captured
// and later uploaded.
extern const base::FilePath::CharType kWebRtcEventLogHistoryExtension[];

// Remote-bound event logs will not be uploaded if the time since their last
// modification (meaning the time when they were completed) exceeds this value.
// Such expired files will be purged from disk when examined.
extern const base::TimeDelta kRemoteBoundWebRtcEventLogsMaxRetention;

// These are made globally visible so that unit tests may check for them.
extern const char kStartRemoteLoggingFailureAlreadyLogging[];
extern const char kStartRemoteLoggingFailureDeadRenderProcessHost[];
extern const char kStartRemoteLoggingFailureFeatureDisabled[];
extern const char kStartRemoteLoggingFailureFileCreationError[];
extern const char kStartRemoteLoggingFailureFilePathUsedHistory[];
extern const char kStartRemoteLoggingFailureFilePathUsedLog[];
extern const char kStartRemoteLoggingFailureIllegalWebAppId[];
extern const char kStartRemoteLoggingFailureLoggingDisabledBrowserContext[];
extern const char kStartRemoteLoggingFailureMaxSizeTooLarge[];
extern const char kStartRemoteLoggingFailureMaxSizeTooSmall[];
extern const char kStartRemoteLoggingFailureNoAdditionalActiveLogsAllowed[];
extern const char kStartRemoteLoggingFailureOutputPeriodMsTooLarge[];
extern const char kStartRemoteLoggingFailureUnknownOrInactivePeerConnection[];
extern const char kStartRemoteLoggingFailureUnlimitedSizeDisallowed[];

// Values for the histogram for the result of the API call to collect
// a WebRTC event log.
// Must match the numbering of WebRtcEventLoggingApiEnum in enums.xml.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class WebRtcEventLoggingApiUma {};

void UmaRecordWebRtcEventLoggingApi(WebRtcEventLoggingApiUma result);

// Values for the histogram for the result of the upload of a WebRTC event log.
// Must match the numbering of WebRtcEventLoggingUploadEnum in enums.xml.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class WebRtcEventLoggingUploadUma {};

void UmaRecordWebRtcEventLoggingUpload(WebRtcEventLoggingUploadUma result);

// Success is signalled by 0.
// All negative values signal errors.
// Positive values are not used.
void UmaRecordWebRtcEventLoggingNetErrorType(int net_error);

// For a given Chrome session, this is a unique key for PeerConnections.
// It's not, however, unique between sessions (after Chrome is restarted).
struct WebRtcEventLogPeerConnectionKey {};

// Sentinel value for an unknown BrowserContext.
extern const WebRtcEventLogPeerConnectionKey::BrowserContextId
    kNullBrowserContextId;

// Holds housekeeping information about log files.
struct WebRtcLogFileInfo {};

// An observer for notifications of local log files being started/stopped, and
// the paths which will be used for these logs.
class WebRtcLocalEventLogsObserver {};

// An observer for notifications of remote-bound log files being
// started/stopped. The start event would likely only interest unit tests
// (because it exposes the randomized filename to them). The stop event is of
// general interest, because it would often mean that WebRTC can stop sending
// us event logs for this peer connection.
// Some cases where OnRemoteLogStopped would be called include:
// 1. The PeerConnection has become inactive.
// 2. The file's maximum size has been reached.
// 3. Any type of error while writing to the file.
class WebRtcRemoteEventLogsObserver {};

// Writes a log to a file while observing a maximum size.
class LogFileWriter {};

// Produces LogFileWriter instances that perform no compression.
class BaseLogFileWriterFactory : public LogFileWriter::Factory {};

// Interface for a class that provides compression of a stream, while attempting
// to observe a limit on the size.
//
// One should note that:
// * For compressors that use a footer, to guarantee proper decompression,
//   the footer must be written to the file.
// * In such a case, usually, nothing can be omitted from the file, or the
//   footer's CRC (if used) would be wrong.
// * Determining a string's size pre-compression, without performing the actual
//   compression, is heuristic in nature.
//
// Therefore, compression might terminate (FULL) earlier than it
// must, or even in theory (which we attempt to avoid in practice) exceed the
// size allowed it, in which case the file will be discarded (ERROR).
class LogCompressor {};

// Estimates the compressed size, without performing compression (except in
// unit tests, where performance is of lesser importance).
// This interface allows unit tests to simulate specific cases, such as
// over/under-estimation, and show that the code using the LogCompressor
// deals with them correctly. (E.g., if the estimation expects the compression
// to not go over-budget, but then it does.)
// The estimator is expected to be stateful. That is, the order of calls to
// EstimateCompressedSize() should correspond to the order of calls
// to Compress().
class CompressedSizeEstimator {};

// Provides a conservative estimation of the number of bytes required to
// compress a string using GZIP. This estimation is not expected to ever
// be overly optimistic, but the code using it should nevertheless be prepared
// to deal with that theoretical possibility.
class DefaultGzippedSizeEstimator : public CompressedSizeEstimator {};

// Interface for producing LogCompressorGzip objects.
class GzipLogCompressorFactory : public LogCompressor::Factory {};

// Produces LogFileWriter instances that perform compression using GZIP.
class GzippedLogFileWriterFactory : public LogFileWriter::Factory {};

// Create a random identifier of 32 hexadecimal (uppercase) characters.
std::string CreateWebRtcEventLogId();

// Translate a BrowserContext into an ID. This lets us associate PeerConnections
// with BrowserContexts, while making sure that we never call the
// BrowserContext's methods outside of the UI thread (because we can't call them
// at all without a cast that would alert us to the danger).
WebRtcEventLogPeerConnectionKey::BrowserContextId GetBrowserContextId(
    const content::BrowserContext* browser_context);

// Fetches the BrowserContext associated with the render process ID, then
// returns its BrowserContextId. (If the render process has already died,
// it would have no BrowserContext associated, so the ID associated with a
// null BrowserContext will be returned.)
WebRtcEventLogPeerConnectionKey::BrowserContextId GetBrowserContextId(
    int render_process_id);

// Given a BrowserContext's directory, return the path to the directory where
// we store the pending remote-bound logs associated with this BrowserContext.
// This function may be called on any task queue.
base::FilePath GetRemoteBoundWebRtcEventLogsDir(
    const base::FilePath& browser_context_dir);

// Produce the path to a remote-bound WebRTC event log file with the given
// log ID, web-app ID and extension, in the given directory.
base::FilePath WebRtcEventLogPath(
    const base::FilePath& remote_logs_dir,
    const std::string& log_id,
    size_t web_app_id,
    const base::FilePath::StringPieceType& extension);

// Checks whether the path/filename would be a valid reference to a remote-bound
// even log. These functions do not examine the file's content or its extension.
bool IsValidRemoteBoundLogFilename(const std::string& filename);
bool IsValidRemoteBoundLogFilePath(const base::FilePath& path);

// Given WebRTC event log's path, return the path to the history file that
// is, or would be, associated with it.
base::FilePath GetWebRtcEventLogHistoryFilePath(const base::FilePath& path);

// Attempts to extract the local ID from the file's path. Returns the empty
// string in case of an error.
std::string ExtractRemoteBoundWebRtcEventLogLocalIdFromPath(
    const base::FilePath& path);

// Attempts to extract the web-app ID from the file's path.
// Returns kInvalidWebRtcEventLogWebAppId in case of an error.
size_t ExtractRemoteBoundWebRtcEventLogWebAppIdFromPath(
    const base::FilePath& path);

// Used to determine the default value for the policy controlling event logging.
bool DoesProfileDefaultToLoggingEnabled(const Profile* const profile);

}  // namespace webrtc_event_logging

#endif  // CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_COMMON_H_