geolocation_dispatcher_host.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
1// Copyright (c) 2012 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#include "content/browser/geolocation/geolocation_dispatcher_host.h" 6 7#include <map> 8#include <set> 9#include <utility> 10 11#include "base/bind.h" 12#include "content/browser/geolocation/geolocation_provider_impl.h" 13#include "content/browser/renderer_host/render_message_filter.h" 14#include "content/browser/renderer_host/render_process_host_impl.h" 15#include "content/browser/renderer_host/render_view_host_impl.h" 16#include "content/public/browser/geolocation_permission_context.h" 17#include "content/public/common/geoposition.h" 18#include "content/common/geolocation_messages.h" 19 20namespace content { 21namespace { 22 23void NotifyArbitratorPermissionGranted() { 24 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 25 GeolocationProviderImpl::GetInstance()->UserDidOptIntoLocationServices(); 26} 27 28void SendGeolocationPermissionResponse(int render_process_id, 29 int render_view_id, 30 int bridge_id, 31 bool allowed) { 32 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 33 RenderViewHostImpl* r = 34 RenderViewHostImpl::FromID(render_process_id, render_view_id); 35 if (!r) 36 return; 37 r->Send(new GeolocationMsg_PermissionSet(render_view_id, bridge_id, allowed)); 38 39 if (allowed) { 40 BrowserThread::PostTask( 41 BrowserThread::IO, FROM_HERE, 42 base::Bind(&NotifyArbitratorPermissionGranted)); 43 } 44} 45 46class GeolocationDispatcherHostImpl : public GeolocationDispatcherHost { 47 public: 48 GeolocationDispatcherHostImpl( 49 int render_process_id, 50 GeolocationPermissionContext* geolocation_permission_context); 51 52 // GeolocationDispatcherHost 53 virtual bool OnMessageReceived(const IPC::Message& msg, 54 bool* msg_was_ok) OVERRIDE; 55 56 private: 57 virtual ~GeolocationDispatcherHostImpl(); 58 59 void OnRequestPermission(int render_view_id, 60 int bridge_id, 61 const GURL& requesting_frame); 62 void OnCancelPermissionRequest(int render_view_id, 63 int bridge_id, 64 const GURL& requesting_frame); 65 void OnStartUpdating(int render_view_id, 66 const GURL& requesting_frame, 67 bool enable_high_accuracy); 68 void OnStopUpdating(int render_view_id); 69 70 // Updates the |location_arbitrator_| with the currently required update 71 // options, based on |renderer_high_accuracy_|. 72 void RefreshHighAccuracy(); 73 74 void OnLocationUpdate(const Geoposition& position); 75 76 int render_process_id_; 77 scoped_refptr<GeolocationPermissionContext> geolocation_permission_context_; 78 79 // Iterated when sending location updates to renderer processes. The fan out 80 // to individual bridge IDs happens renderer side, in order to minimize 81 // context switches. 82 // Only used on the IO thread. 83 std::set<int> geolocation_renderer_ids_; 84 // Maps renderer_id to whether high accuracy is requestd for this particular 85 // bridge. 86 std::map<int, bool> renderer_high_accuracy_; 87 // Only set whilst we are registered with the arbitrator. 88 GeolocationProviderImpl* location_provider_; 89 90 GeolocationProviderImpl::LocationUpdateCallback callback_; 91 92 DISALLOW_COPY_AND_ASSIGN(GeolocationDispatcherHostImpl); 93}; 94 95GeolocationDispatcherHostImpl::GeolocationDispatcherHostImpl( 96 int render_process_id, 97 GeolocationPermissionContext* geolocation_permission_context) 98 : render_process_id_(render_process_id), 99 geolocation_permission_context_(geolocation_permission_context), 100 location_provider_(NULL) { 101 callback_ = base::Bind( 102 &GeolocationDispatcherHostImpl::OnLocationUpdate, base::Unretained(this)); 103 // This is initialized by ResourceMessageFilter. Do not add any non-trivial 104 // initialization here, defer to OnRegisterBridge which is triggered whenever 105 // a javascript geolocation object is actually initialized. 106} 107 108GeolocationDispatcherHostImpl::~GeolocationDispatcherHostImpl() { 109 if (location_provider_) 110 location_provider_->RemoveLocationUpdateCallback(callback_); 111} 112 113bool GeolocationDispatcherHostImpl::OnMessageReceived( 114 const IPC::Message& msg, bool* msg_was_ok) { 115 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 116 *msg_was_ok = true; 117 bool handled = true; 118 IPC_BEGIN_MESSAGE_MAP_EX(GeolocationDispatcherHostImpl, msg, *msg_was_ok) 119 IPC_MESSAGE_HANDLER(GeolocationHostMsg_CancelPermissionRequest, 120 OnCancelPermissionRequest) 121 IPC_MESSAGE_HANDLER(GeolocationHostMsg_RequestPermission, 122 OnRequestPermission) 123 IPC_MESSAGE_HANDLER(GeolocationHostMsg_StartUpdating, OnStartUpdating) 124 IPC_MESSAGE_HANDLER(GeolocationHostMsg_StopUpdating, OnStopUpdating) 125 IPC_MESSAGE_UNHANDLED(handled = false) 126 IPC_END_MESSAGE_MAP() 127 return handled; 128} 129 130void GeolocationDispatcherHostImpl::OnLocationUpdate( 131 const Geoposition& geoposition) { 132 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 133 for (std::set<int>::iterator it = geolocation_renderer_ids_.begin(); 134 it != geolocation_renderer_ids_.end(); ++it) { 135 Send(new GeolocationMsg_PositionUpdated(*it, geoposition)); 136 } 137} 138 139void GeolocationDispatcherHostImpl::OnRequestPermission( 140 int render_view_id, 141 int bridge_id, 142 const GURL& requesting_frame) { 143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 144 DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":" 145 << render_view_id << ":" << bridge_id; 146 if (geolocation_permission_context_) { 147 geolocation_permission_context_->RequestGeolocationPermission( 148 render_process_id_, render_view_id, bridge_id, requesting_frame, 149 base::Bind(&SendGeolocationPermissionResponse, render_process_id_, 150 render_view_id, bridge_id)); 151 } else { 152 BrowserThread::PostTask( 153 BrowserThread::UI, FROM_HERE, 154 base::Bind(&SendGeolocationPermissionResponse, render_process_id_, 155 render_view_id, bridge_id, true)); 156 } 157} 158 159void GeolocationDispatcherHostImpl::OnCancelPermissionRequest( 160 int render_view_id, 161 int bridge_id, 162 const GURL& requesting_frame) { 163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 164 DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":" 165 << render_view_id << ":" << bridge_id; 166 if (geolocation_permission_context_) { 167 geolocation_permission_context_->CancelGeolocationPermissionRequest( 168 render_process_id_, render_view_id, bridge_id, requesting_frame); 169 } 170} 171 172void GeolocationDispatcherHostImpl::OnStartUpdating( 173 int render_view_id, 174 const GURL& requesting_frame, 175 bool enable_high_accuracy) { 176 // StartUpdating() can be invoked as a result of high-accuracy mode 177 // being enabled / disabled. No need to record the dispatcher again. 178 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 179 DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":" 180 << render_view_id; 181 if (!geolocation_renderer_ids_.count(render_view_id)) 182 geolocation_renderer_ids_.insert(render_view_id); 183 184 renderer_high_accuracy_[render_view_id] = enable_high_accuracy; 185 RefreshHighAccuracy(); 186} 187 188void GeolocationDispatcherHostImpl::OnStopUpdating(int render_view_id) { 189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 190 DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":" 191 << render_view_id; 192 if (renderer_high_accuracy_.erase(render_view_id)) 193 RefreshHighAccuracy(); 194 195 DCHECK_EQ(1U, geolocation_renderer_ids_.count(render_view_id)); 196 geolocation_renderer_ids_.erase(render_view_id); 197} 198 199void GeolocationDispatcherHostImpl::RefreshHighAccuracy() { 200 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 201 if (renderer_high_accuracy_.empty()) { 202 if (location_provider_) { 203 location_provider_->RemoveLocationUpdateCallback(callback_); 204 location_provider_ = NULL; 205 } 206 } else { 207 if (!location_provider_) 208 location_provider_ = GeolocationProviderImpl::GetInstance(); 209 // Re-add to re-establish our options, in case they changed. 210 bool use_high_accuracy = false; 211 std::map<int, bool>::iterator i = renderer_high_accuracy_.begin(); 212 for (; i != renderer_high_accuracy_.end(); ++i) { 213 if (i->second) { 214 use_high_accuracy = true; 215 break; 216 } 217 } 218 location_provider_->AddLocationUpdateCallback(callback_, use_high_accuracy); 219 } 220} 221} // namespace 222 223 224// GeolocationDispatcherHost -------------------------------------------------- 225 226// static 227GeolocationDispatcherHost* GeolocationDispatcherHost::New( 228 int render_process_id, 229 GeolocationPermissionContext* geolocation_permission_context) { 230 return new GeolocationDispatcherHostImpl( 231 render_process_id, 232 geolocation_permission_context); 233} 234 235GeolocationDispatcherHost::GeolocationDispatcherHost() { 236} 237 238GeolocationDispatcherHost::~GeolocationDispatcherHost() { 239} 240 241} // namespace content 242