OLD | NEW |
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" |
(...skipping 13 matching lines...) Expand all Loading... |
24 DVLOG(level) << "MR #" << instance_id_ << ": " | 24 DVLOG(level) << "MR #" << instance_id_ << ": " |
25 | 25 |
26 #define DLOG_WITH_INSTANCE(level) DLOG(level) << "MR #" << instance_id_ << ": " | 26 #define DLOG_WITH_INSTANCE(level) DLOG(level) << "MR #" << instance_id_ << ": " |
27 | 27 |
28 namespace media_router { | 28 namespace media_router { |
29 | 29 |
30 using SinkAvailability = interfaces::MediaRouter::SinkAvailability; | 30 using SinkAvailability = interfaces::MediaRouter::SinkAvailability; |
31 | 31 |
32 namespace { | 32 namespace { |
33 | 33 |
34 // TODO(imcheng): We should handle failure in this case. One way is to invoke | |
35 // all pending requests with failure. (crbug.com/490787) | |
36 void EventPageWakeComplete(bool success) { | |
37 if (!success) | |
38 LOG(ERROR) << "An error encountered while waking the event page."; | |
39 } | |
40 | |
41 scoped_ptr<content::PresentationSessionMessage> | 34 scoped_ptr<content::PresentationSessionMessage> |
42 ConvertToPresentationSessionMessage(interfaces::RouteMessagePtr input) { | 35 ConvertToPresentationSessionMessage(interfaces::RouteMessagePtr input) { |
43 DCHECK(!input.is_null()); | 36 DCHECK(!input.is_null()); |
44 scoped_ptr<content::PresentationSessionMessage> output; | 37 scoped_ptr<content::PresentationSessionMessage> output; |
45 switch (input->type) { | 38 switch (input->type) { |
46 case interfaces::RouteMessage::Type::TYPE_TEXT: { | 39 case interfaces::RouteMessage::Type::TYPE_TEXT: { |
47 DCHECK(!input->message.is_null()); | 40 DCHECK(!input->message.is_null()); |
48 DCHECK(input->data.is_null()); | 41 DCHECK(input->data.is_null()); |
49 output.reset(new content::PresentationSessionMessage( | 42 output.reset(new content::PresentationSessionMessage( |
50 content::PresentationMessageType::TEXT)); | 43 content::PresentationMessageType::TEXT)); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
97 router_->UpdateHasLocalRoute(has_local_route); | 90 router_->UpdateHasLocalRoute(has_local_route); |
98 } | 91 } |
99 | 92 |
100 // TODO(mfoltz): Flip the default sink availability to UNAVAILABLE, once the | 93 // TODO(mfoltz): Flip the default sink availability to UNAVAILABLE, once the |
101 // MRPM sends initial availability status. | 94 // MRPM sends initial availability status. |
102 MediaRouterMojoImpl::MediaRouterMojoImpl( | 95 MediaRouterMojoImpl::MediaRouterMojoImpl( |
103 extensions::EventPageTracker* event_page_tracker) | 96 extensions::EventPageTracker* event_page_tracker) |
104 : event_page_tracker_(event_page_tracker), | 97 : event_page_tracker_(event_page_tracker), |
105 instance_id_(base::GenerateGUID()), | 98 instance_id_(base::GenerateGUID()), |
106 has_local_route_(false), | 99 has_local_route_(false), |
107 availability_(interfaces::MediaRouter::SINK_AVAILABILITY_AVAILABLE) { | 100 availability_(interfaces::MediaRouter::SINK_AVAILABILITY_AVAILABLE), |
| 101 wakeup_attempt_count_(0), |
| 102 weak_factory_(this) { |
108 DCHECK(event_page_tracker_); | 103 DCHECK(event_page_tracker_); |
109 } | 104 } |
110 | 105 |
111 MediaRouterMojoImpl::~MediaRouterMojoImpl() { | 106 MediaRouterMojoImpl::~MediaRouterMojoImpl() { |
112 DCHECK(thread_checker_.CalledOnValidThread()); | 107 DCHECK(thread_checker_.CalledOnValidThread()); |
113 | 108 |
114 // Make sure |routes_observer_| is destroyed first, because it triggers | 109 // Make sure |routes_observer_| is destroyed first, because it triggers |
115 // additional cleanup logic in this class that depends on other fields. | 110 // additional cleanup logic in this class that depends on other fields. |
116 routes_observer_.reset(); | 111 routes_observer_.reset(); |
117 } | 112 } |
(...skipping 16 matching lines...) Expand all Loading... |
134 DCHECK(thread_checker_.CalledOnValidThread()); | 129 DCHECK(thread_checker_.CalledOnValidThread()); |
135 | 130 |
136 binding_.reset( | 131 binding_.reset( |
137 new mojo::Binding<interfaces::MediaRouter>(this, request.Pass())); | 132 new mojo::Binding<interfaces::MediaRouter>(this, request.Pass())); |
138 binding_->set_connection_error_handler(base::Bind( | 133 binding_->set_connection_error_handler(base::Bind( |
139 &MediaRouterMojoImpl::OnConnectionError, base::Unretained(this))); | 134 &MediaRouterMojoImpl::OnConnectionError, base::Unretained(this))); |
140 | 135 |
141 media_route_provider_extension_id_ = extension_id; | 136 media_route_provider_extension_id_ = extension_id; |
142 } | 137 } |
143 | 138 |
144 // TODO(imcheng): If this occurs while there are pending requests, we should | |
145 // probably invoke them with failure. (crbug.com/490787) | |
146 void MediaRouterMojoImpl::OnConnectionError() { | 139 void MediaRouterMojoImpl::OnConnectionError() { |
147 DCHECK(thread_checker_.CalledOnValidThread()); | 140 DCHECK(thread_checker_.CalledOnValidThread()); |
148 | 141 |
149 media_route_provider_.reset(); | 142 media_route_provider_.reset(); |
150 binding_.reset(); | 143 binding_.reset(); |
| 144 |
| 145 // If |OnConnectionError| is invoked while there are pending requests, then |
| 146 // it means we tried to wake the extension, but weren't able to complete the |
| 147 // connection to media route provider. Since we do not know whether the error |
| 148 // is transient, reattempt the wakeup. |
| 149 if (!pending_requests_.empty()) { |
| 150 DLOG_WITH_INSTANCE(ERROR) << "A connection error while there are pending " |
| 151 "requests."; |
| 152 AttemptWakeEventPage(); |
| 153 } |
151 } | 154 } |
152 | 155 |
153 void MediaRouterMojoImpl::RegisterMediaRouteProvider( | 156 void MediaRouterMojoImpl::RegisterMediaRouteProvider( |
154 interfaces::MediaRouteProviderPtr media_route_provider_ptr, | 157 interfaces::MediaRouteProviderPtr media_route_provider_ptr, |
155 const interfaces::MediaRouter::RegisterMediaRouteProviderCallback& | 158 const interfaces::MediaRouter::RegisterMediaRouteProviderCallback& |
156 callback) { | 159 callback) { |
157 DCHECK(thread_checker_.CalledOnValidThread()); | 160 DCHECK(thread_checker_.CalledOnValidThread()); |
158 | 161 |
| 162 if (event_page_tracker_->IsEventPageSuspended( |
| 163 media_route_provider_extension_id_)) { |
| 164 DVLOG_WITH_INSTANCE(1) |
| 165 << "ExecutePendingRequests was called while extension is suspended."; |
| 166 media_route_provider_.reset(); |
| 167 AttemptWakeEventPage(); |
| 168 return; |
| 169 } |
| 170 |
159 media_route_provider_ = media_route_provider_ptr.Pass(); | 171 media_route_provider_ = media_route_provider_ptr.Pass(); |
160 media_route_provider_.set_connection_error_handler(base::Bind( | 172 media_route_provider_.set_connection_error_handler(base::Bind( |
161 &MediaRouterMojoImpl::OnConnectionError, base::Unretained(this))); | 173 &MediaRouterMojoImpl::OnConnectionError, base::Unretained(this))); |
162 callback.Run(instance_id_); | 174 callback.Run(instance_id_); |
163 ExecutePendingRequests(); | 175 ExecutePendingRequests(); |
| 176 wakeup_attempt_count_ = 0; |
164 } | 177 } |
165 | 178 |
166 void MediaRouterMojoImpl::OnIssue(const interfaces::IssuePtr issue) { | 179 void MediaRouterMojoImpl::OnIssue(const interfaces::IssuePtr issue) { |
167 DCHECK(thread_checker_.CalledOnValidThread()); | 180 DCHECK(thread_checker_.CalledOnValidThread()); |
168 DVLOG_WITH_INSTANCE(1) << "OnIssue " << issue->title; | 181 DVLOG_WITH_INSTANCE(1) << "OnIssue " << issue->title; |
169 const Issue& issue_converted = issue.To<Issue>(); | 182 const Issue& issue_converted = issue.To<Issue>(); |
170 issue_manager_.AddIssue(issue_converted); | 183 issue_manager_.AddIssue(issue_converted); |
171 } | 184 } |
172 | 185 |
173 void MediaRouterMojoImpl::OnSinksReceived( | 186 void MediaRouterMojoImpl::OnSinksReceived( |
(...skipping 504 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
678 media_route_provider_->StartObservingMediaRoutes(); | 691 media_route_provider_->StartObservingMediaRoutes(); |
679 } | 692 } |
680 | 693 |
681 void MediaRouterMojoImpl::DoStopObservingMediaRoutes() { | 694 void MediaRouterMojoImpl::DoStopObservingMediaRoutes() { |
682 DVLOG_WITH_INSTANCE(1) << "DoStopObservingMediaRoutes"; | 695 DVLOG_WITH_INSTANCE(1) << "DoStopObservingMediaRoutes"; |
683 media_route_provider_->StopObservingMediaRoutes(); | 696 media_route_provider_->StopObservingMediaRoutes(); |
684 } | 697 } |
685 | 698 |
686 void MediaRouterMojoImpl::EnqueueTask(const base::Closure& closure) { | 699 void MediaRouterMojoImpl::EnqueueTask(const base::Closure& closure) { |
687 pending_requests_.push_back(closure); | 700 pending_requests_.push_back(closure); |
| 701 if (pending_requests_.size() > kMaxPendingRequests) { |
| 702 DLOG_WITH_INSTANCE(ERROR) << "Reached max queue size. Dropping oldest " |
| 703 << "request."; |
| 704 pending_requests_.pop_front(); |
| 705 } |
688 DVLOG_WITH_INSTANCE(2) << "EnqueueTask (queue-length=" | 706 DVLOG_WITH_INSTANCE(2) << "EnqueueTask (queue-length=" |
689 << pending_requests_.size() << ")"; | 707 << pending_requests_.size() << ")"; |
690 } | 708 } |
691 | 709 |
692 void MediaRouterMojoImpl::RunOrDefer(const base::Closure& request) { | 710 void MediaRouterMojoImpl::RunOrDefer(const base::Closure& request) { |
693 DCHECK(event_page_tracker_); | 711 DCHECK(event_page_tracker_); |
694 | 712 |
695 if (media_route_provider_extension_id_.empty()) { | 713 if (media_route_provider_extension_id_.empty()) { |
696 DVLOG_WITH_INSTANCE(1) << "Extension ID not known yet."; | 714 DVLOG_WITH_INSTANCE(1) << "Extension ID not known yet."; |
697 EnqueueTask(request); | 715 EnqueueTask(request); |
698 } else if (event_page_tracker_->IsEventPageSuspended( | 716 } else if (event_page_tracker_->IsEventPageSuspended( |
699 media_route_provider_extension_id_)) { | 717 media_route_provider_extension_id_)) { |
700 DVLOG_WITH_INSTANCE(1) << "Waking event page."; | 718 DVLOG_WITH_INSTANCE(1) << "Waking event page."; |
701 EnqueueTask(request); | 719 EnqueueTask(request); |
702 if (!event_page_tracker_->WakeEventPage( | 720 AttemptWakeEventPage(); |
703 media_route_provider_extension_id_, | |
704 base::Bind(&EventPageWakeComplete))) { | |
705 LOG(ERROR) << "An error encountered while waking the event page."; | |
706 } | |
707 media_route_provider_.reset(); | 721 media_route_provider_.reset(); |
708 } else if (!media_route_provider_) { | 722 } else if (!media_route_provider_) { |
709 DVLOG_WITH_INSTANCE(1) << "Extension is awake, awaiting ProvideMediaRouter " | 723 DVLOG_WITH_INSTANCE(1) << "Extension is awake, awaiting ProvideMediaRouter " |
710 " to be called."; | 724 " to be called."; |
711 EnqueueTask(request); | 725 EnqueueTask(request); |
712 } else { | 726 } else { |
713 request.Run(); | 727 request.Run(); |
714 } | 728 } |
715 } | 729 } |
716 | 730 |
| 731 void MediaRouterMojoImpl::AttemptWakeEventPage() { |
| 732 ++wakeup_attempt_count_; |
| 733 if (wakeup_attempt_count_ > kMaxWakeupAttemptCount) { |
| 734 DLOG_WITH_INSTANCE(ERROR) << "Attempted too many times to wake up event " |
| 735 << "page."; |
| 736 DrainPendingRequests(); |
| 737 wakeup_attempt_count_ = 0; |
| 738 return; |
| 739 } |
| 740 |
| 741 DVLOG_WITH_INSTANCE(1) << "Attempting to wake up event page: attempt " |
| 742 << wakeup_attempt_count_; |
| 743 |
| 744 // This return false if the extension is already awake. |
| 745 // Callback is bound using WeakPtr because |event_page_tracker_| outlives |
| 746 // |this|. |
| 747 if (!event_page_tracker_->WakeEventPage( |
| 748 media_route_provider_extension_id_, |
| 749 base::Bind(&MediaRouterMojoImpl::EventPageWakeComplete, |
| 750 weak_factory_.GetWeakPtr()))) { |
| 751 DLOG_WITH_INSTANCE(ERROR) << "Failed to schedule a wakeup for event page."; |
| 752 } |
| 753 } |
| 754 |
717 void MediaRouterMojoImpl::ExecutePendingRequests() { | 755 void MediaRouterMojoImpl::ExecutePendingRequests() { |
718 DCHECK(thread_checker_.CalledOnValidThread()); | 756 DCHECK(thread_checker_.CalledOnValidThread()); |
719 DCHECK(media_route_provider_); | 757 DCHECK(media_route_provider_); |
720 DCHECK(event_page_tracker_); | 758 DCHECK(event_page_tracker_); |
721 DCHECK(!media_route_provider_extension_id_.empty()); | 759 DCHECK(!media_route_provider_extension_id_.empty()); |
722 | 760 |
723 if (event_page_tracker_->IsEventPageSuspended( | |
724 media_route_provider_extension_id_)) { | |
725 DVLOG_WITH_INSTANCE(1) | |
726 << "ExecutePendingRequests was called while extension is suspended."; | |
727 return; | |
728 } | |
729 | |
730 for (const auto& next_request : pending_requests_) | 761 for (const auto& next_request : pending_requests_) |
731 next_request.Run(); | 762 next_request.Run(); |
732 | 763 |
733 pending_requests_.clear(); | 764 pending_requests_.clear(); |
734 } | 765 } |
735 | 766 |
| 767 void MediaRouterMojoImpl::EventPageWakeComplete(bool success) { |
| 768 if (success) |
| 769 return; |
| 770 |
| 771 // This is likely an non-retriable error. Drop the pending requests. |
| 772 DLOG_WITH_INSTANCE(ERROR) |
| 773 << "An error encountered while waking the event page."; |
| 774 DrainPendingRequests(); |
| 775 } |
| 776 |
| 777 void MediaRouterMojoImpl::DrainPendingRequests() { |
| 778 DLOG_WITH_INSTANCE(ERROR) |
| 779 << "Draining request queue. (queue-length=" << pending_requests_.size() |
| 780 << ")"; |
| 781 pending_requests_.clear(); |
| 782 } |
| 783 |
736 } // namespace media_router | 784 } // namespace media_router |
OLD | NEW |