// Copyright (c) 2010 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/geolocation/geolocation_dispatcher_host_old.h" #include #include #include #include "chrome/common/geoposition.h" #include "chrome/browser/geolocation/geolocation_permission_context.h" #include "chrome/browser/geolocation/geolocation_provider.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_view_host.h" #include "chrome/browser/renderer_host/render_view_host_notification_task.h" #include "chrome/browser/renderer_host/resource_message_filter.h" #include "chrome/common/render_messages.h" #include "ipc/ipc_message.h" namespace { class GeolocationDispatcherHostOldImpl : public GeolocationDispatcherHostOld, public GeolocationObserver { public: GeolocationDispatcherHostOldImpl( int resource_message_filter_process_id, GeolocationPermissionContext* geolocation_permission_context); // GeolocationDispatcherHostOld // Called to possibly handle the incoming IPC message. Returns true if // handled. Called in the browser process. virtual bool OnMessageReceived(const IPC::Message& msg, bool* msg_was_ok); // GeolocationArbitrator::Delegate virtual void OnLocationUpdate(const Geoposition& position); private: friend class base::RefCountedThreadSafe; virtual ~GeolocationDispatcherHostOldImpl(); void OnRegisterDispatcher(int render_view_id); void OnUnregisterDispatcher(int render_view_id); void OnRequestPermission( int render_view_id, int bridge_id, const GURL& requesting_frame); void OnCancelPermissionRequest( int render_view_id, int bridge_id, const GURL& requesting_frame); void OnStartUpdating( int render_view_id, int bridge_id, const GURL& requesting_frame, bool enable_high_accuracy); void OnStopUpdating(int render_view_id, int bridge_id); void OnSuspend(int render_view_id, int bridge_id); void OnResume(int render_view_id, int bridge_id); // Updates the |location_arbitrator_| with the currently required update // options, based on |bridge_update_options_|. void RefreshGeolocationObserverOptions(); int resource_message_filter_process_id_; scoped_refptr geolocation_permission_context_; // Iterated when sending location updates to renderer processes. The fan out // to individual bridge IDs happens renderer side, in order to minimize // context switches. // Only used on the IO thread. std::set geolocation_renderer_ids_; // Maps to the location arbitrator update options // that correspond to this particular bridge. std::map, GeolocationObserverOptions> bridge_update_options_; // Only set whilst we are registered with the arbitrator. GeolocationProvider* location_provider_; DISALLOW_COPY_AND_ASSIGN(GeolocationDispatcherHostOldImpl); }; GeolocationDispatcherHostOldImpl::GeolocationDispatcherHostOldImpl( int resource_message_filter_process_id, GeolocationPermissionContext* geolocation_permission_context) : resource_message_filter_process_id_(resource_message_filter_process_id), geolocation_permission_context_(geolocation_permission_context), location_provider_(NULL) { // This is initialized by ResourceMessageFilter. Do not add any non-trivial // initialization here, defer to OnRegisterBridge which is triggered whenever // a javascript geolocation object is actually initialized. } GeolocationDispatcherHostOldImpl::~GeolocationDispatcherHostOldImpl() { if (location_provider_) location_provider_->RemoveObserver(this); } bool GeolocationDispatcherHostOldImpl::OnMessageReceived( const IPC::Message& msg, bool* msg_was_ok) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); *msg_was_ok = true; bool handled = true; IPC_BEGIN_MESSAGE_MAP_EX(GeolocationDispatcherHostOldImpl, msg, *msg_was_ok) IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_RegisterDispatcher, OnRegisterDispatcher) IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_UnregisterDispatcher, OnUnregisterDispatcher) IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_CancelPermissionRequest, OnCancelPermissionRequest) IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_RequestPermission, OnRequestPermission) IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_StartUpdating, OnStartUpdating) IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_StopUpdating, OnStopUpdating) IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_Suspend, OnSuspend) IPC_MESSAGE_HANDLER(ViewHostMsg_Geolocation_Resume, OnResume) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void GeolocationDispatcherHostOldImpl::OnLocationUpdate( const Geoposition& geoposition) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); for (std::set::iterator it = geolocation_renderer_ids_.begin(); it != geolocation_renderer_ids_.end(); ++it) { IPC::Message* message = new ViewMsg_Geolocation_PositionUpdated(*it, geoposition); CallRenderViewHost(resource_message_filter_process_id_, *it, &RenderViewHost::Send, message); } } void GeolocationDispatcherHostOldImpl::OnRegisterDispatcher( int render_view_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK_EQ(0u, geolocation_renderer_ids_.count(render_view_id)); geolocation_renderer_ids_.insert(render_view_id); } void GeolocationDispatcherHostOldImpl::OnUnregisterDispatcher( int render_view_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DCHECK_EQ(1u, geolocation_renderer_ids_.count(render_view_id)); geolocation_renderer_ids_.erase(render_view_id); } void GeolocationDispatcherHostOldImpl::OnRequestPermission( int render_view_id, int bridge_id, const GURL& requesting_frame) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DVLOG(1) << __FUNCTION__ << " " << resource_message_filter_process_id_ << ":" << render_view_id << ":" << bridge_id; geolocation_permission_context_->RequestGeolocationPermission( resource_message_filter_process_id_, render_view_id, bridge_id, requesting_frame); } void GeolocationDispatcherHostOldImpl::OnCancelPermissionRequest( int render_view_id, int bridge_id, const GURL& requesting_frame) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DVLOG(1) << __FUNCTION__ << " " << resource_message_filter_process_id_ << ":" << render_view_id << ":" << bridge_id; geolocation_permission_context_->CancelGeolocationPermissionRequest( resource_message_filter_process_id_, render_view_id, bridge_id, requesting_frame); } void GeolocationDispatcherHostOldImpl::OnStartUpdating( int render_view_id, int bridge_id, const GURL& requesting_frame, bool enable_high_accuracy) { // WebKit sends the startupdating request before checking permissions, to // optimize the no-location-available case and reduce latency in the success // case (location lookup happens in parallel with the permission request). DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DVLOG(1) << __FUNCTION__ << " " << resource_message_filter_process_id_ << ":" << render_view_id << ":" << bridge_id; bridge_update_options_[std::make_pair(render_view_id, bridge_id)] = GeolocationObserverOptions(enable_high_accuracy); geolocation_permission_context_->StartUpdatingRequested( resource_message_filter_process_id_, render_view_id, bridge_id, requesting_frame); RefreshGeolocationObserverOptions(); } void GeolocationDispatcherHostOldImpl::OnStopUpdating(int render_view_id, int bridge_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DVLOG(1) << __FUNCTION__ << " " << resource_message_filter_process_id_ << ":" << render_view_id << ":" << bridge_id; if (bridge_update_options_.erase(std::make_pair(render_view_id, bridge_id))) RefreshGeolocationObserverOptions(); geolocation_permission_context_->StopUpdatingRequested( resource_message_filter_process_id_, render_view_id, bridge_id); } void GeolocationDispatcherHostOldImpl::OnSuspend(int render_view_id, int bridge_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DVLOG(1) << __FUNCTION__ << " " << resource_message_filter_process_id_ << ":" << render_view_id << ":" << bridge_id; // TODO(bulach): connect this with GeolocationArbitrator. } void GeolocationDispatcherHostOldImpl::OnResume(int render_view_id, int bridge_id) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); DVLOG(1) << __FUNCTION__ << " " << resource_message_filter_process_id_ << ":" << render_view_id << ":" << bridge_id; // TODO(bulach): connect this with GeolocationArbitrator. } void GeolocationDispatcherHostOldImpl::RefreshGeolocationObserverOptions() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); if (bridge_update_options_.empty()) { if (location_provider_) { location_provider_->RemoveObserver(this); location_provider_ = NULL; } } else { if (!location_provider_) location_provider_ = GeolocationProvider::GetInstance(); // Re-add to re-establish our options, in case they changed. location_provider_->AddObserver( this, GeolocationObserverOptions::Collapse(bridge_update_options_)); } } } // namespace GeolocationDispatcherHostOld* GeolocationDispatcherHostOld::New( int resource_message_filter_process_id, GeolocationPermissionContext* geolocation_permission_context) { return new GeolocationDispatcherHostOldImpl( resource_message_filter_process_id, geolocation_permission_context); }