Home | History | Annotate | Download | only in geolocation
      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 
     20 namespace content {
     21 namespace {
     22 
     23 void NotifyArbitratorPermissionGranted() {
     24   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     25   GeolocationProviderImpl::GetInstance()->UserDidOptIntoLocationServices();
     26 }
     27 
     28 void 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 
     46 class 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 
     95 GeolocationDispatcherHostImpl::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 
    108 GeolocationDispatcherHostImpl::~GeolocationDispatcherHostImpl() {
    109   if (location_provider_)
    110     location_provider_->RemoveLocationUpdateCallback(callback_);
    111 }
    112 
    113 bool 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 
    130 void 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 
    139 void 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_.get()) {
    147     geolocation_permission_context_->RequestGeolocationPermission(
    148         render_process_id_,
    149         render_view_id,
    150         bridge_id,
    151         requesting_frame,
    152         base::Bind(&SendGeolocationPermissionResponse,
    153                    render_process_id_,
    154                    render_view_id,
    155                    bridge_id));
    156   } else {
    157     BrowserThread::PostTask(
    158         BrowserThread::UI, FROM_HERE,
    159         base::Bind(&SendGeolocationPermissionResponse, render_process_id_,
    160                    render_view_id, bridge_id, true));
    161   }
    162 }
    163 
    164 void GeolocationDispatcherHostImpl::OnCancelPermissionRequest(
    165     int render_view_id,
    166     int bridge_id,
    167     const GURL& requesting_frame) {
    168   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    169   DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":"
    170            << render_view_id << ":" << bridge_id;
    171   if (geolocation_permission_context_.get()) {
    172     geolocation_permission_context_->CancelGeolocationPermissionRequest(
    173         render_process_id_, render_view_id, bridge_id, requesting_frame);
    174   }
    175 }
    176 
    177 void GeolocationDispatcherHostImpl::OnStartUpdating(
    178     int render_view_id,
    179     const GURL& requesting_frame,
    180     bool enable_high_accuracy) {
    181   // StartUpdating() can be invoked as a result of high-accuracy mode
    182   // being enabled / disabled. No need to record the dispatcher again.
    183   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    184   DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":"
    185            << render_view_id;
    186   if (!geolocation_renderer_ids_.count(render_view_id))
    187     geolocation_renderer_ids_.insert(render_view_id);
    188 
    189   renderer_high_accuracy_[render_view_id] = enable_high_accuracy;
    190   RefreshHighAccuracy();
    191 }
    192 
    193 void GeolocationDispatcherHostImpl::OnStopUpdating(int render_view_id) {
    194   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    195   DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":"
    196            << render_view_id;
    197   if (renderer_high_accuracy_.erase(render_view_id))
    198     RefreshHighAccuracy();
    199 
    200   DCHECK_EQ(1U, geolocation_renderer_ids_.count(render_view_id));
    201   geolocation_renderer_ids_.erase(render_view_id);
    202 }
    203 
    204 void GeolocationDispatcherHostImpl::RefreshHighAccuracy() {
    205   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    206   if (renderer_high_accuracy_.empty()) {
    207     if (location_provider_) {
    208       location_provider_->RemoveLocationUpdateCallback(callback_);
    209       location_provider_ = NULL;
    210     }
    211   } else {
    212     if (!location_provider_)
    213       location_provider_ = GeolocationProviderImpl::GetInstance();
    214     // Re-add to re-establish our options, in case they changed.
    215     bool use_high_accuracy = false;
    216     std::map<int, bool>::iterator i = renderer_high_accuracy_.begin();
    217     for (; i != renderer_high_accuracy_.end(); ++i) {
    218       if (i->second) {
    219         use_high_accuracy = true;
    220         break;
    221       }
    222     }
    223     location_provider_->AddLocationUpdateCallback(callback_, use_high_accuracy);
    224   }
    225 }
    226 }  // namespace
    227 
    228 
    229 // GeolocationDispatcherHost --------------------------------------------------
    230 
    231 // static
    232 GeolocationDispatcherHost* GeolocationDispatcherHost::New(
    233     int render_process_id,
    234     GeolocationPermissionContext* geolocation_permission_context) {
    235   return new GeolocationDispatcherHostImpl(
    236       render_process_id,
    237       geolocation_permission_context);
    238 }
    239 
    240 GeolocationDispatcherHost::GeolocationDispatcherHost() {
    241 }
    242 
    243 GeolocationDispatcherHost::~GeolocationDispatcherHost() {
    244 }
    245 
    246 }  // namespace content
    247