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_COMMON_H_
6 #define CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_COMMON_H_
7 
8 #include <memory>
9 #include <string>
10 
11 #include "base/files/file_path.h"
12 #include "base/optional.h"
13 #include "base/time/time.h"
14 #include "build/build_config.h"
15 
16 class Profile;
17 
18 namespace content {
19 class BrowserContext;
20 }  // namespace content
21 
22 namespace webrtc_event_logging {
23 
24 // This file is intended for:
25 // 1. Code shared between WebRtcEventLogManager, WebRtcLocalEventLogManager
26 //    and WebRtcRemoteEventLogManager.
27 // 2. Code specific to either of the above classes, but which also needs
28 //    to be seen by unit tests (such as constants).
29 
30 extern const size_t kWebRtcEventLogManagerUnlimitedFileSize;
31 
32 extern const size_t kDefaultMaxLocalLogFileSizeBytes;
33 extern const size_t kMaxNumberLocalWebRtcEventLogFiles;
34 
35 extern const size_t kMaxRemoteLogFileSizeBytes;
36 
37 extern const int kMaxOutputPeriodMs;
38 
39 // Maximum size for a response from Crash, which is the upload ID.
40 extern const size_t kWebRtcEventLogMaxUploadIdBytes;
41 
42 // The number of digits required to encode a remote-bound log ID.
43 extern const size_t kWebRtcEventLogIdLength;
44 
45 // Min/max legal web-app IDs.
46 extern const size_t kMinWebRtcEventLogWebAppId;
47 extern const size_t kMaxWebRtcEventLogWebAppId;
48 
49 // Sentinel value, guaranteed not to fall inside the range of min-max valid IDs.
50 extern const size_t kInvalidWebRtcEventLogWebAppId;
51 
52 // Limit over the number of concurrently active (currently being written to
53 // disk) remote-bound log files. This limits IO operations, and so it is
54 // applied globally (all browser contexts are limited together).
55 extern const size_t kMaxActiveRemoteBoundWebRtcEventLogs;
56 
57 // Limit over the number of pending logs (logs stored on disk and awaiting to
58 // be uploaded to a remote server). This limit avoids excessive storage. If a
59 // user chooses to have multiple profiles (and hence browser contexts) on a
60 // system, it is assumed that the user has enough storage to accommodate
61 // the increased storage consumption that comes with it. Therefore, this
62 // limit is applied per browser context.
63 extern const size_t kMaxPendingRemoteBoundWebRtcEventLogs;
64 
65 // Max number of history files that may be kept; after this number is exceeded,
66 // the oldest logs should be pruned.
67 extern const size_t kMaxWebRtcEventLogHistoryFiles;
68 
69 // Overhead incurred by GZIP due to its header and footer.
70 extern const size_t kGzipOverheadBytes;
71 
72 // Remote-bound log files' names will be of the format:
73 // [prefix]_[web_app_id]_[log_id].[ext]
74 // Where:
75 // * |prefix| is equal to kRemoteBoundWebRtcEventLogFileNamePrefix.
76 // * |web_app_id| is a number between kMinWebRtcEventLogWebAppId and
77 //   kMaxWebRtcEventLogWebAppId, with zero padding.
78 // * |log_id| is composed of 32 random characters from '0'-'9' and 'A'-'F'.
79 // * |ext| is the extension determined by the used LogCompressor::Factory,
80 //   which will be either kWebRtcEventLogUncompressedExtension or
81 //   kWebRtcEventLogGzippedExtension.
82 extern const char kRemoteBoundWebRtcEventLogFileNamePrefix[];
83 extern const base::FilePath::CharType kWebRtcEventLogUncompressedExtension[];
84 extern const base::FilePath::CharType kWebRtcEventLogGzippedExtension[];
85 
86 // Logs themselves are kept on disk for kRemoteBoundWebRtcEventLogsMaxRetention,
87 // or until uploaded. Smaller history files are kept for a longer time, allowing
88 // Chrome to display on chrome://webrtc-logs/ that these files were captured
89 // and later uploaded.
90 extern const base::FilePath::CharType kWebRtcEventLogHistoryExtension[];
91 
92 // Remote-bound event logs will not be uploaded if the time since their last
93 // modification (meaning the time when they were completed) exceeds this value.
94 // Such expired files will be purged from disk when examined.
95 extern const base::TimeDelta kRemoteBoundWebRtcEventLogsMaxRetention;
96 
97 // These are made globally visible so that unit tests may check for them.
98 extern const char kStartRemoteLoggingFailureAlreadyLogging[];
99 extern const char kStartRemoteLoggingFailureDeadRenderProcessHost[];
100 extern const char kStartRemoteLoggingFailureFeatureDisabled[];
101 extern const char kStartRemoteLoggingFailureFileCreationError[];
102 extern const char kStartRemoteLoggingFailureFilePathUsedHistory[];
103 extern const char kStartRemoteLoggingFailureFilePathUsedLog[];
104 extern const char kStartRemoteLoggingFailureIllegalWebAppId[];
105 extern const char kStartRemoteLoggingFailureLoggingDisabledBrowserContext[];
106 extern const char kStartRemoteLoggingFailureMaxSizeTooLarge[];
107 extern const char kStartRemoteLoggingFailureMaxSizeTooSmall[];
108 extern const char kStartRemoteLoggingFailureNoAdditionalActiveLogsAllowed[];
109 extern const char kStartRemoteLoggingFailureOutputPeriodMsTooLarge[];
110 extern const char kStartRemoteLoggingFailureUnknownOrInactivePeerConnection[];
111 extern const char kStartRemoteLoggingFailureUnlimitedSizeDisallowed[];
112 
113 // Values for the histogram for the result of the API call to collect
114 // a WebRTC event log.
115 // Must match the numbering of WebRtcEventLoggingApiEnum in enums.xml.
116 // These values are persisted to logs. Entries should not be renumbered and
117 // numeric values should never be reused.
118 enum class WebRtcEventLoggingApiUma {
119   kSuccess = 0,                         // Log successfully collected.
120   kDeadRph = 1,                         // Log not collected.
121   kFeatureDisabled = 2,                 // Log not collected.
122   kIncognito = 3,                       // Log not collected.
123   kInvalidArguments = 4,                // Log not collected.
124   kIllegalSessionId = 5,                // Log not collected.
125   kDisabledBrowserContext = 6,          // Log not collected.
126   kUnknownOrInvalidPeerConnection = 7,  // Log not collected.
127   kAlreadyLogging = 8,                  // Log not collected.
128   kNoAdditionalLogsAllowed = 9,         // Log not collected.
129   kLogPathNotAvailable = 10,            // Log not collected.
130   kHistoryPathNotAvailable = 11,        // Log not collected.
131   kFileCreationError = 12,              // Log not collected.
132   kMaxValue = kFileCreationError
133 };
134 
135 void UmaRecordWebRtcEventLoggingApi(WebRtcEventLoggingApiUma result);
136 
137 // Values for the histogram for the result of the upload of a WebRTC event log.
138 // Must match the numbering of WebRtcEventLoggingUploadEnum in enums.xml.
139 // These values are persisted to logs. Entries should not be renumbered and
140 // numeric values should never be reused.
141 enum class WebRtcEventLoggingUploadUma {
142   kSuccess = 0,                            // Uploaded successfully.
143   kLogFileWriteError = 1,                  // Will not be uploaded.
144   kActiveLogCancelledDueToCacheClear = 2,  // Will not be uploaded.
145   kPendingLogDeletedDueToCacheClear = 3,   // Will not be uploaded.
146   kHistoryFileCreationError = 4,           // Will not be uploaded.
147   kHistoryFileWriteError = 5,              // Will not be uploaded.
148   kLogFileReadError = 6,                   // Will not be uploaded.
149   kLogFileNameError = 7,                   // Will not be uploaded.
150   kUploadCancelled = 8,                    // Upload started then cancelled.
151   kUploadFailure = 9,                      // Upload attempted and failed.
152   kIncompletePastUpload = 10,              // Upload attempted and failed.
153   kExpiredLogFileAtChromeStart = 11,       // Expired before upload opportunity.
154   kExpiredLogFileDuringSession = 12,       // Expired before upload opportunity.
155   kMaxValue = kExpiredLogFileDuringSession
156 };
157 
158 void UmaRecordWebRtcEventLoggingUpload(WebRtcEventLoggingUploadUma result);
159 
160 // Success is signalled by 0.
161 // All negative values signal errors.
162 // Positive values are not used.
163 void UmaRecordWebRtcEventLoggingNetErrorType(int net_error);
164 
165 // For a given Chrome session, this is a unique key for PeerConnections.
166 // It's not, however, unique between sessions (after Chrome is restarted).
167 struct WebRtcEventLogPeerConnectionKey {
168   using BrowserContextId = uintptr_t;
169 
WebRtcEventLogPeerConnectionKeyWebRtcEventLogPeerConnectionKey170   constexpr WebRtcEventLogPeerConnectionKey()
171       : WebRtcEventLogPeerConnectionKey(
172             /* render_process_id = */ 0,
173             /* lid = */ 0,
174             reinterpret_cast<BrowserContextId>(nullptr)) {}
175 
WebRtcEventLogPeerConnectionKeyWebRtcEventLogPeerConnectionKey176   constexpr WebRtcEventLogPeerConnectionKey(int render_process_id,
177                                             int lid,
178                                             BrowserContextId browser_context_id)
179       : render_process_id(render_process_id),
180         lid(lid),
181         browser_context_id(browser_context_id) {}
182 
183   bool operator==(const WebRtcEventLogPeerConnectionKey& other) const {
184     // Each RPH is associated with exactly one BrowserContext.
185     DCHECK(render_process_id != other.render_process_id ||
186            browser_context_id == other.browser_context_id);
187 
188     const bool equal = std::tie(render_process_id, lid) ==
189                        std::tie(other.render_process_id, other.lid);
190     return equal;
191   }
192 
193   bool operator<(const WebRtcEventLogPeerConnectionKey& other) const {
194     // Each RPH is associated with exactly one BrowserContext.
195     DCHECK(render_process_id != other.render_process_id ||
196            browser_context_id == other.browser_context_id);
197 
198     return std::tie(render_process_id, lid) <
199            std::tie(other.render_process_id, other.lid);
200   }
201 
202   // These two fields are the actual key; any peer connection is uniquely
203   // identifiable by the renderer process in which it lives, and its ID within
204   // that process.
205   int render_process_id;
206   int lid;  // Renderer-local PeerConnection ID.
207 
208   // The BrowserContext is not actually part of the key, but each PeerConnection
209   // is associated with a BrowserContext, and that BrowserContext is almost
210   // always necessary, so it makes sense to remember it along with the key.
211   BrowserContextId browser_context_id;
212 };
213 
214 // Sentinel value for an unknown BrowserContext.
215 extern const WebRtcEventLogPeerConnectionKey::BrowserContextId
216     kNullBrowserContextId;
217 
218 // Holds housekeeping information about log files.
219 struct WebRtcLogFileInfo {
WebRtcLogFileInfoWebRtcLogFileInfo220   WebRtcLogFileInfo(
221       WebRtcEventLogPeerConnectionKey::BrowserContextId browser_context_id,
222       const base::FilePath& path,
223       base::Time last_modified)
224       : browser_context_id(browser_context_id),
225         path(path),
226         last_modified(last_modified) {}
227 
WebRtcLogFileInfoWebRtcLogFileInfo228   WebRtcLogFileInfo(const WebRtcLogFileInfo& other)
229       : browser_context_id(other.browser_context_id),
230         path(other.path),
231         last_modified(other.last_modified) {}
232 
233   bool operator<(const WebRtcLogFileInfo& other) const {
234     if (last_modified != other.last_modified) {
235       return last_modified < other.last_modified;
236     }
237     return path < other.path;  // Break ties arbitrarily, but consistently.
238   }
239 
240   // The BrowserContext which produced this file.
241   const WebRtcEventLogPeerConnectionKey::BrowserContextId browser_context_id;
242 
243   // The path to the log file itself.
244   const base::FilePath path;
245 
246   // |last_modified| recorded at BrowserContext initialization. Chrome will
247   // not modify it afterwards, and neither should the user.
248   const base::Time last_modified;
249 };
250 
251 // An observer for notifications of local log files being started/stopped, and
252 // the paths which will be used for these logs.
253 class WebRtcLocalEventLogsObserver {
254  public:
255   virtual void OnLocalLogStarted(WebRtcEventLogPeerConnectionKey key,
256                                  const base::FilePath& file_path) = 0;
257   virtual void OnLocalLogStopped(WebRtcEventLogPeerConnectionKey key) = 0;
258 
259  protected:
260   virtual ~WebRtcLocalEventLogsObserver() = default;
261 };
262 
263 // An observer for notifications of remote-bound log files being
264 // started/stopped. The start event would likely only interest unit tests
265 // (because it exposes the randomized filename to them). The stop event is of
266 // general interest, because it would often mean that WebRTC can stop sending
267 // us event logs for this peer connection.
268 // Some cases where OnRemoteLogStopped would be called include:
269 // 1. The PeerConnection has become inactive.
270 // 2. The file's maximum size has been reached.
271 // 3. Any type of error while writing to the file.
272 class WebRtcRemoteEventLogsObserver {
273  public:
274   virtual void OnRemoteLogStarted(WebRtcEventLogPeerConnectionKey key,
275                                   const base::FilePath& file_path,
276                                   int output_period_ms) = 0;
277   virtual void OnRemoteLogStopped(WebRtcEventLogPeerConnectionKey key) = 0;
278 
279  protected:
280   virtual ~WebRtcRemoteEventLogsObserver() = default;
281 };
282 
283 // Writes a log to a file while observing a maximum size.
284 class LogFileWriter {
285  public:
286   class Factory {
287    public:
288     virtual ~Factory() = default;
289 
290     // The smallest size a log file of this type may assume.
291     virtual size_t MinFileSizeBytes() const = 0;
292 
293     // The extension type associated with this type of log files.
294     virtual base::FilePath::StringPieceType Extension() const = 0;
295 
296     // Instantiate and initialize a LogFileWriter.
297     // If creation or initialization fail, an empty unique_ptr will be returned,
298     // and it will be guaranteed that the file itself is not created. (If |path|
299     // had pointed to an existing file, that file will be deleted.)
300     // If !max_file_size_bytes.has_value(), the LogFileWriter is unlimited.
301     virtual std::unique_ptr<LogFileWriter> Create(
302         const base::FilePath& path,
303         base::Optional<size_t> max_file_size_bytes) const = 0;
304   };
305 
306   virtual ~LogFileWriter() = default;
307 
308   // Init() must be called on each LogFileWriter exactly once, before it's used.
309   // If initialization fails, no further actions may be performed on the object
310   // other than Close() and Delete().
311   virtual bool Init() = 0;
312 
313   // Getter for the path of the file |this| wraps.
314   virtual const base::FilePath& path() const = 0;
315 
316   // Whether the maximum file size was reached.
317   virtual bool MaxSizeReached() const = 0;
318 
319   // Writes to the log file while respecting the file's size limit.
320   // True is returned if and only if the message was written to the file in
321   // it entirety. That is, |false| is returned either if a genuine error
322   // occurs, or when the budget does not allow the next write.
323   // If |false| is ever returned, only Close() and Delete() may subsequently
324   // be called.
325   // The function does *not* close the file.
326   // The function may not be called if MaxSizeReached().
327   virtual bool Write(const std::string& input) = 0;
328 
329   // If the file was successfully closed, true is returned, and the file may
330   // now be used. Otherwise, the file is deleted, and false is returned.
331   virtual bool Close() = 0;
332 
333   // Delete the file from disk.
334   virtual void Delete() = 0;
335 };
336 
337 // Produces LogFileWriter instances that perform no compression.
338 class BaseLogFileWriterFactory : public LogFileWriter::Factory {
339  public:
340   ~BaseLogFileWriterFactory() override = default;
341 
342   size_t MinFileSizeBytes() const override;
343 
344   base::FilePath::StringPieceType Extension() const override;
345 
346   std::unique_ptr<LogFileWriter> Create(
347       const base::FilePath& path,
348       base::Optional<size_t> max_file_size_bytes) const override;
349 };
350 
351 // Interface for a class that provides compression of a stream, while attempting
352 // to observe a limit on the size.
353 //
354 // One should note that:
355 // * For compressors that use a footer, to guarantee proper decompression,
356 //   the footer must be written to the file.
357 // * In such a case, usually, nothing can be omitted from the file, or the
358 //   footer's CRC (if used) would be wrong.
359 // * Determining a string's size pre-compression, without performing the actual
360 //   compression, is heuristic in nature.
361 //
362 // Therefore, compression might terminate (FULL) earlier than it
363 // must, or even in theory (which we attempt to avoid in practice) exceed the
364 // size allowed it, in which case the file will be discarded (ERROR).
365 class LogCompressor {
366  public:
367   // By subclassing this factory, concrete implementations of LogCompressor can
368   // be produced by unit tests, while keeping their definition in the .cc file.
369   // (Only the factory needs to be declared in the header.)
370   class Factory {
371    public:
372     virtual ~Factory() = default;
373 
374     // The smallest size a log file of this type may assume.
375     virtual size_t MinSizeBytes() const = 0;
376 
377     // Returns a LogCompressor if the parameters are valid and all
378     // initializations are successful; en empty unique_ptr otherwise.
379     // If !max_size_bytes.has_value(), an unlimited compressor is created.
380     virtual std::unique_ptr<LogCompressor> Create(
381         base::Optional<size_t> max_size_bytes) const = 0;
382   };
383 
384   // Result of a call to Compress().
385   // * OK and ERROR_ENCOUNTERED are self-explanatory.
386   // * DISALLOWED means that, due to budget constraints, the input could
387   //   not be compressed. The stream is still in a legal state, but only
388   //   a call to CreateFooter() is now allowed.
389   enum class Result { OK, DISALLOWED, ERROR_ENCOUNTERED };
390 
391   virtual ~LogCompressor() = default;
392 
393   // Produces a compression header and writes it to |output|.
394   // The size does not count towards the max size limit.
395   // Guaranteed not to fail (nothing can realistically go wrong).
396   virtual void CreateHeader(std::string* output) = 0;
397 
398   // Compresses |input| into |output|.
399   // * If compression succeeded, and the budget was observed, OK is returned.
400   // * If the compressor thinks the string, once compressed, will exceed the
401   //   maximum size (when combined with previously compressed strings),
402   //   compression will not be done, and DISALLOWED will be returned.
403   //   This allows producing a valid footer without exceeding the size limit.
404   // * Unexpected errors in the underlying compressor (e.g. zlib, etc.),
405   //   or unexpectedly getting a compressed string which exceeds the budget,
406   //   will return ERROR_ENCOUNTERED.
407   // This function may not be called again if DISALLOWED or ERROR_ENCOUNTERED
408   // were ever returned before, or after CreateFooter() was called.
409   virtual Result Compress(const std::string& input, std::string* output) = 0;
410 
411   // Produces a compression footer and writes it to |output|.
412   // The footer does not count towards the max size limit.
413   // May not be called more than once, or if Compress() returned ERROR.
414   virtual bool CreateFooter(std::string* output) = 0;
415 };
416 
417 // Estimates the compressed size, without performing compression (except in
418 // unit tests, where performance is of lesser importance).
419 // This interface allows unit tests to simulate specific cases, such as
420 // over/under-estimation, and show that the code using the LogCompressor
421 // deals with them correctly. (E.g., if the estimation expects the compression
422 // to not go over-budget, but then it does.)
423 // The estimator is expected to be stateful. That is, the order of calls to
424 // EstimateCompressedSize() should correspond to the order of calls
425 // to Compress().
426 class CompressedSizeEstimator {
427  public:
428   class Factory {
429    public:
430     virtual ~Factory() = default;
431     virtual std::unique_ptr<CompressedSizeEstimator> Create() const = 0;
432   };
433 
434   virtual ~CompressedSizeEstimator() = default;
435 
436   virtual size_t EstimateCompressedSize(const std::string& input) const = 0;
437 };
438 
439 // Provides a conservative estimation of the number of bytes required to
440 // compress a string using GZIP. This estimation is not expected to ever
441 // be overly optimistic, but the code using it should nevertheless be prepared
442 // to deal with that theoretical possibility.
443 class DefaultGzippedSizeEstimator : public CompressedSizeEstimator {
444  public:
445   class Factory : public CompressedSizeEstimator::Factory {
446    public:
447     ~Factory() override = default;
448 
449     std::unique_ptr<CompressedSizeEstimator> Create() const override;
450   };
451 
452   ~DefaultGzippedSizeEstimator() override = default;
453 
454   size_t EstimateCompressedSize(const std::string& input) const override;
455 };
456 
457 // Interface for producing LogCompressorGzip objects.
458 class GzipLogCompressorFactory : public LogCompressor::Factory {
459  public:
460   explicit GzipLogCompressorFactory(
461       std::unique_ptr<CompressedSizeEstimator::Factory> estimator_factory);
462   ~GzipLogCompressorFactory() override;
463 
464   size_t MinSizeBytes() const override;
465 
466   std::unique_ptr<LogCompressor> Create(
467       base::Optional<size_t> max_size_bytes) const override;
468 
469  private:
470   std::unique_ptr<CompressedSizeEstimator::Factory> estimator_factory_;
471 };
472 
473 // Produces LogFileWriter instances that perform compression using GZIP.
474 class GzippedLogFileWriterFactory : public LogFileWriter::Factory {
475  public:
476   explicit GzippedLogFileWriterFactory(
477       std::unique_ptr<GzipLogCompressorFactory> gzip_compressor_factory);
478 
479   ~GzippedLogFileWriterFactory() override;
480 
481   size_t MinFileSizeBytes() const override;
482 
483   base::FilePath::StringPieceType Extension() const override;
484 
485   std::unique_ptr<LogFileWriter> Create(
486       const base::FilePath& path,
487       base::Optional<size_t> max_file_size_bytes) const override;
488 
489  private:
490   std::unique_ptr<GzipLogCompressorFactory> gzip_compressor_factory_;
491 };
492 
493 // Create a random identifier of 32 hexadecimal (uppercase) characters.
494 std::string CreateWebRtcEventLogId();
495 
496 // Translate a BrowserContext into an ID. This lets us associate PeerConnections
497 // with BrowserContexts, while making sure that we never call the
498 // BrowserContext's methods outside of the UI thread (because we can't call them
499 // at all without a cast that would alert us to the danger).
500 WebRtcEventLogPeerConnectionKey::BrowserContextId GetBrowserContextId(
501     const content::BrowserContext* browser_context);
502 
503 // Fetches the BrowserContext associated with the render process ID, then
504 // returns its BrowserContextId. (If the render process has already died,
505 // it would have no BrowserContext associated, so the ID associated with a
506 // null BrowserContext will be returned.)
507 WebRtcEventLogPeerConnectionKey::BrowserContextId GetBrowserContextId(
508     int render_process_id);
509 
510 // Given a BrowserContext's directory, return the path to the directory where
511 // we store the pending remote-bound logs associated with this BrowserContext.
512 // This function may be called on any task queue.
513 base::FilePath GetRemoteBoundWebRtcEventLogsDir(
514     const base::FilePath& browser_context_dir);
515 
516 // Produce the path to a remote-bound WebRTC event log file with the given
517 // log ID, web-app ID and extension, in the given directory.
518 base::FilePath WebRtcEventLogPath(
519     const base::FilePath& remote_logs_dir,
520     const std::string& log_id,
521     size_t web_app_id,
522     const base::FilePath::StringPieceType& extension);
523 
524 // Checks whether the path/filename would be a valid reference to a remote-bound
525 // even log. These functions do not examine the file's content or its extension.
526 bool IsValidRemoteBoundLogFilename(const std::string& filename);
527 bool IsValidRemoteBoundLogFilePath(const base::FilePath& path);
528 
529 // Given WebRTC event log's path, return the path to the history file that
530 // is, or would be, associated with it.
531 base::FilePath GetWebRtcEventLogHistoryFilePath(const base::FilePath& path);
532 
533 // Attempts to extract the local ID from the file's path. Returns the empty
534 // string in case of an error.
535 std::string ExtractRemoteBoundWebRtcEventLogLocalIdFromPath(
536     const base::FilePath& path);
537 
538 // Attempts to extract the web-app ID from the file's path.
539 // Returns kInvalidWebRtcEventLogWebAppId in case of an error.
540 size_t ExtractRemoteBoundWebRtcEventLogWebAppIdFromPath(
541     const base::FilePath& path);
542 
543 // Used to determine the default value for the policy controlling event logging.
544 bool DoesProfileDefaultToLoggingEnabled(const Profile* const profile);
545 
546 }  // namespace webrtc_event_logging
547 
548 #endif  // CHROME_BROWSER_MEDIA_WEBRTC_WEBRTC_EVENT_LOG_MANAGER_COMMON_H_
549