1 // Copyright 2018 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 "third_party/blink/renderer/modules/sensor/sensor_proxy_impl.h"
6
7 #include "services/device/public/cpp/generic_sensor/sensor_traits.h"
8 #include "third_party/blink/public/platform/platform.h"
9 #include "third_party/blink/public/platform/task_type.h"
10 #include "third_party/blink/renderer/modules/sensor/sensor_provider_proxy.h"
11 #include "third_party/blink/renderer/modules/sensor/sensor_reading_remapper.h"
12 #include "third_party/blink/renderer/platform/mojo/mojo_helper.h"
13
14 using device::mojom::blink::SensorCreationResult;
15
16 namespace blink {
17
SensorProxyImpl(device::mojom::blink::SensorType sensor_type,SensorProviderProxy * provider,Page * page)18 SensorProxyImpl::SensorProxyImpl(device::mojom::blink::SensorType sensor_type,
19 SensorProviderProxy* provider,
20 Page* page)
21 : SensorProxy(sensor_type, provider, page),
22 sensor_remote_(provider->GetSupplementable()->GetExecutionContext()),
23 client_receiver_(this,
24 provider->GetSupplementable()->GetExecutionContext()),
25 task_runner_(
26 provider->GetSupplementable()->GetTaskRunner(TaskType::kSensor)),
27 polling_timer_(
28 provider->GetSupplementable()->GetTaskRunner(TaskType::kSensor),
29 this,
30 &SensorProxyImpl::OnPollingTimer) {}
31
~SensorProxyImpl()32 SensorProxyImpl::~SensorProxyImpl() {}
33
Trace(Visitor * visitor) const34 void SensorProxyImpl::Trace(Visitor* visitor) const {
35 visitor->Trace(sensor_remote_);
36 visitor->Trace(client_receiver_);
37 SensorProxy::Trace(visitor);
38 }
39
Initialize()40 void SensorProxyImpl::Initialize() {
41 if (state_ != kUninitialized)
42 return;
43
44 if (!sensor_provider_proxy()) {
45 HandleSensorError();
46 return;
47 }
48
49 state_ = kInitializing;
50 sensor_provider_proxy()->GetSensor(
51 type_,
52 WTF::Bind(&SensorProxyImpl::OnSensorCreated, WrapWeakPersistent(this)));
53 }
54
AddConfiguration(device::mojom::blink::SensorConfigurationPtr configuration,base::OnceCallback<void (bool)> callback)55 void SensorProxyImpl::AddConfiguration(
56 device::mojom::blink::SensorConfigurationPtr configuration,
57 base::OnceCallback<void(bool)> callback) {
58 DCHECK(IsInitialized());
59 AddActiveFrequency(configuration->frequency);
60 sensor_remote_->AddConfiguration(std::move(configuration),
61 std::move(callback));
62 }
63
RemoveConfiguration(device::mojom::blink::SensorConfigurationPtr configuration)64 void SensorProxyImpl::RemoveConfiguration(
65 device::mojom::blink::SensorConfigurationPtr configuration) {
66 DCHECK(IsInitialized());
67 RemoveActiveFrequency(configuration->frequency);
68 if (sensor_remote_.is_bound())
69 sensor_remote_->RemoveConfiguration(std::move(configuration));
70 }
71
GetDefaultFrequency() const72 double SensorProxyImpl::GetDefaultFrequency() const {
73 DCHECK(IsInitialized());
74 return default_frequency_;
75 }
76
GetFrequencyLimits() const77 std::pair<double, double> SensorProxyImpl::GetFrequencyLimits() const {
78 DCHECK(IsInitialized());
79 return frequency_limits_;
80 }
81
Suspend()82 void SensorProxyImpl::Suspend() {
83 if (suspended_ || !sensor_remote_.is_bound())
84 return;
85
86 sensor_remote_->Suspend();
87 suspended_ = true;
88 UpdatePollingStatus();
89 }
90
Resume()91 void SensorProxyImpl::Resume() {
92 if (!suspended_ || !sensor_remote_.is_bound())
93 return;
94
95 sensor_remote_->Resume();
96 suspended_ = false;
97 UpdatePollingStatus();
98 }
99
UpdateSensorReading()100 void SensorProxyImpl::UpdateSensorReading() {
101 DCHECK(ShouldProcessReadings());
102 DCHECK(shared_buffer_reader_);
103
104 // Try to read the latest value from shared memory. Failure should not be
105 // fatal because we only retry a finite number of times.
106 device::SensorReading reading_data;
107 if (!shared_buffer_reader_->GetReading(&reading_data))
108 return;
109
110 double latest_timestamp = reading_data.timestamp();
111 if (reading_.timestamp() != latest_timestamp &&
112 latest_timestamp != 0.0) // The shared buffer is zeroed when
113 // sensor is stopped, we skip this
114 // reading.
115 {
116 DCHECK_GT(latest_timestamp, reading_.timestamp())
117 << "Timestamps must increase monotonically";
118 reading_ = reading_data;
119 for (Observer* observer : observers_)
120 observer->OnSensorReadingChanged();
121 }
122 }
123
RaiseError()124 void SensorProxyImpl::RaiseError() {
125 HandleSensorError();
126 }
127
SensorReadingChanged()128 void SensorProxyImpl::SensorReadingChanged() {
129 DCHECK_EQ(device::mojom::blink::ReportingMode::ON_CHANGE, mode_);
130 if (ShouldProcessReadings())
131 UpdateSensorReading();
132 }
133
ReportError(DOMExceptionCode code,const String & message)134 void SensorProxyImpl::ReportError(DOMExceptionCode code,
135 const String& message) {
136 state_ = kUninitialized;
137 active_frequencies_.clear();
138 reading_ = device::SensorReading();
139 UpdatePollingStatus();
140
141 // The m_sensor.reset() will release all callbacks and its bound parameters,
142 // therefore, handleSensorError accepts messages by value.
143 sensor_remote_.reset();
144 shared_buffer_reader_.reset();
145 default_frequency_ = 0.0;
146 frequency_limits_ = {0.0, 0.0};
147 client_receiver_.reset();
148
149 SensorProxy::ReportError(code, message);
150 }
151
HandleSensorError(SensorCreationResult error)152 void SensorProxyImpl::HandleSensorError(SensorCreationResult error) {
153 if (error == SensorCreationResult::ERROR_NOT_ALLOWED) {
154 String description = "Permissions to access sensor are not granted";
155 ReportError(DOMExceptionCode::kNotAllowedError, std::move(description));
156 } else {
157 ReportError(DOMExceptionCode::kNotReadableError, kDefaultErrorDescription);
158 }
159 }
160
OnSensorCreated(SensorCreationResult result,device::mojom::blink::SensorInitParamsPtr params)161 void SensorProxyImpl::OnSensorCreated(
162 SensorCreationResult result,
163 device::mojom::blink::SensorInitParamsPtr params) {
164 DCHECK_EQ(kInitializing, state_);
165 if (!params) {
166 DCHECK_NE(SensorCreationResult::SUCCESS, result);
167 HandleSensorError(result);
168 return;
169 }
170
171 DCHECK_EQ(SensorCreationResult::SUCCESS, result);
172
173 mode_ = params->mode;
174 if (!params->default_configuration) {
175 HandleSensorError();
176 return;
177 }
178
179 default_frequency_ = params->default_configuration->frequency;
180 DCHECK_GT(default_frequency_, 0.0);
181
182 sensor_remote_.Bind(std::move(params->sensor), task_runner_);
183 client_receiver_.Bind(std::move(params->client_receiver), task_runner_);
184
185 shared_buffer_reader_ = device::SensorReadingSharedBufferReader::Create(
186 std::move(params->memory), params->buffer_offset);
187 if (!shared_buffer_reader_) {
188 HandleSensorError();
189 return;
190 }
191
192 shared_buffer_reader_->GetReading(&reading_);
193
194 frequency_limits_.first = params->minimum_frequency;
195 frequency_limits_.second = params->maximum_frequency;
196
197 DCHECK_GT(frequency_limits_.first, 0.0);
198 DCHECK_GE(frequency_limits_.second, frequency_limits_.first);
199 DCHECK_GE(device::GetSensorMaxAllowedFrequency(type_),
200 frequency_limits_.second);
201
202 auto error_callback =
203 WTF::Bind(&SensorProxyImpl::HandleSensorError, WrapWeakPersistent(this),
204 SensorCreationResult::ERROR_NOT_AVAILABLE);
205 sensor_remote_.set_disconnect_handler(std::move(error_callback));
206
207 state_ = kInitialized;
208
209 UpdateSuspendedStatus();
210
211 for (Observer* observer : observers_)
212 observer->OnSensorInitialized();
213 }
214
OnPollingTimer(TimerBase *)215 void SensorProxyImpl::OnPollingTimer(TimerBase*) {
216 UpdateSensorReading();
217 }
218
ShouldProcessReadings() const219 bool SensorProxyImpl::ShouldProcessReadings() const {
220 return IsInitialized() && !suspended_ && !active_frequencies_.IsEmpty();
221 }
222
UpdatePollingStatus()223 void SensorProxyImpl::UpdatePollingStatus() {
224 if (mode_ != device::mojom::blink::ReportingMode::CONTINUOUS)
225 return;
226
227 if (ShouldProcessReadings()) {
228 // TODO(crbug/721297) : We need to find out an algorithm for resulting
229 // polling frequency.
230 polling_timer_.StartRepeating(
231 base::TimeDelta::FromSecondsD(1 / active_frequencies_.back()),
232 FROM_HERE);
233 } else {
234 polling_timer_.Stop();
235 }
236 }
237
RemoveActiveFrequency(double frequency)238 void SensorProxyImpl::RemoveActiveFrequency(double frequency) {
239 // Can use binary search as active_frequencies_ is sorted.
240 Vector<double>::iterator it = std::lower_bound(
241 active_frequencies_.begin(), active_frequencies_.end(), frequency);
242 if (it == active_frequencies_.end() || *it != frequency) {
243 NOTREACHED() << "Attempted to remove active frequency which is not present "
244 "in the list";
245 return;
246 }
247
248 active_frequencies_.erase(it);
249 UpdatePollingStatus();
250
251 if (active_frequencies_.IsEmpty())
252 reading_ = device::SensorReading();
253 }
254
AddActiveFrequency(double frequency)255 void SensorProxyImpl::AddActiveFrequency(double frequency) {
256 Vector<double>::iterator it = std::lower_bound(
257 active_frequencies_.begin(), active_frequencies_.end(), frequency);
258 if (it == active_frequencies_.end()) {
259 active_frequencies_.push_back(frequency);
260 } else {
261 active_frequencies_.insert(
262 static_cast<wtf_size_t>(std::distance(active_frequencies_.begin(), it)),
263 frequency);
264 }
265 UpdatePollingStatus();
266 }
267
268 } // namespace blink
269