blob: 292e45ab51c482a4cc8f6befb82164256f896378 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2015 The Chromium Authors
avayvodbca35fad2015-01-29 20:20:572// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CONTENT_BROWSER_PRESENTATION_PRESENTATION_SERVICE_IMPL_H_
6#define CONTENT_BROWSER_PRESENTATION_PRESENTATION_SERVICE_IMPL_H_
7
kmarshallf5367c642015-08-20 19:23:138#include <map>
dcheng59716272016-04-09 05:19:089#include <memory>
kmarshallf5367c642015-08-20 19:23:1310#include <string>
Takuto Ikutaadf31eb2019-01-05 00:32:4811#include <unordered_map>
mfoltzfcad52622016-09-03 03:08:3312#include <vector>
imcheng271b9ef2015-03-18 19:43:1913
Avi Drissmanadac21992023-01-11 23:46:3914#include "base/functional/callback.h"
imcheng9f515d02015-02-10 20:09:2415#include "base/gtest_prod_util.h"
Keishi Hattori0e45c022021-11-27 09:25:5216#include "base/memory/raw_ptr.h"
imcheng271b9ef2015-03-18 19:43:1917#include "base/memory/weak_ptr.h"
imcheng9f515d02015-02-10 20:09:2418#include "content/common/content_export.h"
imcheng9f515d02015-02-10 20:09:2419#include "content/public/browser/navigation_details.h"
20#include "content/public/browser/presentation_screen_availability_listener.h"
21#include "content/public/browser/presentation_service_delegate.h"
22#include "content/public/browser/web_contents_observer.h"
Mario Sanchez Prada2311a9e2019-08-26 14:29:4923#include "mojo/public/cpp/bindings/pending_receiver.h"
24#include "mojo/public/cpp/bindings/pending_remote.h"
Clovis PJ535cff6a2020-08-06 14:40:0425#include "mojo/public/cpp/bindings/receiver_set.h"
Mario Sanchez Prada2ae29e5a2019-08-26 14:42:2326#include "mojo/public/cpp/bindings/remote.h"
mark a. foltz6bbe59f2018-07-24 20:06:2427#include "third_party/blink/public/mojom/presentation/presentation.mojom.h"
mfoltzfcad52622016-09-03 03:08:3328#include "url/gurl.h"
avayvodbca35fad2015-01-29 20:20:5729
avayvodbca35fad2015-01-29 20:20:5730namespace content {
31
imcheng9f515d02015-02-10 20:09:2432class RenderFrameHost;
33
34// Implementation of Mojo PresentationService.
35// It handles Presentation API requests coming from Blink / renderer process
36// and delegates the requests to the embedder's media router via
37// PresentationServiceDelegate.
38// An instance of this class tied to a RenderFrameHost and listens to events
39// related to the RFH via implementing WebContentsObserver.
40// This class is instantiated on-demand via Mojo's ConnectToRemoteService
41// from the renderer when the first presentation API request is handled.
Derek Cheng4de47c52017-10-10 01:05:5442// This class currently handles requests from both controller and receiver
43// frames. The sequence of calls from a controller looks like the following:
44// Create()
45// SetClient()
46// StartPresentation()
Derek Cheng4de47c52017-10-10 01:05:5447// ...
Alison Gale923a33e2024-04-22 23:34:2848// TODO(crbug.com/41336031): Split the controller and receiver logic into
49// separate classes so that each is easier to reason about.
imcheng9f515d02015-02-10 20:09:2450class CONTENT_EXPORT PresentationServiceImpl
Nico Weber43ddd7a32017-08-15 19:19:2751 : public blink::mojom::PresentationService,
imcheng9f515d02015-02-10 20:09:2452 public WebContentsObserver,
53 public PresentationServiceDelegate::Observer {
avayvodbca35fad2015-01-29 20:20:5754 public:
mfoltz11fc4df82017-03-20 23:49:1855 using NewPresentationCallback =
btolsch8ca10fb22018-08-29 01:35:0956 base::OnceCallback<void(blink::mojom::PresentationConnectionResultPtr,
mark a. foltzd9d2a4512018-04-16 20:42:4557 blink::mojom::PresentationErrorPtr)>;
mfoltzdfbd7c32017-02-03 20:04:1958
Derek Cheng4de47c52017-10-10 01:05:5459 // Creates a PresentationServiceImpl using the given RenderFrameHost.
60 static std::unique_ptr<PresentationServiceImpl> Create(
61 RenderFrameHost* render_frame_host);
62
Peter Boström828b9022021-09-21 02:28:4363 PresentationServiceImpl(const PresentationServiceImpl&) = delete;
64 PresentationServiceImpl& operator=(const PresentationServiceImpl&) = delete;
65
Derek Cheng4de47c52017-10-10 01:05:5466 ~PresentationServiceImpl() override;
67
Mario Sanchez Pradad960266d2019-08-26 15:11:5368 // Creates a binding between this object and |receiver|. Note that a
69 // PresentationServiceImpl instance can be bound to multiple receivers.
70 void Bind(mojo::PendingReceiver<blink::mojom::PresentationService> receiver);
avayvodbca35fad2015-01-29 20:20:5771
imchengfafb67d02017-06-15 17:30:1472 // PresentationService implementation.
73 void SetDefaultPresentationUrls(
74 const std::vector<GURL>& presentation_urls) override;
Mario Sanchez Prada2ae29e5a2019-08-26 14:42:2375 void SetController(mojo::PendingRemote<blink::mojom::PresentationController>
76 presentation_controller_remote) override;
Mario Sanchez Prada23a91b22019-08-26 14:45:3377 void SetReceiver(mojo::PendingRemote<blink::mojom::PresentationReceiver>
78 presentation_receiver_remote) override;
imchengfafb67d02017-06-15 17:30:1479 void ListenForScreenAvailability(const GURL& url) override;
80 void StopListeningForScreenAvailability(const GURL& url) override;
81 void StartPresentation(const std::vector<GURL>& presentation_urls,
82 NewPresentationCallback callback) override;
83 void ReconnectPresentation(const std::vector<GURL>& presentation_urls,
Derek Cheng71ede792017-07-27 07:58:1684 const std::string& presentation_id,
imchengfafb67d02017-06-15 17:30:1485 NewPresentationCallback callback) override;
86 void CloseConnection(const GURL& presentation_url,
87 const std::string& presentation_id) override;
88 void Terminate(const GURL& presentation_url,
89 const std::string& presentation_id) override;
imchengfafb67d02017-06-15 17:30:1490
Rakina Zata Amnic7bc82632019-12-09 05:21:2291 void SetControllerDelegateForTesting(
92 ControllerPresentationServiceDelegate* controller_delegate);
93
avayvodbca35fad2015-01-29 20:20:5794 private:
imcheng9ce5394b2015-05-12 19:27:0195 friend class PresentationServiceImplTest;
Derek Cheng4de47c52017-10-10 01:05:5496 FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, OnDelegateDestroyed);
imcheng9ce5394b2015-05-12 19:27:0197 FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest, DelegateFails);
98 FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
imcheng22578da2017-07-11 23:09:1199 SetDefaultPresentationUrlsNoopsOnNonMainFrame);
100 FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
imcheng1ebdd162017-01-26 22:01:52101 ListenForConnectionStateChange);
imchenged10e962016-02-23 06:34:44102 FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
103 ListenForConnectionClose);
zhaobinf3704f82017-01-12 07:19:36104 FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
imchengfafb67d02017-06-15 17:30:14105 MaxPendingStartPresentationRequests);
106 FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
107 MaxPendingReconnectPresentationRequests);
zhaobinf3704f82017-01-12 07:19:36108 FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
109 ReceiverPresentationServiceDelegate);
zhaobindca98f632017-06-29 18:42:28110 FRIEND_TEST_ALL_PREFIXES(PresentationServiceImplTest,
111 ReceiverDelegateOnSubFrame);
Rakina Zata Amnic7bc82632019-12-09 05:21:22112 FRIEND_TEST_ALL_PREFIXES(BackForwardCacheBrowserTest,
113 PresentationConnectionClosed);
imchengf3e5a012015-11-20 04:08:37114
mfoltz11fc4df82017-03-20 23:49:18115 // Maximum number of pending ReconnectPresentation requests at any given time.
116 static const int kMaxQueuedRequests = 10;
imcheng27e2b56b2015-05-15 21:39:30117
imcheng9ce5394b2015-05-12 19:27:01118 // Listener implementation owned by PresentationServiceImpl. An instance of
mfoltz3f30502f2015-08-11 16:13:38119 // this is created when PresentationRequest.getAvailability() is resolved.
imcheng9ce5394b2015-05-12 19:27:01120 // The instance receives screen availability results from the embedder and
121 // propagates results back to PresentationServiceImpl.
122 class CONTENT_EXPORT ScreenAvailabilityListenerImpl
imcheng271b9ef2015-03-18 19:43:19123 : public PresentationScreenAvailabilityListener {
124 public:
mfoltz7a2c823b2016-10-08 01:35:24125 ScreenAvailabilityListenerImpl(const GURL& availability_url,
126 PresentationServiceImpl* service);
imcheng9ce5394b2015-05-12 19:27:01127 ~ScreenAvailabilityListenerImpl() override;
imcheng271b9ef2015-03-18 19:43:19128
imcheng271b9ef2015-03-18 19:43:19129 // PresentationScreenAvailabilityListener implementation.
Lucas Furukawa Gadani4b4eed02019-06-04 23:12:04130 GURL GetAvailabilityUrl() override;
Anton Vayvode3c39862017-06-20 20:53:32131 void OnScreenAvailabilityChanged(
132 blink::mojom::ScreenAvailability availability) override;
imcheng271b9ef2015-03-18 19:43:19133
imcheng271b9ef2015-03-18 19:43:19134 private:
mfoltz7a2c823b2016-10-08 01:35:24135 const GURL availability_url_;
Keishi Hattori0e45c022021-11-27 09:25:52136 const raw_ptr<PresentationServiceImpl> service_;
imcheng271b9ef2015-03-18 19:43:19137 };
138
mfoltz11fc4df82017-03-20 23:49:18139 // Ensures the provided NewPresentationCallback is invoked exactly once
imcheng27e2b56b2015-05-15 21:39:30140 // before it goes out of scope.
mfoltz11fc4df82017-03-20 23:49:18141 class NewPresentationCallbackWrapper {
imcheng27e2b56b2015-05-15 21:39:30142 public:
tzikcf7bcd652017-06-15 04:19:30143 explicit NewPresentationCallbackWrapper(NewPresentationCallback callback);
Peter Boström828b9022021-09-21 02:28:43144
145 NewPresentationCallbackWrapper(const NewPresentationCallbackWrapper&) =
146 delete;
147 NewPresentationCallbackWrapper& operator=(
148 const NewPresentationCallbackWrapper&) = delete;
149
mfoltz11fc4df82017-03-20 23:49:18150 ~NewPresentationCallbackWrapper();
imcheng27e2b56b2015-05-15 21:39:30151
btolsch8ca10fb22018-08-29 01:35:09152 void Run(blink::mojom::PresentationConnectionResultPtr result,
mark a. foltzd9d2a4512018-04-16 20:42:45153 blink::mojom::PresentationErrorPtr error);
imcheng27e2b56b2015-05-15 21:39:30154
155 private:
mfoltz11fc4df82017-03-20 23:49:18156 NewPresentationCallback callback_;
imcheng27e2b56b2015-05-15 21:39:30157 };
158
Derek Cheng4de47c52017-10-10 01:05:54159 // Note: Use |PresentationServiceImpl::Create| instead. This constructor
160 // should only be directly invoked in tests.
imcheng9f515d02015-02-10 20:09:24161 // |render_frame_host|: The RFH this instance is associated with.
162 // |web_contents|: The WebContents to observe.
zhaobinf3704f82017-01-12 07:19:36163 // |controller_delegate|: Where Presentation API requests are delegated to in
164 // controller frame. Set to nullptr if current frame is receiver frame. Not
165 // owned by this class.
166 // |receiver_delegate|: Where Presentation API requests are delegated to in
167 // receiver frame. Set to nullptr if current frame is controller frame. Not
168 // owned by this class.
imcheng9f515d02015-02-10 20:09:24169 PresentationServiceImpl(
170 RenderFrameHost* render_frame_host,
171 WebContents* web_contents,
zhaobinf3704f82017-01-12 07:19:36172 ControllerPresentationServiceDelegate* controller_delegate,
173 ReceiverPresentationServiceDelegate* receiver_delegate);
avayvodbca35fad2015-01-29 20:20:57174
imcheng9f515d02015-02-10 20:09:24175 // WebContentsObserver override.
jam5fdbb58d2017-02-06 22:09:59176 void DidFinishNavigation(NavigationHandle* navigation_handle) override;
imcheng9f515d02015-02-10 20:09:24177
178 // PresentationServiceDelegate::Observer
179 void OnDelegateDestroyed() override;
imchengfa43aae02015-11-11 17:28:44180
181 // Passed to embedder's implementation of PresentationServiceDelegate for
182 // later invocation when default presentation has started.
mark a. foltze2084383c2018-05-11 19:21:50183 void OnDefaultPresentationStarted(
btolsch8ca10fb22018-08-29 01:35:09184 blink::mojom::PresentationConnectionResultPtr result);
imcheng9f515d02015-02-10 20:09:24185
mfoltz11fc4df82017-03-20 23:49:18186 // Finds the callback from |pending_reconnect_presentation_cbs_| using
187 // |request_id|.
btolsch8ca10fb22018-08-29 01:35:09188 // If it exists, invoke it with |result| and |error|, then erase it
mfoltz11fc4df82017-03-20 23:49:18189 // from |pending_reconnect_presentation_cbs_|. Returns true if the callback
190 // was found.
191 bool RunAndEraseReconnectPresentationMojoCallback(
192 int request_id,
btolsch8ca10fb22018-08-29 01:35:09193 blink::mojom::PresentationConnectionResultPtr result,
mark a. foltzd9d2a4512018-04-16 20:42:45194 blink::mojom::PresentationErrorPtr error);
imcheng31fe0da92015-03-26 02:08:50195
imcheng271b9ef2015-03-18 19:43:19196 // Removes all listeners and resets default presentation URL on this instance
197 // and informs the PresentationServiceDelegate of such.
198 void Reset();
199
s.singapati834d10a12015-05-11 16:29:47200 // These functions are bound as base::Callbacks and passed to
imcheng271b9ef2015-03-18 19:43:19201 // embedder's implementation of PresentationServiceDelegate for later
202 // invocation.
mark a. foltze2084383c2018-05-11 19:21:50203 void OnStartPresentationSucceeded(
204 int request_id,
btolsch8ca10fb22018-08-29 01:35:09205 blink::mojom::PresentationConnectionResultPtr result);
mark a. foltzd9d2a4512018-04-16 20:42:45206 void OnStartPresentationError(int request_id,
207 const blink::mojom::PresentationError& error);
mfoltz11fc4df82017-03-20 23:49:18208 void OnReconnectPresentationSucceeded(
209 int request_id,
btolsch8ca10fb22018-08-29 01:35:09210 blink::mojom::PresentationConnectionResultPtr result);
mark a. foltzd9d2a4512018-04-16 20:42:45211 void OnReconnectPresentationError(
212 int request_id,
213 const blink::mojom::PresentationError& error);
imcheng271b9ef2015-03-18 19:43:19214
imchengf3e5a012015-11-20 04:08:37215 // Calls to |delegate_| to start listening for state changes for |connection|.
imcheng1ebdd162017-01-26 22:01:52216 // State changes will be returned via |OnConnectionStateChanged|.
mark a. foltze2084383c2018-05-11 19:21:50217 void ListenForConnectionStateChange(
218 const blink::mojom::PresentationInfo& connection);
imchengf3e5a012015-11-20 04:08:37219
Takumi Fujimoto6d2b0f22017-10-30 23:01:33220 // A callback registered to LocalPresentationManager when
zhaobinf3704f82017-01-12 07:19:36221 // the PresentationServiceImpl for the presentation receiver is initialized.
Derek Chengf8ffbec52017-12-06 19:43:04222 // Calls |receiver_| to create a new PresentationConnection on receiver page.
zhaobinf3704f82017-01-12 07:19:36223 void OnReceiverConnectionAvailable(
Wei4 Wange1c8c002023-04-24 23:30:25224 blink::mojom::PresentationConnectionResultPtr result);
zhaobinf3704f82017-01-12 07:19:36225
mfoltz11fc4df82017-03-20 23:49:18226 // Associates a ReconnectPresentation |callback| with a unique request ID and
tzikcf7bcd652017-06-15 04:19:30227 // stores it in a map. Moves out |callback| object if |callback| is registered
228 // successfully. If the queue is full, returns a negative value and leaves
229 // |callback| as is.
230 int RegisterReconnectPresentationCallback(NewPresentationCallback* callback);
imcheng31fe0da92015-03-26 02:08:50231
imcheng1709d152015-07-10 21:14:11232 // Invoked by the embedder's PresentationServiceDelegate when a
imchengf3e5a012015-11-20 04:08:37233 // PresentationConnection's state has changed.
imchenged10e962016-02-23 06:34:44234 void OnConnectionStateChanged(
mark a. foltze2084383c2018-05-11 19:21:50235 const blink::mojom::PresentationInfo& connection,
imchenged10e962016-02-23 06:34:44236 const PresentationConnectionStateChangeInfo& info);
imcheng1709d152015-07-10 21:14:11237
imcheng2ed5f8202015-04-24 19:41:17238 // Returns true if this object is associated with |render_frame_host|.
239 bool FrameMatches(content::RenderFrameHost* render_frame_host) const;
240
Derek Cheng1ad77242018-04-16 18:55:11241 // Invoked on Mojo connection error. Closes all Mojo message pipes held by
242 // |this|.
243 void OnConnectionError();
244
zhaobinf3704f82017-01-12 07:19:36245 // Returns |controller_delegate| if current frame is controller frame; Returns
246 // |receiver_delegate| if current frame is receiver frame.
247 PresentationServiceDelegate* GetPresentationServiceDelegate();
248
Derek Cheng1071a232017-07-25 22:23:56249 // The RenderFrameHost associated with this object.
Keishi Hattori0e45c022021-11-27 09:25:52250 const raw_ptr<RenderFrameHost> render_frame_host_;
Derek Cheng1071a232017-07-25 22:23:56251
zhaobinf3704f82017-01-12 07:19:36252 // Embedder-specific delegate for controller to forward Presentation requests
253 // to. Must be nullptr if current page is receiver page or
254 // embedder does not support Presentation API .
Keishi Hattori0e45c022021-11-27 09:25:52255 raw_ptr<ControllerPresentationServiceDelegate> controller_delegate_;
zhaobinf3704f82017-01-12 07:19:36256
257 // Embedder-specific delegate for receiver to forward Presentation requests
258 // to. Must be nullptr if current page is receiver page or
259 // embedder does not support Presentation API.
Keishi Hattori0e45c022021-11-27 09:25:52260 raw_ptr<ReceiverPresentationServiceDelegate> receiver_delegate_;
imcheng9f515d02015-02-10 20:09:24261
Derek Chengf8ffbec52017-12-06 19:43:04262 // Pointer to the PresentationController implementation in the renderer.
Mario Sanchez Prada2ae29e5a2019-08-26 14:42:23263 mojo::Remote<blink::mojom::PresentationController>
264 presentation_controller_remote_;
imcheng9f515d02015-02-10 20:09:24265
Derek Chengf8ffbec52017-12-06 19:43:04266 // Pointer to the PresentationReceiver implementation in the renderer.
Mario Sanchez Prada23a91b22019-08-26 14:45:33267 mojo::Remote<blink::mojom::PresentationReceiver>
268 presentation_receiver_remote_;
Derek Cheng4de47c52017-10-10 01:05:54269
mfoltz7a2c823b2016-10-08 01:35:24270 std::vector<GURL> default_presentation_urls_;
imcheng271b9ef2015-03-18 19:43:19271
mfoltz3f30502f2015-08-11 16:13:38272 using ScreenAvailabilityListenerMap =
mfoltz7a2c823b2016-10-08 01:35:24273 std::map<GURL, std::unique_ptr<ScreenAvailabilityListenerImpl>>;
mfoltz3f30502f2015-08-11 16:13:38274 ScreenAvailabilityListenerMap screen_availability_listeners_;
imcheng9ce5394b2015-05-12 19:27:01275
mfoltz11fc4df82017-03-20 23:49:18276 // For StartPresentation requests.
277 // Set to a positive value when a StartPresentation request is being
278 // processed.
279 int start_presentation_request_id_;
280 std::unique_ptr<NewPresentationCallbackWrapper>
281 pending_start_presentation_cb_;
rockot5d5dbf0d2015-04-14 18:31:15282
mfoltz11fc4df82017-03-20 23:49:18283 // For ReconnectPresentation requests.
Takuto Ikutaadf31eb2019-01-05 00:32:48284 std::unordered_map<int, std::unique_ptr<NewPresentationCallbackWrapper>>
mfoltz11fc4df82017-03-20 23:49:18285 pending_reconnect_presentation_cbs_;
imcheng31fe0da92015-03-26 02:08:50286
Clovis PJ535cff6a2020-08-06 14:40:04287 mojo::ReceiverSet<blink::mojom::PresentationService>
288 presentation_service_receivers_;
imcheng16819b92015-04-03 08:52:45289
imcheng2ed5f8202015-04-24 19:41:17290 // ID of the RenderFrameHost this object is associated with.
291 int render_process_id_;
292 int render_frame_id_;
293
Claudio DeSouzaee45cae2021-11-24 20:30:27294 // If current frame is the outermost frame (not an iframe nor a fenced frame).
295 bool is_outermost_document_;
zhaobindca98f632017-06-29 18:42:28296
imcheng271b9ef2015-03-18 19:43:19297 // NOTE: Weak pointers must be invalidated before all other member variables.
Jeremy Roman3bca4bf2019-07-11 03:41:25298 base::WeakPtrFactory<PresentationServiceImpl> weak_factory_{this};
avayvodbca35fad2015-01-29 20:20:57299};
300
301} // namespace content
302
303#endif // CONTENT_BROWSER_PRESENTATION_PRESENTATION_SERVICE_IMPL_H_