blob: b5e16e7422517991b8b99648b6a2f20bdeb423c3 [file] [log] [blame]
#include "sensor_ndk_thread.h"
#include <cutils/log.h>
#include <dvr/performance_client_api.h>
namespace android {
namespace dvr {
namespace {
static constexpr int kLooperIdUser = 5;
} // namespace
SensorNdkThread::SensorNdkThread(bool* out_success)
: shutting_down_(false),
paused_(true),
thread_started_(false),
initialization_result_(false),
looper_(nullptr),
sensor_manager_(nullptr),
event_queue_(nullptr),
sensor_list_(nullptr),
sensor_count_(0) {
// Assume failure; we will change this to true on success.
*out_success = false;
// These structs are the same, but sanity check the sizes.
static_assert(sizeof(sensors_event_t) == sizeof(ASensorEvent),
"Error: sizeof(sensors_event_t) != sizeof(ASensorEvent)");
thread_.reset(new std::thread([this] {
const int priority_error = dvrSetSchedulerClass(0, "sensors:high");
LOG_ALWAYS_FATAL_IF(
priority_error < 0,
"SensorHalTread::StartPolling: Failed to set scheduler class: %s",
strerror(-priority_error));
// Start ALooper and initialize sensor access.
{
std::unique_lock<std::mutex> lock(mutex_);
initialization_result_ = InitializeSensors();
thread_started_ = true;
init_condition_.notify_one();
if (!initialization_result_)
return;
}
EventConsumer consumer;
for (;;) {
for (;;) {
std::unique_lock<std::mutex> lock(mutex_);
UpdateSensorUse();
if (!consumer)
consumer = consumer_;
if (shutting_down_)
return;
if (!paused_)
break;
condition_.wait(lock);
}
constexpr int kMaxEvents = 100;
sensors_event_t events[kMaxEvents];
ssize_t event_count = 0;
if (looper_ && sensor_manager_) {
int poll_fd, poll_events;
void* poll_source;
// Poll for events.
int ident = ALooper_pollAll(-1, &poll_fd, &poll_events, &poll_source);
if (ident != kLooperIdUser)
continue;
ASensorEvent* event = reinterpret_cast<ASensorEvent*>(&events[0]);
event_count =
ASensorEventQueue_getEvents(event_queue_, event, kMaxEvents);
if (event_count == 0) {
ALOGE("Detected sensor service failure, restarting sensors");
// This happens when sensorservice has died and restarted. To avoid
// spinning we need to restart the sensor access.
DestroySensors();
InitializeSensors();
}
} else {
// When there is no sensor_device_, we still call the consumer at
// regular intervals in case mock poses are in use. Note that this
// will never be the case for production devices, but this helps
// during bringup.
usleep(5000);
}
if (event_count == kMaxEvents)
ALOGI("max events (%d) reached", kMaxEvents);
if (event_count >= 0) {
consumer(events, events + event_count);
} else {
ALOGE(
"SensorNdkThread::StartPolling: Error while polling sensor: %s "
"(%zd)",
strerror(-event_count), -event_count);
}
}
// About to exit sensor thread, destroy sensor objects.
DestroySensors();
}));
// Wait for thread to startup and initialize sensors so that we know whether
// it succeeded.
{
std::unique_lock<std::mutex> lock(mutex_);
while (!thread_started_)
init_condition_.wait(lock);
}
// At this point, we've successfully initialized everything.
*out_success = initialization_result_;
}
SensorNdkThread::~SensorNdkThread() {
{
if (looper_)
ALooper_wake(looper_);
std::unique_lock<std::mutex> lock(mutex_);
shutting_down_ = true;
condition_.notify_one();
}
thread_->join();
}
bool SensorNdkThread::InitializeSensors() {
looper_ = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
if (!looper_) {
ALOGE("Failed to create ALooper.");
return false;
}
// Prepare to monitor accelerometer
sensor_manager_ = ASensorManager_getInstanceForPackage(nullptr);
if (!sensor_manager_) {
ALOGE("Failed to create ASensorManager.");
return false;
}
event_queue_ = ASensorManager_createEventQueue(
sensor_manager_, looper_, kLooperIdUser, nullptr, nullptr);
if (!event_queue_) {
ALOGE("Failed to create sensor EventQueue.");
return false;
}
sensor_count_ = ASensorManager_getSensorList(sensor_manager_, &sensor_list_);
ALOGI("Sensor count %d", sensor_count_);
sensor_user_count_.resize(sensor_count_, 0);
// To recover from sensorservice restart, enable the sensors that are already
// requested.
for (size_t sensor_index = 0; sensor_index < sensor_user_count_.size();
++sensor_index) {
if (sensor_user_count_[sensor_index] > 0) {
int result = ASensorEventQueue_registerSensor(
event_queue_, sensor_list_[sensor_index], 0, 0);
ALOGE_IF(result < 0, "ASensorEventQueue_registerSensor failed: %d",
result);
}
}
return true;
}
void SensorNdkThread::DestroySensors() {
for (size_t sensor_index = 0; sensor_index < sensor_user_count_.size();
++sensor_index) {
if (sensor_user_count_[sensor_index] > 0) {
ASensorEventQueue_disableSensor(event_queue_, sensor_list_[sensor_index]);
}
}
ASensorManager_destroyEventQueue(sensor_manager_, event_queue_);
}
void SensorNdkThread::UpdateSensorUse() {
if (!enable_sensors_.empty()) {
for (int sensor_index : enable_sensors_) {
if (sensor_user_count_[sensor_index]++ == 0) {
int result = ASensorEventQueue_registerSensor(
event_queue_, sensor_list_[sensor_index], 0, 0);
ALOGE_IF(result < 0, "ASensorEventQueue_registerSensor failed: %d",
result);
}
}
enable_sensors_.clear();
}
if (!disable_sensors_.empty()) {
for (int sensor_index : disable_sensors_) {
if (--sensor_user_count_[sensor_index] == 0) {
int result = ASensorEventQueue_disableSensor(
event_queue_, sensor_list_[sensor_index]);
ALOGE_IF(result < 0, "ASensorEventQueue_disableSensor failed: %d",
result);
}
}
disable_sensors_.clear();
}
}
void SensorNdkThread::StartPolling(const EventConsumer& consumer) {
{
std::unique_lock<std::mutex> lock(mutex_);
if (consumer_) {
ALOGE("Already started sensor thread.");
return;
}
consumer_ = consumer;
}
SetPaused(false);
}
void SensorNdkThread::SetPaused(bool is_paused) {
std::unique_lock<std::mutex> lock(mutex_);
// SetPaused may be called before we have StartPolling, make sure we have
// an event consumer. Otherwise we defer until StartPolling is called.
if (!consumer_)
return;
paused_ = is_paused;
condition_.notify_one();
ALooper_wake(looper_);
}
void SensorNdkThread::StartUsingSensor(const int sensor_index) {
std::unique_lock<std::mutex> lock(mutex_);
if (sensor_index < 0 || sensor_index >= sensor_count_) {
ALOGE("StartUsingSensor(): sensor index %d out of range [0, %d)",
sensor_index, sensor_count_);
return;
}
enable_sensors_.push_back(sensor_index);
ALooper_wake(looper_);
}
void SensorNdkThread::StopUsingSensor(const int sensor_index) {
std::unique_lock<std::mutex> lock(mutex_);
if (sensor_index < 0 || sensor_index >= sensor_count_) {
ALOGE("StopUsingSensor(): sensor index %d out of range [0, %d)",
sensor_index, sensor_count_);
return;
}
disable_sensors_.push_back(sensor_index);
ALooper_wake(looper_);
}
} // namespace dvr
} // namespace android