Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: content/browser/geolocation/geolocation_dispatcher_host.cc

Issue 273523007: Dispatch geolocation IPCs on the UI thread. Aside from simplifying the code to avoid a lot of threa… (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: fix android Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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 "content/browser/geolocation/geolocation_dispatcher_host.h" 5 #include "content/browser/geolocation/geolocation_dispatcher_host.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
11 #include "content/browser/renderer_host/render_message_filter.h" 11 #include "content/browser/renderer_host/render_message_filter.h"
12 #include "content/browser/renderer_host/render_process_host_impl.h" 12 #include "content/browser/renderer_host/render_process_host_impl.h"
13 #include "content/browser/renderer_host/render_view_host_impl.h" 13 #include "content/browser/renderer_host/render_view_host_impl.h"
14 #include "content/browser/web_contents/web_contents_impl.h"
15 #include "content/public/browser/browser_context.h"
14 #include "content/public/browser/geolocation_permission_context.h" 16 #include "content/public/browser/geolocation_permission_context.h"
15 #include "content/public/common/geoposition.h" 17 #include "content/public/common/geoposition.h"
16 #include "content/common/geolocation_messages.h" 18 #include "content/common/geolocation_messages.h"
17 19
18 namespace content { 20 namespace content {
19 namespace { 21 namespace {
20 22
21 // Geoposition error codes for reporting in UMA. 23 // Geoposition error codes for reporting in UMA.
22 enum GeopositionErrorCode { 24 enum GeopositionErrorCode {
23 // NOTE: Do not renumber these as that would confuse interpretation of 25 // NOTE: Do not renumber these as that would confuse interpretation of
(...skipping 30 matching lines...) Expand all
54 break; 56 break;
55 case Geoposition::ERROR_CODE_TIMEOUT: 57 case Geoposition::ERROR_CODE_TIMEOUT:
56 code = GEOPOSITION_ERROR_CODE_TIMEOUT; 58 code = GEOPOSITION_ERROR_CODE_TIMEOUT;
57 break; 59 break;
58 } 60 }
59 UMA_HISTOGRAM_ENUMERATION("Geolocation.LocationUpdate.ErrorCode", 61 UMA_HISTOGRAM_ENUMERATION("Geolocation.LocationUpdate.ErrorCode",
60 code, 62 code,
61 GEOPOSITION_ERROR_CODE_COUNT); 63 GEOPOSITION_ERROR_CODE_COUNT);
62 } 64 }
63 65
64 void NotifyGeolocationProviderPermissionGranted() {
65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
66 GeolocationProviderImpl::GetInstance()->UserDidOptIntoLocationServices();
67 }
68
69 void SendGeolocationPermissionResponse(int render_process_id, 66 void SendGeolocationPermissionResponse(int render_process_id,
70 int render_view_id, 67 int render_view_id,
71 int bridge_id, 68 int bridge_id,
72 bool allowed) { 69 bool allowed) {
73 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
74 RenderViewHostImpl* render_view_host = 70 RenderViewHostImpl* render_view_host =
75 RenderViewHostImpl::FromID(render_process_id, render_view_id); 71 RenderViewHostImpl::FromID(render_process_id, render_view_id);
76 if (!render_view_host) 72 if (!render_view_host)
77 return; 73 return;
78 render_view_host->Send( 74 render_view_host->Send(
79 new GeolocationMsg_PermissionSet(render_view_id, bridge_id, allowed)); 75 new GeolocationMsg_PermissionSet(render_view_id, bridge_id, allowed));
80 76
81 if (allowed) { 77 if (allowed)
82 BrowserThread::PostTask( 78 GeolocationProviderImpl::GetInstance()->UserDidOptIntoLocationServices();
83 BrowserThread::IO, FROM_HERE,
84 base::Bind(&NotifyGeolocationProviderPermissionGranted));
85 }
86 } 79 }
87 80
88 } // namespace 81 } // namespace
89 82
90 GeolocationDispatcherHost::GeolocationDispatcherHost( 83 GeolocationDispatcherHost::GeolocationDispatcherHost(
91 int render_process_id, 84 WebContents* web_contents)
92 GeolocationPermissionContext* geolocation_permission_context) 85 : WebContentsObserver(web_contents),
93 : BrowserMessageFilter(GeolocationMsgStart), 86 watching_requested_(false),
94 render_process_id_(render_process_id), 87 paused_(false),
95 geolocation_permission_context_(geolocation_permission_context), 88 high_accuracy_(false) {
96 geolocation_provider_(NULL) { 89 // This is initialized by WebContentsImpl. Do not add any non-trivial
97 callback_ = base::Bind(
98 &GeolocationDispatcherHost::OnLocationUpdate, base::Unretained(this));
99 // This is initialized by ResourceMessageFilter. Do not add any non-trivial
100 // initialization here, defer to OnRegisterBridge which is triggered whenever 90 // initialization here, defer to OnRegisterBridge which is triggered whenever
101 // a javascript geolocation object is actually initialized. 91 // a javascript geolocation object is actually initialized.
102 } 92 }
103 93
104 GeolocationDispatcherHost::~GeolocationDispatcherHost() { 94 GeolocationDispatcherHost::~GeolocationDispatcherHost() {
105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
106 if (geolocation_provider_)
107 geolocation_provider_->RemoveLocationUpdateCallback(callback_);
108 } 95 }
109 96
110 bool GeolocationDispatcherHost::OnMessageReceived( 97 void GeolocationDispatcherHost::RenderViewHostChanged(
111 const IPC::Message& msg, bool* msg_was_ok) { 98 RenderViewHost* old_host,
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 99 RenderViewHost* new_host) {
113 *msg_was_ok = true; 100 watching_requested_ = false;
101 paused_ = false;
102 geolocation_subscription_.reset();
103 }
104
105 bool GeolocationDispatcherHost::OnMessageReceived(const IPC::Message& msg) {
114 bool handled = true; 106 bool handled = true;
115 IPC_BEGIN_MESSAGE_MAP_EX(GeolocationDispatcherHost, msg, *msg_was_ok) 107 IPC_BEGIN_MESSAGE_MAP(GeolocationDispatcherHost, msg)
116 IPC_MESSAGE_HANDLER(GeolocationHostMsg_CancelPermissionRequest, 108 IPC_MESSAGE_HANDLER(GeolocationHostMsg_CancelPermissionRequest,
117 OnCancelPermissionRequest) 109 OnCancelPermissionRequest)
118 IPC_MESSAGE_HANDLER(GeolocationHostMsg_RequestPermission, 110 IPC_MESSAGE_HANDLER(GeolocationHostMsg_RequestPermission,
119 OnRequestPermission) 111 OnRequestPermission)
120 IPC_MESSAGE_HANDLER(GeolocationHostMsg_StartUpdating, OnStartUpdating) 112 IPC_MESSAGE_HANDLER(GeolocationHostMsg_StartUpdating, OnStartUpdating)
121 IPC_MESSAGE_HANDLER(GeolocationHostMsg_StopUpdating, OnStopUpdating) 113 IPC_MESSAGE_HANDLER(GeolocationHostMsg_StopUpdating, OnStopUpdating)
122 IPC_MESSAGE_UNHANDLED(handled = false) 114 IPC_MESSAGE_UNHANDLED(handled = false)
123 IPC_END_MESSAGE_MAP() 115 IPC_END_MESSAGE_MAP()
124 return handled; 116 return handled;
125 } 117 }
126 118
119 void GeolocationDispatcherHost::OnRequestPermission(
120 int bridge_id,
121 const GURL& requesting_frame,
122 bool user_gesture) {
123 GeolocationPermissionContext* context =
124 web_contents()->GetBrowserContext()->GetGeolocationPermissionContext();
125 int render_process_id = web_contents()->GetRenderProcessHost()->GetID();
126 int render_view_id = web_contents()->GetRenderViewHost()->GetRoutingID();
127 if (context) {
128 context->RequestGeolocationPermission(
129 web_contents(),
130 bridge_id,
131 requesting_frame,
132 user_gesture,
133 base::Bind(&SendGeolocationPermissionResponse,
134 render_process_id,
135 render_view_id,
136 bridge_id));
137 } else {
138 SendGeolocationPermissionResponse(
139 render_process_id, render_view_id, bridge_id, true);
140 }
141 }
142
143 void GeolocationDispatcherHost::OnCancelPermissionRequest(
144 int bridge_id,
145 const GURL& requesting_frame) {
146 GeolocationPermissionContext* context =
147 web_contents()->GetBrowserContext()->GetGeolocationPermissionContext();
148 if (context) {
149 context->CancelGeolocationPermissionRequest(
150 web_contents(), bridge_id, requesting_frame);
151 }
152 }
153
154 void GeolocationDispatcherHost::OnStartUpdating(
155 const GURL& requesting_frame,
156 bool enable_high_accuracy) {
157 // StartUpdating() can be invoked as a result of high-accuracy mode
158 // being enabled / disabled. No need to record the dispatcher again.
159 UMA_HISTOGRAM_BOOLEAN(
160 "Geolocation.GeolocationDispatcherHostImpl.EnableHighAccuracy",
161 enable_high_accuracy);
162
163 watching_requested_ = true;
164 high_accuracy_ = enable_high_accuracy;
165 RefreshGeolocationOptions();
166 }
167
168 void GeolocationDispatcherHost::OnStopUpdating() {
169 watching_requested_ = false;
170 RefreshGeolocationOptions();
171 }
172
173 void GeolocationDispatcherHost::PauseOrResume(bool should_pause) {
174 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
175 paused_ = should_pause;
176 RefreshGeolocationOptions();
177 }
178
179 void GeolocationDispatcherHost::RefreshGeolocationOptions() {
180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
181
182 if (watching_requested_ & !paused_) {
183 geolocation_subscription_ = GeolocationProvider::GetInstance()->
184 AddLocationUpdateCallback(
185 base::Bind(&GeolocationDispatcherHost::OnLocationUpdate,
186 base::Unretained(this)),
187 high_accuracy_);
188 } else {
189 geolocation_subscription_.reset();
190 }
191 }
192
127 void GeolocationDispatcherHost::OnLocationUpdate( 193 void GeolocationDispatcherHost::OnLocationUpdate(
Michael van Ouwerkerk 2014/05/08 13:20:02 nit: if this method remains before OnRequestPermis
jam 2014/05/08 15:04:58 Done.
128 const Geoposition& geoposition) { 194 const Geoposition& geoposition) {
129 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
196
130 RecordGeopositionErrorCode(geoposition.error_code); 197 RecordGeopositionErrorCode(geoposition.error_code);
131 for (std::map<int, RendererGeolocationOptions>::iterator it = 198 if (!paused_)
132 geolocation_renderers_.begin(); 199 Send(new GeolocationMsg_PositionUpdated(routing_id(), geoposition));
133 it != geolocation_renderers_.end(); ++it) {
134 if (!(it->second.is_paused))
135 Send(new GeolocationMsg_PositionUpdated(it->first, geoposition));
136 }
137 }
138
139 void GeolocationDispatcherHost::OnRequestPermission(
140 int render_view_id,
141 int bridge_id,
142 const GURL& requesting_frame,
143 bool user_gesture) {
144 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
145 DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":"
146 << render_view_id << ":" << bridge_id;
147 if (geolocation_permission_context_.get()) {
148 geolocation_permission_context_->RequestGeolocationPermission(
149 render_process_id_,
150 render_view_id,
151 bridge_id,
152 requesting_frame,
153 user_gesture,
154 base::Bind(&SendGeolocationPermissionResponse,
155 render_process_id_,
156 render_view_id,
157 bridge_id));
158 } else {
159 BrowserThread::PostTask(
160 BrowserThread::UI, FROM_HERE,
161 base::Bind(&SendGeolocationPermissionResponse, render_process_id_,
162 render_view_id, bridge_id, true));
163 }
164 }
165
166 void GeolocationDispatcherHost::OnCancelPermissionRequest(
167 int render_view_id,
168 int bridge_id,
169 const GURL& requesting_frame) {
170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
171 DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":"
172 << render_view_id << ":" << bridge_id;
173 if (geolocation_permission_context_.get()) {
174 geolocation_permission_context_->CancelGeolocationPermissionRequest(
175 render_process_id_, render_view_id, bridge_id, requesting_frame);
176 }
177 }
178
179 void GeolocationDispatcherHost::OnStartUpdating(
180 int render_view_id,
181 const GURL& requesting_frame,
182 bool enable_high_accuracy) {
183 // StartUpdating() can be invoked as a result of high-accuracy mode
184 // being enabled / disabled. No need to record the dispatcher again.
185 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
186 DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":"
187 << render_view_id;
188 UMA_HISTOGRAM_BOOLEAN(
189 "Geolocation.GeolocationDispatcherHostImpl.EnableHighAccuracy",
190 enable_high_accuracy);
191
192 std::map<int, RendererGeolocationOptions>::iterator it =
193 geolocation_renderers_.find(render_view_id);
194 if (it == geolocation_renderers_.end()) {
195 bool should_start_paused = false;
196 if (pending_paused_geolocation_renderers_.erase(render_view_id) == 1) {
197 should_start_paused = true;
198 }
199 RendererGeolocationOptions opts = {
200 enable_high_accuracy,
201 should_start_paused
202 };
203 geolocation_renderers_[render_view_id] = opts;
204 } else {
205 it->second.high_accuracy = enable_high_accuracy;
206 }
207 RefreshGeolocationOptions();
208 }
209
210 void GeolocationDispatcherHost::OnStopUpdating(int render_view_id) {
211 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
212 DVLOG(1) << __FUNCTION__ << " " << render_process_id_ << ":"
213 << render_view_id;
214 DCHECK_EQ(1U, geolocation_renderers_.count(render_view_id));
215 geolocation_renderers_.erase(render_view_id);
216 RefreshGeolocationOptions();
217 }
218
219 void GeolocationDispatcherHost::PauseOrResume(int render_view_id,
220 bool should_pause) {
221 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
222 std::map<int, RendererGeolocationOptions>::iterator it =
223 geolocation_renderers_.find(render_view_id);
224 if (it == geolocation_renderers_.end()) {
225 // This renderer is not using geolocation yet, but if it does before
226 // we get a call to resume, we should start it up in the paused state.
227 if (should_pause) {
228 pending_paused_geolocation_renderers_.insert(render_view_id);
229 } else {
230 pending_paused_geolocation_renderers_.erase(render_view_id);
231 }
232 } else {
233 RendererGeolocationOptions* opts = &(it->second);
234 if (opts->is_paused != should_pause)
235 opts->is_paused = should_pause;
236 RefreshGeolocationOptions();
237 }
238 }
239
240 void GeolocationDispatcherHost::RefreshGeolocationOptions() {
241 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
242
243 bool needs_updates = false;
244 bool use_high_accuracy = false;
245 std::map<int, RendererGeolocationOptions>::const_iterator i =
246 geolocation_renderers_.begin();
247 for (; i != geolocation_renderers_.end(); ++i) {
248 needs_updates |= !(i->second.is_paused);
249 use_high_accuracy |= i->second.high_accuracy;
250 if (needs_updates && use_high_accuracy)
251 break;
252 }
253 if (needs_updates) {
254 if (!geolocation_provider_)
255 geolocation_provider_ = GeolocationProviderImpl::GetInstance();
256 // Re-add to re-establish our options, in case they changed.
257 geolocation_provider_->AddLocationUpdateCallback(
258 callback_, use_high_accuracy);
259 } else {
260 if (geolocation_provider_)
261 geolocation_provider_->RemoveLocationUpdateCallback(callback_);
262 geolocation_provider_ = NULL;
263 }
264 } 200 }
265 201
266 } // namespace content 202 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698