blob: fe1d643d08cfd6d0155664df5833fe449cb32f84 [file] [log] [blame]
// Copyright 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 CHROME_BROWSER_MEDIA_ROUTER_EVENT_PAGE_REQUEST_MANAGER_H_
#define CHROME_BROWSER_MEDIA_ROUTER_EVENT_PAGE_REQUEST_MANAGER_H_
#include <string>
#include "base/callback.h"
#include "base/containers/circular_deque.h"
#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/media/router/mojo/media_router_mojo_metrics.h"
#include "components/keyed_service/core/keyed_service.h"
namespace content {
class BrowserContext;
}
namespace extensions {
class EventPageTracker;
}
namespace media_router {
// A class that is responsible for running closures that are requests to the
// Media Router component extension while the extension is awake, or queueing
// requests and waking the extension up if it's suspended.
class EventPageRequestManager : public KeyedService {
public:
~EventPageRequestManager() override;
// KeyedService:
void Shutdown() override;
// Sets the ID of the component extension.
virtual void SetExtensionId(const std::string& extension_id);
// Runs a closure if the Mojo connections to the extensions are valid, or
// defers the execution until the connections have been established. If this
// call resulted in waking the extension, |wake_reason| is recorded as the
// reason.
virtual void RunOrDefer(base::OnceClosure request,
MediaRouteProviderWakeReason wake_reason);
// Executes the Mojo requests queued in |pending_requests_|.
virtual void OnMojoConnectionsReady();
// Attempts to wake the component extension again if there are pending
// requests. Otherwise the extension will be woken up the next time a request
// is received.
virtual void OnMojoConnectionError();
const std::string& media_route_provider_extension_id() const {
return media_route_provider_extension_id_;
}
bool mojo_connections_ready() const { return mojo_connections_ready_; }
void set_mojo_connections_ready_for_test(bool ready) {
mojo_connections_ready_ = ready;
}
protected:
explicit EventPageRequestManager(content::BrowserContext* context);
private:
friend class EventPageRequestManagerFactory;
friend class EventPageRequestManagerTest;
FRIEND_TEST_ALL_PREFIXES(EventPageRequestManagerTest,
DropOldestPendingRequest);
FRIEND_TEST_ALL_PREFIXES(EventPageRequestManagerTest,
TooManyWakeupAttemptsDrainsQueue);
// Max consecutive attempts to wake up the component extension before
// giving up and draining the pending request queue.
static const int kMaxWakeupAttemptCount = 3;
// The max number of pending requests allowed. When number of pending requests
// exceeds this number, the oldest request will be dropped.
static const int kMaxPendingRequests = 30;
// Enqueues a request to be executed when the Mojo connections to the
// component extension are ready.
void EnqueueRequest(base::OnceClosure request);
// Drops all pending requests. Called when we have a connection error to
// component extension and further reattempts are unlikely to help.
void DrainPendingRequests();
// Sets the reason why we are attempting to wake the extension. Since
// multiple tasks may be enqueued for execution each time the extension runs,
// we record the first such reason.
virtual void SetWakeReason(MediaRouteProviderWakeReason reason);
// Whether the component extension event page is suspended.
bool IsEventPageSuspended() const;
// Calls to |event_page_tracker_| to wake the component extension.
// |media_route_provider_extension_id_| must not be empty and the extension
// should be currently suspended. If there have already been too many wakeup
// attempts, give up and drain the pending request queue.
void AttemptWakeEventPage();
// Callback invoked by |event_page_tracker_| after an attempt to wake the
// component extension. If |success| is false, the pending request queue is
// drained.
void OnWakeComplete(bool success);
// Clears the wake reason after the extension has been awoken.
void ClearWakeReason();
// ID of the component extension. Used for managing its suspend/wake state
// via |event_page_tracker_|.
std::string media_route_provider_extension_id_;
// Pending requests queued to be executed once component extension
// becomes ready.
base::circular_deque<base::OnceClosure> pending_requests_;
// Allows the extension to be monitored for suspend, and woken.
// This is a reference to a BrowserContext keyed service that outlives this
// instance.
extensions::EventPageTracker* event_page_tracker_;
int wakeup_attempt_count_ = 0;
bool mojo_connections_ready_ = false;
// Records the current reason the extension is being woken up. Is set to
// MediaRouteProviderWakeReason::TOTAL_COUNT if there is no pending reason.
MediaRouteProviderWakeReason current_wake_reason_ =
MediaRouteProviderWakeReason::TOTAL_COUNT;
base::WeakPtrFactory<EventPageRequestManager> weak_factory_;
};
} // namespace media_router
#endif // CHROME_BROWSER_MEDIA_ROUTER_EVENT_PAGE_REQUEST_MANAGER_H_