OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef CONTENT_RENDERER_DEVICE_SENSORS_DEVICE_SENSOR_EVENT_PUMP_H_ | 5 #ifndef CONTENT_RENDERER_DEVICE_SENSORS_DEVICE_SENSOR_EVENT_PUMP_H_ |
6 #define CONTENT_RENDERER_DEVICE_SENSORS_DEVICE_SENSOR_EVENT_PUMP_H_ | 6 #define CONTENT_RENDERER_DEVICE_SENSORS_DEVICE_SENSOR_EVENT_PUMP_H_ |
7 | 7 |
| 8 #include <memory> |
| 9 #include <utility> |
| 10 #include <vector> |
| 11 |
8 #include "base/bind.h" | 12 #include "base/bind.h" |
9 #include "base/bind_helpers.h" | 13 #include "base/bind_helpers.h" |
10 #include "base/macros.h" | 14 #include "base/macros.h" |
11 #include "base/memory/shared_memory.h" | |
12 #include "base/time/time.h" | 15 #include "base/time/time.h" |
13 #include "base/timer/timer.h" | 16 #include "base/timer/timer.h" |
14 #include "content/public/common/service_names.mojom.h" | 17 #include "content/public/common/service_names.mojom.h" |
15 #include "content/public/renderer/platform_event_observer.h" | 18 #include "content/public/renderer/platform_event_observer.h" |
16 #include "content/renderer/render_thread_impl.h" | 19 #include "content/renderer/render_thread_impl.h" |
| 20 #include "device/generic_sensor/public/cpp/sensor_reading.h" |
| 21 #include "device/generic_sensor/public/interfaces/sensor.mojom.h" |
| 22 #include "device/generic_sensor/public/interfaces/sensor_provider.mojom.h" |
| 23 #include "mojo/public/cpp/bindings/binding.h" |
17 #include "mojo/public/cpp/system/platform_handle.h" | 24 #include "mojo/public/cpp/system/platform_handle.h" |
18 #include "services/device/public/interfaces/constants.mojom.h" | 25 #include "services/device/public/interfaces/constants.mojom.h" |
19 #include "services/service_manager/public/cpp/connector.h" | 26 #include "services/service_manager/public/cpp/connector.h" |
20 | 27 |
21 namespace content { | 28 namespace content { |
22 | 29 |
23 template <typename Base, typename MojoInterface> | 30 template <typename ListenerType> |
24 class CONTENT_EXPORT DeviceSensorMojoClientMixin : public Base { | 31 class CONTENT_EXPORT DeviceSensorEventPump |
| 32 : NON_EXPORTED_BASE(public PlatformEventObserver<ListenerType>) { |
25 public: | 33 public: |
26 template <typename... Args> | 34 // PlatformEventObserver: |
27 explicit DeviceSensorMojoClientMixin(Args&&... args) | 35 void Start(blink::WebPlatformEventListener* listener) override { |
28 : Base(std::forward<Args>(args)...) { | 36 DVLOG(2) << "requested start"; |
29 auto request = mojo::MakeRequest(&mojo_interface_); | 37 |
| 38 if (state_ != PumpState::STOPPED) |
| 39 return; |
| 40 |
| 41 DCHECK(!timer_.IsRunning()); |
| 42 |
| 43 PlatformEventObserver<ListenerType>::Start(listener); |
| 44 state_ = PumpState::PENDING_START; |
| 45 } |
| 46 |
| 47 // PlatformEventObserver: |
| 48 void Stop() override { |
| 49 DVLOG(2) << "requested stop"; |
| 50 |
| 51 if (state_ == PumpState::STOPPED) |
| 52 return; |
| 53 |
| 54 DCHECK((state_ == PumpState::PENDING_START && !timer_.IsRunning()) || |
| 55 (state_ == PumpState::RUNNING && timer_.IsRunning())); |
| 56 |
| 57 if (timer_.IsRunning()) |
| 58 timer_.Stop(); |
| 59 |
| 60 PlatformEventObserver<ListenerType>::Stop(); |
| 61 state_ = PumpState::STOPPED; |
| 62 } |
| 63 |
| 64 // PlatformEventObserver: |
| 65 void SendStopMessage() override { |
| 66 sensors_.clear(); |
| 67 num_sensors_tried_ = 0; |
| 68 num_available_sensors_ = 0; |
| 69 } |
| 70 |
| 71 protected: |
| 72 explicit DeviceSensorEventPump(RenderThread* thread) |
| 73 : PlatformEventObserver<ListenerType>(thread), |
| 74 pump_delay_microseconds_(kDefaultPumpDelayMicroseconds), |
| 75 num_sensors_tried_(0), |
| 76 num_available_sensors_(0), |
| 77 state_(PumpState::STOPPED) { |
| 78 auto request = mojo::MakeRequest(&sensor_provider_); |
30 | 79 |
31 // When running layout tests, those observers should not listen to the | 80 // When running layout tests, those observers should not listen to the |
32 // actual hardware changes. In order to make that happen, don't connect | 81 // actual hardware changes. In order to make that happen, don't connect |
33 // the other end of the mojo pipe to anything. | 82 // the other end of the mojo pipe to anything. |
34 // | |
35 // TODO(sammc): Remove this when JS layout test support for shared buffers | |
36 // is ready and the layout tests are converted to use that for mocking. | |
37 if (RenderThreadImpl::current() && | 83 if (RenderThreadImpl::current() && |
38 !RenderThreadImpl::current()->layout_test_mode()) { | 84 !RenderThreadImpl::current()->layout_test_mode()) { |
39 RenderThread::Get()->GetConnector()->BindInterface( | 85 RenderThread::Get()->GetConnector()->BindInterface( |
40 device::mojom::kServiceName, std::move(request)); | 86 device::mojom::kServiceName, std::move(request)); |
41 } | 87 sensor_provider_.set_connection_error_handler( |
42 } | 88 base::Bind(&DeviceSensorEventPump::HandleSensorProviderError, |
43 | 89 base::Unretained(this))); |
44 void SendStartMessage() override { | 90 } |
45 mojo_interface_->StartPolling( | 91 } |
46 base::Bind(&DeviceSensorMojoClientMixin<Base, MojoInterface>::DidStart, | |
47 base::Unretained(this))); | |
48 } | |
49 void SendStopMessage() override { mojo_interface_->StopPolling(); } | |
50 | |
51 protected: | |
52 void DidStart(mojo::ScopedSharedBufferHandle buffer_handle) { | |
53 Base::DidStart(std::move(buffer_handle)); | |
54 } | |
55 | |
56 private: | |
57 mojo::InterfacePtr<MojoInterface> mojo_interface_; | |
58 }; | |
59 | |
60 template <typename ListenerType> | |
61 class CONTENT_EXPORT DeviceSensorEventPump | |
62 : NON_EXPORTED_BASE(public PlatformEventObserver<ListenerType>) { | |
63 public: | |
64 // Default rate for firing events. | |
65 static const int kDefaultPumpFrequencyHz = 60; | |
66 static const int kDefaultPumpDelayMicroseconds = | |
67 base::Time::kMicrosecondsPerSecond / kDefaultPumpFrequencyHz; | |
68 | |
69 // PlatformEventObserver | |
70 void Start(blink::WebPlatformEventListener* listener) override { | |
71 DVLOG(2) << "requested start"; | |
72 | |
73 if (state_ != STOPPED) | |
74 return; | |
75 | |
76 DCHECK(!timer_.IsRunning()); | |
77 | |
78 PlatformEventObserver<ListenerType>::Start(listener); | |
79 state_ = PENDING_START; | |
80 } | |
81 | |
82 void Stop() override { | |
83 DVLOG(2) << "stop"; | |
84 | |
85 if (state_ == STOPPED) | |
86 return; | |
87 | |
88 DCHECK((state_ == PENDING_START && !timer_.IsRunning()) || | |
89 (state_ == RUNNING && timer_.IsRunning())); | |
90 | |
91 if (timer_.IsRunning()) | |
92 timer_.Stop(); | |
93 PlatformEventObserver<ListenerType>::Stop(); | |
94 state_ = STOPPED; | |
95 } | |
96 | |
97 protected: | |
98 explicit DeviceSensorEventPump(RenderThread* thread) | |
99 : PlatformEventObserver<ListenerType>(thread), | |
100 pump_delay_microseconds_(kDefaultPumpDelayMicroseconds), | |
101 state_(STOPPED) {} | |
102 | 92 |
103 ~DeviceSensorEventPump() override { | 93 ~DeviceSensorEventPump() override { |
104 PlatformEventObserver<ListenerType>::StopIfObserving(); | 94 PlatformEventObserver<ListenerType>::StopIfObserving(); |
105 } | 95 } |
106 | 96 |
| 97 // Default rate for firing events. |
| 98 static constexpr int kDefaultPumpFrequencyHz = 60; |
| 99 static constexpr int kDefaultPumpDelayMicroseconds = |
| 100 base::Time::kMicrosecondsPerSecond / kDefaultPumpFrequencyHz; |
| 101 |
| 102 static constexpr int kMaxReadAttemptsCount = 10; |
| 103 |
| 104 struct CONTENT_EXPORT SensorEntry : public device::mojom::SensorClient { |
| 105 explicit SensorEntry(DeviceSensorEventPump* pump) |
| 106 : event_pump(pump), active(false), client_binding(this) {} |
| 107 |
| 108 ~SensorEntry() { client_binding.Close(); } |
| 109 |
| 110 // device::mojom::SensorClient: |
| 111 void RaiseError() override { HandleSensorError(); } |
| 112 |
| 113 // device::mojom::SensorClient: |
| 114 void SensorReadingChanged() override { |
| 115 // Since DeviceSensorEventPump::FireEvent is called in a certain |
| 116 // frequency, the |shared_buffer| is read frequently, so this |
| 117 // method doesn't need to be implemented. |
| 118 } |
| 119 |
| 120 // Mojo callback for SensorProvider::GetSensor(). |
| 121 void OnSensorCreated(device::mojom::SensorInitParamsPtr params, |
| 122 device::mojom::SensorClientRequest client_request) { |
| 123 ++event_pump->num_sensors_tried_; |
| 124 |
| 125 if (!params) { |
| 126 HandleSensorError(); |
| 127 if (event_pump->CanStart()) |
| 128 event_pump->DidStart(); |
| 129 return; |
| 130 } |
| 131 |
| 132 constexpr size_t kReadBufferSize = |
| 133 sizeof(device::SensorReadingSharedBuffer); |
| 134 |
| 135 DCHECK_EQ(0u, params->buffer_offset % kReadBufferSize); |
| 136 |
| 137 mode = params->mode; |
| 138 default_config = params->default_configuration; |
| 139 |
| 140 DCHECK(sensor.is_bound()); |
| 141 client_binding.Bind(std::move(client_request)); |
| 142 |
| 143 shared_buffer_handle = std::move(params->memory); |
| 144 DCHECK(!shared_buffer); |
| 145 shared_buffer = shared_buffer_handle->MapAtOffset(kReadBufferSize, |
| 146 params->buffer_offset); |
| 147 |
| 148 if (!shared_buffer) { |
| 149 HandleSensorError(); |
| 150 if (event_pump->CanStart()) |
| 151 event_pump->DidStart(); |
| 152 return; |
| 153 } |
| 154 |
| 155 ++event_pump->num_available_sensors_; |
| 156 |
| 157 frequency_limits.first = params->minimum_frequency; |
| 158 frequency_limits.second = params->maximum_frequency; |
| 159 |
| 160 DCHECK_GT(frequency_limits.first, 0.0); |
| 161 DCHECK_GE(frequency_limits.second, frequency_limits.first); |
| 162 constexpr double kMaxAllowedFrequency = |
| 163 device::mojom::SensorConfiguration::kMaxAllowedFrequency; |
| 164 DCHECK_GE(kMaxAllowedFrequency, frequency_limits.second); |
| 165 |
| 166 sensor.set_connection_error_handler( |
| 167 base::Bind(&SensorEntry::HandleSensorError, base::Unretained(this))); |
| 168 sensor->AddConfiguration( |
| 169 default_config, base::Bind(&SensorEntry::OnSensorAddConfiguration, |
| 170 base::Unretained(this))); |
| 171 } |
| 172 |
| 173 // Mojo callback for Sensor::AddConfiguration(). |
| 174 void OnSensorAddConfiguration(bool success) { |
| 175 active = success; |
| 176 if (event_pump->CanStart()) |
| 177 event_pump->DidStart(); |
| 178 } |
| 179 |
| 180 void HandleSensorError() { |
| 181 sensor.reset(); |
| 182 active = false; |
| 183 shared_buffer_handle.reset(); |
| 184 shared_buffer.reset(); |
| 185 client_binding.Close(); |
| 186 } |
| 187 |
| 188 // Updates sensor reading from shared buffer. |
| 189 bool UpdateSensorReading() { |
| 190 int read_attempts = 0; |
| 191 device::SensorReading reading_data; |
| 192 while (!TryReadFromBuffer(&reading_data)) { |
| 193 if (++read_attempts == kMaxReadAttemptsCount) { |
| 194 HandleSensorError(); |
| 195 return false; |
| 196 } |
| 197 } |
| 198 |
| 199 reading = reading_data; |
| 200 return true; |
| 201 } |
| 202 |
| 203 bool TryReadFromBuffer(device::SensorReading* result) { |
| 204 const device::SensorReadingSharedBuffer* buffer = |
| 205 static_cast<const device::SensorReadingSharedBuffer*>( |
| 206 shared_buffer.get()); |
| 207 const device::OneWriterSeqLock& seqlock = buffer->seqlock.value(); |
| 208 auto version = seqlock.ReadBegin(); |
| 209 auto reading_data = buffer->reading; |
| 210 if (seqlock.ReadRetry(version)) |
| 211 return false; |
| 212 *result = reading_data; |
| 213 return true; |
| 214 } |
| 215 |
| 216 bool SensorReadingUpdated() { return active && UpdateSensorReading(); } |
| 217 |
| 218 DeviceSensorEventPump* event_pump; |
| 219 device::mojom::SensorPtr sensor; |
| 220 device::mojom::SensorType type; |
| 221 bool active; |
| 222 device::mojom::ReportingMode mode; |
| 223 device::PlatformSensorConfiguration default_config; |
| 224 mojo::ScopedSharedBufferHandle shared_buffer_handle; |
| 225 mojo::ScopedSharedBufferMapping shared_buffer; |
| 226 device::SensorReading reading; |
| 227 std::pair<double, double> frequency_limits; |
| 228 mojo::Binding<device::mojom::SensorClient> client_binding; |
| 229 }; |
| 230 |
| 231 friend struct SensorEntry; |
| 232 |
107 // The pump is a tri-state automaton with allowed transitions as follows: | 233 // The pump is a tri-state automaton with allowed transitions as follows: |
108 // STOPPED -> PENDING_START | 234 // STOPPED -> PENDING_START |
109 // PENDING_START -> RUNNING | 235 // PENDING_START -> RUNNING |
110 // PENDING_START -> STOPPED | 236 // PENDING_START -> STOPPED |
111 // RUNNING -> STOPPED | 237 // RUNNING -> STOPPED |
112 enum PumpState { | 238 enum class PumpState { STOPPED, RUNNING, PENDING_START }; |
113 STOPPED, | 239 |
114 RUNNING, | 240 void GetSensor(device::mojom::SensorType type, SensorEntry* sensor_entry) { |
115 PENDING_START | 241 sensor_entry->type = type; |
116 }; | 242 auto request = mojo::MakeRequest(&sensor_entry->sensor); |
117 | 243 sensor_provider_->GetSensor(type, std::move(request), |
118 void DidStart(mojo::ScopedSharedBufferHandle buffer_handle) { | 244 base::Bind(&SensorEntry::OnSensorCreated, |
| 245 base::Unretained(sensor_entry))); |
| 246 } |
| 247 |
| 248 void DidStart() { |
119 DVLOG(2) << "did start sensor event pump"; | 249 DVLOG(2) << "did start sensor event pump"; |
120 | 250 |
121 if (state_ != PENDING_START) | 251 if (state_ != PumpState::PENDING_START) |
122 return; | 252 return; |
123 | 253 |
124 DCHECK(!timer_.IsRunning()); | 254 DCHECK(!timer_.IsRunning()); |
125 | 255 |
126 base::SharedMemoryHandle handle; | 256 timer_.Start(FROM_HERE, |
127 MojoResult result = mojo::UnwrapSharedMemoryHandle( | 257 base::TimeDelta::FromMicroseconds(pump_delay_microseconds_), |
128 std::move(buffer_handle), &handle, nullptr, nullptr); | 258 this, &DeviceSensorEventPump::FireEvent); |
129 DCHECK_EQ(MOJO_RESULT_OK, result); | 259 state_ = PumpState::RUNNING; |
130 | 260 } |
131 if (InitializeReader(handle)) { | 261 |
132 timer_.Start(FROM_HERE, | 262 void HandleSensorProviderError() { |
133 base::TimeDelta::FromMicroseconds(pump_delay_microseconds_), | 263 sensor_provider_.reset(); |
134 this, | 264 for (auto& sensor : sensors_) |
135 &DeviceSensorEventPump::FireEvent); | 265 sensor->HandleSensorError(); |
136 state_ = RUNNING; | 266 } |
137 } | 267 |
138 } | 268 // Notify the renderer of a certain device event. |
139 | |
140 virtual void FireEvent() = 0; | 269 virtual void FireEvent() = 0; |
141 virtual bool InitializeReader(base::SharedMemoryHandle handle) = 0; | 270 |
142 | 271 mojo::InterfacePtr<device::mojom::SensorProvider> sensor_provider_; |
| 272 std::vector<std::unique_ptr<SensorEntry>> sensors_; |
143 int pump_delay_microseconds_; | 273 int pump_delay_microseconds_; |
| 274 // The number of sensors that are tried obtaining by calling |
| 275 // SensorProvider::GetSensor(). |
| 276 int num_sensors_tried_; |
| 277 // The number of sensors that are available from a successful |
| 278 // SensorProvider::GetSensor() call. |
| 279 int num_available_sensors_; |
| 280 |
| 281 private: |
| 282 // Returns if the |sensors_| are ready to start a certain device event. |
| 283 virtual bool CanStart() const = 0; |
| 284 |
144 PumpState state_; | 285 PumpState state_; |
145 base::RepeatingTimer timer_; | 286 base::RepeatingTimer timer_; |
146 | 287 |
147 DISALLOW_COPY_AND_ASSIGN(DeviceSensorEventPump); | 288 DISALLOW_COPY_AND_ASSIGN(DeviceSensorEventPump); |
148 }; | 289 }; |
149 | 290 |
150 } // namespace content | 291 } // namespace content |
151 | 292 |
152 #endif // CONTENT_RENDERER_DEVICE_SENSORS_DEVICE_SENSOR_EVENT_PUMP_H_ | 293 #endif // CONTENT_RENDERER_DEVICE_SENSORS_DEVICE_SENSOR_EVENT_PUMP_H_ |
OLD | NEW |