Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(104)

Side by Side Diff: chrome/browser/media/router/media_router_mojo_impl.cc

Issue 1419853003: [Media Router] Connection reattempt logic and bound pending request queue size. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/media/router/media_router_mojo_impl.h" 5 #include "chrome/browser/media/router/media_router_mojo_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/guid.h" 8 #include "base/guid.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/scoped_vector.h" 10 #include "base/memory/scoped_vector.h"
11 #include "base/observer_list.h" 11 #include "base/observer_list.h"
12 #include "base/strings/stringprintf.h" 12 #include "base/strings/stringprintf.h"
13 #include "chrome/browser/media/router/issues_observer.h" 13 #include "chrome/browser/media/router/issues_observer.h"
14 #include "chrome/browser/media/router/local_media_routes_observer.h" 14 #include "chrome/browser/media/router/local_media_routes_observer.h"
15 #include "chrome/browser/media/router/media_router_factory.h" 15 #include "chrome/browser/media/router/media_router_factory.h"
16 #include "chrome/browser/media/router/media_router_type_converters.h" 16 #include "chrome/browser/media/router/media_router_type_converters.h"
17 #include "chrome/browser/media/router/media_routes_observer.h" 17 #include "chrome/browser/media/router/media_routes_observer.h"
18 #include "chrome/browser/media/router/media_sinks_observer.h" 18 #include "chrome/browser/media/router/media_sinks_observer.h"
19 #include "chrome/browser/media/router/presentation_session_messages_observer.h" 19 #include "chrome/browser/media/router/presentation_session_messages_observer.h"
20 #include "extensions/browser/process_manager.h" 20 #include "extensions/browser/process_manager.h"
21 21
22 #define DVLOG_WITH_INSTANCE(level) \ 22 #define DVLOG_WITH_INSTANCE(level) \
23 DVLOG(level) << "MR #" << instance_id_ << ": " 23 DVLOG(level) << "MR #" << instance_id_ << ": "
24 24
25 #define DLOG_WITH_INSTANCE(level) DLOG(level) << "MR #" << instance_id_ << ": " 25 #define DLOG_WITH_INSTANCE(level) DLOG(level) << "MR #" << instance_id_ << ": "
26 26
27 namespace media_router { 27 namespace media_router {
28 namespace { 28 namespace {
29 29
30 // TODO(imcheng): We should handle failure in this case. One way is to invoke
31 // all pending requests with failure. (crbug.com/490787)
32 void EventPageWakeComplete(bool success) {
33 if (!success)
34 LOG(ERROR) << "An error encountered while waking the event page.";
35 }
36
37 scoped_ptr<content::PresentationSessionMessage> 30 scoped_ptr<content::PresentationSessionMessage>
38 ConvertToPresentationSessionMessage(interfaces::RouteMessagePtr input) { 31 ConvertToPresentationSessionMessage(interfaces::RouteMessagePtr input) {
39 DCHECK(!input.is_null()); 32 DCHECK(!input.is_null());
40 scoped_ptr<content::PresentationSessionMessage> output; 33 scoped_ptr<content::PresentationSessionMessage> output;
41 switch (input->type) { 34 switch (input->type) {
42 case interfaces::RouteMessage::Type::TYPE_TEXT: { 35 case interfaces::RouteMessage::Type::TYPE_TEXT: {
43 DCHECK(!input->message.is_null()); 36 DCHECK(!input->message.is_null());
44 DCHECK(input->data.is_null()); 37 DCHECK(input->data.is_null());
45 output.reset(new content::PresentationSessionMessage( 38 output.reset(new content::PresentationSessionMessage(
46 content::PresentationMessageType::TEXT)); 39 content::PresentationMessageType::TEXT));
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 // |this| will be deleted in UpdateHasLocalRoute() if |has_local_route| is 79 // |this| will be deleted in UpdateHasLocalRoute() if |has_local_route| is
87 // false. Note that ObserverList supports removing an observer while 80 // false. Note that ObserverList supports removing an observer while
88 // iterating through it. 81 // iterating through it.
89 router_->UpdateHasLocalRoute(has_local_route); 82 router_->UpdateHasLocalRoute(has_local_route);
90 } 83 }
91 84
92 MediaRouterMojoImpl::MediaRouterMojoImpl( 85 MediaRouterMojoImpl::MediaRouterMojoImpl(
93 extensions::EventPageTracker* event_page_tracker) 86 extensions::EventPageTracker* event_page_tracker)
94 : event_page_tracker_(event_page_tracker), 87 : event_page_tracker_(event_page_tracker),
95 instance_id_(base::GenerateGUID()), 88 instance_id_(base::GenerateGUID()),
96 has_local_route_(false) { 89 has_local_route_(false),
90 wakeup_attempt_count_(0),
91 weak_factory_(this) {
97 DCHECK(event_page_tracker_); 92 DCHECK(event_page_tracker_);
98 } 93 }
99 94
100 MediaRouterMojoImpl::~MediaRouterMojoImpl() { 95 MediaRouterMojoImpl::~MediaRouterMojoImpl() {
101 DCHECK(thread_checker_.CalledOnValidThread()); 96 DCHECK(thread_checker_.CalledOnValidThread());
102 97
103 // Make sure |routes_observer_| is destroyed first, because it triggers 98 // Make sure |routes_observer_| is destroyed first, because it triggers
104 // additional cleanup logic in this class that depends on other fields. 99 // additional cleanup logic in this class that depends on other fields.
105 routes_observer_.reset(); 100 routes_observer_.reset();
106 } 101 }
(...skipping 16 matching lines...) Expand all
123 DCHECK(thread_checker_.CalledOnValidThread()); 118 DCHECK(thread_checker_.CalledOnValidThread());
124 119
125 binding_.reset( 120 binding_.reset(
126 new mojo::Binding<interfaces::MediaRouter>(this, request.Pass())); 121 new mojo::Binding<interfaces::MediaRouter>(this, request.Pass()));
127 binding_->set_connection_error_handler(base::Bind( 122 binding_->set_connection_error_handler(base::Bind(
128 &MediaRouterMojoImpl::OnConnectionError, base::Unretained(this))); 123 &MediaRouterMojoImpl::OnConnectionError, base::Unretained(this)));
129 124
130 media_route_provider_extension_id_ = extension_id; 125 media_route_provider_extension_id_ = extension_id;
131 } 126 }
132 127
133 // TODO(imcheng): If this occurs while there are pending requests, we should
134 // probably invoke them with failure. (crbug.com/490787)
135 void MediaRouterMojoImpl::OnConnectionError() { 128 void MediaRouterMojoImpl::OnConnectionError() {
136 DCHECK(thread_checker_.CalledOnValidThread()); 129 DCHECK(thread_checker_.CalledOnValidThread());
137 130
138 media_route_provider_.reset(); 131 media_route_provider_.reset();
139 binding_.reset(); 132 binding_.reset();
133
134 // If |OnConnectionError| is invoked while there are pending requests, then
135 // it means we tried to wake the extension, but weren't able to complete the
136 // connection to media route provider. Since we do not know whether the error
137 // is transient, reattempt the wakeup.
138 if (!pending_requests_.empty()) {
139 DLOG_WITH_INSTANCE(ERROR) << "A connection error while there are pending "
140 "requests.";
141 AttemptWakeEventPage();
142 }
140 } 143 }
141 144
142 void MediaRouterMojoImpl::RegisterMediaRouteProvider( 145 void MediaRouterMojoImpl::RegisterMediaRouteProvider(
143 interfaces::MediaRouteProviderPtr media_route_provider_ptr, 146 interfaces::MediaRouteProviderPtr media_route_provider_ptr,
144 const interfaces::MediaRouter::RegisterMediaRouteProviderCallback& 147 const interfaces::MediaRouter::RegisterMediaRouteProviderCallback&
145 callback) { 148 callback) {
146 DCHECK(thread_checker_.CalledOnValidThread()); 149 DCHECK(thread_checker_.CalledOnValidThread());
147 150
151 if (event_page_tracker_->IsEventPageSuspended(
152 media_route_provider_extension_id_)) {
153 DVLOG_WITH_INSTANCE(1)
154 << "ExecutePendingRequests was called while extension is suspended.";
155 media_route_provider_.reset();
156 AttemptWakeEventPage();
157 return;
158 }
159
148 media_route_provider_ = media_route_provider_ptr.Pass(); 160 media_route_provider_ = media_route_provider_ptr.Pass();
149 media_route_provider_.set_connection_error_handler(base::Bind( 161 media_route_provider_.set_connection_error_handler(base::Bind(
150 &MediaRouterMojoImpl::OnConnectionError, base::Unretained(this))); 162 &MediaRouterMojoImpl::OnConnectionError, base::Unretained(this)));
151 callback.Run(instance_id_); 163 callback.Run(instance_id_);
152 ExecutePendingRequests(); 164 ExecutePendingRequests();
165 wakeup_attempt_count_ = 0;
153 } 166 }
154 167
155 void MediaRouterMojoImpl::OnIssue(const interfaces::IssuePtr issue) { 168 void MediaRouterMojoImpl::OnIssue(const interfaces::IssuePtr issue) {
156 DCHECK(thread_checker_.CalledOnValidThread()); 169 DCHECK(thread_checker_.CalledOnValidThread());
157 DVLOG_WITH_INSTANCE(1) << "OnIssue " << issue->title; 170 DVLOG_WITH_INSTANCE(1) << "OnIssue " << issue->title;
158 const Issue& issue_converted = issue.To<Issue>(); 171 const Issue& issue_converted = issue.To<Issue>();
159 issue_manager_.AddIssue(issue_converted); 172 issue_manager_.AddIssue(issue_converted);
160 } 173 }
161 174
162 void MediaRouterMojoImpl::OnSinksReceived( 175 void MediaRouterMojoImpl::OnSinksReceived(
(...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after
607 media_route_provider_->StartObservingMediaRoutes(); 620 media_route_provider_->StartObservingMediaRoutes();
608 } 621 }
609 622
610 void MediaRouterMojoImpl::DoStopObservingMediaRoutes() { 623 void MediaRouterMojoImpl::DoStopObservingMediaRoutes() {
611 DVLOG_WITH_INSTANCE(1) << "DoStopObservingMediaRoutes"; 624 DVLOG_WITH_INSTANCE(1) << "DoStopObservingMediaRoutes";
612 media_route_provider_->StopObservingMediaRoutes(); 625 media_route_provider_->StopObservingMediaRoutes();
613 } 626 }
614 627
615 void MediaRouterMojoImpl::EnqueueTask(const base::Closure& closure) { 628 void MediaRouterMojoImpl::EnqueueTask(const base::Closure& closure) {
616 pending_requests_.push_back(closure); 629 pending_requests_.push_back(closure);
630 if (pending_requests_.size() > kMaxPendingRequests) {
631 DLOG_WITH_INSTANCE(ERROR) << "Reached max queue size. Dropping oldest "
632 << "request.";
633 pending_requests_.pop_front();
634 }
617 DVLOG_WITH_INSTANCE(2) << "EnqueueTask (queue-length=" 635 DVLOG_WITH_INSTANCE(2) << "EnqueueTask (queue-length="
618 << pending_requests_.size() << ")"; 636 << pending_requests_.size() << ")";
619 } 637 }
620 638
621 void MediaRouterMojoImpl::RunOrDefer(const base::Closure& request) { 639 void MediaRouterMojoImpl::RunOrDefer(const base::Closure& request) {
622 DCHECK(event_page_tracker_); 640 DCHECK(event_page_tracker_);
623 641
624 if (media_route_provider_extension_id_.empty()) { 642 if (media_route_provider_extension_id_.empty()) {
625 DVLOG_WITH_INSTANCE(1) << "Extension ID not known yet."; 643 DVLOG_WITH_INSTANCE(1) << "Extension ID not known yet.";
626 EnqueueTask(request); 644 EnqueueTask(request);
627 } else if (event_page_tracker_->IsEventPageSuspended( 645 } else if (event_page_tracker_->IsEventPageSuspended(
628 media_route_provider_extension_id_)) { 646 media_route_provider_extension_id_)) {
629 DVLOG_WITH_INSTANCE(1) << "Waking event page."; 647 DVLOG_WITH_INSTANCE(1) << "Waking event page.";
630 EnqueueTask(request); 648 EnqueueTask(request);
631 if (!event_page_tracker_->WakeEventPage( 649 AttemptWakeEventPage();
632 media_route_provider_extension_id_,
633 base::Bind(&EventPageWakeComplete))) {
634 LOG(ERROR) << "An error encountered while waking the event page.";
635 }
636 media_route_provider_.reset(); 650 media_route_provider_.reset();
637 } else if (!media_route_provider_) { 651 } else if (!media_route_provider_) {
638 DVLOG_WITH_INSTANCE(1) << "Extension is awake, awaiting ProvideMediaRouter " 652 DVLOG_WITH_INSTANCE(1) << "Extension is awake, awaiting ProvideMediaRouter "
639 " to be called."; 653 " to be called.";
640 EnqueueTask(request); 654 EnqueueTask(request);
641 } else { 655 } else {
642 request.Run(); 656 request.Run();
643 } 657 }
644 } 658 }
645 659
660 void MediaRouterMojoImpl::AttemptWakeEventPage() {
661 if (wakeup_attempt_count_ >= kMaxWakeupAttemptCount) {
662 DLOG_WITH_INSTANCE(ERROR) << "Attempted too many times to wake up event "
663 << "page.";
664 DrainPendingRequests();
665 wakeup_attempt_count_ = 0;
666 return;
667 }
668
669 ++wakeup_attempt_count_;
670 DVLOG_WITH_INSTANCE(1) << "Attempting to wake up event page: attempt "
671 << wakeup_attempt_count_;
672
673 // This return false if the extension is already awake.
674 // Callback is bound using WeakPtr because |event_page_tracker_| outlives
675 // |this|.
676 if (!event_page_tracker_->WakeEventPage(
677 media_route_provider_extension_id_,
678 base::Bind(&MediaRouterMojoImpl::EventPageWakeComplete,
679 weak_factory_.GetWeakPtr()))) {
680 DLOG_WITH_INSTANCE(ERROR) << "Failed to schedule a wakeup for event page.";
681 }
682 }
683
646 void MediaRouterMojoImpl::ExecutePendingRequests() { 684 void MediaRouterMojoImpl::ExecutePendingRequests() {
647 DCHECK(thread_checker_.CalledOnValidThread()); 685 DCHECK(thread_checker_.CalledOnValidThread());
648 DCHECK(media_route_provider_); 686 DCHECK(media_route_provider_);
649 DCHECK(event_page_tracker_); 687 DCHECK(event_page_tracker_);
650 DCHECK(!media_route_provider_extension_id_.empty()); 688 DCHECK(!media_route_provider_extension_id_.empty());
651 689
652 if (event_page_tracker_->IsEventPageSuspended(
653 media_route_provider_extension_id_)) {
654 DVLOG_WITH_INSTANCE(1)
655 << "ExecutePendingRequests was called while extension is suspended.";
656 return;
657 }
658
659 for (const auto& next_request : pending_requests_) 690 for (const auto& next_request : pending_requests_)
660 next_request.Run(); 691 next_request.Run();
661 692
662 pending_requests_.clear(); 693 pending_requests_.clear();
663 } 694 }
664 695
696 void MediaRouterMojoImpl::EventPageWakeComplete(bool success) {
697 if (success)
698 return;
699
700 // This is likely an non-retriable error. Drop the pending requests.
701 DLOG_WITH_INSTANCE(ERROR)
702 << "An error encountered while waking the event page.";
703 DrainPendingRequests();
704 }
705
706 void MediaRouterMojoImpl::DrainPendingRequests() {
707 DLOG_WITH_INSTANCE(ERROR)
708 << "Draining request queue. (queue-length=" << pending_requests_.size()
709 << ")";
710 pending_requests_.clear();
711 }
712
665 } // namespace media_router 713 } // namespace media_router
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698