Bug 1194721: Add poll interface and module for Gonk sensors, r=gsvelto

The sensor daemon's poll service reads events from the device's
sensors. This patch adds Gecko support for this service. Gecko
receives information about existing sensors and can subscribe to
sensor events. Events will be delivered for each enabled sensor.
This commit is contained in:
Thomas Zimmermann 2016-02-04 12:35:13 +01:00
parent fa3a3b1b24
commit b35d1a74c1
3 changed files with 774 additions and 0 deletions

View File

@ -0,0 +1,430 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GonkSensorsPollInterface.h"
#include "HalLog.h"
namespace mozilla {
namespace hal {
using namespace mozilla::ipc;
//
// GonkSensorsPollResultHandler
//
void
GonkSensorsPollResultHandler::OnError(SensorsError aError)
{
HAL_ERR("Received error code %d", static_cast<int>(aError));
}
void
GonkSensorsPollResultHandler::EnableSensor()
{ }
void
GonkSensorsPollResultHandler::DisableSensor()
{ }
void
GonkSensorsPollResultHandler::SetPeriod()
{ }
GonkSensorsPollResultHandler::~GonkSensorsPollResultHandler()
{ }
//
// GonkSensorsPollNotificationHandler
//
void
GonkSensorsPollNotificationHandler::ErrorNotification(SensorsError aError)
{
HAL_ERR("Received error code %d", static_cast<int>(aError));
}
void
GonkSensorsPollNotificationHandler::SensorDetectedNotification(
int32_t aId,
SensorsType aType,
float aRange,
float aResolution,
float aPower,
int32_t aMinPeriod,
int32_t aMaxPeriod,
SensorsTriggerMode aTriggerMode,
SensorsDeliveryMode aDeliveryMode)
{ }
void
GonkSensorsPollNotificationHandler::SensorLostNotification(int32_t aId)
{ }
void
GonkSensorsPollNotificationHandler::EventNotification(int32_t aId,
const SensorsEvent& aEvent)
{ }
GonkSensorsPollNotificationHandler::~GonkSensorsPollNotificationHandler()
{ }
//
// GonkSensorsPollModule
//
GonkSensorsPollModule::GonkSensorsPollModule()
: mProtocolVersion(0)
{ }
GonkSensorsPollModule::~GonkSensorsPollModule()
{ }
nsresult
GonkSensorsPollModule::SetProtocolVersion(unsigned long aProtocolVersion)
{
if ((aProtocolVersion < MIN_PROTOCOL_VERSION) ||
(aProtocolVersion > MAX_PROTOCOL_VERSION)) {
HAL_ERR("Sensors Poll protocol version %lu not supported",
aProtocolVersion);
return NS_ERROR_ILLEGAL_VALUE;
}
mProtocolVersion = aProtocolVersion;
return NS_OK;
}
void
GonkSensorsPollModule::HandleSvc(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
DaemonSocketResultHandler* aRes)
{
static void (GonkSensorsPollModule::* const HandleOp[])(
const DaemonSocketPDUHeader&, DaemonSocketPDU&,
DaemonSocketResultHandler*) = {
[0] = &GonkSensorsPollModule::HandleRsp,
[1] = &GonkSensorsPollModule::HandleNtf
};
MOZ_ASSERT(!NS_IsMainThread()); // I/O thread
// Negate twice to map bit to 0/1
unsigned long isNtf = !!(aHeader.mOpcode & 0x80);
(this->*(HandleOp[isNtf]))(aHeader, aPDU, aRes);
}
// Commands
//
nsresult
GonkSensorsPollModule::EnableSensorCmd(int32_t aId, GonkSensorsPollResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoPtr<DaemonSocketPDU> pdu(
new DaemonSocketPDU(SERVICE_ID, OPCODE_ENABLE_SENSOR, 0));
nsresult rv = PackPDU(aId, *pdu);
if (NS_FAILED(rv)) {
return rv;
}
rv = Send(pdu, aRes);
if (NS_FAILED(rv)) {
return rv;
}
Unused << pdu.forget();
return NS_OK;
}
nsresult
GonkSensorsPollModule::DisableSensorCmd(int32_t aId, GonkSensorsPollResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoPtr<DaemonSocketPDU> pdu(
new DaemonSocketPDU(SERVICE_ID, OPCODE_DISABLE_SENSOR, 0));
nsresult rv = PackPDU(aId, *pdu);
if (NS_FAILED(rv)) {
return rv;
}
rv = Send(pdu, aRes);
if (NS_FAILED(rv)) {
return rv;
}
Unused << pdu.forget();
return NS_OK;
}
nsresult
GonkSensorsPollModule::SetPeriodCmd(int32_t aId, uint64_t aPeriod,
GonkSensorsPollResultHandler* aRes)
{
MOZ_ASSERT(NS_IsMainThread());
nsAutoPtr<DaemonSocketPDU> pdu(
new DaemonSocketPDU(SERVICE_ID, OPCODE_SET_PERIOD, 0));
nsresult rv = PackPDU(aId, *pdu);
if (NS_FAILED(rv)) {
return rv;
}
rv = PackPDU(aPeriod, *pdu);
if (NS_FAILED(rv)) {
return rv;
}
rv = Send(pdu, aRes);
if (NS_FAILED(rv)) {
return rv;
}
Unused << pdu.forget();
return NS_OK;
}
// Responses
//
void
GonkSensorsPollModule::ErrorRsp(
const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU, GonkSensorsPollResultHandler* aRes)
{
ErrorRunnable::Dispatch(
aRes, &GonkSensorsPollResultHandler::OnError, UnpackPDUInitOp(aPDU));
}
void
GonkSensorsPollModule::EnableSensorRsp(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
GonkSensorsPollResultHandler* aRes)
{
ResultRunnable::Dispatch(
aRes, &GonkSensorsPollResultHandler::EnableSensor, UnpackPDUInitOp(aPDU));
}
void
GonkSensorsPollModule::DisableSensorRsp(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
GonkSensorsPollResultHandler* aRes)
{
ResultRunnable::Dispatch(
aRes, &GonkSensorsPollResultHandler::DisableSensor, UnpackPDUInitOp(aPDU));
}
void
GonkSensorsPollModule::SetPeriodRsp(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
GonkSensorsPollResultHandler* aRes)
{
ResultRunnable::Dispatch(
aRes, &GonkSensorsPollResultHandler::SetPeriod, UnpackPDUInitOp(aPDU));
}
void
GonkSensorsPollModule::HandleRsp(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
DaemonSocketResultHandler* aRes)
{
static void (GonkSensorsPollModule::* const sHandleRsp[])(
const DaemonSocketPDUHeader&, DaemonSocketPDU&,
GonkSensorsPollResultHandler*) = {
[OPCODE_ERROR] = &GonkSensorsPollModule::ErrorRsp,
[OPCODE_ENABLE_SENSOR] = &GonkSensorsPollModule::EnableSensorRsp,
[OPCODE_DISABLE_SENSOR] = &GonkSensorsPollModule::DisableSensorRsp,
[OPCODE_SET_PERIOD] = &GonkSensorsPollModule::SetPeriodRsp,
};
MOZ_ASSERT(!NS_IsMainThread()); // I/O thread
if (!(aHeader.mOpcode < MOZ_ARRAY_LENGTH(sHandleRsp)) ||
!sHandleRsp[aHeader.mOpcode]) {
HAL_ERR("Sensors poll response opcode %d unknown", aHeader.mOpcode);
return;
}
RefPtr<GonkSensorsPollResultHandler> res =
static_cast<GonkSensorsPollResultHandler*>(aRes);
if (!res) {
return; // Return early if no result handler has been set for response
}
(this->*(sHandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res);
}
// Notifications
//
// Returns the current notification handler to a notification runnable
class GonkSensorsPollModule::NotificationHandlerWrapper final
{
public:
typedef GonkSensorsPollNotificationHandler ObjectType;
static ObjectType* GetInstance()
{
MOZ_ASSERT(NS_IsMainThread());
return sNotificationHandler;
}
static GonkSensorsPollNotificationHandler* sNotificationHandler;
};
GonkSensorsPollNotificationHandler*
GonkSensorsPollModule::NotificationHandlerWrapper::sNotificationHandler;
void
GonkSensorsPollModule::ErrorNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
ErrorNotification::Dispatch(
&GonkSensorsPollNotificationHandler::ErrorNotification,
UnpackPDUInitOp(aPDU));
}
void
GonkSensorsPollModule::SensorDetectedNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
SensorDetectedNotification::Dispatch(
&GonkSensorsPollNotificationHandler::SensorDetectedNotification,
UnpackPDUInitOp(aPDU));
}
void
GonkSensorsPollModule::SensorLostNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
SensorLostNotification::Dispatch(
&GonkSensorsPollNotificationHandler::SensorLostNotification,
UnpackPDUInitOp(aPDU));
}
void
GonkSensorsPollModule::EventNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
{
EventNotification::Dispatch(
&GonkSensorsPollNotificationHandler::EventNotification,
UnpackPDUInitOp(aPDU));
}
void
GonkSensorsPollModule::HandleNtf(
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
DaemonSocketResultHandler* aRes)
{
static void (GonkSensorsPollModule::* const sHandleNtf[])(
const DaemonSocketPDUHeader&, DaemonSocketPDU&) = {
[0] = &GonkSensorsPollModule::ErrorNtf,
[1] = &GonkSensorsPollModule::SensorDetectedNtf,
[2] = &GonkSensorsPollModule::SensorLostNtf,
[3] = &GonkSensorsPollModule::EventNtf
};
MOZ_ASSERT(!NS_IsMainThread());
uint8_t index = aHeader.mOpcode - 0x80;
if (!(index < MOZ_ARRAY_LENGTH(sHandleNtf)) || !sHandleNtf[index]) {
HAL_ERR("Sensors poll notification opcode %d unknown", aHeader.mOpcode);
return;
}
(this->*(sHandleNtf[index]))(aHeader, aPDU);
}
//
// GonkSensorsPollInterface
//
GonkSensorsPollInterface::GonkSensorsPollInterface(
GonkSensorsPollModule* aModule)
: mModule(aModule)
{ }
GonkSensorsPollInterface::~GonkSensorsPollInterface()
{ }
void
GonkSensorsPollInterface::SetNotificationHandler(
GonkSensorsPollNotificationHandler* aNotificationHandler)
{
MOZ_ASSERT(NS_IsMainThread());
GonkSensorsPollModule::NotificationHandlerWrapper::sNotificationHandler =
aNotificationHandler;
}
nsresult
GonkSensorsPollInterface::SetProtocolVersion(unsigned long aProtocolVersion)
{
MOZ_ASSERT(mModule);
return mModule->SetProtocolVersion(aProtocolVersion);
}
void
GonkSensorsPollInterface::EnableSensor(int32_t aId,
GonkSensorsPollResultHandler* aRes)
{
MOZ_ASSERT(mModule);
nsresult rv = mModule->EnableSensorCmd(aId, aRes);
if (NS_FAILED(rv)) {
DispatchError(aRes, rv);
}
}
void
GonkSensorsPollInterface::DisableSensor(int32_t aId,
GonkSensorsPollResultHandler* aRes)
{
MOZ_ASSERT(mModule);
nsresult rv = mModule->DisableSensorCmd(aId, aRes);
if (NS_FAILED(rv)) {
DispatchError(aRes, rv);
}
}
void
GonkSensorsPollInterface::SetPeriod(int32_t aId, uint64_t aPeriod,
GonkSensorsPollResultHandler* aRes)
{
MOZ_ASSERT(mModule);
nsresult rv = mModule->SetPeriodCmd(aId, aPeriod, aRes);
if (NS_FAILED(rv)) {
DispatchError(aRes, rv);
}
}
void
GonkSensorsPollInterface::DispatchError(
GonkSensorsPollResultHandler* aRes, SensorsError aError)
{
DaemonResultRunnable1<GonkSensorsPollResultHandler, void,
SensorsError, SensorsError>::Dispatch(
aRes, &GonkSensorsPollResultHandler::OnError,
ConstantInitOp1<SensorsError>(aError));
}
void
GonkSensorsPollInterface::DispatchError(
GonkSensorsPollResultHandler* aRes, nsresult aRv)
{
SensorsError error;
if (NS_FAILED(Convert(aRv, error))) {
error = SENSORS_ERROR_FAIL;
}
DispatchError(aRes, error);
}
} // namespace hal
} // namespace mozilla

