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

Side by Side Diff: content/browser/geolocation/geolocation_provider_impl.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_provider_impl.h" 5 #include "content/browser/geolocation/geolocation_provider_impl.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/callback.h" 9 #include "base/callback.h"
10 #include "base/location.h" 10 #include "base/location.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/memory/singleton.h" 12 #include "base/memory/singleton.h"
13 #include "base/message_loop/message_loop.h" 13 #include "base/message_loop/message_loop.h"
14 #include "content/browser/geolocation/location_arbitrator_impl.h" 14 #include "content/browser/geolocation/location_arbitrator_impl.h"
15 #include "content/public/browser/browser_thread.h" 15 #include "content/public/browser/browser_thread.h"
16 16
17 namespace content { 17 namespace content {
18 18
19 namespace {
20 void OverrideLocationForTestingOnIOThread(
21 const Geoposition& position,
22 const base::Closure& completion_callback,
23 scoped_refptr<base::MessageLoopProxy> callback_loop) {
24 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
25 GeolocationProviderImpl::GetInstance()->OverrideLocationForTesting(position);
26 callback_loop->PostTask(FROM_HERE, completion_callback);
27 }
28 } // namespace
29
30 GeolocationProvider* GeolocationProvider::GetInstance() { 19 GeolocationProvider* GeolocationProvider::GetInstance() {
31 return GeolocationProviderImpl::GetInstance(); 20 return GeolocationProviderImpl::GetInstance();
32 } 21 }
33 22
34 void GeolocationProvider::OverrideLocationForTesting( 23 scoped_ptr<GeolocationProvider::Subscription>
35 const Geoposition& position, 24 GeolocationProviderImpl::AddLocationUpdateCallback(
36 const base::Closure& completion_callback) {
37 base::Closure closure = base::Bind(&OverrideLocationForTestingOnIOThread,
38 position,
39 completion_callback,
40 base::MessageLoopProxy::current());
41 if (!BrowserThread::CurrentlyOn(BrowserThread::IO))
42 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, closure);
43 else
44 closure.Run();
45 }
46
47 void GeolocationProviderImpl::AddLocationUpdateCallback(
48 const LocationUpdateCallback& callback, bool use_high_accuracy) { 25 const LocationUpdateCallback& callback, bool use_high_accuracy) {
49 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 26 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
50 bool found = false; 27 scoped_ptr<GeolocationProvider::Subscription> rv;
Michael van Ouwerkerk 2014/05/08 13:20:02 Nit: s/rv/subscription/
jam 2014/05/08 15:04:58 Done.
51 CallbackList::iterator i = callbacks_.begin(); 28 if (use_high_accuracy) {
52 for (; i != callbacks_.end(); ++i) { 29 rv = high_accuracy_callbacks_.Add(callback);
53 if (i->first.Equals(callback)) { 30 } else {
54 i->second = use_high_accuracy; 31 rv = low_accuracy_callbacks_.Add(callback);
55 found = true;
56 break;
57 }
58 } 32 }
59 if (!found)
60 callbacks_.push_back(std::make_pair(callback, use_high_accuracy));
61 33
62 OnClientsChanged(); 34 OnClientsChanged();
63 if (position_.Validate() || 35 if (position_.Validate() ||
64 position_.error_code != Geoposition::ERROR_CODE_NONE) { 36 position_.error_code != Geoposition::ERROR_CODE_NONE) {
65 callback.Run(position_); 37 callback.Run(position_);
66 } 38 }
67 }
68 39
69 bool GeolocationProviderImpl::RemoveLocationUpdateCallback( 40 return rv.Pass();
70 const LocationUpdateCallback& callback) {
71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
72 bool removed = false;
73 CallbackList::iterator i = callbacks_.begin();
74 for (; i != callbacks_.end(); ++i) {
75 if (i->first.Equals(callback)) {
76 callbacks_.erase(i);
77 removed = true;
78 break;
79 }
80 }
81 if (removed)
82 OnClientsChanged();
83 return removed;
84 } 41 }
85 42
86 void GeolocationProviderImpl::UserDidOptIntoLocationServices() { 43 void GeolocationProviderImpl::UserDidOptIntoLocationServices() {
87 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 44 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
88 bool was_permission_granted = user_did_opt_into_location_services_; 45 bool was_permission_granted = user_did_opt_into_location_services_;
89 user_did_opt_into_location_services_ = true; 46 user_did_opt_into_location_services_ = true;
90 if (IsRunning() && !was_permission_granted) 47 if (IsRunning() && !was_permission_granted)
91 InformProvidersPermissionGranted(); 48 InformProvidersPermissionGranted();
92 } 49 }
93 50
94 bool GeolocationProviderImpl::LocationServicesOptedIn() const { 51 void GeolocationProviderImpl::OverrideLocationForTesting(
95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 52 const Geoposition& position) {
96 return user_did_opt_into_location_services_; 53 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
54 position_ = position;
55 ignore_location_updates_ = true;
56 NotifyClients(position);
97 } 57 }
98 58
99 void GeolocationProviderImpl::OnLocationUpdate(const Geoposition& position) { 59 void GeolocationProviderImpl::OnLocationUpdate(const Geoposition& position) {
100 DCHECK(OnGeolocationThread()); 60 DCHECK(OnGeolocationThread());
101 // Will be true only in testing. 61 // Will be true only in testing.
102 if (ignore_location_updates_) 62 if (ignore_location_updates_)
103 return; 63 return;
104 BrowserThread::PostTask(BrowserThread::IO, 64 BrowserThread::PostTask(BrowserThread::UI,
105 FROM_HERE, 65 FROM_HERE,
106 base::Bind(&GeolocationProviderImpl::NotifyClients, 66 base::Bind(&GeolocationProviderImpl::NotifyClients,
107 base::Unretained(this), position)); 67 base::Unretained(this), position));
108 } 68 }
109 69
110 void GeolocationProviderImpl::OverrideLocationForTesting(
111 const Geoposition& position) {
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
113 position_ = position;
114 ignore_location_updates_ = true;
115 NotifyClients(position);
116 }
117
118 GeolocationProviderImpl* GeolocationProviderImpl::GetInstance() { 70 GeolocationProviderImpl* GeolocationProviderImpl::GetInstance() {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 71 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
120 return Singleton<GeolocationProviderImpl>::get(); 72 return Singleton<GeolocationProviderImpl>::get();
121 } 73 }
122 74
123 GeolocationProviderImpl::GeolocationProviderImpl() 75 GeolocationProviderImpl::GeolocationProviderImpl()
124 : base::Thread("Geolocation"), 76 : base::Thread("Geolocation"),
125 user_did_opt_into_location_services_(false), 77 user_did_opt_into_location_services_(false),
126 ignore_location_updates_(false), 78 ignore_location_updates_(false),
127 arbitrator_(NULL) { 79 arbitrator_(NULL) {
128 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
81 high_accuracy_callbacks_.set_removal_callback(
82 base::Bind(&GeolocationProviderImpl::OnClientsChanged,
83 base::Unretained(this)));
84 low_accuracy_callbacks_.set_removal_callback(
85 base::Bind(&GeolocationProviderImpl::OnClientsChanged,
86 base::Unretained(this)));
129 } 87 }
130 88
131 GeolocationProviderImpl::~GeolocationProviderImpl() { 89 GeolocationProviderImpl::~GeolocationProviderImpl() {
132 // All callbacks should have unregistered before this singleton is destructed.
133 DCHECK(callbacks_.empty());
134 Stop(); 90 Stop();
135 DCHECK(!arbitrator_); 91 DCHECK(!arbitrator_);
136 } 92 }
137 93
138 bool GeolocationProviderImpl::OnGeolocationThread() const { 94 bool GeolocationProviderImpl::OnGeolocationThread() const {
139 return base::MessageLoop::current() == message_loop(); 95 return base::MessageLoop::current() == message_loop();
140 } 96 }
141 97
142 void GeolocationProviderImpl::OnClientsChanged() { 98 void GeolocationProviderImpl::OnClientsChanged() {
143 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 99 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
144 base::Closure task; 100 base::Closure task;
145 if (callbacks_.empty()) { 101 if (high_accuracy_callbacks_.empty() && low_accuracy_callbacks_.empty()) {
146 DCHECK(IsRunning()); 102 DCHECK(IsRunning());
147 // We have no more observers, so we clear the cached geoposition so that 103 // We have no more observers, so we clear the cached geoposition so that
148 // when the next observer is added we will not provide a stale position. 104 // when the next observer is added we will not provide a stale position.
149 position_ = Geoposition(); 105 position_ = Geoposition();
150 task = base::Bind(&GeolocationProviderImpl::StopProviders, 106 task = base::Bind(&GeolocationProviderImpl::StopProviders,
151 base::Unretained(this)); 107 base::Unretained(this));
152 } else { 108 } else {
153 if (!IsRunning()) { 109 if (!IsRunning()) {
154 Start(); 110 Start();
155 if (LocationServicesOptedIn()) 111 if (user_did_opt_into_location_services_)
156 InformProvidersPermissionGranted(); 112 InformProvidersPermissionGranted();
157 } 113 }
158 // Determine a set of options that satisfies all clients. 114 // Determine a set of options that satisfies all clients.
159 bool use_high_accuracy = false; 115 bool use_high_accuracy = !high_accuracy_callbacks_.empty();
160 CallbackList::iterator i = callbacks_.begin();
161 for (; i != callbacks_.end(); ++i) {
162 if (i->second) {
163 use_high_accuracy = true;
164 break;
165 }
166 }
167 116
168 // Send the current options to the providers as they may have changed. 117 // Send the current options to the providers as they may have changed.
169 task = base::Bind(&GeolocationProviderImpl::StartProviders, 118 task = base::Bind(&GeolocationProviderImpl::StartProviders,
170 base::Unretained(this), 119 base::Unretained(this),
171 use_high_accuracy); 120 use_high_accuracy);
172 } 121 }
173 122
174 message_loop()->PostTask(FROM_HERE, task); 123 message_loop()->PostTask(FROM_HERE, task);
175 } 124 }
176 125
(...skipping 17 matching lines...) Expand all
194 base::Bind(&GeolocationProviderImpl::InformProvidersPermissionGranted, 143 base::Bind(&GeolocationProviderImpl::InformProvidersPermissionGranted,
195 base::Unretained(this))); 144 base::Unretained(this)));
196 return; 145 return;
197 } 146 }
198 DCHECK(OnGeolocationThread()); 147 DCHECK(OnGeolocationThread());
199 DCHECK(arbitrator_); 148 DCHECK(arbitrator_);
200 arbitrator_->OnPermissionGranted(); 149 arbitrator_->OnPermissionGranted();
201 } 150 }
202 151
203 void GeolocationProviderImpl::NotifyClients(const Geoposition& position) { 152 void GeolocationProviderImpl::NotifyClients(const Geoposition& position) {
204 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 153 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
205 DCHECK(position.Validate() || 154 DCHECK(position.Validate() ||
206 position.error_code != Geoposition::ERROR_CODE_NONE); 155 position.error_code != Geoposition::ERROR_CODE_NONE);
207 position_ = position; 156 position_ = position;
208 CallbackList::const_iterator it = callbacks_.begin(); 157 high_accuracy_callbacks_.Notify(position_);
209 while (it != callbacks_.end()) { 158 low_accuracy_callbacks_.Notify(position_);
210 // Advance iterator before calling the observer to guard against synchronous
211 // unregister.
212 LocationUpdateCallback callback = it->first;
213 ++it;
214 callback.Run(position_);
215 }
216 } 159 }
217 160
218 void GeolocationProviderImpl::Init() { 161 void GeolocationProviderImpl::Init() {
219 DCHECK(OnGeolocationThread()); 162 DCHECK(OnGeolocationThread());
220 DCHECK(!arbitrator_); 163 DCHECK(!arbitrator_);
221 arbitrator_ = CreateArbitrator(); 164 arbitrator_ = CreateArbitrator();
222 } 165 }
223 166
224 void GeolocationProviderImpl::CleanUp() { 167 void GeolocationProviderImpl::CleanUp() {
225 DCHECK(OnGeolocationThread()); 168 DCHECK(OnGeolocationThread());
226 delete arbitrator_; 169 delete arbitrator_;
227 arbitrator_ = NULL; 170 arbitrator_ = NULL;
228 } 171 }
229 172
230 LocationArbitrator* GeolocationProviderImpl::CreateArbitrator() { 173 LocationArbitrator* GeolocationProviderImpl::CreateArbitrator() {
231 LocationArbitratorImpl::LocationUpdateCallback callback = base::Bind( 174 LocationArbitratorImpl::LocationUpdateCallback callback = base::Bind(
232 &GeolocationProviderImpl::OnLocationUpdate, base::Unretained(this)); 175 &GeolocationProviderImpl::OnLocationUpdate, base::Unretained(this));
233 return new LocationArbitratorImpl(callback); 176 return new LocationArbitratorImpl(callback);
234 } 177 }
235 178
236 } // namespace content 179 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698