1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117

media / base / android / media_service_throttler.h [blame]

// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef MEDIA_BASE_ANDROID_MEDIA_SERVICE_THROTTLER_H_
#define MEDIA_BASE_ANDROID_MEDIA_SERVICE_THROTTLER_H_

#include <memory>

#include "base/cancelable_callback.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/tick_clock.h"
#include "base/time/time.h"
#include "media/base/media_export.h"

namespace media {
class MediaServerCrashListener;

// The MediaServiceThrottler's purpose is to prevent a compromised process from
// attempting to crash the MediaServer, by repeatedly requesting resources or
// issuing malformed requests. It is used to delay the creation of Android
// MediaServer clients (currently only the MediaPlayerBridge) by some amount
// that makes it impractical to DOS the MediaServer (by requesting the
// playback of hundreds of malformed URLs per second, for example).
//
// GetDelayForClientCreation() linearly spaces out client creations and
// guarantees that the clients will never be scheduled faster than some
// threshold (see the .cc file for the latest values).
// The MediaServiceThrottler also uses a MediaServerCrashListener to monitor for
// MediaServer crashes. The delay between client creations is exponentially
// increased (up to a cap) based on the number of recent MediaServer crashes.
//
// NOTE: The MediaServiceThrottler has small moving window that allows a certain
// number of clients to be immediately scheduled, while still respecting the
// max scheduling rates. This allows clients to be 'burst created' to account
// for a burst of requests from a new page load.
//
// For an example of usage, look at MediaPlayerRenderer::Initialize().
class MEDIA_EXPORT MediaServiceThrottler {
 public:
  // Called to get the singleton MediaServiceThrottler instance.
  // The first thread on which GetInstance() is called is the thread on which
  // calls to OnMediaServerCrash() will be signaled.
  static MediaServiceThrottler* GetInstance();

  MediaServiceThrottler(const MediaServiceThrottler&) = delete;
  MediaServiceThrottler& operator=(const MediaServiceThrottler&) = delete;

  // Returns the delay to wait until a new client is allowed to be created.
  base::TimeDelta GetDelayForClientCreation();

  // Test only methods.
  void SetTickClockForTesting(const base::TickClock* clock);
  void ResetInternalStateForTesting();
  base::TimeDelta GetBaseThrottlingRateForTesting();
  bool IsCrashListenerAliveForTesting();
  void SetCrashListenerTaskRunnerForTesting(
      scoped_refptr<base::SingleThreadTaskRunner> crash_listener_task_runner);

 private:
  friend class MediaServiceThrottlerTest;

  MediaServiceThrottler();
  virtual ~MediaServiceThrottler();

  // Called by the |crash_listener_| whenever a crash is detected.
  void OnMediaServerCrash(bool watchdog_needs_release);

  // Updates |current_crashes_| according to a linear decay function.
  void UpdateServerCrashes();

  // Ensures that the MediaServerCrashListener was properly started (can lead
  // to OnMediaServerCrash() being called in the case it hasn't).
  void EnsureCrashListenerStarted();

  // Frees up the resources used by |crash_listener_|;
  void ReleaseCrashListener();

  // Gets the delay for ScheduleClientCreation(), which grows exponentially
  // based on |current_crashes_|.
  base::TimeDelta GetThrottlingDelayFromServerCrashes();

  raw_ptr<const base::TickClock> clock_;

  // Effective number of media server crashes.
  // NOTE: This is of type double because we decay the number of crashes at a
  // rate of one per minute (e.g. 30s after a single crash, |current_crashes_|
  // should be equal to 0.5).
  double current_crashes_;

  // Next time at which a client creation can be scheduled.
  base::TimeTicks next_schedulable_slot_;

  // Last media server crash time.
  base::TimeTicks last_server_crash_;

  // Last time UpdateServerCrashes() was called.
  base::TimeTicks last_current_crash_update_time_;

  // Last time ScheduleClientCreation() was called.
  base::TimeTicks last_schedule_call_;

  // Callbacks used to release |crash_listener_| after 60s of inactivity.
  base::RepeatingClosure release_crash_listener_cb_;
  base::CancelableRepeatingClosure cancelable_release_crash_listener_cb_;

  // Listens for MediaServer crashes using a watchdog MediaPlayer.
  std::unique_ptr<MediaServerCrashListener> crash_listener_;

  scoped_refptr<base::SingleThreadTaskRunner> crash_listener_task_runner_;
};

}  // namespace media

#endif  // MEDIA_BASE_ANDROID_MEDIA_SERVICE_THROTTLER_H_