| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 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_ROUTER_MEDIA_ROUTER_MOJO_IMPL_H_ | |
| 6 #define CHROME_BROWSER_MEDIA_ROUTER_MEDIA_ROUTER_MOJO_IMPL_H_ | |
| 7 | |
| 8 #include <stdint.h> | |
| 9 | |
| 10 #include <deque> | |
| 11 #include <map> | |
| 12 #include <set> | |
| 13 #include <string> | |
| 14 #include <vector> | |
| 15 | |
| 16 #include "base/containers/hash_tables.h" | |
| 17 #include "base/containers/scoped_ptr_hash_map.h" | |
| 18 #include "base/gtest_prod_util.h" | |
| 19 #include "base/macros.h" | |
| 20 #include "base/memory/scoped_ptr.h" | |
| 21 #include "base/memory/weak_ptr.h" | |
| 22 #include "base/observer_list.h" | |
| 23 #include "base/thread_task_runner_handle.h" | |
| 24 #include "build/build_config.h" | |
| 25 #include "chrome/browser/media/router/issue.h" | |
| 26 #include "chrome/browser/media/router/issue_manager.h" | |
| 27 #include "chrome/browser/media/router/media_router.mojom.h" | |
| 28 #include "chrome/browser/media/router/media_router_base.h" | |
| 29 #include "chrome/browser/media/router/media_routes_observer.h" | |
| 30 #include "mojo/public/cpp/bindings/binding.h" | |
| 31 | |
| 32 namespace content { | |
| 33 class BrowserContext; | |
| 34 } | |
| 35 | |
| 36 namespace extensions { | |
| 37 class EventPageTracker; | |
| 38 class Extension; | |
| 39 } | |
| 40 | |
| 41 namespace media_router { | |
| 42 | |
| 43 enum class MediaRouteProviderWakeReason; | |
| 44 | |
| 45 // MediaRouter implementation that delegates calls to the component extension. | |
| 46 // Also handles the suspension and wakeup of the component extension. | |
| 47 class MediaRouterMojoImpl : public MediaRouterBase, | |
| 48 public interfaces::MediaRouter { | |
| 49 public: | |
| 50 ~MediaRouterMojoImpl() override; | |
| 51 | |
| 52 // Sets up the MediaRouterMojoImpl instance owned by |context| to handle | |
| 53 // MediaRouterObserver requests from the component extension given by | |
| 54 // |extension|. Creates the MediaRouterMojoImpl instance if it does not | |
| 55 // exist. | |
| 56 // Called by the Mojo module registry. | |
| 57 // |extension|: The component extension, used for querying | |
| 58 // suspension state. | |
| 59 // |context|: The BrowserContext which owns the extension process. | |
| 60 // |request|: The Mojo connection request used for binding. | |
| 61 static void BindToRequest( | |
| 62 const extensions::Extension* extension, | |
| 63 content::BrowserContext* context, | |
| 64 mojo::InterfaceRequest<interfaces::MediaRouter> request); | |
| 65 | |
| 66 // MediaRouter implementation. | |
| 67 // Execution of the requests is delegated to the Do* methods, which can be | |
| 68 // enqueued for later use if the extension is temporarily suspended. | |
| 69 void CreateRoute(const MediaSource::Id& source_id, | |
| 70 const MediaSink::Id& sink_id, | |
| 71 const GURL& origin, | |
| 72 content::WebContents* web_contents, | |
| 73 const std::vector<MediaRouteResponseCallback>& callbacks, | |
| 74 base::TimeDelta timeout, | |
| 75 bool off_the_record) override; | |
| 76 void JoinRoute(const MediaSource::Id& source_id, | |
| 77 const std::string& presentation_id, | |
| 78 const GURL& origin, | |
| 79 content::WebContents* web_contents, | |
| 80 const std::vector<MediaRouteResponseCallback>& callbacks, | |
| 81 base::TimeDelta timeout, | |
| 82 bool off_the_record) override; | |
| 83 void ConnectRouteByRouteId( | |
| 84 const MediaSource::Id& source, | |
| 85 const MediaRoute::Id& route_id, | |
| 86 const GURL& origin, | |
| 87 content::WebContents* web_contents, | |
| 88 const std::vector<MediaRouteResponseCallback>& callbacks, | |
| 89 base::TimeDelta timeout, | |
| 90 bool off_the_record) override; | |
| 91 void TerminateRoute(const MediaRoute::Id& route_id) override; | |
| 92 void DetachRoute(const MediaRoute::Id& route_id) override; | |
| 93 void SendRouteMessage(const MediaRoute::Id& route_id, | |
| 94 const std::string& message, | |
| 95 const SendRouteMessageCallback& callback) override; | |
| 96 void SendRouteBinaryMessage( | |
| 97 const MediaRoute::Id& route_id, | |
| 98 scoped_ptr<std::vector<uint8_t>> data, | |
| 99 const SendRouteMessageCallback& callback) override; | |
| 100 void AddIssue(const Issue& issue) override; | |
| 101 void ClearIssue(const Issue::Id& issue_id) override; | |
| 102 void OnUserGesture() override; | |
| 103 | |
| 104 const std::string& media_route_provider_extension_id() const { | |
| 105 return media_route_provider_extension_id_; | |
| 106 } | |
| 107 | |
| 108 void set_instance_id_for_test(const std::string& instance_id) { | |
| 109 instance_id_ = instance_id; | |
| 110 } | |
| 111 | |
| 112 private: | |
| 113 friend class MediaRouterFactory; | |
| 114 friend class MediaRouterMojoExtensionTest; | |
| 115 friend class MediaRouterMojoTest; | |
| 116 FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest, | |
| 117 RegisterAndUnregisterMediaSinksObserver); | |
| 118 FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest, | |
| 119 RegisterMediaSinksObserverWithAvailabilityChange); | |
| 120 FRIEND_TEST_ALL_PREFIXES( | |
| 121 MediaRouterMojoImplTest, | |
| 122 RegisterAndUnregisterMediaSinksObserverWithAvailabilityChange); | |
| 123 FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest, | |
| 124 RegisterAndUnregisterMediaRoutesObserver); | |
| 125 FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest, HandleIssue); | |
| 126 FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoExtensionTest, | |
| 127 DeferredBindingAndSuspension); | |
| 128 FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoExtensionTest, | |
| 129 DrainPendingRequestQueue); | |
| 130 FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoExtensionTest, | |
| 131 DropOldestPendingRequest); | |
| 132 FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoExtensionTest, | |
| 133 AttemptedWakeupTooManyTimes); | |
| 134 FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoExtensionTest, | |
| 135 WakeupFailedDrainsQueue); | |
| 136 | |
| 137 // The max number of pending requests allowed. When number of pending requests | |
| 138 // exceeds this number, the oldest request will be dropped. | |
| 139 static const int kMaxPendingRequests = 30; | |
| 140 | |
| 141 // Max consecutive attempts to wake up the component extension before | |
| 142 // giving up and draining the pending request queue. | |
| 143 static const int kMaxWakeupAttemptCount = 3; | |
| 144 | |
| 145 // Represents a query to the MRPM for media sinks and holds observers for the | |
| 146 // query. | |
| 147 struct MediaSinksQuery { | |
| 148 public: | |
| 149 MediaSinksQuery(); | |
| 150 ~MediaSinksQuery(); | |
| 151 | |
| 152 // True if the query has been sent to the MRPM. | |
| 153 bool is_active = false; | |
| 154 | |
| 155 // True if cached result is available. | |
| 156 bool has_cached_result = false; | |
| 157 | |
| 158 // Cached list of sinks for the query, if |has_cached_result| is true. | |
| 159 // Empty otherwise. | |
| 160 std::vector<MediaSink> cached_sink_list; | |
| 161 std::vector<GURL> origins; | |
| 162 base::ObserverList<MediaSinksObserver> observers; | |
| 163 | |
| 164 private: | |
| 165 DISALLOW_COPY_AND_ASSIGN(MediaSinksQuery); | |
| 166 }; | |
| 167 | |
| 168 struct MediaRoutesQuery { | |
| 169 public: | |
| 170 MediaRoutesQuery(); | |
| 171 ~MediaRoutesQuery(); | |
| 172 | |
| 173 // True if the query has been sent to the MRPM. False otherwise. | |
| 174 bool is_active = false; | |
| 175 base::ObserverList<MediaRoutesObserver> observers; | |
| 176 | |
| 177 private: | |
| 178 DISALLOW_COPY_AND_ASSIGN(MediaRoutesQuery); | |
| 179 }; | |
| 180 | |
| 181 // Standard constructor, used by | |
| 182 // MediaRouterMojoImplFactory::GetApiForBrowserContext. | |
| 183 explicit MediaRouterMojoImpl( | |
| 184 extensions::EventPageTracker* event_page_tracker); | |
| 185 | |
| 186 // Binds |this| to a Mojo interface request, so that clients can acquire a | |
| 187 // handle to a MediaRouterMojoImpl instance via the Mojo service connector. | |
| 188 // Stores the ID of |extension| in |media_route_provider_extension_id_|. | |
| 189 void BindToMojoRequest( | |
| 190 mojo::InterfaceRequest<interfaces::MediaRouter> request, | |
| 191 const extensions::Extension& extension); | |
| 192 | |
| 193 // Enqueues a closure for later execution by ExecutePendingRequests(). | |
| 194 void EnqueueTask(const base::Closure& closure); | |
| 195 | |
| 196 // Runs a closure if the extension monitored by |extension_monitor_| is | |
| 197 // active, or defers it for later execution if the extension is suspended. | |
| 198 void RunOrDefer(const base::Closure& request); | |
| 199 | |
| 200 // Dispatches the Mojo requests queued in |pending_requests_|. | |
| 201 void ExecutePendingRequests(); | |
| 202 | |
| 203 // Drops all pending requests. Called when we have a connection error to | |
| 204 // component extension and further reattempts are unlikely to help. | |
| 205 void DrainPendingRequests(); | |
| 206 | |
| 207 // MediaRouter implementation. | |
| 208 bool RegisterMediaSinksObserver(MediaSinksObserver* observer) override; | |
| 209 void UnregisterMediaSinksObserver(MediaSinksObserver* observer) override; | |
| 210 void RegisterMediaRoutesObserver(MediaRoutesObserver* observer) override; | |
| 211 void UnregisterMediaRoutesObserver(MediaRoutesObserver* observer) override; | |
| 212 void RegisterIssuesObserver(IssuesObserver* observer) override; | |
| 213 void UnregisterIssuesObserver(IssuesObserver* observer) override; | |
| 214 void RegisterPresentationSessionMessagesObserver( | |
| 215 PresentationSessionMessagesObserver* observer) override; | |
| 216 void UnregisterPresentationSessionMessagesObserver( | |
| 217 PresentationSessionMessagesObserver* observer) override; | |
| 218 | |
| 219 // These calls invoke methods in the component extension via Mojo. | |
| 220 void DoCreateRoute(const MediaSource::Id& source_id, | |
| 221 const MediaSink::Id& sink_id, | |
| 222 const std::string& origin, | |
| 223 int tab_id, | |
| 224 const std::vector<MediaRouteResponseCallback>& callbacks, | |
| 225 base::TimeDelta timeout, | |
| 226 bool off_the_record); | |
| 227 void DoJoinRoute(const MediaSource::Id& source_id, | |
| 228 const std::string& presentation_id, | |
| 229 const std::string& origin, | |
| 230 int tab_id, | |
| 231 const std::vector<MediaRouteResponseCallback>& callbacks, | |
| 232 base::TimeDelta timeout, | |
| 233 bool off_the_record); | |
| 234 void DoConnectRouteByRouteId( | |
| 235 const MediaSource::Id& source_id, | |
| 236 const MediaRoute::Id& route_id, | |
| 237 const std::string& origin, | |
| 238 int tab_id, | |
| 239 const std::vector<MediaRouteResponseCallback>& callbacks, | |
| 240 base::TimeDelta timeout, | |
| 241 bool off_the_record); | |
| 242 void DoTerminateRoute(const MediaRoute::Id& route_id); | |
| 243 void DoDetachRoute(const MediaRoute::Id& route_id); | |
| 244 void DoSendSessionMessage(const MediaRoute::Id& route_id, | |
| 245 const std::string& message, | |
| 246 const SendRouteMessageCallback& callback); | |
| 247 void DoSendSessionBinaryMessage(const MediaRoute::Id& route_id, | |
| 248 scoped_ptr<std::vector<uint8_t>> data, | |
| 249 const SendRouteMessageCallback& callback); | |
| 250 void DoListenForRouteMessages(const MediaRoute::Id& route_id); | |
| 251 void DoStopListeningForRouteMessages(const MediaRoute::Id& route_id); | |
| 252 void DoStartObservingMediaSinks(const MediaSource::Id& source_id); | |
| 253 void DoStopObservingMediaSinks(const MediaSource::Id& source_id); | |
| 254 void DoStartObservingMediaRoutes(const MediaSource::Id& source_id); | |
| 255 void DoStopObservingMediaRoutes(const MediaSource::Id& source_id); | |
| 256 | |
| 257 // Invoked when the next batch of messages arrives. | |
| 258 // |route_id|: ID of route of the messages. | |
| 259 // |messages|: A list of messages received. | |
| 260 // |error|: true if an error occurred. | |
| 261 void OnRouteMessagesReceived( | |
| 262 const MediaRoute::Id& route_id, | |
| 263 mojo::Array<interfaces::RouteMessagePtr> messages, | |
| 264 bool error); | |
| 265 | |
| 266 // Error handler callback for |binding_| and |media_route_provider_|. | |
| 267 void OnConnectionError(); | |
| 268 | |
| 269 // interfaces::MediaRouter implementation. | |
| 270 void RegisterMediaRouteProvider( | |
| 271 interfaces::MediaRouteProviderPtr media_route_provider_ptr, | |
| 272 const interfaces::MediaRouter::RegisterMediaRouteProviderCallback& | |
| 273 callback) override; | |
| 274 void OnIssue(interfaces::IssuePtr issue) override; | |
| 275 void OnSinksReceived(const mojo::String& media_source, | |
| 276 mojo::Array<interfaces::MediaSinkPtr> sinks, | |
| 277 mojo::Array<mojo::String> origins) override; | |
| 278 void OnRoutesUpdated(mojo::Array<interfaces::MediaRoutePtr> routes, | |
| 279 const mojo::String& media_source, | |
| 280 mojo::Array<mojo::String> joinable_route_ids) override; | |
| 281 void OnSinkAvailabilityUpdated( | |
| 282 interfaces::MediaRouter::SinkAvailability availability) override; | |
| 283 void OnPresentationConnectionStateChanged( | |
| 284 const mojo::String& route_id, | |
| 285 interfaces::MediaRouter::PresentationConnectionState state) override; | |
| 286 void OnPresentationConnectionClosed( | |
| 287 const mojo::String& route_id, | |
| 288 interfaces::MediaRouter::PresentationConnectionCloseReason reason, | |
| 289 const mojo::String& message) override; | |
| 290 | |
| 291 // Converts the callback result of calling Mojo CreateRoute()/JoinRoute() | |
| 292 // into a local callback. | |
| 293 void RouteResponseReceived( | |
| 294 const std::string& presentation_id, | |
| 295 bool off_the_record, | |
| 296 const std::vector<MediaRouteResponseCallback>& callbacks, | |
| 297 interfaces::MediaRoutePtr media_route, | |
| 298 const mojo::String& error_text, | |
| 299 interfaces::RouteRequestResultCode result_code); | |
| 300 | |
| 301 // Callback invoked by |event_page_tracker_| after an attempt to wake the | |
| 302 // component extension. If |success| is false, the pending request queue is | |
| 303 // drained. | |
| 304 void EventPageWakeComplete(bool success); | |
| 305 | |
| 306 // Removes all requests from the pending requests queue. Called when there is | |
| 307 // a permanent error connecting to component extension. | |
| 308 void DrainRequestQueue(); | |
| 309 | |
| 310 // Calls to |event_page_tracker_| to wake the component extension. | |
| 311 // |media_route_provider_extension_id_| must not be empty and the extension | |
| 312 // should be currently suspended. | |
| 313 // If there have already been too many wakeup attempts, give up and drain | |
| 314 // the pending request queue. | |
| 315 void AttemptWakeEventPage(); | |
| 316 | |
| 317 // Sets the reason why we are attempting to wake the extension. Since | |
| 318 // multiple tasks may be enqueued for execution each time the extension runs, | |
| 319 // we record the first such reason. | |
| 320 void SetWakeReason(MediaRouteProviderWakeReason reason); | |
| 321 | |
| 322 // Clears the wake reason after the extension has been awoken. | |
| 323 void ClearWakeReason(); | |
| 324 | |
| 325 #if defined(OS_WIN) | |
| 326 // Ensures that mDNS discovery is enabled in the MRPM extension. This can be | |
| 327 // called many times but the MRPM will only be called once per registration | |
| 328 // period. | |
| 329 void EnsureMdnsDiscoveryEnabled(); | |
| 330 void DoEnsureMdnsDiscoveryEnabled(); | |
| 331 | |
| 332 // Callback used to enabled mDNS in the MRPM if a firewall prompt will not be | |
| 333 // triggered. If a firewall prompt would be triggered, enabling mDNS won't | |
| 334 // happen until the user is clearly interacting with MR. | |
| 335 void OnFirewallCheckComplete(bool firewall_can_use_local_ports); | |
| 336 #endif | |
| 337 | |
| 338 // Pending requests queued to be executed once component extension | |
| 339 // becomes ready. | |
| 340 std::deque<base::Closure> pending_requests_; | |
| 341 | |
| 342 base::ScopedPtrHashMap<MediaSource::Id, scoped_ptr<MediaSinksQuery>> | |
| 343 sinks_queries_; | |
| 344 | |
| 345 base::ScopedPtrHashMap<MediaSource::Id, scoped_ptr<MediaRoutesQuery>> | |
| 346 routes_queries_; | |
| 347 | |
| 348 using PresentationSessionMessagesObserverList = | |
| 349 base::ObserverList<PresentationSessionMessagesObserver>; | |
| 350 base::ScopedPtrHashMap<MediaRoute::Id, | |
| 351 scoped_ptr<PresentationSessionMessagesObserverList>> | |
| 352 messages_observers_; | |
| 353 | |
| 354 // IDs of MediaRoutes being listened for messages. Note that this is | |
| 355 // different from |message_observers_| because we might be waiting for | |
| 356 // |OnRouteMessagesReceived()| to be invoked after all observers for that | |
| 357 // route have been removed. | |
| 358 std::set<MediaRoute::Id> route_ids_listening_for_messages_; | |
| 359 | |
| 360 IssueManager issue_manager_; | |
| 361 | |
| 362 // Binds |this| to a Mojo connection stub for interfaces::MediaRouter. | |
| 363 scoped_ptr<mojo::Binding<interfaces::MediaRouter>> binding_; | |
| 364 | |
| 365 // Mojo proxy object for the Media Route Provider Manager. | |
| 366 // Set to null initially, and later set to the Provider Manager proxy object | |
| 367 // passed in via |RegisterMediaRouteProvider()|. | |
| 368 // This is set to null again when the component extension is suspended | |
| 369 // if or a Mojo channel error occured. | |
| 370 interfaces::MediaRouteProviderPtr media_route_provider_; | |
| 371 | |
| 372 // Id of the component extension. Used for managing its suspend/wake state | |
| 373 // via event_page_tracker_. | |
| 374 std::string media_route_provider_extension_id_; | |
| 375 | |
| 376 // Allows the extension to be monitored for suspend, and woken. | |
| 377 // This is a reference to a BrowserContext keyed service that outlives this | |
| 378 // instance. | |
| 379 extensions::EventPageTracker* event_page_tracker_; | |
| 380 | |
| 381 // GUID unique to each browser run. Component extension uses this to detect | |
| 382 // when its persisted state was written by an older browser instance, and is | |
| 383 // therefore stale. | |
| 384 std::string instance_id_; | |
| 385 | |
| 386 // The last reported sink availability from the media route provider manager. | |
| 387 interfaces::MediaRouter::SinkAvailability availability_; | |
| 388 | |
| 389 int wakeup_attempt_count_ = 0; | |
| 390 | |
| 391 // Records the current reason the extension is being woken up. Is set to | |
| 392 // MediaRouteProviderWakeReason::TOTAL_COUNT if there is no pending reason. | |
| 393 MediaRouteProviderWakeReason current_wake_reason_; | |
| 394 | |
| 395 // A flag to ensure that we record the provider version once, during the | |
| 396 // initial event page wakeup attempt. | |
| 397 bool provider_version_was_recorded_ = false; | |
| 398 | |
| 399 #if defined(OS_WIN) | |
| 400 // A pair of flags to ensure that mDNS discovery is only enabled on Windows | |
| 401 // when there will be appropriate context for the user to associate a firewall | |
| 402 // prompt with Media Router. |should_enable_mdns_discovery_| can only go from | |
| 403 // |false| to |true|. On Windows, |is_mdns_enabled_| is set to |false| in | |
| 404 // RegisterMediaRouteProvider and only set to |true| when we successfully call | |
| 405 // the extension to enable mDNS. | |
| 406 bool is_mdns_enabled_ = false; | |
| 407 bool should_enable_mdns_discovery_ = false; | |
| 408 #endif | |
| 409 | |
| 410 base::WeakPtrFactory<MediaRouterMojoImpl> weak_factory_; | |
| 411 | |
| 412 DISALLOW_COPY_AND_ASSIGN(MediaRouterMojoImpl); | |
| 413 }; | |
| 414 | |
| 415 } // namespace media_router | |
| 416 | |
| 417 #endif // CHROME_BROWSER_MEDIA_ROUTER_MEDIA_ROUTER_MOJO_IMPL_H_ | |
| OLD | NEW |