1// Copyright 2014 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_sensors/data_fetcher_shared_memory_base.h" 6 7#include "base/bind.h" 8#include "base/logging.h" 9#include "base/stl_util.h" 10#include "base/threading/thread.h" 11#include "base/timer/timer.h" 12#include "content/common/device_sensors/device_light_hardware_buffer.h" 13#include "content/common/device_sensors/device_motion_hardware_buffer.h" 14#include "content/common/device_sensors/device_orientation_hardware_buffer.h" 15 16namespace content { 17 18namespace { 19 20static size_t GetConsumerSharedMemoryBufferSize(ConsumerType consumer_type) { 21 switch (consumer_type) { 22 case CONSUMER_TYPE_MOTION: 23 return sizeof(DeviceMotionHardwareBuffer); 24 case CONSUMER_TYPE_ORIENTATION: 25 return sizeof(DeviceOrientationHardwareBuffer); 26 case CONSUMER_TYPE_LIGHT: 27 return sizeof(DeviceLightHardwareBuffer); 28 default: 29 NOTREACHED(); 30 } 31 return 0; 32} 33 34} // namespace 35 36class DataFetcherSharedMemoryBase::PollingThread : public base::Thread { 37 public: 38 PollingThread(const char* name, DataFetcherSharedMemoryBase* fetcher); 39 virtual ~PollingThread(); 40 41 void AddConsumer(ConsumerType consumer_type, void* buffer); 42 void RemoveConsumer(ConsumerType consumer_type); 43 44 unsigned GetConsumersBitmask() const { return consumers_bitmask_; } 45 bool IsTimerRunning() const { return timer_ ? timer_->IsRunning() : false; } 46 47 private: 48 void DoPoll(); 49 50 unsigned consumers_bitmask_; 51 DataFetcherSharedMemoryBase* fetcher_; 52 scoped_ptr<base::RepeatingTimer<PollingThread> > timer_; 53 54 DISALLOW_COPY_AND_ASSIGN(PollingThread); 55}; 56 57// --- PollingThread methods 58 59DataFetcherSharedMemoryBase::PollingThread::PollingThread( 60 const char* name, DataFetcherSharedMemoryBase* fetcher) 61 : base::Thread(name), 62 consumers_bitmask_(0), 63 fetcher_(fetcher) { 64} 65 66DataFetcherSharedMemoryBase::PollingThread::~PollingThread() { 67} 68 69void DataFetcherSharedMemoryBase::PollingThread::AddConsumer( 70 ConsumerType consumer_type, void* buffer) { 71 DCHECK(fetcher_); 72 if (!fetcher_->Start(consumer_type, buffer)) 73 return; 74 75 consumers_bitmask_ |= consumer_type; 76 77 if (!timer_ && fetcher_->GetType() == FETCHER_TYPE_POLLING_CALLBACK) { 78 timer_.reset(new base::RepeatingTimer<PollingThread>()); 79 timer_->Start(FROM_HERE, 80 fetcher_->GetInterval(), 81 this, &PollingThread::DoPoll); 82 } 83} 84 85void DataFetcherSharedMemoryBase::PollingThread::RemoveConsumer( 86 ConsumerType consumer_type) { 87 DCHECK(fetcher_); 88 if (!fetcher_->Stop(consumer_type)) 89 return; 90 91 consumers_bitmask_ ^= consumer_type; 92 93 if (!consumers_bitmask_) 94 timer_.reset(); // will also stop the timer. 95} 96 97void DataFetcherSharedMemoryBase::PollingThread::DoPoll() { 98 DCHECK(fetcher_); 99 DCHECK(consumers_bitmask_); 100 fetcher_->Fetch(consumers_bitmask_); 101} 102 103// --- end of PollingThread methods 104 105DataFetcherSharedMemoryBase::DataFetcherSharedMemoryBase() 106 : started_consumers_(0) { 107} 108 109DataFetcherSharedMemoryBase::~DataFetcherSharedMemoryBase() { 110 DCHECK_EQ(0u, started_consumers_); 111 112 // make sure polling thread stops asap. 113 if (polling_thread_) 114 polling_thread_->Stop(); 115 116 STLDeleteContainerPairSecondPointers(shared_memory_map_.begin(), 117 shared_memory_map_.end()); 118} 119 120bool DataFetcherSharedMemoryBase::StartFetchingDeviceData( 121 ConsumerType consumer_type) { 122 if (started_consumers_ & consumer_type) 123 return true; 124 125 void* buffer = GetSharedMemoryBuffer(consumer_type); 126 if (!buffer) 127 return false; 128 129 if (GetType() != FETCHER_TYPE_DEFAULT) { 130 if (!InitAndStartPollingThreadIfNecessary()) 131 return false; 132 polling_thread_->message_loop()->PostTask( 133 FROM_HERE, 134 base::Bind(&PollingThread::AddConsumer, 135 base::Unretained(polling_thread_.get()), 136 consumer_type, buffer)); 137 } else { 138 if (!Start(consumer_type, buffer)) 139 return false; 140 } 141 142 started_consumers_ |= consumer_type; 143 144 return true; 145} 146 147bool DataFetcherSharedMemoryBase::StopFetchingDeviceData( 148 ConsumerType consumer_type) { 149 if (!(started_consumers_ & consumer_type)) 150 return true; 151 152 if (GetType() != FETCHER_TYPE_DEFAULT) { 153 polling_thread_->message_loop()->PostTask( 154 FROM_HERE, 155 base::Bind(&PollingThread::RemoveConsumer, 156 base::Unretained(polling_thread_.get()), 157 consumer_type)); 158 } else { 159 if (!Stop(consumer_type)) 160 return false; 161 } 162 163 started_consumers_ ^= consumer_type; 164 165 return true; 166} 167 168void DataFetcherSharedMemoryBase::StopFetchingAllDeviceData() { 169 StopFetchingDeviceData(CONSUMER_TYPE_MOTION); 170 StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION); 171 StopFetchingDeviceData(CONSUMER_TYPE_LIGHT); 172} 173 174base::SharedMemoryHandle 175DataFetcherSharedMemoryBase::GetSharedMemoryHandleForProcess( 176 ConsumerType consumer_type, base::ProcessHandle process) { 177 SharedMemoryMap::const_iterator it = shared_memory_map_.find(consumer_type); 178 if (it == shared_memory_map_.end()) 179 return base::SharedMemory::NULLHandle(); 180 181 base::SharedMemoryHandle renderer_handle; 182 it->second->ShareToProcess(process, &renderer_handle); 183 return renderer_handle; 184} 185 186bool DataFetcherSharedMemoryBase::InitAndStartPollingThreadIfNecessary() { 187 if (polling_thread_) 188 return true; 189 190 polling_thread_.reset( 191 new PollingThread("Inertial Device Sensor poller", this)); 192 193 if (!polling_thread_->Start()) { 194 LOG(ERROR) << "Failed to start inertial sensor data polling thread"; 195 return false; 196 } 197 return true; 198} 199 200void DataFetcherSharedMemoryBase::Fetch(unsigned consumer_bitmask) { 201 NOTIMPLEMENTED(); 202} 203 204DataFetcherSharedMemoryBase::FetcherType 205DataFetcherSharedMemoryBase::GetType() const { 206 return FETCHER_TYPE_DEFAULT; 207} 208 209base::TimeDelta DataFetcherSharedMemoryBase::GetInterval() const { 210 return base::TimeDelta::FromMilliseconds(kInertialSensorIntervalMillis); 211} 212 213base::SharedMemory* DataFetcherSharedMemoryBase::GetSharedMemory( 214 ConsumerType consumer_type) { 215 SharedMemoryMap::const_iterator it = shared_memory_map_.find(consumer_type); 216 if (it != shared_memory_map_.end()) 217 return it->second; 218 219 size_t buffer_size = GetConsumerSharedMemoryBufferSize(consumer_type); 220 if (buffer_size == 0) 221 return NULL; 222 223 scoped_ptr<base::SharedMemory> new_shared_mem(new base::SharedMemory); 224 if (new_shared_mem->CreateAndMapAnonymous(buffer_size)) { 225 if (void* mem = new_shared_mem->memory()) { 226 memset(mem, 0, buffer_size); 227 base::SharedMemory* shared_mem = new_shared_mem.release(); 228 shared_memory_map_[consumer_type] = shared_mem; 229 return shared_mem; 230 } 231 } 232 LOG(ERROR) << "Failed to initialize shared memory"; 233 return NULL; 234} 235 236void* DataFetcherSharedMemoryBase::GetSharedMemoryBuffer( 237 ConsumerType consumer_type) { 238 if (base::SharedMemory* shared_memory = GetSharedMemory(consumer_type)) 239 return shared_memory->memory(); 240 return NULL; 241} 242 243base::MessageLoop* DataFetcherSharedMemoryBase::GetPollingMessageLoop() const { 244 return polling_thread_ ? polling_thread_->message_loop() : NULL; 245} 246 247bool DataFetcherSharedMemoryBase::IsPollingTimerRunningForTesting() const { 248 return polling_thread_ ? polling_thread_->IsTimerRunning() : false; 249} 250 251} // namespace content 252