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