Save errno for logging before potentially overwriting it.
[chromium-blink-merge.git] / content / browser / device_orientation / provider_impl.cc
blob25e9bfd968769567b7a1d51b61e30e41634c15a9
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.
5 #include "content/browser/device_orientation/provider_impl.h"
7 #include <set>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "base/message_loop.h"
13 #include "base/threading/thread.h"
14 #include "base/threading/worker_pool.h"
16 namespace {
18 void DeleteThread(base::Thread* thread) {
19 delete thread;
24 namespace content {
26 class ProviderImpl::PollingThread : public base::Thread {
27 public:
28 PollingThread(const char* name,
29 base::WeakPtr<ProviderImpl> provider,
30 base::MessageLoop* creator_loop);
31 virtual ~PollingThread();
33 // Method for creating a DataFetcher and starting the polling, if the fetcher
34 // can provide this type of data.
35 void Initialize(DataFetcherFactory factory, DeviceData::Type type);
37 // Method for adding a type of data to poll for.
38 void DoAddPollingDataType(DeviceData::Type type);
40 private:
41 // Method for polling a DataFetcher.
42 void DoPoll();
43 void ScheduleDoPoll();
45 // Schedule a notification to the |provider_| which lives on a different
46 // thread (|creator_loop_| is its message loop).
47 void ScheduleDoNotify(const scoped_refptr<const DeviceData>& device_data,
48 DeviceData::Type device_data_type);
50 enum { kDesiredSamplingIntervalMs = 100 };
51 base::TimeDelta SamplingInterval() const;
53 // The Message Loop on which this object was created.
54 // Typically the I/O loop, but may be something else during testing.
55 base::MessageLoop* creator_loop_;
57 scoped_ptr<DataFetcher> data_fetcher_;
58 std::map<DeviceData::Type, scoped_refptr<const DeviceData> >
59 last_device_data_map_;
60 std::set<DeviceData::Type> polling_data_types_;
62 base::WeakPtr<ProviderImpl> provider_;
65 ProviderImpl::PollingThread::PollingThread(const char* name,
66 base::WeakPtr<ProviderImpl> provider,
67 base::MessageLoop* creator_loop)
68 : base::Thread(name), creator_loop_(creator_loop), provider_(provider) {}
70 ProviderImpl::PollingThread::~PollingThread() {
71 Stop();
74 void ProviderImpl::PollingThread::DoAddPollingDataType(DeviceData::Type type) {
75 DCHECK(base::MessageLoop::current() == message_loop());
77 polling_data_types_.insert(type);
80 void ProviderImpl::PollingThread::Initialize(DataFetcherFactory factory,
81 DeviceData::Type type) {
82 DCHECK(base::MessageLoop::current() == message_loop());
84 if (factory != NULL) {
85 // Try to use factory to create a fetcher that can provide this type of
86 // data. If factory creates a fetcher that provides this type of data,
87 // start polling.
88 scoped_ptr<DataFetcher> fetcher(factory());
90 if (fetcher) {
91 scoped_refptr<const DeviceData> device_data(fetcher->GetDeviceData(type));
92 if (device_data.get() != NULL) {
93 // Pass ownership of fetcher to provider_.
94 data_fetcher_.swap(fetcher);
95 last_device_data_map_[type] = device_data;
97 // Notify observers.
98 ScheduleDoNotify(device_data, type);
100 // Start polling.
101 ScheduleDoPoll();
102 return;
107 // When no device data can be provided.
108 ScheduleDoNotify(NULL, type);
111 void ProviderImpl::PollingThread::ScheduleDoNotify(
112 const scoped_refptr<const DeviceData>& device_data,
113 DeviceData::Type device_data_type) {
114 DCHECK(base::MessageLoop::current() == message_loop());
116 creator_loop_->PostTask(FROM_HERE,
117 base::Bind(&ProviderImpl::DoNotify, provider_,
118 device_data, device_data_type));
121 void ProviderImpl::PollingThread::DoPoll() {
122 DCHECK(base::MessageLoop::current() == message_loop());
124 // Poll the fetcher for each type of data.
125 typedef std::set<DeviceData::Type>::const_iterator SetIterator;
126 for (SetIterator i = polling_data_types_.begin();
127 i != polling_data_types_.end(); ++i) {
128 DeviceData::Type device_data_type = *i;
129 scoped_refptr<const DeviceData> device_data(data_fetcher_->GetDeviceData(
130 device_data_type));
132 if (device_data.get() == NULL) {
133 LOG(ERROR) << "Failed to poll device data fetcher.";
134 ScheduleDoNotify(NULL, device_data_type);
135 continue;
138 const DeviceData* old_data = last_device_data_map_[device_data_type].get();
139 if (old_data != NULL && !device_data->ShouldFireEvent(old_data))
140 continue;
142 // Update the last device data of this type and notify observers.
143 last_device_data_map_[device_data_type] = device_data;
144 ScheduleDoNotify(device_data, device_data_type);
147 ScheduleDoPoll();
150 void ProviderImpl::PollingThread::ScheduleDoPoll() {
151 DCHECK(base::MessageLoop::current() == message_loop());
153 message_loop()->PostDelayedTask(
154 FROM_HERE,
155 base::Bind(&PollingThread::DoPoll, base::Unretained(this)),
156 SamplingInterval());
159 base::TimeDelta ProviderImpl::PollingThread::SamplingInterval() const {
160 DCHECK(base::MessageLoop::current() == message_loop());
161 DCHECK(data_fetcher_.get());
163 // TODO(erg): There used to be unused code here, that called a default
164 // implementation on the DataFetcherInterface that was never defined. I'm
165 // removing unused methods from headers.
166 return base::TimeDelta::FromMilliseconds(kDesiredSamplingIntervalMs);
169 ProviderImpl::ProviderImpl(DataFetcherFactory factory)
170 : creator_loop_(base::MessageLoop::current()),
171 factory_(factory),
172 weak_factory_(this),
173 polling_thread_(NULL) {
176 ProviderImpl::~ProviderImpl() {
177 Stop();
180 void ProviderImpl::ScheduleDoAddPollingDataType(DeviceData::Type type) {
181 DCHECK(base::MessageLoop::current() == creator_loop_);
183 base::MessageLoop* polling_loop = polling_thread_->message_loop();
184 polling_loop->PostTask(FROM_HERE,
185 base::Bind(&PollingThread::DoAddPollingDataType,
186 base::Unretained(polling_thread_),
187 type));
190 void ProviderImpl::AddObserver(Observer* observer) {
191 DCHECK(base::MessageLoop::current() == creator_loop_);
193 DeviceData::Type type = observer->device_data_type();
195 observers_.insert(observer);
196 if (observers_.size() == 1)
197 Start(type);
198 else {
199 // Notify observer of most recent notification if one exists.
200 const DeviceData* last_notification = last_notifications_map_[type].get();
201 if (last_notification != NULL)
202 observer->OnDeviceDataUpdate(last_notification, type);
205 ScheduleDoAddPollingDataType(type);
208 void ProviderImpl::RemoveObserver(Observer* observer) {
209 DCHECK(base::MessageLoop::current() == creator_loop_);
211 observers_.erase(observer);
212 if (observers_.empty())
213 Stop();
216 void ProviderImpl::Start(DeviceData::Type type) {
217 DCHECK(base::MessageLoop::current() == creator_loop_);
218 DCHECK(!polling_thread_);
220 polling_thread_ = new PollingThread("Device data polling thread",
221 weak_factory_.GetWeakPtr(),
222 creator_loop_);
223 #if defined(OS_WIN)
224 polling_thread_->init_com_with_mta(true);
225 #endif
226 if (!polling_thread_->Start()) {
227 LOG(ERROR) << "Failed to start device data polling thread";
228 delete polling_thread_;
229 polling_thread_ = NULL;
230 return;
232 ScheduleInitializePollingThread(type);
235 void ProviderImpl::Stop() {
236 DCHECK(base::MessageLoop::current() == creator_loop_);
238 weak_factory_.InvalidateWeakPtrs();
239 if (polling_thread_) {
240 polling_thread_->StopSoon();
241 bool posted = base::WorkerPool::PostTask(
242 FROM_HERE,
243 base::Bind(&DeleteThread, base::Unretained(polling_thread_)),
244 true /* task is slow */);
245 DCHECK(posted);
246 polling_thread_ = NULL;
250 void ProviderImpl::ScheduleInitializePollingThread(
251 DeviceData::Type device_data_type) {
252 DCHECK(base::MessageLoop::current() == creator_loop_);
254 base::MessageLoop* polling_loop = polling_thread_->message_loop();
255 polling_loop->PostTask(FROM_HERE,
256 base::Bind(&PollingThread::Initialize,
257 base::Unretained(polling_thread_),
258 factory_,
259 device_data_type));
262 void ProviderImpl::DoNotify(const scoped_refptr<const DeviceData>& data,
263 DeviceData::Type device_data_type) {
264 DCHECK(base::MessageLoop::current() == creator_loop_);
266 // Update last notification of this type.
267 last_notifications_map_[device_data_type] = data;
269 // Notify observers of this type of the new data.
270 typedef std::set<Observer*>::const_iterator ConstIterator;
271 for (ConstIterator i = observers_.begin(); i != observers_.end(); ++i) {
272 if ((*i)->device_data_type() == device_data_type)
273 (*i)->OnDeviceDataUpdate(data.get(), device_data_type);
276 if (data.get() == NULL) {
277 // Notify observers exactly once about failure to provide data.
278 typedef std::set<Observer*>::iterator Iterator;
279 Iterator i = observers_.begin();
280 while (i != observers_.end()) {
281 Iterator current = i++;
282 if ((*current)->device_data_type() == device_data_type)
283 observers_.erase(current);
286 if (observers_.empty())
287 Stop();
292 } // namespace content