View File

@ -0,0 +1,343 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* The poll interface gives yo access to the Sensors daemon's Poll service,
* which handles sensors. The poll service will inform you when sensors are
* detected or removed from the system. You can activate (or deactivate)
* existing sensors and poll will deliver the sensors' events.
*
* All public methods and callback methods run on the main thread.
*/
#ifndef hal_gonk_GonkSensorsPollInterface_h
#define hal_gonk_GonkSensorsPollInterface_h
#include <mozilla/ipc/DaemonRunnables.h>
#include <mozilla/ipc/DaemonSocketMessageHandlers.h>
#include "SensorsTypes.h"
namespace mozilla {
namespace ipc {
class DaemonSocketPDU;
class DaemonSocketPDUHeader;
}
}
namespace mozilla {
namespace hal {
class SensorsInterface;
using mozilla::ipc::DaemonSocketPDU;
using mozilla::ipc::DaemonSocketPDUHeader;
using mozilla::ipc::DaemonSocketResultHandler;
/**
* This class is the result-handler interface for the Sensors
* Poll interface. Methods always run on the main thread.
*/
class GonkSensorsPollResultHandler : public DaemonSocketResultHandler
{
public:
/**
* Called if a poll command failed.
*
* @param aError The error code.
*/
virtual void OnError(SensorsError aError);
/**
* The callback method for |GonkSensorsPollInterface::EnableSensor|.
*/
virtual void EnableSensor();
/**
* The callback method for |GonkSensorsPollInterface::DisableSensor|.
*/
virtual void DisableSensor();
/**
* The callback method for |GonkSensorsPollInterface::SetPeriod|.
*/
virtual void SetPeriod();
protected:
virtual ~GonkSensorsPollResultHandler();
};
/**
* This is the notification-handler interface. Implement this classes
* methods to handle event and notifications from the sensors daemon.
*/
class GonkSensorsPollNotificationHandler
{
public:
/**
* The notification handler for errors. You'll receive this call if
* there's been a critical error in the daemon. Either try to handle
* the error, or restart the daemon.
*
* @param aError The error code.
*/
virtual void ErrorNotification(SensorsError aError);
/**
* This methods gets call when a new sensor has been detected.
*
* @param aId The sensor's id.
* @param aType The sensor's type.
* @param aRange The sensor's maximum value.
* @param aResolution The minimum difference between two consecutive values.
* @param aPower The sensor's power consumption (in mA).
* @param aMinPeriod The minimum time between two events (in ns).
* @param aMaxPeriod The maximum time between two events (in ns).
* @param aTriggerMode The sensor's mode for triggering events.
* @param aDeliveryMode The sensor's urgency for event delivery.
*/
virtual void SensorDetectedNotification(int32_t aId, SensorsType aType,
float aRange, float aResolution,
float aPower, int32_t aMinPeriod,
int32_t aMaxPeriod,
SensorsTriggerMode aTriggerMode,
SensorsDeliveryMode aDeliveryMode);
/**
* This methods gets call when an existing sensor has been removed.
*
* @param aId The sensor's id.
*/
virtual void SensorLostNotification(int32_t aId);
/**
* This is the callback methods for sensor events. Only activated sensors
* generate events. All sensors are disabled by default. The actual data
* of the event depends on the sensor type.
*
* @param aId The sensor's id.
* @param aEvent The event's data.
*/
virtual void EventNotification(int32_t aId, const SensorsEvent& aEvent);
protected:
virtual ~GonkSensorsPollNotificationHandler();
};
/**
* This is the module class for the Sensors poll component. It handles PDU
* packing and unpacking. Methods are either executed on the main thread or
* the I/O thread.
*
* This is an internal class, use |GonkSensorsPollInterface| instead.
*/
class GonkSensorsPollModule
{
public:
class NotificationHandlerWrapper;
enum {
SERVICE_ID = 0x01
};
enum {
OPCODE_ERROR = 0x00,
OPCODE_ENABLE_SENSOR = 0x01,
OPCODE_DISABLE_SENSOR = 0x02,
OPCODE_SET_PERIOD = 0x03
};
enum {
MIN_PROTOCOL_VERSION = 1,
MAX_PROTOCOL_VERSION = 1
};
virtual nsresult Send(DaemonSocketPDU* aPDU,
DaemonSocketResultHandler* aRes) = 0;
nsresult SetProtocolVersion(unsigned long aProtocolVersion);
//
// Commands
//
nsresult EnableSensorCmd(int32_t aId,
GonkSensorsPollResultHandler* aRes);
nsresult DisableSensorCmd(int32_t aId,
GonkSensorsPollResultHandler* aRes);
nsresult SetPeriodCmd(int32_t aId, uint64_t aPeriod,
GonkSensorsPollResultHandler* aRes);
protected:
GonkSensorsPollModule();
virtual ~GonkSensorsPollModule();
void HandleSvc(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
DaemonSocketResultHandler* aRes);
private:
//
// Responses
//
typedef mozilla::ipc::DaemonResultRunnable0<
GonkSensorsPollResultHandler, void>
ResultRunnable;
typedef mozilla::ipc::DaemonResultRunnable1<
GonkSensorsPollResultHandler, void, SensorsError, SensorsError>
ErrorRunnable;
void ErrorRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
GonkSensorsPollResultHandler* aRes);
void EnableSensorRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
GonkSensorsPollResultHandler* aRes);
void DisableSensorRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
GonkSensorsPollResultHandler* aRes);
void SetPeriodRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
GonkSensorsPollResultHandler* aRes);
void HandleRsp(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
DaemonSocketResultHandler* aRes);
//
// Notifications
//
typedef mozilla::ipc::DaemonNotificationRunnable1<
NotificationHandlerWrapper, void, SensorsError>
ErrorNotification;
typedef mozilla::ipc::DaemonNotificationRunnable9<
NotificationHandlerWrapper, void, int32_t, SensorsType,
float, float, float, int32_t, int32_t, SensorsTriggerMode,
SensorsDeliveryMode>
SensorDetectedNotification;
typedef mozilla::ipc::DaemonNotificationRunnable1<
NotificationHandlerWrapper, void, int32_t>
SensorLostNotification;
typedef mozilla::ipc::DaemonNotificationRunnable2<
NotificationHandlerWrapper, void, int32_t, SensorsEvent, int32_t,
const SensorsEvent&>
EventNotification;
class SensorDetectedInitOp;
class SensorLostInitOp;
class EventInitOp;
void ErrorNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void SensorDetectedNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void SensorLostNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void EventNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU);
void HandleNtf(const DaemonSocketPDUHeader& aHeader,
DaemonSocketPDU& aPDU,
DaemonSocketResultHandler* aRes);
private:
unsigned long mProtocolVersion;
};
/**
* This class implements the public interface to the Sensors poll
* component. Use |SensorsInterface::GetPollInterface| to retrieve
* an instance. All methods run on the main thread.
*/
class GonkSensorsPollInterface final
{
public:
friend class GonkSensorsInterface;
/**
* This method sets the notification handler for poll notifications. Call
* this method immediately after registering the module. Otherwise you won't
* be able able to receive poll notifications. You may not free the handler
* class while the poll component is regsitered.
*
* @param aNotificationHandler An instance of a poll notification handler.
*/
void SetNotificationHandler(
GonkSensorsPollNotificationHandler* aNotificationHandler);
/**
* This method sets the protocol version. You should set it to the
* value that has been returned from the backend when registering the
* Poll service. You cannot send or receive messages before setting
* the protocol version.
*
* @param aProtocolVersion
* @return NS_OK for supported versions, or an XPCOM error code otherwise.
*/
nsresult SetProtocolVersion(unsigned long aProtocolVersion);
/**
* Enables an existing sensor. The sensor id will have been delivered in
* a SensorDetectedNotification.
*
* @param aId The sensor's id.
* @param aRes The result handler.
*/
void EnableSensor(int32_t aId, GonkSensorsPollResultHandler* aRes);
/**
* Disables an existing sensor. The sensor id will have been delivered in
* a SensorDetectedNotification.
*
* @param aId The sensor's id.
* @param aRes The result handler.
*/
void DisableSensor(int32_t aId, GonkSensorsPollResultHandler* aRes);
/**
* Sets the period for a sensor. The sensor id will have been delivered in
* a SensorDetectedNotification. The value for the period should be between
* the sensor's minimum and maximum period.
*
* @param aId The sensor's id.
* @param aPeriod The sensor's new period.
* @param aRes The result handler.
*/
void SetPeriod(int32_t aId, uint64_t aPeriod, GonkSensorsPollResultHandler* aRes);
~GonkSensorsPollInterface();
private:
GonkSensorsPollInterface(GonkSensorsPollModule* aModule);
void DispatchError(GonkSensorsPollResultHandler* aRes, SensorsError aError);
void DispatchError(GonkSensorsPollResultHandler* aRes, nsresult aRv);
GonkSensorsPollModule* mModule;
};
} // hal
} // namespace mozilla
#endif // hal_gonk_GonkSensorsPollInterface_h

View File

@ -52,6 +52,7 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
'gonk/GonkFMRadio.cpp',
'gonk/GonkSensor.cpp',
'gonk/GonkSensorsHelpers.cpp',
'gonk/GonkSensorsPollInterface.cpp',
'gonk/GonkSensorsRegistryInterface.cpp',
'gonk/GonkSwitch.cpp',
'gonk/SystemService.cpp',