Commit 31fe0da9 authored by imcheng's avatar imcheng Committed by Commit bot

[Presentation API] Fix potential callback leaks in PSImpl.

Background: mojo rolled out a new version that requires callbacks (as
defined by the => syntax in mojom) must be invoked before they go out
of scope, otherwise it indicates a connection error on the callback's
recipient, which will destroy mojom implementations that are strongly
bound to the connection.

Note that a partial fix was added in crrev.com/1019173002. This patch
addresses the remaining points.

BUG=468575

Review URL: https://codereview.chromium.org/996173006

Cr-Commit-Position: refs/heads/master@{#322299}
parent efb5a135
...@@ -25,6 +25,7 @@ PresentationServiceImpl::PresentationServiceImpl( ...@@ -25,6 +25,7 @@ PresentationServiceImpl::PresentationServiceImpl(
: WebContentsObserver(web_contents), : WebContentsObserver(web_contents),
render_frame_host_(render_frame_host), render_frame_host_(render_frame_host),
delegate_(delegate), delegate_(delegate),
next_request_session_id_(0),
weak_factory_(this) { weak_factory_(this) {
DCHECK(render_frame_host_); DCHECK(render_frame_host_);
DCHECK(web_contents); DCHECK(web_contents);
...@@ -133,10 +134,7 @@ void PresentationServiceImpl::StartSession( ...@@ -133,10 +134,7 @@ void PresentationServiceImpl::StartSession(
const NewSessionMojoCallback& callback) { const NewSessionMojoCallback& callback) {
DVLOG(2) << "StartSession"; DVLOG(2) << "StartSession";
if (!delegate_) { if (!delegate_) {
callback.Run( InvokeNewSessionMojoCallbackWithError(callback);
presentation::PresentationSessionInfoPtr(),
presentation::PresentationError::From(
PresentationError(PRESENTATION_ERROR_UNKNOWN, "")));
return; return;
} }
...@@ -152,23 +150,20 @@ void PresentationServiceImpl::JoinSession( ...@@ -152,23 +150,20 @@ void PresentationServiceImpl::JoinSession(
const NewSessionMojoCallback& callback) { const NewSessionMojoCallback& callback) {
DVLOG(2) << "JoinSession"; DVLOG(2) << "JoinSession";
if (!delegate_) { if (!delegate_) {
callback.Run( InvokeNewSessionMojoCallbackWithError(callback);
presentation::PresentationSessionInfoPtr(),
presentation::PresentationError::From(
PresentationError(PRESENTATION_ERROR_UNKNOWN, "")));
return; return;
} }
int request_session_id = RegisterNewSessionCallback(callback);
delegate_->JoinSession( delegate_->JoinSession(
render_frame_host_->GetProcess()->GetID(), render_frame_host_->GetProcess()->GetID(),
render_frame_host_->GetRoutingID(), render_frame_host_->GetRoutingID(),
presentation_url, presentation_url,
presentation_id, presentation_id,
// TODO(imcheng): These callbacks may be dropped. http://crbug.com/468575
base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded, base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded,
weak_factory_.GetWeakPtr(), false, callback), weak_factory_.GetWeakPtr(), false, request_session_id),
base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionError, base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionError,
weak_factory_.GetWeakPtr(), false, callback)); weak_factory_.GetWeakPtr(), false, request_session_id));
} }
void PresentationServiceImpl::HandleQueuedStartSessionRequests() { void PresentationServiceImpl::HandleQueuedStartSessionRequests() {
...@@ -183,27 +178,36 @@ void PresentationServiceImpl::HandleQueuedStartSessionRequests() { ...@@ -183,27 +178,36 @@ void PresentationServiceImpl::HandleQueuedStartSessionRequests() {
} }
} }
int PresentationServiceImpl::RegisterNewSessionCallback(
const NewSessionMojoCallback& callback) {
++next_request_session_id_;
pending_session_cbs_[next_request_session_id_].reset(
new NewSessionMojoCallback(callback));
return next_request_session_id_;
}
void PresentationServiceImpl::DoStartSession( void PresentationServiceImpl::DoStartSession(
const std::string& presentation_url, const std::string& presentation_url,
const std::string& presentation_id, const std::string& presentation_id,
const NewSessionMojoCallback& callback) { const NewSessionMojoCallback& callback) {
int request_session_id = RegisterNewSessionCallback(callback);
delegate_->StartSession( delegate_->StartSession(
render_frame_host_->GetProcess()->GetID(), render_frame_host_->GetProcess()->GetID(),
render_frame_host_->GetRoutingID(), render_frame_host_->GetRoutingID(),
presentation_url, presentation_url,
presentation_id, presentation_id,
// TODO(imcheng): These callbacks may be dropped. http://crbug.com/468575
base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded, base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionSucceeded,
weak_factory_.GetWeakPtr(), true, callback), weak_factory_.GetWeakPtr(), true, request_session_id),
base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionError, base::Bind(&PresentationServiceImpl::OnStartOrJoinSessionError,
weak_factory_.GetWeakPtr(), true, callback)); weak_factory_.GetWeakPtr(), true, request_session_id));
} }
void PresentationServiceImpl::OnStartOrJoinSessionSucceeded( void PresentationServiceImpl::OnStartOrJoinSessionSucceeded(
bool is_start_session, bool is_start_session,
const NewSessionMojoCallback& callback, int request_session_id,
const PresentationSessionInfo& session_info) { const PresentationSessionInfo& session_info) {
callback.Run( RunAndEraseNewSessionMojoCallback(
request_session_id,
presentation::PresentationSessionInfo::From(session_info), presentation::PresentationSessionInfo::From(session_info),
presentation::PresentationErrorPtr()); presentation::PresentationErrorPtr());
if (is_start_session) if (is_start_session)
...@@ -212,15 +216,29 @@ void PresentationServiceImpl::OnStartOrJoinSessionSucceeded( ...@@ -212,15 +216,29 @@ void PresentationServiceImpl::OnStartOrJoinSessionSucceeded(
void PresentationServiceImpl::OnStartOrJoinSessionError( void PresentationServiceImpl::OnStartOrJoinSessionError(
bool is_start_session, bool is_start_session,
const NewSessionMojoCallback& callback, int request_session_id,
const PresentationError& error) { const PresentationError& error) {
callback.Run( RunAndEraseNewSessionMojoCallback(
request_session_id,
presentation::PresentationSessionInfoPtr(), presentation::PresentationSessionInfoPtr(),
presentation::PresentationError::From(error)); presentation::PresentationError::From(error));
if (is_start_session) if (is_start_session)
HandleQueuedStartSessionRequests(); HandleQueuedStartSessionRequests();
} }
void PresentationServiceImpl::RunAndEraseNewSessionMojoCallback(
int request_session_id,
presentation::PresentationSessionInfoPtr session,
presentation::PresentationErrorPtr error) {
auto it = pending_session_cbs_.find(request_session_id);
if (it == pending_session_cbs_.end())
return;
DCHECK(it->second.get());
it->second->Run(session.Pass(), error.Pass());
pending_session_cbs_.erase(it);
}
void PresentationServiceImpl::DoSetDefaultPresentationUrl( void PresentationServiceImpl::DoSetDefaultPresentationUrl(
const std::string& default_presentation_url, const std::string& default_presentation_url,
const std::string& default_presentation_id) { const std::string& default_presentation_id) {
...@@ -332,12 +350,26 @@ void PresentationServiceImpl::Reset() { ...@@ -332,12 +350,26 @@ void PresentationServiceImpl::Reset() {
default_presentation_url_.clear(); default_presentation_url_.clear();
default_presentation_id_.clear(); default_presentation_id_.clear();
for (const auto& context : availability_contexts_) { for (const auto& context_entry : availability_contexts_) {
context.second->OnScreenAvailabilityChanged(false); context_entry.second->OnScreenAvailabilityChanged(false);
} }
availability_contexts_.clear(); availability_contexts_.clear();
// TODO(imcheng): This may drop callbacks. See http://crbug.com/468575. for (auto& request_ptr : queued_start_session_requests_) {
InvokeNewSessionMojoCallbackWithError(request_ptr->callback);
}
queued_start_session_requests_.clear(); queued_start_session_requests_.clear();
for (auto& pending_entry : pending_session_cbs_) {
InvokeNewSessionMojoCallbackWithError(*pending_entry.second);
}
pending_session_cbs_.clear();
}
void PresentationServiceImpl::InvokeNewSessionMojoCallbackWithError(
const NewSessionMojoCallback& callback) {
callback.Run(
presentation::PresentationSessionInfoPtr(),
presentation::PresentationError::From(
PresentationError(PRESENTATION_ERROR_UNKNOWN, "Internal error")));
} }
void PresentationServiceImpl::OnDelegateDestroyed() { void PresentationServiceImpl::OnDelegateDestroyed() {
......
...@@ -186,6 +186,14 @@ class CONTENT_EXPORT PresentationServiceImpl ...@@ -186,6 +186,14 @@ class CONTENT_EXPORT PresentationServiceImpl
// PresentationServiceDelegate::Observer // PresentationServiceDelegate::Observer
void OnDelegateDestroyed() override; void OnDelegateDestroyed() override;
// Finds the callback from |pending_session_cbs_| using |request_session_id|.
// If it exists, invoke it with |session| and |error|, then erase it from
// |pending_session_cbs_|.
void RunAndEraseNewSessionMojoCallback(
int request_session_id,
presentation::PresentationSessionInfoPtr session,
presentation::PresentationErrorPtr error);
// Sets |default_presentation_url_| to |presentation_url| and informs the // Sets |default_presentation_url_| to |presentation_url| and informs the
// delegate of new default presentation URL and ID. // delegate of new default presentation URL and ID.
void DoSetDefaultPresentationUrl( void DoSetDefaultPresentationUrl(
...@@ -201,11 +209,11 @@ class CONTENT_EXPORT PresentationServiceImpl ...@@ -201,11 +209,11 @@ class CONTENT_EXPORT PresentationServiceImpl
// invocation. // invocation.
void OnStartOrJoinSessionSucceeded( void OnStartOrJoinSessionSucceeded(
bool is_start_session, bool is_start_session,
const NewSessionMojoCallback& callback, int request_session_id,
const PresentationSessionInfo& session_info); const PresentationSessionInfo& session_info);
void OnStartOrJoinSessionError( void OnStartOrJoinSessionError(
bool is_start_session, bool is_start_session,
const NewSessionMojoCallback& callback, int request_session_id,
const PresentationError& error); const PresentationError& error);
// Requests delegate to start a session. // Requests delegate to start a session.
...@@ -220,6 +228,14 @@ class CONTENT_EXPORT PresentationServiceImpl ...@@ -220,6 +228,14 @@ class CONTENT_EXPORT PresentationServiceImpl
// the first one in the queue. // the first one in the queue.
void HandleQueuedStartSessionRequests(); void HandleQueuedStartSessionRequests();
// Associates |callback| with a unique request ID and stores it in a map.
int RegisterNewSessionCallback(
const NewSessionMojoCallback& callback);
// Invokes |callback| with an error.
void InvokeNewSessionMojoCallbackWithError(
const NewSessionMojoCallback& callback);
// Gets the ScreenAvailabilityContext for |presentation_url|, or creates one // Gets the ScreenAvailabilityContext for |presentation_url|, or creates one
// if it does not exist. // if it does not exist.
ScreenAvailabilityContext* GetOrCreateAvailabilityContext( ScreenAvailabilityContext* GetOrCreateAvailabilityContext(
...@@ -240,6 +256,9 @@ class CONTENT_EXPORT PresentationServiceImpl ...@@ -240,6 +256,9 @@ class CONTENT_EXPORT PresentationServiceImpl
// it is removed from head of the queue. // it is removed from head of the queue.
std::deque<linked_ptr<StartSessionRequest>> queued_start_session_requests_; std::deque<linked_ptr<StartSessionRequest>> queued_start_session_requests_;
int next_request_session_id_;
base::hash_map<int, linked_ptr<NewSessionMojoCallback>> pending_session_cbs_;
// NOTE: Weak pointers must be invalidated before all other member variables. // NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<PresentationServiceImpl> weak_factory_; base::WeakPtrFactory<PresentationServiceImpl> weak_factory_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment