PageRenderTime 75ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/third_party/blink/renderer/modules/sensor/sensor.cc

https://github.com/chromium/chromium
C++ | 371 lines | 286 code | 64 blank | 21 comment | 44 complexity | c36068cdbcf51c77a13631a6bdfdb8ff MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause
  1. // Copyright 2016 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. #include "third_party/blink/renderer/modules/sensor/sensor.h"
  5. #include <utility>
  6. #include "services/device/public/cpp/generic_sensor/sensor_traits.h"
  7. #include "services/device/public/mojom/sensor.mojom-blink.h"
  8. #include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom-blink.h"
  9. #include "third_party/blink/public/platform/task_type.h"
  10. #include "third_party/blink/renderer/core/frame/local_dom_window.h"
  11. #include "third_party/blink/renderer/core/frame/local_frame.h"
  12. #include "third_party/blink/renderer/core/inspector/console_message.h"
  13. #include "third_party/blink/renderer/core/timing/dom_window_performance.h"
  14. #include "third_party/blink/renderer/core/timing/window_performance.h"
  15. #include "third_party/blink/renderer/modules/sensor/sensor_error_event.h"
  16. #include "third_party/blink/renderer/modules/sensor/sensor_provider_proxy.h"
  17. #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
  18. #include "third_party/blink/renderer/platform/web_test_support.h"
  19. namespace blink {
  20. namespace {
  21. const double kWaitingIntervalThreshold = 0.01;
  22. bool AreFeaturesEnabled(
  23. ExecutionContext* context,
  24. const Vector<mojom::blink::PermissionsPolicyFeature>& features) {
  25. return std::all_of(features.begin(), features.end(),
  26. [context](mojom::blink::PermissionsPolicyFeature feature) {
  27. return context->IsFeatureEnabled(
  28. feature, ReportOptions::kReportOnFailure);
  29. });
  30. }
  31. } // namespace
  32. Sensor::Sensor(ExecutionContext* execution_context,
  33. const SensorOptions* sensor_options,
  34. ExceptionState& exception_state,
  35. device::mojom::blink::SensorType type,
  36. const Vector<mojom::blink::PermissionsPolicyFeature>& features)
  37. : ExecutionContextLifecycleObserver(execution_context),
  38. frequency_(0.0),
  39. type_(type),
  40. state_(SensorState::kIdle),
  41. last_reported_timestamp_(0.0) {
  42. // [SecureContext] in idl.
  43. DCHECK(execution_context->IsSecureContext());
  44. DCHECK(!features.IsEmpty());
  45. if (!AreFeaturesEnabled(execution_context, features)) {
  46. exception_state.ThrowSecurityError(
  47. "Access to sensor features is disallowed by permissions policy");
  48. return;
  49. }
  50. // Check the given frequency value.
  51. if (sensor_options->hasFrequency()) {
  52. frequency_ = sensor_options->frequency();
  53. const double max_allowed_frequency =
  54. device::GetSensorMaxAllowedFrequency(type_);
  55. if (frequency_ > max_allowed_frequency) {
  56. frequency_ = max_allowed_frequency;
  57. String message = String::Format(
  58. "Maximum allowed frequency value for this sensor type is %.0f Hz.",
  59. max_allowed_frequency);
  60. auto* console_message = MakeGarbageCollected<ConsoleMessage>(
  61. mojom::ConsoleMessageSource::kJavaScript,
  62. mojom::ConsoleMessageLevel::kInfo, std::move(message));
  63. execution_context->AddConsoleMessage(console_message);
  64. }
  65. }
  66. }
  67. Sensor::Sensor(ExecutionContext* execution_context,
  68. const SpatialSensorOptions* options,
  69. ExceptionState& exception_state,
  70. device::mojom::blink::SensorType sensor_type,
  71. const Vector<mojom::blink::PermissionsPolicyFeature>& features)
  72. : Sensor(execution_context,
  73. static_cast<const SensorOptions*>(options),
  74. exception_state,
  75. sensor_type,
  76. features) {
  77. use_screen_coords_ = (options->referenceFrame() == "screen");
  78. }
  79. Sensor::~Sensor() = default;
  80. void Sensor::start() {
  81. if (!GetExecutionContext())
  82. return;
  83. if (state_ != SensorState::kIdle)
  84. return;
  85. state_ = SensorState::kActivating;
  86. Activate();
  87. }
  88. void Sensor::stop() {
  89. if (state_ == SensorState::kIdle)
  90. return;
  91. Deactivate();
  92. state_ = SensorState::kIdle;
  93. }
  94. // Getters
  95. bool Sensor::activated() const {
  96. return state_ == SensorState::kActivated;
  97. }
  98. bool Sensor::hasReading() const {
  99. if (!activated())
  100. return false;
  101. DCHECK(sensor_proxy_);
  102. return sensor_proxy_->GetReading().timestamp() != 0.0;
  103. }
  104. absl::optional<DOMHighResTimeStamp> Sensor::timestamp(
  105. ScriptState* script_state) const {
  106. if (!hasReading()) {
  107. return absl::nullopt;
  108. }
  109. LocalDOMWindow* window = LocalDOMWindow::From(script_state);
  110. if (!window) {
  111. return absl::nullopt;
  112. }
  113. WindowPerformance* performance = DOMWindowPerformance::performance(*window);
  114. DCHECK(performance);
  115. DCHECK(sensor_proxy_);
  116. return performance->MonotonicTimeToDOMHighResTimeStamp(
  117. base::TimeTicks() +
  118. base::Seconds(sensor_proxy_->GetReading().timestamp()));
  119. }
  120. void Sensor::Trace(Visitor* visitor) const {
  121. visitor->Trace(sensor_proxy_);
  122. ActiveScriptWrappable::Trace(visitor);
  123. ExecutionContextLifecycleObserver::Trace(visitor);
  124. EventTargetWithInlineData::Trace(visitor);
  125. }
  126. bool Sensor::HasPendingActivity() const {
  127. if (state_ == SensorState::kIdle)
  128. return false;
  129. return GetExecutionContext() && HasEventListeners();
  130. }
  131. auto Sensor::CreateSensorConfig() -> SensorConfigurationPtr {
  132. auto result = SensorConfiguration::New();
  133. double default_frequency = sensor_proxy_->GetDefaultFrequency();
  134. double minimum_frequency = sensor_proxy_->GetFrequencyLimits().first;
  135. double maximum_frequency = sensor_proxy_->GetFrequencyLimits().second;
  136. if (frequency_ == 0.0) // i.e. was never set.
  137. frequency_ = default_frequency;
  138. if (frequency_ > maximum_frequency)
  139. frequency_ = maximum_frequency;
  140. if (frequency_ < minimum_frequency)
  141. frequency_ = minimum_frequency;
  142. result->frequency = frequency_;
  143. return result;
  144. }
  145. void Sensor::InitSensorProxyIfNeeded() {
  146. if (sensor_proxy_)
  147. return;
  148. LocalDOMWindow* window = To<LocalDOMWindow>(GetExecutionContext());
  149. auto* provider = SensorProviderProxy::From(window);
  150. sensor_proxy_ = provider->GetSensorProxy(type_);
  151. if (!sensor_proxy_) {
  152. sensor_proxy_ =
  153. provider->CreateSensorProxy(type_, window->GetFrame()->GetPage());
  154. }
  155. }
  156. void Sensor::ContextDestroyed() {
  157. if (!IsIdleOrErrored())
  158. Deactivate();
  159. if (sensor_proxy_)
  160. sensor_proxy_->Detach();
  161. }
  162. void Sensor::OnSensorInitialized() {
  163. if (state_ != SensorState::kActivating)
  164. return;
  165. RequestAddConfiguration();
  166. }
  167. void Sensor::OnSensorReadingChanged() {
  168. if (state_ != SensorState::kActivated)
  169. return;
  170. // Return if reading update is already scheduled or the cached
  171. // reading is up-to-date.
  172. if (pending_reading_notification_.IsActive())
  173. return;
  174. double elapsedTime =
  175. sensor_proxy_->GetReading().timestamp() - last_reported_timestamp_;
  176. DCHECK_GT(elapsedTime, 0.0);
  177. DCHECK_GT(configuration_->frequency, 0.0);
  178. double waitingTime = 1 / configuration_->frequency - elapsedTime;
  179. // Negative or zero 'waitingTime' means that polling period has elapsed.
  180. // We also avoid scheduling if the elapsed time is slightly behind the
  181. // polling period.
  182. auto sensor_reading_changed =
  183. WTF::Bind(&Sensor::NotifyReading, WrapWeakPersistent(this));
  184. if (waitingTime < kWaitingIntervalThreshold) {
  185. // Invoke JS callbacks in a different callchain to obviate
  186. // possible modifications of SensorProxy::observers_ container
  187. // while it is being iterated through.
  188. pending_reading_notification_ = PostCancellableTask(
  189. *GetExecutionContext()->GetTaskRunner(TaskType::kSensor), FROM_HERE,
  190. std::move(sensor_reading_changed));
  191. } else {
  192. pending_reading_notification_ = PostDelayedCancellableTask(
  193. *GetExecutionContext()->GetTaskRunner(TaskType::kSensor), FROM_HERE,
  194. std::move(sensor_reading_changed), base::Seconds(waitingTime));
  195. }
  196. }
  197. void Sensor::OnSensorError(DOMExceptionCode code,
  198. const String& sanitized_message,
  199. const String& unsanitized_message) {
  200. HandleError(code, sanitized_message, unsanitized_message);
  201. }
  202. void Sensor::OnAddConfigurationRequestCompleted(bool result) {
  203. if (state_ != SensorState::kActivating)
  204. return;
  205. if (!result) {
  206. HandleError(DOMExceptionCode::kNotReadableError,
  207. "start() call has failed.");
  208. return;
  209. }
  210. if (!GetExecutionContext())
  211. return;
  212. pending_activated_notification_ = PostCancellableTask(
  213. *GetExecutionContext()->GetTaskRunner(TaskType::kSensor), FROM_HERE,
  214. WTF::Bind(&Sensor::NotifyActivated, WrapWeakPersistent(this)));
  215. }
  216. void Sensor::Activate() {
  217. DCHECK_EQ(state_, SensorState::kActivating);
  218. InitSensorProxyIfNeeded();
  219. DCHECK(sensor_proxy_);
  220. if (sensor_proxy_->IsInitialized())
  221. RequestAddConfiguration();
  222. else
  223. sensor_proxy_->Initialize();
  224. sensor_proxy_->AddObserver(this);
  225. }
  226. void Sensor::Deactivate() {
  227. DCHECK_NE(state_, SensorState::kIdle);
  228. // state_ is not set to kIdle here as on error it should
  229. // transition to the kIdle state in the same call chain
  230. // the error event is dispatched, i.e. inside NotifyError().
  231. pending_reading_notification_.Cancel();
  232. pending_activated_notification_.Cancel();
  233. pending_error_notification_.Cancel();
  234. if (!sensor_proxy_)
  235. return;
  236. if (sensor_proxy_->IsInitialized()) {
  237. DCHECK(configuration_);
  238. sensor_proxy_->RemoveConfiguration(configuration_->Clone());
  239. last_reported_timestamp_ = 0.0;
  240. }
  241. sensor_proxy_->RemoveObserver(this);
  242. }
  243. void Sensor::RequestAddConfiguration() {
  244. if (!configuration_) {
  245. configuration_ = CreateSensorConfig();
  246. DCHECK(configuration_);
  247. DCHECK_GE(configuration_->frequency,
  248. sensor_proxy_->GetFrequencyLimits().first);
  249. DCHECK_LE(configuration_->frequency,
  250. sensor_proxy_->GetFrequencyLimits().second);
  251. }
  252. DCHECK(sensor_proxy_);
  253. sensor_proxy_->AddConfiguration(
  254. configuration_->Clone(),
  255. WTF::Bind(&Sensor::OnAddConfigurationRequestCompleted,
  256. WrapWeakPersistent(this)));
  257. }
  258. void Sensor::HandleError(DOMExceptionCode code,
  259. const String& sanitized_message,
  260. const String& unsanitized_message) {
  261. if (!GetExecutionContext()) {
  262. // Deactivate() is already called from Sensor::ContextDestroyed().
  263. return;
  264. }
  265. if (IsIdleOrErrored())
  266. return;
  267. Deactivate();
  268. auto* error = MakeGarbageCollected<DOMException>(code, sanitized_message,
  269. unsanitized_message);
  270. pending_error_notification_ = PostCancellableTask(
  271. *GetExecutionContext()->GetTaskRunner(TaskType::kSensor), FROM_HERE,
  272. WTF::Bind(&Sensor::NotifyError, WrapWeakPersistent(this),
  273. WrapPersistent(error)));
  274. }
  275. void Sensor::NotifyReading() {
  276. DCHECK_EQ(state_, SensorState::kActivated);
  277. last_reported_timestamp_ = sensor_proxy_->GetReading().timestamp();
  278. DispatchEvent(*Event::Create(event_type_names::kReading));
  279. }
  280. void Sensor::NotifyActivated() {
  281. DCHECK_EQ(state_, SensorState::kActivating);
  282. state_ = SensorState::kActivated;
  283. if (hasReading()) {
  284. // If reading has already arrived, process the reading values (a subclass
  285. // may do some filtering, for example) and then send an initial "reading"
  286. // event right away.
  287. DCHECK(!pending_reading_notification_.IsActive());
  288. pending_reading_notification_ = PostCancellableTask(
  289. *GetExecutionContext()->GetTaskRunner(TaskType::kSensor), FROM_HERE,
  290. WTF::Bind(&Sensor::OnSensorReadingChanged, WrapWeakPersistent(this)));
  291. }
  292. DispatchEvent(*Event::Create(event_type_names::kActivate));
  293. }
  294. void Sensor::NotifyError(DOMException* error) {
  295. DCHECK_NE(state_, SensorState::kIdle);
  296. state_ = SensorState::kIdle;
  297. DispatchEvent(*SensorErrorEvent::Create(event_type_names::kError, error));
  298. }
  299. bool Sensor::IsIdleOrErrored() const {
  300. return (state_ == SensorState::kIdle) ||
  301. pending_error_notification_.IsActive();
  302. }
  303. const device::SensorReading& Sensor::GetReading() const {
  304. DCHECK(sensor_proxy_);
  305. return sensor_proxy_->GetReading(use_screen_coords_);
  306. }
  307. } // namespace blink