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/device_orientation/provider_impl.h" 6 7 #include <set> 8 #include <vector> 9 10 #include "base/bind.h" 11 #include "base/logging.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/threading/thread.h" 14 #include "base/threading/worker_pool.h" 15 16 namespace { 17 18 void DeleteThread(base::Thread* thread) { 19 delete thread; 20 } 21 22 } 23 24 namespace content { 25 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(); 32 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); 36 37 // Method for adding a type of data to poll for. 38 void DoAddPollingDataType(DeviceData::Type type); 39 40 private: 41 // Method for polling a DataFetcher. 42 void DoPoll(); 43 void ScheduleDoPoll(); 44 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); 49 50 enum { kDesiredSamplingIntervalMs = 100 }; 51 base::TimeDelta SamplingInterval() const; 52 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_; 56 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_; 61 62 base::WeakPtr<ProviderImpl> provider_; 63 }; 64 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) {} 69 70 ProviderImpl::PollingThread::~PollingThread() { 71 Stop(); 72 } 73 74 void ProviderImpl::PollingThread::DoAddPollingDataType(DeviceData::Type type) { 75 DCHECK(base::MessageLoop::current() == message_loop()); 76 77 polling_data_types_.insert(type); 78 } 79 80 void ProviderImpl::PollingThread::Initialize(DataFetcherFactory factory, 81 DeviceData::Type type) { 82 DCHECK(base::MessageLoop::current() == message_loop()); 83 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()); 89 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; 96 97 // Notify observers. 98 ScheduleDoNotify(device_data, type); 99 100 // Start polling. 101 ScheduleDoPoll(); 102 return; 103 } 104 } 105 } 106 107 // When no device data can be provided. 108 ScheduleDoNotify(NULL, type); 109 } 110 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()); 115 116 creator_loop_->PostTask(FROM_HERE, 117 base::Bind(&ProviderImpl::DoNotify, provider_, 118 device_data, device_data_type)); 119 } 120 121 void ProviderImpl::PollingThread::DoPoll() { 122 DCHECK(base::MessageLoop::current() == message_loop()); 123 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)); 131 132 if (device_data.get() == NULL) { 133 LOG(ERROR) << "Failed to poll device data fetcher."; 134 ScheduleDoNotify(NULL, device_data_type); 135 continue; 136 } 137 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; 141 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); 145 } 146 147 ScheduleDoPoll(); 148 } 149 150 void ProviderImpl::PollingThread::ScheduleDoPoll() { 151 DCHECK(base::MessageLoop::current() == message_loop()); 152 153 message_loop()->PostDelayedTask( 154 FROM_HERE, 155 base::Bind(&PollingThread::DoPoll, base::Unretained(this)), 156 SamplingInterval()); 157 } 158 159 base::TimeDelta ProviderImpl::PollingThread::SamplingInterval() const { 160 DCHECK(base::MessageLoop::current() == message_loop()); 161 DCHECK(data_fetcher_.get()); 162 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); 167 } 168 169 ProviderImpl::ProviderImpl(DataFetcherFactory factory) 170 : creator_loop_(base::MessageLoop::current()), 171 factory_(factory), 172 weak_factory_(this), 173 polling_thread_(NULL) { 174 } 175 176 ProviderImpl::~ProviderImpl() { 177 Stop(); 178 } 179 180 void ProviderImpl::ScheduleDoAddPollingDataType(DeviceData::Type type) { 181 DCHECK(base::MessageLoop::current() == creator_loop_); 182 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)); 188 } 189 190 void ProviderImpl::AddObserver(Observer* observer) { 191 DCHECK(base::MessageLoop::current() == creator_loop_); 192 193 DeviceData::Type type = observer->device_data_type(); 194 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); 203 } 204 205 ScheduleDoAddPollingDataType(type); 206 } 207 208 void ProviderImpl::RemoveObserver(Observer* observer) { 209 DCHECK(base::MessageLoop::current() == creator_loop_); 210 211 observers_.erase(observer); 212 if (observers_.empty()) 213 Stop(); 214 } 215 216 void ProviderImpl::Start(DeviceData::Type type) { 217 DCHECK(base::MessageLoop::current() == creator_loop_); 218 DCHECK(!polling_thread_); 219 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; 231 } 232 ScheduleInitializePollingThread(type); 233 } 234 235 void ProviderImpl::Stop() { 236 DCHECK(base::MessageLoop::current() == creator_loop_); 237 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; 247 } 248 } 249 250 void ProviderImpl::ScheduleInitializePollingThread( 251 DeviceData::Type device_data_type) { 252 DCHECK(base::MessageLoop::current() == creator_loop_); 253 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)); 260 } 261 262 void ProviderImpl::DoNotify(const scoped_refptr<const DeviceData>& data, 263 DeviceData::Type device_data_type) { 264 DCHECK(base::MessageLoop::current() == creator_loop_); 265 266 // Update last notification of this type. 267 last_notifications_map_[device_data_type] = data; 268 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); 274 } 275 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); 284 } 285 286 if (observers_.empty()) 287 Stop(); 288 } 289 } 290 291 292 } // namespace content 293