Commit fbf954d4 authored by wjmaclean's avatar wjmaclean Committed by Commit bot

Revert of [Sensors] Align sensor reading updates and 'onchange' notification...

Revert of [Sensors] Align sensor reading updates and 'onchange' notification with rAF. (patchset #6 id:140001 of https://codereview.chromium.org/2551223003/ )

Reason for revert:
Seems like a likely cause for failures on:

https://test-results.appspot.com/dashboards/flakiness_dashboard.html#tests=sensor%2Faccelerometer.html&testType=webkit_tests

Original issue's description:
> [Sensors] Align sensor reading updates and 'onchange' notification with rAF.
>
> For all sensors new reading values are read and 'onchange' notfication is send from rAF callbacks, thus avoiding possible Critical Rendering Path interruption.
>
> Before this change a timers were used and this could unnecessarily drain CPU and battery.
>
> BUG=668052
> BUG=606766
>
> Committed: https://crrev.com/6b071fe7dc3bd64a2914eadd5c67b483d064a6cb
> Cr-Commit-Position: refs/heads/master@{#439467}

TBR=reillyg@chromium.org,alexander.shalamov@intel.com,haraken@chromium.org,foolip@chromium.org,mikhail.pozdnyakov@intel.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=668052

Review-Url: https://codereview.chromium.org/2590513002
Cr-Commit-Position: refs/heads/master@{#439487}
parent dc9f8282
......@@ -304,10 +304,7 @@ function runGenericSensorTests(sensorType, updateReading, verifyReading) {
// By the moment slow sensor (9 Hz) is notified for the
// next time, the fast sensor (30 Hz) has been notified
// for int(30/9) = 3 times.
// In actual implementation updates are bound to rAF,
// (not to a timer) sometimes fast sensor gets invoked 4 times.
assert_true(fastSensorNotifiedCounter == 3 ||
fastSensorNotifiedCounter == 4);
assert_equals(fastSensorNotifiedCounter, 3);
fastSensor.stop();
slowSensor.stop();
resolve(mockSensor);
......
......@@ -32,8 +32,8 @@ blink_modules_sources("sensor") {
"SensorProxy.h",
"SensorReading.cpp",
"SensorReading.h",
"SensorReadingUpdater.cpp",
"SensorReadingUpdater.h",
"SensorUpdateNotificationStrategy.cpp",
"SensorUpdateNotificationStrategy.h",
]
deps = [
......
......@@ -13,6 +13,7 @@
#include "modules/sensor/SensorErrorEvent.h"
#include "modules/sensor/SensorProviderProxy.h"
#include "modules/sensor/SensorReading.h"
#include "modules/sensor/SensorUpdateNotificationStrategy.h"
using namespace device::mojom::blink;
......@@ -25,8 +26,7 @@ Sensor::Sensor(ExecutionContext* executionContext,
: ContextLifecycleObserver(executionContext),
m_sensorOptions(sensorOptions),
m_type(type),
m_state(Sensor::SensorState::Idle),
m_lastUpdateTimestamp(0.0) {
m_state(Sensor::SensorState::Idle) {
// Check secure context.
String errorMessage;
if (!executionContext->isSecureContext(errorMessage)) {
......@@ -164,7 +164,7 @@ void Sensor::initSensorProxyIfNeeded() {
m_sensorProxy = provider->getSensorProxy(m_type);
if (!m_sensorProxy) {
m_sensorProxy = provider->createSensorProxy(m_type, document,
m_sensorProxy = provider->createSensorProxy(m_type, document->page(),
createSensorReadingFactory());
}
}
......@@ -182,15 +182,10 @@ void Sensor::onSensorInitialized() {
startListening();
}
void Sensor::onSensorReadingChanged(double timestamp) {
if (m_state != Sensor::SensorState::Activated)
return;
DCHECK_GT(m_configuration->frequency, 0.0);
double period = 1 / m_configuration->frequency;
if (timestamp - m_lastUpdateTimestamp >= period) {
m_lastUpdateTimestamp = timestamp;
notifySensorReadingChanged();
void Sensor::onSensorReadingChanged() {
if (m_state == Sensor::SensorState::Activated) {
DCHECK(m_sensorUpdateNotifier);
m_sensorUpdateNotifier->onSensorReadingChanged();
}
}
......@@ -198,6 +193,8 @@ void Sensor::onSensorError(ExceptionCode code,
const String& sanitizedMessage,
const String& unsanitizedMessage) {
reportError(code, sanitizedMessage, unsanitizedMessage);
if (m_sensorUpdateNotifier)
m_sensorUpdateNotifier->cancelPendingNotifications();
}
void Sensor::onStartRequestCompleted(bool result) {
......@@ -211,6 +208,13 @@ void Sensor::onStartRequestCompleted(bool result) {
return;
}
DCHECK(m_configuration);
DCHECK(m_sensorProxy);
auto updateCallback =
WTF::bind(&Sensor::onSensorUpdateNotification, wrapWeakPersistent(this));
DCHECK_GT(m_configuration->frequency, 0);
m_sensorUpdateNotifier = SensorUpdateNotificationStrategy::create(
m_configuration->frequency, std::move(updateCallback));
updateState(Sensor::SensorState::Activated);
}
......@@ -241,6 +245,9 @@ void Sensor::stopListening() {
DCHECK(m_sensorProxy);
updateState(Sensor::SensorState::Idle);
if (m_sensorUpdateNotifier)
m_sensorUpdateNotifier->cancelPendingNotifications();
if (m_sensorProxy->isInitialized()) {
DCHECK(m_configuration);
m_sensorProxy->removeConfiguration(m_configuration->Clone());
......@@ -248,6 +255,25 @@ void Sensor::stopListening() {
m_sensorProxy->removeObserver(this);
}
void Sensor::onSensorUpdateNotification() {
if (m_state != Sensor::SensorState::Activated)
return;
DCHECK(m_sensorProxy);
DCHECK(m_sensorProxy->isInitialized());
DCHECK(m_sensorProxy->sensorReading());
if (getExecutionContext() &&
m_sensorProxy->sensorReading()->isReadingUpdated(m_storedData)) {
getExecutionContext()->postTask(
TaskType::Sensor, BLINK_FROM_HERE,
createSameThreadTask(&Sensor::notifySensorReadingChanged,
wrapWeakPersistent(this)));
}
m_storedData = m_sensorProxy->sensorReading()->data();
}
void Sensor::updateState(Sensor::SensorState newState) {
if (newState == m_state)
return;
......@@ -277,14 +303,13 @@ void Sensor::reportError(ExceptionCode code,
}
}
void Sensor::notifySensorReadingChanged() {
DCHECK(m_sensorProxy);
DCHECK(m_sensorProxy->sensorReading());
void Sensor::onSuspended() {
if (m_sensorUpdateNotifier)
m_sensorUpdateNotifier->cancelPendingNotifications();
}
if (m_sensorProxy->sensorReading()->isReadingUpdated(m_storedData)) {
m_storedData = m_sensorProxy->sensorReading()->data();
dispatchEvent(Event::create(EventTypeNames::change));
}
void Sensor::notifySensorReadingChanged() {
dispatchEvent(Event::create(EventTypeNames::change));
}
void Sensor::notifyOnActivate() {
......
......@@ -20,6 +20,7 @@ namespace blink {
class ExceptionState;
class ExecutionContext;
class SensorReading;
class SensorUpdateNotificationStrategy;
class Sensor : public EventTargetWithInlineData,
public ActiveScriptWrappable<Sensor>,
......@@ -82,10 +83,11 @@ class Sensor : public EventTargetWithInlineData,
// SensorController::Observer overrides.
void onSensorInitialized() override;
void onSensorReadingChanged(double timestamp) override;
void onSensorReadingChanged() override;
void onSensorError(ExceptionCode,
const String& sanitizedMessage,
const String& unsanitizedMessage) override;
void onSuspended() override;
void onStartRequestCompleted(bool);
void onStopRequestCompleted(bool);
......@@ -93,6 +95,8 @@ class Sensor : public EventTargetWithInlineData,
void startListening();
void stopListening();
void onSensorUpdateNotification();
void updateState(SensorState newState);
void reportError(ExceptionCode = UnknownError,
const String& sanitizedMessage = String(),
......@@ -107,9 +111,9 @@ class Sensor : public EventTargetWithInlineData,
device::mojom::blink::SensorType m_type;
SensorState m_state;
Member<SensorProxy> m_sensorProxy;
std::unique_ptr<SensorUpdateNotificationStrategy> m_sensorUpdateNotifier;
device::SensorReading m_storedData;
SensorConfigurationPtr m_configuration;
double m_lastUpdateTimestamp;
};
} // namespace blink
......
......@@ -55,12 +55,12 @@ DEFINE_TRACE(SensorProviderProxy) {
SensorProxy* SensorProviderProxy::createSensorProxy(
device::mojom::blink::SensorType type,
Document* document,
Page* page,
std::unique_ptr<SensorReadingFactory> readingFactory) {
DCHECK(!getSensorProxy(type));
SensorProxy* sensor =
new SensorProxy(type, this, document, std::move(readingFactory));
new SensorProxy(type, this, page, std::move(readingFactory));
m_sensorProxies.add(sensor);
return sensor;
......
......@@ -13,7 +13,7 @@
namespace blink {
class Document;
class Page;
class SensorProxy;
class SensorReadingFactory;
......@@ -31,7 +31,7 @@ class SensorProviderProxy final
~SensorProviderProxy();
SensorProxy* createSensorProxy(device::mojom::blink::SensorType,
Document*,
Page*,
std::unique_ptr<SensorReadingFactory>);
SensorProxy* getSensorProxy(device::mojom::blink::SensorType);
......
......@@ -4,11 +4,9 @@
#include "modules/sensor/SensorProxy.h"
#include "core/dom/Document.h"
#include "core/frame/LocalFrame.h"
#include "modules/sensor/SensorProviderProxy.h"
#include "modules/sensor/SensorReading.h"
#include "modules/sensor/SensorReadingUpdater.h"
#include "platform/mojo/MojoHelper.h"
#include "public/platform/Platform.h"
......@@ -18,18 +16,18 @@ namespace blink {
SensorProxy::SensorProxy(SensorType sensorType,
SensorProviderProxy* provider,
Document* document,
Page* page,
std::unique_ptr<SensorReadingFactory> readingFactory)
: PageVisibilityObserver(document->page()),
: PageVisibilityObserver(page),
m_type(sensorType),
m_mode(ReportingMode::CONTINUOUS),
m_provider(provider),
m_clientBinding(this),
m_state(SensorProxy::Uninitialized),
m_suspended(false),
m_document(document),
m_readingFactory(std::move(readingFactory)),
m_maximumFrequency(0.0) {}
m_maximumFrequency(0.0),
m_timer(this, &SensorProxy::onTimerFired) {}
SensorProxy::~SensorProxy() {}
......@@ -38,8 +36,6 @@ void SensorProxy::dispose() {
}
DEFINE_TRACE(SensorProxy) {
visitor->trace(m_document);
visitor->trace(m_readingUpdater);
visitor->trace(m_reading);
visitor->trace(m_observers);
visitor->trace(m_provider);
......@@ -71,10 +67,6 @@ void SensorProxy::initialize() {
callback);
}
bool SensorProxy::isActive() const {
return isInitialized() && !m_suspended && !m_frequenciesUsed.isEmpty();
}
void SensorProxy::addConfiguration(
SensorConfigurationPtr configuration,
std::unique_ptr<Function<void(bool)>> callback) {
......@@ -101,6 +93,12 @@ void SensorProxy::suspend() {
m_sensor->Suspend();
m_suspended = true;
if (usesPollingTimer())
updatePollingStatus();
for (Observer* observer : m_observers)
observer->onSuspended();
}
void SensorProxy::resume() {
......@@ -111,8 +109,8 @@ void SensorProxy::resume() {
m_sensor->Resume();
m_suspended = false;
if (isActive())
m_readingUpdater->start();
if (usesPollingTimer())
updatePollingStatus();
}
const SensorConfiguration* SensorProxy::defaultConfig() const {
......@@ -120,6 +118,10 @@ const SensorConfiguration* SensorProxy::defaultConfig() const {
return m_defaultConfig.get();
}
bool SensorProxy::usesPollingTimer() const {
return isInitialized() && (m_mode == ReportingMode::CONTINUOUS);
}
void SensorProxy::updateSensorReading() {
DCHECK(isInitialized());
DCHECK(m_readingFactory);
......@@ -134,14 +136,9 @@ void SensorProxy::updateSensorReading() {
}
m_reading = m_readingFactory->createSensorReading(readingData);
}
void SensorProxy::notifySensorChanged(double timestamp) {
// This notification leads to sync 'onchange' event sending, so
// we must cache m_observers as it can be modified within event handlers.
auto copy = m_observers;
for (Observer* observer : copy)
observer->onSensorReadingChanged(timestamp);
for (Observer* observer : m_observers)
observer->onSensorReadingChanged();
}
void SensorProxy::RaiseError() {
......@@ -150,8 +147,7 @@ void SensorProxy::RaiseError() {
void SensorProxy::SensorReadingChanged() {
DCHECK_EQ(ReportingMode::ON_CHANGE, m_mode);
if (isActive())
m_readingUpdater->start();
updateSensorReading();
}
void SensorProxy::pageVisibilityChanged() {
......@@ -173,9 +169,12 @@ void SensorProxy::handleSensorError(ExceptionCode code,
return;
}
m_state = Uninitialized;
m_frequenciesUsed.clear();
if (usesPollingTimer()) { // Stop polling.
m_frequenciesUsed.clear();
updatePollingStatus();
}
m_state = Uninitialized;
// The m_sensor.reset() will release all callbacks and its bound parameters,
// therefore, handleSensorError accepts messages by value.
m_sensor.reset();
......@@ -229,10 +228,7 @@ void SensorProxy::onSensorCreated(SensorInitParamsPtr params,
m_sensor.set_connection_error_handler(
convertToBaseCallback(std::move(errorCallback)));
m_readingUpdater = SensorReadingUpdater::create(this, m_mode);
m_state = Initialized;
for (Observer* observer : m_observers)
observer->onSensorInitialized();
}
......@@ -241,11 +237,9 @@ void SensorProxy::onAddConfigurationCompleted(
double frequency,
std::unique_ptr<Function<void(bool)>> callback,
bool result) {
if (result) {
if (usesPollingTimer() && result) {
m_frequenciesUsed.append(frequency);
std::sort(m_frequenciesUsed.begin(), m_frequenciesUsed.end());
if (isActive())
m_readingUpdater->start();
updatePollingStatus();
}
(*callback)(result);
......@@ -256,6 +250,9 @@ void SensorProxy::onRemoveConfigurationCompleted(double frequency,
if (!result)
DVLOG(1) << "Failure at sensor configuration removal";
if (!usesPollingTimer())
return;
size_t index = m_frequenciesUsed.find(frequency);
if (index == kNotFound) {
// Could happen e.g. if 'handleSensorError' was called before.
......@@ -263,6 +260,7 @@ void SensorProxy::onRemoveConfigurationCompleted(double frequency,
}
m_frequenciesUsed.remove(index);
updatePollingStatus();
}
bool SensorProxy::tryReadFromBuffer(device::SensorReading& result) {
......@@ -278,4 +276,28 @@ bool SensorProxy::tryReadFromBuffer(device::SensorReading& result) {
return true;
}
void SensorProxy::updatePollingStatus() {
DCHECK(usesPollingTimer());
if (m_suspended || m_frequenciesUsed.isEmpty()) {
m_timer.stop();
return;
}
// TODO(Mikhail): Consider using sorted queue instead of searching
// max element each time.
auto it =
std::max_element(m_frequenciesUsed.begin(), m_frequenciesUsed.end());
DCHECK_GT(*it, 0.0);
double repeatInterval = 1 / *it;
if (!m_timer.isActive() || m_timer.repeatInterval() != repeatInterval) {
updateSensorReading();
m_timer.startRepeating(repeatInterval, BLINK_FROM_HERE);
}
}
void SensorProxy::onTimerFired(TimerBase*) {
updateSensorReading();
}
} // namespace blink
......@@ -12,6 +12,7 @@
#include "device/generic_sensor/public/interfaces/sensor_provider.mojom-blink.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "platform/Supplementable.h"
#include "platform/Timer.h"
#include "platform/heap/Handle.h"
#include "wtf/Vector.h"
......@@ -20,7 +21,6 @@ namespace blink {
class SensorProviderProxy;
class SensorReading;
class SensorReadingFactory;
class SensorReadingUpdater;
// This class wraps 'Sensor' mojo interface and used by multiple
// JS sensor instances of the same type (within a single frame).
......@@ -38,16 +38,13 @@ class SensorProxy final : public GarbageCollectedFinalized<SensorProxy>,
// methods can be called.
virtual void onSensorInitialized() {}
// Platfrom sensort reading has changed.
// |timestamp| Reference timestamp in seconds of the moment when
// sensor reading was updated from the buffer.
// Note: |timestamp| values are only used to calculate elapsed time
// between shared buffer readings. These values *do not* correspond
// to sensor reading timestamps which are obtained on platform side.
virtual void onSensorReadingChanged(double timestamp) {}
virtual void onSensorReadingChanged() {}
// An error has occurred.
virtual void onSensorError(ExceptionCode,
const String& sanitizedMessage,
const String& unsanitizedMessage) {}
// Sensor reading change notification is suspended.
virtual void onSuspended() {}
};
~SensorProxy();
......@@ -62,10 +59,6 @@ class SensorProxy final : public GarbageCollectedFinalized<SensorProxy>,
bool isInitializing() const { return m_state == Initializing; }
bool isInitialized() const { return m_state == Initialized; }
// Is watching new reading data (initialized, not suspended and has
// configurations added).
bool isActive() const;
void addConfiguration(device::mojom::blink::SensorConfigurationPtr,
std::unique_ptr<Function<void(bool)>>);
......@@ -86,25 +79,20 @@ class SensorProxy final : public GarbageCollectedFinalized<SensorProxy>,
double maximumFrequency() const { return m_maximumFrequency; }
Document* document() const { return m_document; }
const WTF::Vector<double>& frequenciesUsed() const {
return m_frequenciesUsed;
}
DECLARE_VIRTUAL_TRACE();
private:
friend class SensorProviderProxy;
friend class SensorReadingUpdaterContinuous;
friend class SensorReadingUpdaterOnChange;
SensorProxy(device::mojom::blink::SensorType,
SensorProviderProxy*,
Document*,
Page*,
std::unique_ptr<SensorReadingFactory>);
// Returns true if this instance is using polling timer to
// periodically fetch reading data from shared buffer.
bool usesPollingTimer() const;
// Updates sensor reading from shared buffer.
void updateSensorReading();
void notifySensorChanged(double timestamp);
// device::mojom::blink::SensorClient overrides.
void RaiseError() override;
......@@ -128,7 +116,8 @@ class SensorProxy final : public GarbageCollectedFinalized<SensorProxy>,
void onRemoveConfigurationCompleted(double frequency, bool result);
bool tryReadFromBuffer(device::SensorReading& result);
void onAnimationFrame(double timestamp);
void updatePollingStatus();
void onTimerFired(TimerBase*);
device::mojom::blink::SensorType m_type;
device::mojom::blink::ReportingMode m_mode;
......@@ -145,14 +134,13 @@ class SensorProxy final : public GarbageCollectedFinalized<SensorProxy>,
mojo::ScopedSharedBufferHandle m_sharedBufferHandle;
mojo::ScopedSharedBufferMapping m_sharedBuffer;
bool m_suspended;
Member<Document> m_document;
Member<SensorReading> m_reading;
std::unique_ptr<SensorReadingFactory> m_readingFactory;
double m_maximumFrequency;
Member<SensorReadingUpdater> m_readingUpdater;
// Used for continious reporting mode.
Timer<SensorProxy> m_timer;
WTF::Vector<double> m_frequenciesUsed;
double m_lastRafTimestamp;
using ReadingBuffer = device::SensorReadingSharedBuffer;
static_assert(
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/sensor/SensorReadingUpdater.h"
#include "core/dom/Document.h"
#include "device/generic_sensor/public/interfaces/sensor.mojom-blink.h"
#include "modules/sensor/SensorProxy.h"
#include "wtf/CurrentTime.h"
using device::mojom::blink::ReportingMode;
namespace blink {
SensorReadingUpdater::SensorReadingUpdater(SensorProxy* sensorProxy)
: m_sensorProxy(sensorProxy), m_hasPendingAnimationFrameTask(false) {}
void SensorReadingUpdater::enqueueAnimationFrameTask() {
if (m_hasPendingAnimationFrameTask)
return;
auto callback = WTF::bind(&SensorReadingUpdater::onAnimationFrame,
wrapWeakPersistent(this));
m_sensorProxy->document()->enqueueAnimationFrameTask(std::move(callback));
m_hasPendingAnimationFrameTask = true;
}
void SensorReadingUpdater::start() {
enqueueAnimationFrameTask();
}
void SensorReadingUpdater::onAnimationFrame() {
m_hasPendingAnimationFrameTask = false;
onAnimationFrameInternal();
}
DEFINE_TRACE(SensorReadingUpdater) {
visitor->trace(m_sensorProxy);
}
class SensorReadingUpdaterContinuous : public SensorReadingUpdater {
public:
explicit SensorReadingUpdaterContinuous(SensorProxy* sensorProxy)
: SensorReadingUpdater(sensorProxy) {}
DEFINE_INLINE_VIRTUAL_TRACE() { SensorReadingUpdater::trace(visitor); }
protected:
void onAnimationFrameInternal() override {
if (!m_sensorProxy->isActive())
return;
m_sensorProxy->updateSensorReading();
m_sensorProxy->notifySensorChanged(WTF::monotonicallyIncreasingTime());
enqueueAnimationFrameTask();
}
};
// New data is fetched from shared buffer only once after 'start()'
// call. Further, notification is send until every client is updated
// (i.e. until longest notification period elapses) rAF stops after that.
class SensorReadingUpdaterOnChange : public SensorReadingUpdater {
public:
explicit SensorReadingUpdaterOnChange(SensorProxy* sensorProxy)
: SensorReadingUpdater(sensorProxy),
m_newDataArrivedTime(0.0),
m_newDataArrived(false) {}
DEFINE_INLINE_VIRTUAL_TRACE() { SensorReadingUpdater::trace(visitor); }
void start() override {
m_newDataArrived = true;
SensorReadingUpdater::start();
}
protected:
void onAnimationFrameInternal() override {
if (!m_sensorProxy->isActive())
return;
double timestamp = WTF::monotonicallyIncreasingTime();
if (m_newDataArrived) {
m_newDataArrived = false;
m_sensorProxy->updateSensorReading();
m_newDataArrivedTime = timestamp;
}
m_sensorProxy->notifySensorChanged(timestamp);
DCHECK_GT(m_sensorProxy->frequenciesUsed().front(), 0.0);
double longestNotificationPeriod =
1 / m_sensorProxy->frequenciesUsed().front();
if (timestamp - m_newDataArrivedTime <= longestNotificationPeriod)
enqueueAnimationFrameTask();
}
private:
double m_newDataArrivedTime;
bool m_newDataArrived;
};
// static
SensorReadingUpdater* SensorReadingUpdater::create(SensorProxy* proxy,
ReportingMode mode) {
if (mode == ReportingMode::CONTINUOUS)
return new SensorReadingUpdaterContinuous(proxy);
return new SensorReadingUpdaterOnChange(proxy);
}
} // namespace blink
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SensorReadingUpdater_h
#define SensorReadingUpdater_h
#include "device/generic_sensor/public/interfaces/sensor_provider.mojom-blink.h"
#include "platform/heap/Handle.h"
namespace blink {
class SensorProxy;
// This class encapsulates sensor reading update notification logic.
class SensorReadingUpdater : public GarbageCollected<SensorProxy> {
public:
static SensorReadingUpdater* create(SensorProxy*,
device::mojom::blink::ReportingMode);
virtual void start();
DECLARE_VIRTUAL_TRACE();
protected:
explicit SensorReadingUpdater(SensorProxy*);
void enqueueAnimationFrameTask();
virtual void onAnimationFrameInternal() = 0;
Member<SensorProxy> m_sensorProxy;
bool m_hasPendingAnimationFrameTask;
private:
void onAnimationFrame();
};
} // namespace blink
#endif // SensorReadingUpdater_h
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modules/sensor/SensorUpdateNotificationStrategy.h"
#include "device/generic_sensor/public/interfaces/sensor.mojom-blink.h"
#include "platform/Timer.h"
#include "wtf/CurrentTime.h"
namespace blink {
// Polls the buffer on signal from platform but not more frequently
// than the given 'pollingPeriod'.
class SensorUpdateNotificationStrategyImpl
: public SensorUpdateNotificationStrategy {
public:
SensorUpdateNotificationStrategyImpl(double frequency,
std::unique_ptr<Function<void()>> func)
: m_pollingPeriod(1 / frequency),
m_func(std::move(func)),
m_timer(this, &SensorUpdateNotificationStrategyImpl::onTimer),
m_lastPollingTimestamp(0.0) {
DCHECK_GT(frequency, 0.0);
DCHECK(m_func);
}
private:
// SensorUpdateNotificationStrategy overrides.
void onSensorReadingChanged() override;
void cancelPendingNotifications() override;
void onTimer(TimerBase*);
void notifyUpdate();
double m_pollingPeriod;
std::unique_ptr<Function<void()>> m_func;
Timer<SensorUpdateNotificationStrategyImpl> m_timer;
double m_lastPollingTimestamp;
};
void SensorUpdateNotificationStrategyImpl::onSensorReadingChanged() {
if (m_timer.isActive())
return; // Skipping changes if update notification was already sheduled.
double elapsedTime =
WTF::monotonicallyIncreasingTime() - m_lastPollingTimestamp;
double waitingTime = m_pollingPeriod - elapsedTime;
const double minInterval =
1 / device::mojom::blink::SensorConfiguration::kMaxAllowedFrequency;
// Negative or zero 'waitingTime' means that polling period has elapsed.
// We also avoid scheduling if the elapsed time is slightly behind the
// polling period.
if (waitingTime < minInterval) {
notifyUpdate();
} else {
m_timer.startOneShot(waitingTime, BLINK_FROM_HERE);
}
}
void SensorUpdateNotificationStrategyImpl::cancelPendingNotifications() {
m_timer.stop();
}
void SensorUpdateNotificationStrategyImpl::notifyUpdate() {
m_lastPollingTimestamp = WTF::monotonicallyIncreasingTime();
(*m_func)();
}
void SensorUpdateNotificationStrategyImpl::onTimer(TimerBase*) {
notifyUpdate();
}
// static
std::unique_ptr<SensorUpdateNotificationStrategy>
SensorUpdateNotificationStrategy::create(
double pollingPeriod,
std::unique_ptr<Function<void()>> func) {
return std::unique_ptr<SensorUpdateNotificationStrategy>(
new SensorUpdateNotificationStrategyImpl(pollingPeriod, std::move(func)));
}
} // namespace blink
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SensorUpdateNotificationStrategy_h
#define SensorUpdateNotificationStrategy_h
#include "wtf/Functional.h"
namespace blink {
// This class encapsulates sensor reading update notification logic:
// the callback is invoked after client calls 'onSensorReadingChanged()'
// however considering the given sample frequency:
// guaranteed not to be called more often than expected.
class SensorUpdateNotificationStrategy {
public:
static std::unique_ptr<SensorUpdateNotificationStrategy> create(
double frequency,
std::unique_ptr<Function<void()>>);
virtual void onSensorReadingChanged() = 0;
virtual void cancelPendingNotifications() = 0;
virtual ~SensorUpdateNotificationStrategy() {}
};
} // namespace blink
#endif // SensorUpdateNotificationStrategy_h
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment