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