blob: 4396851c4625119d49c6f2a983d9dd926030abfd [file] [log] [blame]
#include "sensor_service.h"
#include <cutils/log.h>
#include <hardware/sensors.h>
#include <poll.h>
#include <pdx/default_transport/service_endpoint.h>
#include <private/dvr/sensor-ipc.h>
#include <time.h>
using android::pdx::default_transport::Endpoint;
namespace android {
namespace dvr {
SensorService::SensorService(SensorThread* sensor_thread)
: BASE("SensorService", Endpoint::Create(DVR_SENSOR_SERVICE_CLIENT)),
sensor_thread_(sensor_thread) {
sensor_clients_.resize(sensor_thread_->GetSensorCount());
for (int i = 0; i < sensor_thread_->GetSensorCount(); ++i)
type_to_sensor_[sensor_thread_->GetSensorType(i)] = i;
}
std::shared_ptr<pdx::Channel> SensorService::OnChannelOpen(pdx::Message& msg) {
std::lock_guard<std::mutex> guard(mutex_);
const pdx::MessageInfo& info = msg.GetInfo();
std::shared_ptr<SensorClient> client(
new SensorClient(*this, info.pid, info.cid));
AddClient(client);
return client;
}
void SensorService::OnChannelClose(pdx::Message& /*msg*/,
const std::shared_ptr<pdx::Channel>& chan) {
std::lock_guard<std::mutex> guard(mutex_);
auto client = std::static_pointer_cast<SensorClient>(chan);
if (!client) {
ALOGW("WARNING: SensorClient was NULL!\n");
return;
}
RemoveClient(client);
}
void SensorService::AddClient(const std::shared_ptr<SensorClient>& client) {
clients_.push_front(client);
}
void SensorService::RemoveClient(const std::shared_ptr<SensorClient>& client) {
// First remove it from the clients associated with its sensor, if any.
RemoveSensorClient(client.get());
// Finally, remove it from the list of clients we're aware of, and decrease
// its reference count.
clients_.remove(client);
}
void SensorService::RemoveSensorClient(SensorClient* client) {
if (!client->has_sensor())
return;
std::forward_list<SensorClient*>& sensor_clients =
sensor_clients_[client->sensor()];
sensor_clients.remove(client);
sensor_thread_->StopUsingSensor(client->sensor());
client->unset_sensor();
}
int SensorService::HandleMessage(pdx::Message& msg) {
int ret = 0;
const pdx::MessageInfo& info = msg.GetInfo();
switch (info.op) {
case DVR_SENSOR_START: {
std::lock_guard<std::mutex> guard(mutex_);
// Associate this channel with the indicated sensor,
// unless it already has an association. In that case,
// fail.
auto client = std::static_pointer_cast<SensorClient>(msg.GetChannel());
if (client->has_sensor())
REPLY_ERROR(msg, EINVAL, error);
int sensor_type;
if (msg.Read(&sensor_type, sizeof(sensor_type)) <
(ssize_t)sizeof(sensor_type))
REPLY_ERROR(msg, EIO, error);
// Find the sensor of the requested type.
if (type_to_sensor_.find(sensor_type) == type_to_sensor_.end())
REPLY_ERROR(msg, EINVAL, error);
const int sensor_index = type_to_sensor_[sensor_type];
sensor_clients_[sensor_index].push_front(client.get());
client->set_sensor(sensor_index);
sensor_thread_->StartUsingSensor(sensor_index);
REPLY_SUCCESS(msg, 0, error);
}
case DVR_SENSOR_STOP: {
std::lock_guard<std::mutex> guard(mutex_);
auto client = std::static_pointer_cast<SensorClient>(msg.GetChannel());
if (!client->has_sensor())
REPLY_ERROR(msg, EINVAL, error);
RemoveSensorClient(client.get());
REPLY_SUCCESS(msg, 0, error);
}
case DVR_SENSOR_POLL: {
std::lock_guard<std::mutex> guard(mutex_);
auto client = std::static_pointer_cast<SensorClient>(msg.GetChannel());
// Package up the events we've got for this client. Number of
// events, followed by 0 or more sensor events, popped from
// this client's queue until it's empty.
int num_events = client->EventCount();
sensors_event_t out_buffer[num_events];
client->WriteEvents(out_buffer);
struct iovec svec[] = {
{.iov_base = &num_events, .iov_len = sizeof(num_events)},
{.iov_base = out_buffer,
.iov_len = num_events * sizeof(sensors_event_t)},
};
ret = msg.WriteVector(svec, 2);
int expected_size = sizeof(int) + num_events * sizeof(sensors_event_t);
if (ret < expected_size) {
ALOGI("error: msg.WriteVector wrote too little.");
REPLY_ERROR(msg, EIO, error);
}
REPLY_SUCCESS(msg, 0, error);
}
default:
// Do not lock mutex_ here, because this may call the on*() handlers,
// which will lock the mutex themselves.
ret = Service::HandleMessage(msg);
break;
}
error:
return ret;
}
void SensorService::EnqueueEvents(const sensors_event_t* begin_events,
const sensors_event_t* end_events) {
std::lock_guard<std::mutex> guard(mutex_);
// Put the sensor values we got in the circular queue for each client that
// cares about the given event.
for (const sensors_event_t* event = begin_events; event != end_events;
++event) {
const int sensor_index = type_to_sensor_[event->type];
for (const auto& client : sensor_clients_[sensor_index]) {
client->EnqueueEvent(*event);
}
}
}
void SensorClient::WriteEvents(sensors_event_t* buffer) {
while (!event_queue_.Empty()) {
*buffer = *(event_queue_.Top());
event_queue_.Pop();
++buffer;
}
}
void SensorClient::CircularQ::Push(const sensors_event_t& event) {
if (count_ != 0 && head_ == tail_) {
Pop(); // If we're full, throw away the oldest event.
}
events_[head_] = event;
head_ = (head_ + 1) % kCqSize;
++count_;
}
const sensors_event_t* SensorClient::CircularQ::Top() const {
if (count_ == 0)
return nullptr;
return &events_[tail_];
}
void SensorClient::CircularQ::Pop() {
if (count_ == 0)
return;
tail_ = (tail_ + 1) % kCqSize;
--count_;
}
} // namespace dvr
} // namespace android