1 // Copyright 2013 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/device_motion_provider.h" 6 7 #include "base/bind.h" 8 #include "base/logging.h" 9 #include "base/threading/thread.h" 10 #include "base/timer/timer.h" 11 #include "content/browser/device_orientation/data_fetcher_shared_memory.h" 12 #include "content/common/device_motion_hardware_buffer.h" 13 14 namespace content { 15 16 namespace { 17 const int kPeriodInMilliseconds = 100; 18 } 19 20 class DeviceMotionProvider::PollingThread : public base::Thread { 21 public: 22 explicit PollingThread(const char* name); 23 virtual ~PollingThread(); 24 25 void StartPolling(DataFetcherSharedMemory* fetcher, 26 DeviceMotionHardwareBuffer* buffer); 27 void StopPolling(); 28 29 private: 30 void DoPoll(); 31 32 scoped_ptr<base::RepeatingTimer<PollingThread> > timer_; 33 DataFetcherSharedMemory* fetcher_; 34 35 DISALLOW_COPY_AND_ASSIGN(PollingThread); 36 }; 37 38 // ---- PollingThread methods 39 40 DeviceMotionProvider::PollingThread::PollingThread(const char* name) 41 : base::Thread(name) { 42 } 43 44 DeviceMotionProvider::PollingThread::~PollingThread() { 45 } 46 47 void DeviceMotionProvider::PollingThread::StartPolling( 48 DataFetcherSharedMemory* fetcher, DeviceMotionHardwareBuffer* buffer) { 49 DCHECK(base::MessageLoop::current() == message_loop()); 50 DCHECK(!timer_); 51 52 fetcher_ = fetcher; 53 fetcher_->StartFetchingDeviceMotionData(buffer); 54 timer_.reset(new base::RepeatingTimer<PollingThread>()); 55 timer_->Start(FROM_HERE, 56 base::TimeDelta::FromMilliseconds(kPeriodInMilliseconds), 57 this, &PollingThread::DoPoll); 58 } 59 60 void DeviceMotionProvider::PollingThread::StopPolling() { 61 DCHECK(base::MessageLoop::current() == message_loop()); 62 DCHECK(fetcher_); 63 // this will also stop the timer before killing it. 64 timer_.reset(); 65 fetcher_->StopFetchingDeviceMotionData(); 66 } 67 68 void DeviceMotionProvider::PollingThread::DoPoll() { 69 DCHECK(base::MessageLoop::current() == message_loop()); 70 fetcher_->FetchDeviceMotionDataIntoBuffer(); 71 } 72 73 // ---- end PollingThread methods 74 75 DeviceMotionProvider::DeviceMotionProvider() 76 : is_started_(false) { 77 Initialize(); 78 } 79 80 DeviceMotionProvider::DeviceMotionProvider( 81 scoped_ptr<DataFetcherSharedMemory> fetcher) 82 : is_started_(false) { 83 data_fetcher_ = fetcher.Pass(); 84 Initialize(); 85 } 86 87 DeviceMotionProvider::~DeviceMotionProvider() { 88 StopFetchingDeviceMotionData(); 89 // make sure polling thread stops before data_fetcher_ gets deleted. 90 if (polling_thread_) 91 polling_thread_->Stop(); 92 data_fetcher_.reset(); 93 } 94 95 void DeviceMotionProvider::Initialize() { 96 size_t data_size = sizeof(DeviceMotionHardwareBuffer); 97 bool res = device_motion_shared_memory_.CreateAndMapAnonymous(data_size); 98 // TODO(timvolodine): consider not crashing the browser if the check fails. 99 CHECK(res); 100 DeviceMotionHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer(); 101 memset(hwbuf, 0, sizeof(DeviceMotionHardwareBuffer)); 102 } 103 104 base::SharedMemoryHandle DeviceMotionProvider::GetSharedMemoryHandleForProcess( 105 base::ProcessHandle process) { 106 base::SharedMemoryHandle renderer_handle; 107 device_motion_shared_memory_.ShareToProcess(process, &renderer_handle); 108 return renderer_handle; 109 } 110 111 void DeviceMotionProvider::StartFetchingDeviceMotionData() { 112 if (is_started_) 113 return; 114 115 if (!data_fetcher_) 116 data_fetcher_.reset(new DataFetcherSharedMemory); 117 118 if (data_fetcher_->NeedsPolling()) { 119 if (!polling_thread_) 120 CreateAndStartPollingThread(); 121 122 polling_thread_->message_loop()->PostTask( 123 FROM_HERE, 124 base::Bind(&PollingThread::StartPolling, 125 base::Unretained(polling_thread_.get()), 126 data_fetcher_.get(), 127 SharedMemoryAsHardwareBuffer())); 128 } else { 129 data_fetcher_->StartFetchingDeviceMotionData( 130 SharedMemoryAsHardwareBuffer()); 131 } 132 133 is_started_ = true; 134 } 135 136 void DeviceMotionProvider::CreateAndStartPollingThread() { 137 polling_thread_.reset( 138 new PollingThread("Device Motion poller")); 139 140 if (!polling_thread_->Start()) { 141 LOG(ERROR) << "Failed to start Device Motion data polling thread"; 142 return; 143 } 144 } 145 146 void DeviceMotionProvider::StopFetchingDeviceMotionData() { 147 if (!is_started_) 148 return; 149 150 DCHECK(data_fetcher_); 151 152 if (data_fetcher_->NeedsPolling()) { 153 DCHECK(polling_thread_); 154 polling_thread_->message_loop()->PostTask( 155 FROM_HERE, 156 base::Bind(&PollingThread::StopPolling, 157 base::Unretained(polling_thread_.get()))); 158 } else { 159 data_fetcher_->StopFetchingDeviceMotionData(); 160 } 161 162 is_started_ = false; 163 } 164 165 DeviceMotionHardwareBuffer* 166 DeviceMotionProvider::SharedMemoryAsHardwareBuffer() { 167 void* mem = device_motion_shared_memory_.memory(); 168 CHECK(mem); 169 return static_cast<DeviceMotionHardwareBuffer*>(mem); 170 } 171 172 } // namespace content 173