diff --git a/core/hybris.pro b/core/hybris.pro index a9c87dc..4804826 100644 --- a/core/hybris.pro +++ b/core/hybris.pro @@ -13,8 +13,18 @@ SENSORFW_INCLUDEPATHS = .. \ DEPENDPATH += $$SENSORFW_INCLUDEPATHS INCLUDEPATH += $$SENSORFW_INCLUDEPATHS -SOURCES += hybrisadaptor.cpp -HEADERS += hybrisadaptor.h +SOURCES += hybrisadaptor.cpp \ + hybrisbackend.cpp \ + hybrisbackend_binder.cpp \ + hybrisbackend_binder_aidl.cpp \ + hybrisbackend_binder_hidl.cpp \ + hybrisbackend_hal.cpp +HEADERS += hybrisadaptor.h \ + hybrisbackend.h \ + hybrisbackend_binder.h \ + hybrisbackend_binder_aidl.h \ + hybrisbackend_binder_hidl.h \ + hybrisbackend_hal.h LIBS += -L$$[QT_INSTALL_LIBS] -L../datatypes -lsensordatatypes-qt$${QT_MAJOR_VERSION} -L. -lsensorfw-qt$${QT_MAJOR_VERSION} CONFIG += link_pkgconfig diff --git a/core/hybrisadaptor.cpp b/core/hybrisadaptor.cpp index 3c78feb..a6bbaf8 100644 --- a/core/hybrisadaptor.cpp +++ b/core/hybrisadaptor.cpp @@ -2,6 +2,7 @@ ** ** Copyright (c) 2013 Jolla Ltd. ** Copyright (c) 2025 Jollyboys Ltd. +** Copyright (c) 2026 Jolla Mobile Ltd ** ** ** $QT_BEGIN_LICENSE:LGPL$ @@ -19,6 +20,7 @@ ****************************************************************************/ #include "hybrisadaptor.h" +#include "hybrisbackend.h" #include "deviceadaptor.h" #include "config.h" @@ -26,59 +28,18 @@ #include #include -#ifndef USE_BINDER -#include -#endif - -#include -#include - -#include #include #include #include #include -#ifdef USE_BINDER -#define SENSOR_BINDER_SERVICE_DEVICE "/dev/hwbinder" -#define SENSOR_BINDER_SERVICE_IFACE_1_0 "android.hardware.sensors@1.0::ISensors" -#define SENSOR_BINDER_SERVICE_NAME_1_0 SENSOR_BINDER_SERVICE_IFACE_1_0 "/default" -#define SENSOR_BINDER_SERVICE_IFACE_2_0 "android.hardware.sensors@2.0::ISensors" -#define SENSOR_BINDER_SERVICE_NAME_2_0 SENSOR_BINDER_SERVICE_IFACE_2_0 "/default" -#define SENSOR_BINDER_SERVICE_CALLBACK_IFACE_2_0 "android.hardware.sensors@2.0::ISensorsCallback" -#define SENSOR_BINDER_SERVICE_IFACE_2_1 "android.hardware.sensors@2.1::ISensors" -#define SENSOR_BINDER_SERVICE_NAME_2_1 SENSOR_BINDER_SERVICE_IFACE_2_1 "/default" -#define SENSOR_BINDER_SERVICE_CALLBACK_IFACE_2_1 "android.hardware.sensors@2.1::ISensorsCallback" -#define MAX_RECEIVE_BUFFER_EVENT_COUNT 128 - -static const GBinderClientIfaceInfo sensors_2_client_ifaces[] = { - {SENSOR_BINDER_SERVICE_IFACE_2_1, INJECT_SENSOR_DATA_2_1 }, - {SENSOR_BINDER_SERVICE_IFACE_2_0, CONFIG_DIRECT_REPORT }, -}; - -G_STATIC_ASSERT - (G_N_ELEMENTS(sensors_2_client_ifaces) == SENSOR_INTERFACE_2_1); - -const char* const sensors_2_callback_ifaces[] = { - SENSOR_BINDER_SERVICE_CALLBACK_IFACE_2_1, - SENSOR_BINDER_SERVICE_CALLBACK_IFACE_2_0, - NULL -}; - -#endif - -namespace { -/* Maximum number of events to transmit over event pipe in one go. - * Also defines maximum number of events to ask from android hal/service. - */ -const size_t maxEvents = 64; -} +#include /* ========================================================================= * * UTILITIES * ========================================================================= */ -static char const * +char const * sensorTypeName(int type) { switch (type) { @@ -234,23 +195,8 @@ Q_GLOBAL_STATIC(HybrisManager, hybrisManager) HybrisManager::HybrisManager(QObject *parent) : QObject(parent) - , m_initialized(false) , m_registeredAdaptors() -#ifdef USE_BINDER - , m_client(NULL) - , m_deathId(0) - , m_pollTransactId(0) - , m_remote(NULL) - , m_serviceManager(NULL) - , m_sensorInterfaceEnum(SENSOR_INTERFACE_COUNT) - , m_sensorCallback(NULL) -#else - , m_halModule(NULL) - , m_halDevice(NULL) -#endif - , m_sensorArray(NULL) , m_eventReaderTid(0) - , m_sensorCount(0) , m_sensorState(NULL) , m_indexOfType() , m_indexOfHandle() @@ -263,81 +209,12 @@ HybrisManager::HybrisManager(QObject *parent) connect(QCoreApplication::instance(), &QCoreApplication::aboutToQuit, this, &HybrisManager::cleanup); -#ifdef USE_BINDER - startConnect(); -#else - int err; - - /* Open android sensor plugin */ - for (int retries = 4; ;) { - // Try module loading in throwaway child process - // so that we can retry from clean slate if needed - fflush(nullptr); - pid_t child_pid = fork(); - - if (child_pid == 0) { - // Child process - const hw_module_t *dummyModule = nullptr; - err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, &dummyModule); - _exit(err ? EXIT_FAILURE : EXIT_SUCCESS); - } - - if (child_pid == -1) { - qCWarning(lcSensorFw) << "w_get_module() probe, fork failed:" << strerror(errno); - QCoreApplication::exit(EXIT_FAILURE); - return; - } - - int status = 0; - if (waitpid(child_pid, &status, 0) == -1) { - qCWarning(lcSensorFw) << "w_get_module() probe, waitpid failed:" << strerror(errno); - QCoreApplication::exit(EXIT_FAILURE); - return; - } - - // If probe in child process was successful, do it for real - if (WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS) { - err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, - (hw_module_t const **)&m_halModule); - if (err == 0) - break; - - qCWarning(lcSensorFw) << "hw_get_module() failed:" << strerror(-err); - m_halModule = nullptr; - QCoreApplication::exit(EXIT_FAILURE); - return; - } - - // Bailout or retry after brief delay - if (--retries < 0) { - qCWarning(lcSensorFw) << "hw_get_module() probe failed - giving up"; - QCoreApplication::exit(EXIT_FAILURE); - return; - } - - qCWarning(lcSensorFw) << "hw_get_module() probe failed"; - QThread::msleep(2000); - } - - /* Open android sensor device */ - err = sensors_open_1(&m_halModule->common, &m_halDevice); - if (err != 0) { - m_halDevice = 0; - qCWarning(lcSensorFw) << "sensors_open() failed:" << strerror(-err); - QCoreApplication::exit(EXIT_FAILURE); - return; - } - - /* Get static sensor information */ - m_sensorCount = m_halModule->get_sensors_list(m_halModule, &m_sensorArray); - if (m_sensorCount <= 0) { - qCWarning(lcSensorFw) << "no sensors found"; + m_backend = getBackend(this); + if (m_backend) { + m_backend->initialize(); + } else { QCoreApplication::exit(EXIT_FAILURE); - return; } - - initManager(); -#endif } bool HybrisManager::typeRequiresWakeup(int type) @@ -375,74 +252,39 @@ void HybrisManager::initManager() initEventPipe(); /* Reserve space for sensor state data */ - m_sensorState = new HybrisSensorState[m_sensorCount]; + m_sensorState = new HybrisSensorState[m_backend->sensorCount()]; /* Selected sensors to use */ - for (int i = 0; i < m_sensorCount; ++i) { -#ifdef USE_BINDER - const char *sensorName = m_sensorArray[i].name.data.str ?: "unknown"; -#else - const char *sensorName = m_sensorArray[i].name ?: "unknown"; -#endif - + for (int i = 0; i < m_backend->sensorCount(); ++i) { /* Always add to handle -> index mapping */ - m_indexOfHandle.insert(m_sensorArray[i].handle, i); + m_indexOfHandle.insert(m_backend->handle(i), i); // some devices have compass and compass raw, // ignore compass raw. compass has range 360 - if (m_sensorArray[i].type == SENSOR_TYPE_ORIENTATION && m_sensorArray[i].maxRange != 360) + if (m_backend->type(i) == SENSOR_TYPE_ORIENTATION && m_backend->maxRange(i) != 360) continue; /* Update type -> index mapping if wake flag requirements are met or we have no candidate yet */ - bool wantWakeup = typeRequiresWakeup(m_sensorArray[i].type); - bool haveWakeup = false; -#if defined(USE_BINDER) - if (m_sensorArray[i].flags & SENSOR_FLAG_WAKE_UP) - haveWakeup = true; -#elif defined(SENSORS_DEVICE_API_VERSION_1_3) - if (m_halDevice->common.version >= SENSORS_DEVICE_API_VERSION_1_3) { - if (m_sensorArray[i].flags & SENSOR_FLAG_WAKE_UP) - haveWakeup = true; - } else { - if (strstr(sensorName, "(WAKE_UP)")) - haveWakeup = true; - } -#else - if (strstr(sensorName, "(WAKE_UP)")) - haveWakeup = true; -#endif - - if (haveWakeup == wantWakeup || !m_indexOfType.contains(m_sensorArray[i].type)) - m_indexOfType.insert(m_sensorArray[i].type, i); + bool wantWakeup = typeRequiresWakeup(m_backend->type(i)); + bool haveWakeup = m_backend->isWakeupSensor(i); + if (haveWakeup == wantWakeup || !m_indexOfType.contains(m_backend->type(i))) + m_indexOfType.insert(m_backend->type(i), i); } /* Initialize selected sensors */ - for (int i = 0; i < m_sensorCount; ++i) { -#ifdef USE_BINDER - const char *sensorName = m_sensorArray[i].name.data.str ?: "unknown"; -#else - const char *sensorName = m_sensorArray[i].name ?: "unknown"; -#endif - bool use = m_indexOfType.value(m_sensorArray[i].type) == i; + for (int i = 0; i < m_backend->sensorCount(); ++i) { + const char *sensorName = m_backend->sensorName(i); + bool use = m_indexOfType.value(m_backend->type(i)) == i; qCInfo(lcSensorFw) << Q_FUNC_INFO << (use ? "SELECT" : "IGNORE") - << "type:" << m_sensorArray[i].type << sensorTypeName(m_sensorArray[i].type) + << "type:" << m_backend->type(i) << sensorTypeName(m_backend->type(i)) << "name:" << sensorName; if (use) { // min/max delay in hal is specified in [us] - int minDelay_us = m_sensorArray[i].minDelay; - int maxDelay_us = -1; // Assume: not defined by hal - -#ifdef USE_BINDER - maxDelay_us = m_sensorArray[i].maxDelay; -#else -#ifdef SENSORS_DEVICE_API_VERSION_1_3 - if (m_halDevice->common.version >= SENSORS_DEVICE_API_VERSION_1_3) - maxDelay_us = m_sensorArray[i].maxDelay; -#endif -#endif + int minDelay_us = m_backend->minDelay(i); + int maxDelay_us = m_backend->maxDelay(i); // Assume: not defined by hal /* If HAL does not define maximum delay, we need to invent * something that a) allows sensorfwd logic to see a range @@ -477,73 +319,37 @@ void HybrisManager::initManager() m_sensorState[i].m_minDelay_us = minDelay_us; m_sensorState[i].m_maxDelay_us = maxDelay_us; - setDelay(m_sensorArray[i].handle, delay_us, true); + setDelay(m_backend->handle(i), delay_us, true); qCInfo(lcSensorFw, "delay = %d [%d, %d]", m_sensorState[i].m_delay_us, m_sensorState[i].m_minDelay_us, m_sensorState[i].m_maxDelay_us); } - m_indexOfType.insert(m_sensorArray[i].type, i); + m_indexOfType.insert(m_backend->type(i), i); /* Set sane fallback values for select sensors in case the * hal does not report initial values. */ sensors_event_t *eve = &m_sensorState[i].m_fallbackEvent; -#ifndef USE_BINDER - eve->version = sizeof *eve; -#endif - eve->sensor = m_sensorArray[i].handle; - eve->type = m_sensorArray[i].type; - switch (m_sensorArray[i].type) { - case SENSOR_TYPE_LIGHT: - // Roughly indoor lightning -#ifdef USE_BINDER - eve->u.scalar = 400; -#else - eve->light = 400; -#endif - break; - - case SENSOR_TYPE_PROXIMITY: - // Not-covered -#ifdef USE_BINDER - eve->u.scalar = m_sensorArray[i].maxRange; -#else - eve->distance = m_sensorArray[i].maxRange; -#endif - break; - default: - eve->sensor = 0; - eve->type = 0; - break; - } + m_backend->initFallbackEvent(i, eve); } /* Make sure all sensors are initially in stopped state */ - setActive(m_sensorArray[i].handle, false); + setActive(m_backend->handle(i), false); } -#ifdef USE_BINDER - if (m_sensorInterfaceEnum == SENSOR_INTERFACE_1_0) { - pollEvents(); - } else { -#endif - int err; - /* Start android sensor event reader */ - err = pthread_create(&m_eventReaderTid, 0, eventReaderThread, this); - if (err) { - m_eventReaderTid = 0; - qCCritical(lcSensorFw) << "Failed to start event reader thread"; - return; - } - qCInfo(lcSensorFw) << "Event reader thread started"; - -#ifdef USE_BINDER + if (m_backend->needsReaderThread()) { + int err; + /* Start android sensor event reader */ + err = pthread_create(&m_eventReaderTid, 0, eventReaderThread, this); + if (err) { + m_eventReaderTid = 0; + qCCritical(lcSensorFw) << "Failed to start event reader thread"; + return; + } + qCInfo(lcSensorFw) << "Event reader thread started"; } -#else - m_initialized = true; -#endif } HybrisManager::~HybrisManager() @@ -564,39 +370,14 @@ void HybrisManager::cleanup() adaptor->stopSensor(); } - /* Stop reacting to async events - */ - -#ifdef USE_BINDER - gbinder_remote_object_remove_handler(m_remote, m_deathId); - m_deathId = 0; - - if (m_pollTransactId) { - gbinder_client_cancel(m_client, m_pollTransactId); - m_pollTransactId = 0; - - // The above code just marks down pending POLL transaction as - // to be cancelled later on when handler thread gets woken up. - // - // If we are exiting right after cleanup(), that is never going - // to happen and gbinder_ipc_exit() cleanup code blocks sensorfwd - // exit indefinitely. - // - // As a workaround: make a dummy POLL transaction, for which a - // reply is sent immediately, which then wakes up the handler - // thread, the cancellation gets processed and exit is unblocked. - - GBinderLocalRequest *req = gbinder_client_new_request2(m_client, POLL); - int32_t status = 0; - gbinder_local_request_append_int32(req, 0); - GBinderRemoteReply *reply = gbinder_client_transact_sync_reply(m_client, POLL, req, &status); - gbinder_remote_reply_unref(reply); - gbinder_local_request_unref(req); + if (m_backend) { + m_backend->cleanup(); + delete m_backend; + m_backend = NULL; } - gbinder_local_object_unref(m_sensorCallback); - m_sensorCallback = NULL; -#endif + /* Stop reacting to async events + */ if (m_eventReaderTid) { qCInfo(lcSensorFw) << "Canceling event reader thread"; @@ -629,43 +410,8 @@ void HybrisManager::cleanup() /* Release remaining dynamic resources */ -#ifdef USE_BINDER - gbinder_fmq_unref(m_wakeLockQueue); - m_wakeLockQueue = NULL; - - gbinder_fmq_unref(m_eventQueue); - m_eventQueue = NULL; - - gbinder_client_unref(m_client); - m_client = NULL; - - gbinder_servicemanager_unref(m_serviceManager); - m_serviceManager = NULL; - m_remote = NULL; // auto-release - - for (int i = 0 ; i < m_sensorCount ; i++) { - g_free((void*)m_sensorArray[i].name.data.str); - g_free((void*)m_sensorArray[i].vendor.data.str); - g_free((void*)m_sensorArray[i].typeAsString.data.str); - g_free((void*)m_sensorArray[i].requiredPermission.data.str); - } - delete[] m_sensorArray; - m_sensorArray = NULL; -#else - if (m_halDevice) { - qCInfo(lcSensorFw) << "close sensor device"; - int errorCode = sensors_close_1(m_halDevice); - if (errorCode != 0) { - qCWarning(lcSensorFw) << "sensors_close() failed:" << strerror(-errorCode); - } - m_halDevice = NULL; - } -#endif - delete[] m_sensorState; m_sensorState = NULL; - m_sensorCount = 0; - m_initialized = false; /* Close sensor data transfer pipe */ cleanupEventPipe(); @@ -677,249 +423,10 @@ HybrisManager *HybrisManager::instance() return priv; } -#ifdef USE_BINDER - -GBinderLocalReply *HybrisManager::sensorCallbackHandler( - GBinderLocalObject* obj, - GBinderRemoteRequest* req, - guint code, - guint flags, - int* status, - void* user_data) -{ - (void)flags; - (void)obj; - (void)user_data; - qCInfo(lcSensorFw) << "sensorCallbackHandler"; - const char *iface = gbinder_remote_request_interface(req); - if (iface && (!strcmp(iface, SENSOR_BINDER_SERVICE_IFACE_2_0) || - !strcmp(iface, SENSOR_BINDER_SERVICE_IFACE_2_1) - )) { - switch (code) { - case DYNAMIC_SENSORS_CONNECTED_2_0: - case DYNAMIC_SENSORS_CONNECTED_2_1: - qCInfo(lcSensorFw) << "Dynamic sensor connected"; - break; - case DYNAMIC_SENSORS_DISCONNECTED_2_0: - qCInfo(lcSensorFw) << "Dynamic sensor disconnected"; - break; - default: - qCWarning(lcSensorFw) << "Unknown code (" << code << ")"; - break; - } - *status = GBINDER_STATUS_OK; - qCInfo(lcSensorFw) << "sensorCallbackHandler valid sensor interface"; - } - return NULL; -} - -void HybrisManager::getSensorList() -{ - qCInfo(lcSensorFw) << "Get sensor list"; - GBinderReader reader; - GBinderRemoteReply *reply; - int status; - - if (m_sensorInterfaceEnum == SENSOR_INTERFACE_2_1) { - reply = gbinder_client_transact_sync_reply(m_client, GET_SENSORS_LIST_2_1, NULL, &status); - } else { - reply = gbinder_client_transact_sync_reply(m_client, GET_SENSORS_LIST, NULL, &status); - } - - if (status != GBINDER_STATUS_OK) { - qCWarning(lcSensorFw) << "Unable to get sensor list: status " << status; - cleanup(); - sleep(1); - startConnect(); - return; - } - - gbinder_remote_reply_init_reader(reply, &reader); - gbinder_reader_read_int32(&reader, &status); - gsize count = 0; - gsize vecSize = 0; - sensor_t *vec = (sensor_t *)gbinder_reader_read_hidl_vec(&reader, &count, &vecSize); - - m_sensorCount = count; - m_sensorArray = new sensor_t[m_sensorCount]; - for (int i = 0 ; i < m_sensorCount ; i++) { - memcpy(&m_sensorArray[i], &vec[i], sizeof(sensor_t)); - - // Read strings - GBinderBuffer *buffer = gbinder_reader_read_buffer(&reader); - m_sensorArray[i].name.data.str = g_strdup((const gchar *)buffer->data); - m_sensorArray[i].name.len = buffer->size; - m_sensorArray[i].name.owns_buffer = true; - gbinder_buffer_free(buffer); - - buffer = gbinder_reader_read_buffer(&reader); - m_sensorArray[i].vendor.data.str = g_strdup((const gchar *)buffer->data); - m_sensorArray[i].vendor.len = buffer->size; - m_sensorArray[i].vendor.owns_buffer = true; - gbinder_buffer_free(buffer); - - buffer = gbinder_reader_read_buffer(&reader); - m_sensorArray[i].typeAsString.data.str = g_strdup((const gchar *)buffer->data); - m_sensorArray[i].typeAsString.len = buffer->size; - m_sensorArray[i].typeAsString.owns_buffer = true; - gbinder_buffer_free(buffer); - - buffer = gbinder_reader_read_buffer(&reader); - m_sensorArray[i].requiredPermission.data.str = g_strdup((const gchar *)buffer->data); - m_sensorArray[i].requiredPermission.len = buffer->size; - m_sensorArray[i].requiredPermission.owns_buffer = true; - gbinder_buffer_free(buffer); - } - gbinder_remote_reply_unref(reply); - - initManager(); - - m_initialized = true; - qCWarning(lcSensorFw) << "Hybris sensor manager initialized"; -} - -void HybrisManager::binderDied(GBinderRemoteObject *, void *user_data) -{ - HybrisManager *conn = - static_cast(user_data); - qCWarning(lcSensorFw) << "Sensor service died! Trying to reconnect."; - conn->cleanup(); - conn->startConnect(); -} - -void HybrisManager::startConnect() -{ - if (!m_serviceManager) { - m_serviceManager = gbinder_servicemanager_new(SENSOR_BINDER_SERVICE_DEVICE); - } - - if (gbinder_servicemanager_wait(m_serviceManager, -1)) { - finishConnect(); - } else { - qCWarning(lcSensorFw) << "Could not get service manager for sensor service"; - cleanup(); - } -} - -void HybrisManager::finishConnect() -{ - int initializeCode; - m_remote = gbinder_servicemanager_get_service_sync(m_serviceManager, - SENSOR_BINDER_SERVICE_NAME_2_1, NULL); - - if (m_remote) { - qCInfo(lcSensorFw) << "Connected to sensor 2.1 service"; - m_sensorInterfaceEnum = SENSOR_INTERFACE_2_1; - initializeCode = INITIALIZE_2_1; - } else { - m_remote = gbinder_servicemanager_get_service_sync(m_serviceManager, - SENSOR_BINDER_SERVICE_NAME_2_0, NULL); - if (m_remote) { - qCInfo(lcSensorFw) << "Connected to sensor 2.0 service"; - m_sensorInterfaceEnum = SENSOR_INTERFACE_2_0; - initializeCode = INITIALIZE_2_0; - } - } - - if (m_remote) { - qCInfo(lcSensorFw) << "Initialize sensor service"; - m_deathId = gbinder_remote_object_add_death_handler(m_remote, binderDied, this); - m_client = gbinder_client_new2(m_remote, sensors_2_client_ifaces, G_N_ELEMENTS(sensors_2_client_ifaces)); - if (!m_client) { - qCInfo(lcSensorFw) << "Could not create client for sensor service. Trying to reconnect."; - } else { - GBinderRemoteReply *reply; - GBinderLocalRequest *req = gbinder_client_new_request2(m_client, initializeCode); - int32_t status; - GBinderWriter writer; - - gbinder_local_request_init_writer(req, &writer); - m_sensorCallback = gbinder_servicemanager_new_local_object2( - m_serviceManager, - sensors_2_callback_ifaces, - sensorCallbackHandler, - this); - - m_eventQueue = gbinder_fmq_new(sizeof(sensors_event_t), 128, - GBINDER_FMQ_TYPE_SYNC_READ_WRITE, GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG, -1, 0); - gbinder_writer_append_fmq_descriptor(&writer, m_eventQueue); - - m_wakeLockQueue = gbinder_fmq_new(sizeof(guint32), 128, - GBINDER_FMQ_TYPE_SYNC_READ_WRITE, GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG, -1, 0); - gbinder_writer_append_fmq_descriptor(&writer, m_wakeLockQueue); - - gbinder_writer_append_local_object(&writer, m_sensorCallback); - - reply = gbinder_client_transact_sync_reply(m_client, initializeCode, req, &status); - gbinder_local_request_unref(req); - - if (status != GBINDER_STATUS_OK) { - qCWarning(lcSensorFw) << "Initialize failed with status" << status << ". Trying to reconnect."; - gbinder_remote_reply_unref(reply); - } else { - int error; - GBinderReader reader; - gbinder_remote_reply_init_reader(reply, &reader); - gbinder_reader_read_int32(&reader, &status); - gbinder_reader_read_int32(&reader, &error); - - gbinder_remote_reply_unref(reply); - if (!error) { - getSensorList(); - return; - } else { - qCWarning(lcSensorFw) << "Initialize failed with error" << error << ". Trying to reconnect."; - } - } - } - } else { - m_remote = gbinder_servicemanager_get_service_sync(m_serviceManager, - SENSOR_BINDER_SERVICE_NAME_1_0, NULL); - if (!m_remote) { - qCInfo(lcSensorFw) << "Could not find remote object for sensor service. Trying to reconnect"; - } else { - m_sensorInterfaceEnum = SENSOR_INTERFACE_1_0; - qCInfo(lcSensorFw) << "Connected to sensor 1.0 service"; - m_deathId = gbinder_remote_object_add_death_handler(m_remote, binderDied, - this); - m_client = gbinder_client_new(m_remote, SENSOR_BINDER_SERVICE_IFACE_1_0); - if (!m_client) { - qCInfo(lcSensorFw) << "Could not create client for sensor service. Trying to reconnect."; - } else { - // Sometimes sensor service has lingering connetion from - // previous client which causes sensor service to restart - // and we need to test with poll if remote is really working. - GBinderRemoteReply *reply; - GBinderLocalRequest *req = gbinder_client_new_request2(m_client, POLL); - int32_t status; - - // Empty poll to test if remote is working - req = gbinder_local_request_append_int32(req, 0); - - reply = gbinder_client_transact_sync_reply(m_client, POLL, req, &status); - gbinder_local_request_unref(req); - gbinder_remote_reply_unref(reply); - - if (status != GBINDER_STATUS_OK) { - qCWarning(lcSensorFw) << "Poll failed with status" << status << ". Trying to reconnect."; - } else { - getSensorList(); - return; - } - } - } - } - // On failure cleanup and wait before reconnecting - cleanup(); - sleep(1); - startConnect(); -} -#endif //USE_BINDER - int HybrisManager::handleForType(int sensorType) const { int index = indexForType(sensorType); - return (index < 0) ? -1 : m_sensorArray[index].handle; + return (index < 0) ? -1 : m_backend->handle(index); } sensors_event_t *HybrisManager::eventForHandle(int handle) const @@ -1039,11 +546,9 @@ float HybrisManager::getMaxRange(int handle) const int index = indexForHandle(handle); if (index != -1) { - const struct sensor_t *sensor = &m_sensorArray[index]; - - range = scaleSensorValue(sensor->maxRange, sensor->type); + range = scaleSensorValue(m_backend->maxRange(index), m_backend->type(index)); qCDebug(lcSensorFw, "HYBRIS CTL getMaxRange(%d=%s) -> %g", - sensor->handle, sensorTypeName(sensor->type), range); + m_backend->handle(index), sensorTypeName(m_backend->type(index)), range); } return range; @@ -1055,11 +560,9 @@ float HybrisManager::getResolution(int handle) const int index = indexForHandle(handle); if (index != -1) { - const struct sensor_t *sensor = &m_sensorArray[index]; - - resolution = scaleSensorValue(sensor->resolution, sensor->type); + resolution = scaleSensorValue(m_backend->resolution(index), m_backend->type(index)); qCDebug(lcSensorFw, "HYBRIS CTL getResolution(%d=%s) -> %g", - sensor->handle, sensorTypeName(sensor->type), resolution); + m_backend->handle(index), sensorTypeName(m_backend->type(index)), resolution); } return resolution; @@ -1071,12 +574,11 @@ int HybrisManager::getMinDelay(int handle) const int index = indexForHandle(handle); if (index != -1) { - const struct sensor_t *sensor = &m_sensorArray[index]; HybrisSensorState *state = &m_sensorState[index]; delay_us = state->m_minDelay_us; qCDebug(lcSensorFw, "HYBRIS CTL getMinDelay(%d=%s) -> %d", - sensor->handle, sensorTypeName(sensor->type), delay_us); + m_backend->handle(index), sensorTypeName(m_backend->type(index)), delay_us); } return delay_us; @@ -1088,12 +590,11 @@ int HybrisManager::getMaxDelay(int handle) const int index = indexForHandle(handle); if (index != -1) { - const struct sensor_t *sensor = &m_sensorArray[index]; HybrisSensorState *state = &m_sensorState[index]; delay_us = state->m_maxDelay_us; qCDebug(lcSensorFw, "HYBRIS CTL getMaxDelay(%d=%s) -> %d", - sensor->handle, sensorTypeName(sensor->type), delay_us); + m_backend->handle(index), sensorTypeName(m_backend->type(index)), delay_us); } return delay_us; @@ -1105,12 +606,11 @@ int HybrisManager::getDelay(int handle) const int index = indexForHandle(handle); if (index != -1) { - const struct sensor_t *sensor = &m_sensorArray[index]; HybrisSensorState *state = &m_sensorState[index]; delay_us = state->m_delay_us; qCDebug(lcSensorFw, "HYBRIS CTL getDelay(%d=%s) -> %d", - sensor->handle, sensorTypeName(sensor->type), delay_us); + m_backend->handle(index), sensorTypeName(m_backend->type(index)), delay_us); } return delay_us; @@ -1122,62 +622,24 @@ bool HybrisManager::setDelay(int handle, int delay_us, bool force) int index = indexForHandle(handle); if (index != -1) { - const struct sensor_t *sensor = &m_sensorArray[index]; HybrisSensorState *state = &m_sensorState[index]; + int handle = m_backend->handle(index); + int type = m_backend->type(index); if (!force && state->m_delay_us == delay_us) { qCDebug(lcSensorFw, "HYBRIS CTL setDelay(%d=%s, %d) -> no-change", - sensor->handle, sensorTypeName(sensor->type), delay_us); + handle, sensorTypeName(type), delay_us); success = true; } else { int64_t delay_ns = delay_us * 1000LL; -#ifdef USE_BINDER - int error; - GBinderLocalRequest *req = gbinder_client_new_request2(m_client, BATCH); - GBinderRemoteReply *reply; - GBinderReader reader; - GBinderWriter writer; - int32_t status; - - gbinder_local_request_init_writer(req, &writer); - - gbinder_writer_append_int32(&writer, sensor->handle); - gbinder_writer_append_int64(&writer, delay_ns); - gbinder_writer_append_int64(&writer, 0); - - reply = gbinder_client_transact_sync_reply(m_client, BATCH, req, &status); - gbinder_local_request_unref(req); - - if (status != GBINDER_STATUS_OK) { - qCWarning(lcSensorFw) << "Set delay failed status " << status; - return false; - } - gbinder_remote_reply_init_reader(reply, &reader); - gbinder_reader_read_int32(&reader, &status); - gbinder_reader_read_int32(&reader, &error); - - gbinder_remote_reply_unref(reply); -#else - int error = EBADSLT; - if (m_halDevice->common.version >= SENSORS_DEVICE_API_VERSION_1_0) { - if (m_halDevice->batch) - error = m_halDevice->batch(m_halDevice, sensor->handle, 0, delay_ns, 0); - else if (m_halDevice->setDelay) - error = m_halDevice->setDelay(&m_halDevice->v0, sensor->handle, delay_ns); - } else { - if (m_halDevice->setDelay) - error = m_halDevice->setDelay(&m_halDevice->v0, sensor->handle, delay_ns); - else if (m_halDevice->batch) // Here be dragons - error = m_halDevice->batch(m_halDevice, sensor->handle, 0, delay_ns, 0); - } -#endif + int error = m_backend->setDelay(handle, delay_ns); if (error) { qCWarning(lcSensorFw, "HYBRIS CTL setDelay(%d=%s, %d) -> %d=%s", - sensor->handle, sensorTypeName(sensor->type), delay_us, + handle, sensorTypeName(type), delay_us, error, strerror(error)); } else { qCInfo(lcSensorFw, "HYBRIS CTL setDelay(%d=%s, %d) -> success", - sensor->handle, sensorTypeName(sensor->type), delay_us); + handle, sensorTypeName(type), delay_us); state->m_delay_us = delay_us; success = true; } @@ -1193,12 +655,11 @@ bool HybrisManager::getActive(int handle) const int index = indexForHandle(handle); if (index != -1) { - const struct sensor_t *sensor = &m_sensorArray[index]; HybrisSensorState *state = &m_sensorState[index]; active = (state->m_active > 0); qCDebug(lcSensorFw, "HYBRIS CTL getActive(%d=%s) -> %s", - sensor->handle, sensorTypeName(sensor->type), + m_backend->handle(index), sensorTypeName(m_backend->type(index)), active ? "true" : "false"); } return active; @@ -1210,126 +671,33 @@ bool HybrisManager::setActive(int handle, bool active) int index = indexForHandle(handle); if (index != -1) { - const struct sensor_t *sensor = &m_sensorArray[index]; HybrisSensorState *state = &m_sensorState[index]; + int handle = m_backend->handle(index); + int type = m_backend->type(index); if (state->m_active == active) { qCDebug(lcSensorFw, "HYBRIS CTL setActive(%d=%s, %s) -> no-change", - sensor->handle, sensorTypeName(sensor->type), active ? "true" : "false"); + handle, sensorTypeName(type), active ? "true" : "false"); success = true; } else { -#ifdef USE_BINDER - if (active && state->m_delay_us != -1) { - qCInfo(lcSensorFw, "HYBRIS CTL FORCE PRE UPDATE %i, %s", sensor->handle, - sensorTypeName(sensor->type)); - int delay_us = state->m_delay_us; - state->m_delay_us = -1; - setDelay(handle, delay_us, true); - } - int error; - GBinderLocalRequest *req = gbinder_client_new_request2(m_client, ACTIVATE); - GBinderRemoteReply *reply; - GBinderReader reader; - GBinderWriter writer; - int32_t status; - - gbinder_local_request_init_writer(req, &writer); - - gbinder_writer_append_int32(&writer, sensor->handle); - gbinder_writer_append_int32(&writer, active); - - reply = gbinder_client_transact_sync_reply(m_client, ACTIVATE, req, &status); - gbinder_local_request_unref(req); - - if (status != GBINDER_STATUS_OK) { - qCWarning(lcSensorFw) << "Activate failed status " << status; - return false; - } - gbinder_remote_reply_init_reader(reply, &reader); - gbinder_reader_read_int32(&reader, &status); - gbinder_reader_read_int32(&reader, &error); - - gbinder_remote_reply_unref(reply); -#else - int error = m_halDevice->activate(&m_halDevice->v0, sensor->handle, active); -#endif + int error = m_backend->setActive(handle, active); if (error) { - qCWarning(lcSensorFw, "HYBRIS CTL setActive(%d=%s, %s) -> %d=%s", sensor->handle, - sensorTypeName(sensor->type), active ? "true" : "false", error, strerror(error)); + qCWarning(lcSensorFw, "HYBRIS CTL setActive(%d=%s, %s) -> %d=%s", handle, + sensorTypeName(type), active ? "true" : "false", error, strerror(error)); } else { - qCInfo(lcSensorFw, "HYBRIS CTL setActive(%d=%s, %s) -> success", sensor->handle, - sensorTypeName(sensor->type), active ? "true" : "false"); + qCInfo(lcSensorFw, "HYBRIS CTL setActive(%d=%s, %s) -> success", handle, + sensorTypeName(type), active ? "true" : "false"); state->m_active = active; success = true; } -#ifndef USE_BINDER - if (state->m_active == true && state->m_delay_us != -1) { - qCInfo(lcSensorFw, "HYBRIS CTL FORCE DELAY UPDATE"); - int delay_us = state->m_delay_us; - state->m_delay_us = -1; - setDelay(handle, delay_us, false); - } -#endif } } return success; } -#ifdef USE_BINDER -/** - * pollEvents is only called during initialization and after that from pollEventsCallback - * triggered by binder reply so there is only maximum of one active poll at all times - */ -void HybrisManager::pollEvents() -{ - if (m_client) { - GBinderLocalRequest *req = gbinder_client_new_request2(m_client, POLL); - - req = gbinder_local_request_append_int32(req, 16); // Same number as for HAL - m_pollTransactId = gbinder_client_transact(m_client, POLL, 0, req, pollEventsCallback, 0, this); - gbinder_local_request_unref(req); - } -} - -void HybrisManager::pollEventsCallback( - GBinderClient* /*client*/, - GBinderRemoteReply* reply, - int status, - void* userData) -{ - HybrisManager *manager = static_cast(userData); - GBinderReader reader; - int32_t readerStatus; - int32_t result; - sensors_event_t *buffer; - - manager->m_pollTransactId = 0; - - if (status != GBINDER_STATUS_OK) { - qCWarning(lcSensorFw) << "Poll failed status " << status; - // In case of binder failure sleep a little before attempting a new poll - struct timespec ts = { 0, 50 * 1000 * 1000 }; // 50 ms - do { } while (nanosleep(&ts, &ts) == -1 && errno == EINTR); - } else { - // Read sensor events from reply - gbinder_remote_reply_init_reader(reply, &reader); - gbinder_reader_read_int32(&reader, &readerStatus); - gbinder_reader_read_int32(&reader, &result); - gsize structSize = 0; - gsize eventCount = 0; - - buffer = (sensors_event_t *)gbinder_reader_read_hidl_vec(&reader, &eventCount , &structSize); - manager->queueEvents(buffer, eventCount); - } - // Initiate new poll - manager->pollEvents(); -} -#endif - void *HybrisManager::eventReaderThread(void *aptr) { HybrisManager *manager = static_cast(aptr); - sensors_event_t buffer[maxEvents]; /* Async cancellation, but disabled */ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); @@ -1342,62 +710,7 @@ void *HybrisManager::eventReaderThread(void *aptr) pthread_sigmask(SIG_BLOCK, &ss, 0); /* Loop until explicitly canceled */ for (;;) { -#ifdef USE_BINDER - size_t availableEvents = gbinder_fmq_available_to_read(manager->m_eventQueue); - - if (availableEvents <= 0) { - guint32 state = 0; - /* Async cancellation point */ - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0); - gint32 ret = gbinder_fmq_wait(manager->m_eventQueue, - EVENT_QUEUE_FLAG_READ_AND_PROCESS, &state); - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); - - if (ret < 0) { - if (ret != -ETIMEDOUT && ret != -EAGAIN) { - qCWarning(lcSensorFw) << "Waiting for events failed" << strerror(-ret); - } - continue; - } - availableEvents = gbinder_fmq_available_to_read(manager->m_eventQueue); - } - size_t numEvents = std::min(availableEvents, maxEvents); - if (numEvents == 0) { - continue; - } - if (gbinder_fmq_read(manager->m_eventQueue, buffer, numEvents)) { - gbinder_fmq_wake(manager->m_eventQueue, EVENT_QUEUE_FLAG_EVENTS_READ); - } else { - qCWarning(lcSensorFw) << "Reading events failed"; - continue; - } - - // Queue received events for processing in main thread - int wakeupEventCount = manager->queueEvents(buffer, numEvents); - - // Acknowledge wakeup events - if (wakeupEventCount) { - if (gbinder_fmq_write(manager->m_wakeLockQueue, &wakeupEventCount, 1)) { - gbinder_fmq_wake(manager->m_wakeLockQueue, WAKE_LOCK_QUEUE_DATA_WRITTEN); - } else { - qCWarning(lcSensorFw) << "Write to wakelock queue failed"; - } - } -#else // HAL reader - /* Async cancellation point at android hal poll() */ - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0); - int numEvents = manager->m_halDevice->poll(&manager->m_halDevice->v0, buffer, maxEvents); - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); - /* Rate limit in poll() error situations */ - if (numEvents < 0) { - qCWarning(lcSensorFw) << "android device->poll() failed" << strerror(-numEvents); - struct timespec ts = { 1, 0 }; // 1000 ms - do { } while (nanosleep(&ts, &ts) == -1 && errno == EINTR); - continue; - } - // Queue received events for processing in main thread - manager->queueEvents(buffer, numEvents); -#endif + manager->m_backend->eventReaderThreadImpl(); } return 0; } @@ -1465,21 +778,13 @@ int HybrisManager::queueEvents(const sensors_event_t *buffer, int numEvents) for (int i = 0; i < numEvents; i++) { const sensors_event_t &data = buffer[i]; qCDebug(lcSensorFw, "QUEUE HYBRIS EVE %s", sensorTypeName(data.type)); -#ifdef USE_BINDER - int index = indexForHandle(data.sensor); - const struct sensor_t *sensor = &m_sensorArray[index]; - if (sensor->flags & SENSOR_FLAG_WAKE_UP) { - ++wakeupEventCount; - } -#else - if (data.version != sizeof(sensors_event_t)) { - qCWarning(lcSensorFw) << QString("incorrect event version (version=%1, expected=%2").arg(data.version).arg(sizeof(sensors_event_t)); + + if (!m_backend->isValid(&data)) { errorInInput = true; } - if (typeRequiresWakeup(data.type)) { + + if (m_backend->needsWakeup(&data)) ++wakeupEventCount; - } -#endif } /* Suspend proof sensor data forwarding */ @@ -1508,17 +813,8 @@ int HybrisManager::processEvents(const sensors_event_t *buffer, int numEvents) int wakeupEventCount = 0; for (int i = 0; i < numEvents; i++) { const sensors_event_t& data = buffer[i]; -#ifdef USE_BINDER - int index = indexForHandle(data.sensor); - const struct sensor_t *sensor = &m_sensorArray[index]; - if (sensor->flags & SENSOR_FLAG_WAKE_UP) { - ++wakeupEventCount; - } -#else - if (typeRequiresWakeup(data.type)) { + if (m_backend->needsWakeup(&data)) ++wakeupEventCount; - } -#endif } /* Suspend proof sensor data processing */ diff --git a/core/hybrisadaptor.h b/core/hybrisadaptor.h index 69958ec..455d435 100644 --- a/core/hybrisadaptor.h +++ b/core/hybrisadaptor.h @@ -2,6 +2,7 @@ ** ** Copyright (c) 2013 Jolla Ltd. ** Copyright (c) 2025 Jollyboys Ltd. +** Copyright (c) 2026 Jolla Mobile Ltd ** ** ** $QT_BEGIN_LICENSE:LGPL$ @@ -29,13 +30,9 @@ #include "deviceadaptor.h" -#ifdef USE_BINDER -#include -#include "hybrisbindertypes.h" -#else -#include +#include "hybrisbackend.h" + #include -#endif /* Older devices probably have old android hal and thus do * not define sensor all sensor types that have been added @@ -238,31 +235,15 @@ class HybrisManager : public QObject void registerAdaptor (HybrisAdaptor * adaptor); void processSample (const sensors_event_t& data); + int queueEvents(const sensors_event_t *buffer, int numEvents); + bool typeRequiresWakeup(int type); + private: // fields - bool m_initialized; QMultiMap m_registeredAdaptors; // type -> obj -#ifdef USE_BINDER - // Binder backend - GBinderClient *m_client; - gulong m_deathId; - gulong m_pollTransactId; - GBinderRemoteObject *m_remote; - GBinderServiceManager *m_serviceManager; - SENSOR_INTERFACE m_sensorInterfaceEnum; - GBinderLocalObject *m_sensorCallback; - GBinderFmq *m_eventQueue; - GBinderFmq *m_wakeLockQueue; - struct sensor_t *m_sensorArray; // [m_sensorCount] -#else - // HAL backend - struct sensors_module_t *m_halModule; - sensors_poll_device_1_t *m_halDevice; - const struct sensor_t *m_sensorArray; // [m_sensorCount] -#endif + HybrisBackend *m_backend; pthread_t m_eventReaderTid; - int m_sensorCount; HybrisSensorState *m_sensorState; // [m_sensorCount] QMap m_indexOfType; // type -> index QMap m_indexOfHandle; // handle -> index @@ -271,25 +252,6 @@ class HybrisManager : public QObject QSocketNotifier *m_eventPipeNotifier; QSet m_doubleStopReaderQuirkSensorTypes; -#ifdef USE_BINDER - static GBinderLocalReply *sensorCallbackHandler( - GBinderLocalObject* obj, - GBinderRemoteRequest* req, - guint code, - guint flags, - int* status, - void* user_data); - void getSensorList(); - void startConnect(); - void finishConnect(); - static void binderDied(GBinderRemoteObject *, void *user_data); - void pollEvents(); - static void pollEventsCallback( - GBinderClient* /*client*/, GBinderRemoteReply* reply, - int status, void* userData); -#endif - bool typeRequiresWakeup(int type); - friend class HybrisAdaptorReader; private: @@ -298,7 +260,6 @@ class HybrisManager : public QObject void initEventPipe(); void cleanupEventPipe(); void eventPipeWakeup(int fd); - int queueEvents(const sensors_event_t *buffer, int numEvents); int processEvents(const sensors_event_t *buffer, int numEvents); }; diff --git a/core/hybrisbackend.cpp b/core/hybrisbackend.cpp new file mode 100644 index 0000000..801c586 --- /dev/null +++ b/core/hybrisbackend.cpp @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (c) 2013 Jolla Ltd. +** Copyright (c) 2025 Jollyboys Ltd. +** Copyright (c) 2026 Jolla Mobile Ltd +** +** +** $QT_BEGIN_LICENSE:LGPL$ +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "hybrisbackend.h" + +HybrisBackend::HybrisBackend(HybrisManager *manager, QObject *parent) + : QObject(parent) + , m_manager(manager) + , m_sensorCount(0) +{ +} + +int HybrisBackend::sensorCount() +{ + return m_sensorCount; +} diff --git a/core/hybrisbackend.h b/core/hybrisbackend.h new file mode 100644 index 0000000..5e5e35a --- /dev/null +++ b/core/hybrisbackend.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (c) 2013 Jolla Ltd. +** Copyright (c) 2025 Jollyboys Ltd. +** Copyright (c) 2026 Jolla Mobile Ltd +** +** +** $QT_BEGIN_LICENSE:LGPL$ +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HybrisBackend_H +#define HybrisBackend_H + +#include + +namespace { +/* Maximum number of events to transmit over event pipe in one go. + * Also defines maximum number of events to ask from android hal/service. + */ +const size_t maxEvents = 64; +} + +#ifdef USE_BINDER +#include +#include "hybrisbindertypes.h" +#else +#include +#include +#endif + +class HybrisManager; + +class HybrisBackend : public QObject +{ + Q_OBJECT +public: + HybrisBackend(HybrisManager *manager, QObject *parent = 0); + virtual void initialize() = 0; + virtual void cleanup() = 0; + virtual int sensorCount(); + virtual bool needsReaderThread() = 0; + virtual bool needsWakeup(const sensors_event_t *eve) = 0; + virtual bool isValid(const sensors_event_t *eve) = 0; + virtual void initFallbackEvent(int index, sensors_event_t *eve) = 0; + virtual int handle(int index) = 0; + virtual int type(int index) = 0; + virtual bool isWakeupSensor(int index) = 0; + virtual const char *sensorName(int index) = 0; + virtual int maxDelay(int index) = 0; + virtual int minDelay(int index) = 0; + virtual float maxRange(int index) = 0; + virtual float resolution(int index) = 0; + virtual int setActive(int handle, bool active) = 0; + virtual int setDelay(int handle, int64_t delay_ns) = 0; + virtual void eventReaderThreadImpl() = 0; + +protected: + HybrisManager *m_manager; + int m_sensorCount; +}; + +HybrisBackend *getBackend(HybrisManager *manager); + +#endif // HybrisBackend_H diff --git a/core/hybrisbackend_binder.cpp b/core/hybrisbackend_binder.cpp new file mode 100644 index 0000000..def2796 --- /dev/null +++ b/core/hybrisbackend_binder.cpp @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (c) 2013 Jolla Ltd. +** Copyright (c) 2025 Jollyboys Ltd. +** Copyright (c) 2026 Jolla Mobile Ltd +** +** +** $QT_BEGIN_LICENSE:LGPL$ +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifdef USE_BINDER + +#include "hybrisbackend_binder.h" +#include "hybrisbackend_binder_aidl.h" +#include "hybrisbackend_binder_hidl.h" +#include "hybrisadaptor.h" + +#include + +HybrisBackend *getBackend(HybrisManager *manager) +{ + HybrisBackend *backend = NULL; + for (int i = 0; i < 5; ++i) { + if (HybrisBackendBinderAidl::isSupported()) { + backend = qobject_cast(new HybrisBackendBinderAidl(manager)); + break; + } else if (HybrisBackendBinderHidl::isSupported()) { + backend = qobject_cast(new HybrisBackendBinderHidl(manager)); + break; + } + sleep(1); + } + return backend; +} + +HybrisBackendBinder::HybrisBackendBinder(HybrisManager *manager, QObject *parent) + : HybrisBackend(manager, parent) + , m_client(NULL) + , m_deathId(0) + , m_remote(NULL) + , m_serviceManager(NULL) + , m_sensorInterfaceEnum(SENSOR_INTERFACE_COUNT) + , m_sensorCallback(NULL) + , m_sensorArray(NULL) +{ +} + +HybrisBackendBinder::~HybrisBackendBinder() +{ +} + +void HybrisBackendBinder::cleanup() +{ + qCInfo(lcSensorFw) << "cleanup"; + gbinder_remote_object_remove_handler(m_remote, m_deathId); + m_deathId = 0; + + gbinder_local_object_unref(m_sensorCallback); + m_sensorCallback = NULL; + + gbinder_fmq_unref(m_wakeLockQueue); + m_wakeLockQueue = NULL; + + gbinder_fmq_unref(m_eventQueue); + m_eventQueue = NULL; + + gbinder_client_unref(m_client); + m_client = NULL; + + gbinder_servicemanager_unref(m_serviceManager); + m_serviceManager = NULL; + m_remote = NULL; // auto-release + + for (int i = 0 ; i < m_sensorCount ; i++) { + g_free((void*)m_sensorArray[i].name.data.str); + g_free((void*)m_sensorArray[i].vendor.data.str); + g_free((void*)m_sensorArray[i].typeAsString.data.str); + g_free((void*)m_sensorArray[i].requiredPermission.data.str); + } + delete[] m_sensorArray; + m_sensorArray = NULL; +} + +bool HybrisBackendBinder::needsWakeup(const sensors_event_t *eve) +{ + int index = m_manager->indexForHandle(eve->sensor); + const struct sensor_t *sensor = &m_sensorArray[index]; + if (sensor->flags & SENSOR_FLAG_WAKE_UP) { + return true; + } + return false; +} + +bool HybrisBackendBinder::isValid(const sensors_event_t *eve) +{ + Q_UNUSED(eve); + return true; +} + +int HybrisBackendBinder::handle(int index) +{ + return m_sensorArray[index].handle; +} + +int HybrisBackendBinder::type(int index) +{ + return m_sensorArray[index].type; +} + +bool HybrisBackendBinder::isWakeupSensor(int index) +{ + return m_sensorArray[index].flags & SENSOR_FLAG_WAKE_UP; +} + +void HybrisBackendBinder::initFallbackEvent(int index, sensors_event_t *eve) +{ + eve->sensor = m_sensorArray[index].handle; + eve->type = m_sensorArray[index].type; + switch (m_sensorArray[index].type) { + case SENSOR_TYPE_LIGHT: + // Roughly indoor lightning + eve->u.scalar = 400; + break; + case SENSOR_TYPE_PROXIMITY: + // Not-covered + eve->u.scalar = m_sensorArray[index].maxRange; + break; + default: + eve->sensor = 0; + eve->type = 0; + break; + } +} + +const char *HybrisBackendBinder::sensorName(int index) +{ + return m_sensorArray[index].name.data.str ?: "unknown"; +} + +int HybrisBackendBinder::maxDelay(int index) +{ + return m_sensorArray[index].maxDelay; +} + +int HybrisBackendBinder::minDelay(int index) +{ + return m_sensorArray[index].minDelay; +} + +float HybrisBackendBinder::maxRange(int index) +{ + return m_sensorArray[index].maxRange; +} + +float HybrisBackendBinder::resolution(int index) +{ + return m_sensorArray[index].resolution; +} + +#endif diff --git a/core/hybrisbackend_binder.h b/core/hybrisbackend_binder.h new file mode 100644 index 0000000..9755a56 --- /dev/null +++ b/core/hybrisbackend_binder.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (c) 2013 Jolla Ltd. +** Copyright (c) 2025 Jollyboys Ltd. +** Copyright (c) 2026 Jolla Mobile Ltd +** +** +** $QT_BEGIN_LICENSE:LGPL$ +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HybrisBackendBinder_H +#define HybrisBackendBinder_H + +#ifdef USE_BINDER +#include + +#include +#include "hybrisbackend.h" + +class HybrisBackendBinder : public HybrisBackend +{ + Q_OBJECT +public: + HybrisBackendBinder(HybrisManager *manager, QObject *parent = 0); + virtual ~HybrisBackendBinder() = 0; + virtual void initialize() = 0; + void cleanup(); + virtual bool needsReaderThread() = 0; + bool needsWakeup(const sensors_event_t *eve); + bool isValid(const sensors_event_t *eve); + void initFallbackEvent(int index, sensors_event_t *eve); + int handle(int index); + int type(int index); + bool isWakeupSensor(int index); + const char *sensorName(int index); + int maxDelay(int index); + int minDelay(int index); + float maxRange(int index); + float resolution(int index); + virtual int setActive(int handle, bool active) = 0; + virtual int setDelay(int handle, int64_t delay_ns) = 0; + virtual void eventReaderThreadImpl() = 0; + +protected: + GBinderClient *m_client; + gulong m_deathId; + GBinderRemoteObject *m_remote; + GBinderServiceManager *m_serviceManager; + SENSOR_INTERFACE m_sensorInterfaceEnum; + GBinderLocalObject *m_sensorCallback; + GBinderFmq *m_eventQueue; + GBinderFmq *m_wakeLockQueue; + struct sensor_t *m_sensorArray; // [m_sensorCount] +}; + +#endif + +#endif // HybrisBackendBinder_H diff --git a/core/hybrisbackend_binder_aidl.cpp b/core/hybrisbackend_binder_aidl.cpp new file mode 100644 index 0000000..1f05cd0 --- /dev/null +++ b/core/hybrisbackend_binder_aidl.cpp @@ -0,0 +1,400 @@ +/**************************************************************************** +** +** Copyright (c) 2013 Jolla Ltd. +** Copyright (c) 2025 Jollyboys Ltd. +** Copyright (c) 2026 Jolla Mobile Ltd +** +** +** $QT_BEGIN_LICENSE:LGPL$ +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "hybrisbackend_binder_aidl.h" + +#ifdef USE_BINDER + +#include "hybrisadaptor.h" +#include "logging.h" + +#include + +#define SENSOR_BINDER_SERVICE_DEVICE "/dev/binder" +#define SENSOR_BINDER_SERVICE_IFACE_AIDL "android.hardware.sensors.ISensors" +#define SENSOR_BINDER_SERVICE_NAME_AIDL SENSOR_BINDER_SERVICE_IFACE_AIDL "/default" +#define SENSOR_BINDER_SERVICE_CALLBACK_IFACE_AIDL "android.hardware.sensors.ISensorsCallback" + +#define MAX_RECEIVE_BUFFER_EVENT_COUNT 128 + +extern char const *sensorTypeName(int type); + +HybrisBackendBinderAidl::HybrisBackendBinderAidl(HybrisManager *manager, QObject *parent) + : HybrisBackendBinder(manager, parent) +{ +} + +HybrisBackendBinderAidl::~HybrisBackendBinderAidl() +{ +} + +void HybrisBackendBinderAidl::initialize() +{ + startConnect(); +} + +bool HybrisBackendBinderAidl::isSupported() +{ + bool ret = false; + GBinderServiceManager *sm = + gbinder_servicemanager_new(SENSOR_BINDER_SERVICE_DEVICE); + + if (gbinder_servicemanager_is_present(sm)) { + /* Fetch remote reference from hwservicemanager */ + GBinderRemoteObject *remote = + gbinder_servicemanager_get_service_sync(sm, + SENSOR_BINDER_SERVICE_NAME_AIDL, NULL); + if (remote) { + ret = true; + } + } + + gbinder_servicemanager_unref(sm); + + return ret; +} + +void HybrisBackendBinderAidl::cleanup() +{ + qCInfo(lcSensorFw) << "cleanup"; + HybrisBackendBinder::cleanup(); +} + +bool HybrisBackendBinderAidl::needsReaderThread() +{ + return true; +} + +int HybrisBackendBinderAidl::setActive(int handle, bool active) +{ + if (active && m_manager->getDelay(handle) != -1) { + int index = m_manager->indexForHandle(handle); + qCInfo(lcSensorFw, "HYBRIS CTL FORCE PRE UPDATE %i, %s", handle, + sensorTypeName(m_sensorArray[index].type)); + int delay_us = m_manager->getDelay(handle); + m_manager->setDelay(handle, delay_us, true); + } + + int error = 0; + GBinderLocalRequest *req = gbinder_client_new_request(m_client); + GBinderRemoteReply *reply; + GBinderReader reader; + GBinderWriter writer; + int32_t status; + + gbinder_local_request_init_writer(req, &writer); + + gbinder_writer_append_int32(&writer, handle); + gbinder_writer_append_int32(&writer, active); + + reply = gbinder_client_transact_sync_reply(m_client, ACTIVATE_AIDL, req, &status); + gbinder_local_request_unref(req); + + if (status != GBINDER_STATUS_OK) { + qCWarning(lcSensorFw) << "Activate failed status " << status; + return false; + } + gbinder_remote_reply_init_reader(reply, &reader); + gbinder_reader_read_int32(&reader, &status); + if (status) { + error = status; + } + + gbinder_remote_reply_unref(reply); + + return error; +} + +int HybrisBackendBinderAidl::setDelay(int handle, int64_t delay_ns) +{ + int error = 0; + GBinderLocalRequest *req = gbinder_client_new_request2(m_client, BATCH); + GBinderRemoteReply *reply; + GBinderReader reader; + GBinderWriter writer; + int32_t status; + + gbinder_local_request_init_writer(req, &writer); + + gbinder_writer_append_int32(&writer, handle); + gbinder_writer_append_int64(&writer, delay_ns); + gbinder_writer_append_int64(&writer, 0); + + reply = gbinder_client_transact_sync_reply(m_client, BATCH_AIDL, req, &status); + gbinder_local_request_unref(req); + + if (status != GBINDER_STATUS_OK) { + qCWarning(lcSensorFw) << "Set delay failed status " << status; + return false; + } + gbinder_remote_reply_init_reader(reply, &reader); + gbinder_reader_read_int32(&reader, &status); + if (status) { + error = status; + } + + gbinder_remote_reply_unref(reply); + + return error; +} + +void HybrisBackendBinderAidl::eventReaderThreadImpl() +{ + sensors_event_t buffer[maxEvents]; + sensors_event_t_aidl aidl_buffer[maxEvents]; + size_t availableEvents = gbinder_fmq_available_to_read(m_eventQueue); + + if (availableEvents <= 0) { + guint32 state = 0; + /* Async cancellation point */ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0); + gint32 ret = gbinder_fmq_wait(m_eventQueue, + EVENT_QUEUE_FLAG_READ_AND_PROCESS, &state); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); + + if (ret < 0) { + if (ret != -ETIMEDOUT && ret != -EAGAIN) { + qCWarning(lcSensorFw) << "Waiting for events failed" << strerror(-ret); + } + return; + } + availableEvents = gbinder_fmq_available_to_read(m_eventQueue); + } + size_t numEvents = std::min(availableEvents, maxEvents); + if (numEvents == 0) { + return; + } + if (gbinder_fmq_read(m_eventQueue, aidl_buffer, numEvents)) { + gbinder_fmq_wake(m_eventQueue, EVENT_QUEUE_FLAG_EVENTS_READ); + } else { + qCWarning(lcSensorFw) << "Reading events failed"; + return; + } + + for (unsigned int i = 0; i < numEvents; ++i) { + buffer[i].timestamp = aidl_buffer[i].timestamp; + buffer[i].sensor = aidl_buffer[i].sensor; + buffer[i].type = aidl_buffer[i].type; + // AIDL struct is too big so copy manually when needed + if (buffer[i].type == SENSOR_TYPE_ADDITIONAL_INFO) { + buffer[i].u.additional.type = aidl_buffer[i].u.data.additional.type; + buffer[i].u.additional.serial = aidl_buffer[i].u.data.additional.serial; + buffer[i].u.additional.u = aidl_buffer[i].u.data.additional.u; + } else { + memcpy(&buffer[i].u, &aidl_buffer[i].u.data, sizeof(SensorEventPayload)); + } + } + + // Queue received events for processing in main thread + int wakeupEventCount = m_manager->queueEvents(buffer, numEvents); + + // Acknowledge wakeup events + if (wakeupEventCount) { + if (gbinder_fmq_write(m_wakeLockQueue, &wakeupEventCount, 1)) { + gbinder_fmq_wake(m_wakeLockQueue, WAKE_LOCK_QUEUE_DATA_WRITTEN); + } else { + qCWarning(lcSensorFw) << "Write to wakelock queue failed"; + } + } +} + +GBinderLocalReply *HybrisBackendBinderAidl::sensorCallbackHandler( + GBinderLocalObject* obj, + GBinderRemoteRequest* req, + guint code, + guint flags, + int* status, + void* user_data) +{ + (void)flags; + (void)obj; + (void)user_data; + qCInfo(lcSensorFw) << "sensorCallbackHandler"; + const char *iface = gbinder_remote_request_interface(req); + if (iface && !strcmp(iface, SENSOR_BINDER_SERVICE_IFACE_AIDL)) { + switch (code) { + case DYNAMIC_SENSORS_CONNECTED_AIDL: + qCInfo(lcSensorFw) << "Dynamic sensor connected"; + break; + case DYNAMIC_SENSORS_DISCONNECTED_AIDL: + qCInfo(lcSensorFw) << "Dynamic sensor disconnected"; + break; + default: + qCWarning(lcSensorFw) << "Unknown code (" << code << ")"; + break; + } + *status = GBINDER_STATUS_OK; + qCInfo(lcSensorFw) << "sensorCallbackHandler valid sensor interface"; + } + return NULL; +} + +void HybrisBackendBinderAidl::getSensorList() +{ + qCInfo(lcSensorFw) << "Get sensor list"; + GBinderReader reader; + GBinderRemoteReply *reply; + int status; + + reply = gbinder_client_transact_sync_reply(m_client, GET_SENSORS_LIST_AIDL, NULL, &status); + + if (status != GBINDER_STATUS_OK) { + qCWarning(lcSensorFw) << "Unable to get sensor list: status " << status; + cleanup(); + sleep(1); + startConnect(); + return; + } + + gbinder_remote_reply_init_reader(reply, &reader); + gint32 count = 0; + gbinder_reader_read_int32(&reader, &status); + gbinder_reader_read_int32(&reader, &count); + + m_sensorCount = count; + m_sensorArray = new sensor_t[m_sensorCount]; + + for (int i = 0 ; i < m_sensorCount ; i++) { + // Parcelable non-null + gbinder_reader_read_int32(&reader, NULL); + // Parcelable size + gbinder_reader_read_int32(&reader, NULL); + + gbinder_reader_read_int32(&reader, &m_sensorArray[i].handle); + m_sensorArray[i].name.data.str = gbinder_reader_read_string16(&reader); + m_sensorArray[i].vendor.data.str = gbinder_reader_read_string16(&reader); + gbinder_reader_read_int32(&reader, &m_sensorArray[i].version); + gbinder_reader_read_int32(&reader, &m_sensorArray[i].type); + m_sensorArray[i].typeAsString.data.str = gbinder_reader_read_string16(&reader); + gbinder_reader_read_float(&reader, &m_sensorArray[i].maxRange); + gbinder_reader_read_float(&reader, &m_sensorArray[i].resolution); + gbinder_reader_read_float(&reader, &m_sensorArray[i].power); + gbinder_reader_read_int32(&reader, &m_sensorArray[i].minDelay); + gbinder_reader_read_uint32(&reader, &m_sensorArray[i].fifoReservedEventCount); + gbinder_reader_read_uint32(&reader, &m_sensorArray[i].fifoMaxEventCount); + m_sensorArray[i].requiredPermission.data.str = gbinder_reader_read_string16(&reader); + gbinder_reader_read_int32(&reader, &m_sensorArray[i].maxDelay); + gbinder_reader_read_uint32(&reader, &m_sensorArray[i].flags); + } + gbinder_remote_reply_unref(reply); + + m_manager->initManager(); + + qCWarning(lcSensorFw) << "Hybris sensor manager initialized"; +} + +void HybrisBackendBinderAidl::binderDied(GBinderRemoteObject *, void *user_data) +{ + HybrisBackendBinderAidl *conn = + static_cast(user_data); + qCWarning(lcSensorFw) << "Sensor service died! Trying to reconnect."; + conn->cleanup(); + conn->startConnect(); +} + +void HybrisBackendBinderAidl::startConnect() +{ + if (!m_serviceManager) { + m_serviceManager = gbinder_servicemanager_new(SENSOR_BINDER_SERVICE_DEVICE); + } + + if (gbinder_servicemanager_wait(m_serviceManager, -1)) { + finishConnect(); + } else { + qCWarning(lcSensorFw) << "Could not get service manager for sensor service"; + cleanup(); + } +} + +void HybrisBackendBinderAidl::finishConnect() +{ + int initializeCode; + m_remote = gbinder_servicemanager_get_service_sync(m_serviceManager, + SENSOR_BINDER_SERVICE_NAME_AIDL, NULL); + + if (m_remote) { + qCInfo(lcSensorFw) << "Connected to sensor AIDL service"; + m_sensorInterfaceEnum = SENSOR_INTERFACE_AIDL; + initializeCode = INITIALIZE_AIDL; + } + + if (m_remote) { + qCInfo(lcSensorFw) << "Initialize sensor service"; + m_deathId = gbinder_remote_object_add_death_handler(m_remote, binderDied, this); + m_client = gbinder_client_new(m_remote, SENSOR_BINDER_SERVICE_IFACE_AIDL); + if (!m_client) { + qCInfo(lcSensorFw) << "Could not create client for sensor service. Trying to reconnect."; + } else { + GBinderRemoteReply *reply; + GBinderLocalRequest *req = gbinder_client_new_request(m_client); + int32_t status; + GBinderWriter writer; + + gbinder_local_request_init_writer(req, &writer); + m_sensorCallback = gbinder_servicemanager_new_local_object( + m_serviceManager, + SENSOR_BINDER_SERVICE_CALLBACK_IFACE_AIDL, + sensorCallbackHandler, + this); + gbinder_local_object_set_stability(m_sensorCallback, GBINDER_STABILITY_VINTF); + + m_eventQueue = gbinder_fmq_new(sizeof(sensors_event_t_aidl), 128, + GBINDER_FMQ_TYPE_SYNC_READ_WRITE, GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG, -1, 0); + gbinder_writer_append_fmq_descriptor(&writer, m_eventQueue); + + m_wakeLockQueue = gbinder_fmq_new(sizeof(guint32), 128, + GBINDER_FMQ_TYPE_SYNC_READ_WRITE, GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG, -1, 0); + gbinder_writer_append_fmq_descriptor(&writer, m_wakeLockQueue); + + gbinder_writer_append_local_object(&writer, m_sensorCallback); + + reply = gbinder_client_transact_sync_reply(m_client, initializeCode, req, &status); + gbinder_local_request_unref(req); + + if (status != GBINDER_STATUS_OK) { + qCWarning(lcSensorFw) << "Initialize failed with status" << status << ". Trying to reconnect."; + gbinder_remote_reply_unref(reply); + } else { + int error = 0; + GBinderReader reader; + gbinder_remote_reply_init_reader(reply, &reader); + gbinder_reader_read_int32(&reader, &status); + if (status) { + error = status; + } + + gbinder_remote_reply_unref(reply); + if (!error) { + getSensorList(); + return; + } else { + qCWarning(lcSensorFw) << "Initialize failed with error" << error << ". Trying to reconnect."; + } + } + } + } + // On failure cleanup and wait before reconnecting + cleanup(); + sleep(1); + startConnect(); +} + +#endif diff --git a/core/hybrisbackend_binder_aidl.h b/core/hybrisbackend_binder_aidl.h new file mode 100644 index 0000000..f041eb3 --- /dev/null +++ b/core/hybrisbackend_binder_aidl.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (c) 2013 Jolla Ltd. +** Copyright (c) 2025 Jollyboys Ltd. +** Copyright (c) 2026 Jolla Mobile Ltd +** +** +** $QT_BEGIN_LICENSE:LGPL$ +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HybrisBackendBinderAidl_H +#define HybrisBackendBinderAidl_H + +#ifdef USE_BINDER +#include + +#include "hybrisbackend_binder.h" + +class HybrisBackendBinderAidl : public HybrisBackendBinder +{ + Q_OBJECT +public: + HybrisBackendBinderAidl(HybrisManager *manager, QObject *parent = 0); + ~HybrisBackendBinderAidl(); + void initialize(); + static bool isSupported(); + void cleanup(); + bool needsReaderThread(); + int setActive(int handle, bool active); + int setDelay(int handle, int64_t delay_ns); + void eventReaderThreadImpl(); + +protected: + static GBinderLocalReply *sensorCallbackHandler( + GBinderLocalObject* obj, + GBinderRemoteRequest* req, + guint code, + guint flags, + int* status, + void* user_data); + void getSensorList(); + void startConnect(); + void finishConnect(); + static void binderDied(GBinderRemoteObject *, void *user_data); +}; + +#endif + +#endif // HybrisBackendBinderAidl_H diff --git a/core/hybrisbackend_binder_hidl.cpp b/core/hybrisbackend_binder_hidl.cpp new file mode 100644 index 0000000..d51d0a5 --- /dev/null +++ b/core/hybrisbackend_binder_hidl.cpp @@ -0,0 +1,544 @@ +/**************************************************************************** +** +** Copyright (c) 2013 Jolla Ltd. +** Copyright (c) 2025 Jollyboys Ltd. +** Copyright (c) 2026 Jolla Mobile Ltd +** +** +** $QT_BEGIN_LICENSE:LGPL$ +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "hybrisbackend_binder_hidl.h" + +#ifdef USE_BINDER + +#include "hybrisadaptor.h" +#include "logging.h" + +#include + +#define SENSOR_BINDER_SERVICE_DEVICE "/dev/hwbinder" +#define SENSOR_BINDER_SERVICE_IFACE_1_0 "android.hardware.sensors@1.0::ISensors" +#define SENSOR_BINDER_SERVICE_NAME_1_0 SENSOR_BINDER_SERVICE_IFACE_1_0 "/default" +#define SENSOR_BINDER_SERVICE_IFACE_2_0 "android.hardware.sensors@2.0::ISensors" +#define SENSOR_BINDER_SERVICE_NAME_2_0 SENSOR_BINDER_SERVICE_IFACE_2_0 "/default" +#define SENSOR_BINDER_SERVICE_CALLBACK_IFACE_2_0 "android.hardware.sensors@2.0::ISensorsCallback" +#define SENSOR_BINDER_SERVICE_IFACE_2_1 "android.hardware.sensors@2.1::ISensors" +#define SENSOR_BINDER_SERVICE_NAME_2_1 SENSOR_BINDER_SERVICE_IFACE_2_1 "/default" +#define SENSOR_BINDER_SERVICE_CALLBACK_IFACE_2_1 "android.hardware.sensors@2.1::ISensorsCallback" +#define MAX_RECEIVE_BUFFER_EVENT_COUNT 128 + +static const GBinderClientIfaceInfo sensors_2_client_ifaces[] = { + {SENSOR_BINDER_SERVICE_IFACE_2_1, INJECT_SENSOR_DATA_2_1 }, + {SENSOR_BINDER_SERVICE_IFACE_2_0, CONFIG_DIRECT_REPORT }, +}; + +G_STATIC_ASSERT + (G_N_ELEMENTS(sensors_2_client_ifaces) == SENSOR_INTERFACE_2_1); + +const char* const sensors_2_callback_ifaces[] = { + SENSOR_BINDER_SERVICE_CALLBACK_IFACE_2_1, + SENSOR_BINDER_SERVICE_CALLBACK_IFACE_2_0, + NULL +}; + +extern char const *sensorTypeName(int type); + +HybrisBackendBinderHidl::HybrisBackendBinderHidl(HybrisManager *manager, QObject *parent) + : HybrisBackendBinder(manager, parent) + , m_pollTransactId(0) +{ +} + +HybrisBackendBinderHidl::~HybrisBackendBinderHidl() +{ +} + +void HybrisBackendBinderHidl::initialize() +{ + startConnect(); +} + +bool HybrisBackendBinderHidl::isSupported() +{ + bool ret = false; + GBinderServiceManager *sm = + gbinder_servicemanager_new(SENSOR_BINDER_SERVICE_DEVICE); + + if (gbinder_servicemanager_is_present(sm)) { + /* Fetch remote reference from hwservicemanager */ + GBinderRemoteObject *remote = + gbinder_servicemanager_get_service_sync(sm, + SENSOR_BINDER_SERVICE_NAME_2_1, NULL); + if (remote) { + ret = true; + } else { + remote = + gbinder_servicemanager_get_service_sync(sm, + SENSOR_BINDER_SERVICE_NAME_2_0, NULL); + if (remote) { + ret = true; + } else { + remote = + gbinder_servicemanager_get_service_sync(sm, + SENSOR_BINDER_SERVICE_NAME_1_0, NULL); + if (remote) { + ret = true; + } + } + } + } + + gbinder_servicemanager_unref(sm); + + return ret; +} + +void HybrisBackendBinderHidl::cleanup() +{ + qCInfo(lcSensorFw) << "cleanup"; + if (m_pollTransactId) { + gbinder_client_cancel(m_client, m_pollTransactId); + m_pollTransactId = 0; + + // The above code just marks down pending POLL transaction as + // to be cancelled later on when handler thread gets woken up. + // + // If we are exiting right after cleanup(), that is never going + // to happen and gbinder_ipc_exit() cleanup code blocks sensorfwd + // exit indefinitely. + // + // As a workaround: make a dummy POLL transaction, for which a + // reply is sent immediately, which then wakes up the handler + // thread, the cancellation gets processed and exit is unblocked. + + GBinderLocalRequest *req = gbinder_client_new_request2(m_client, POLL); + int32_t status = 0; + gbinder_local_request_append_int32(req, 0); + GBinderRemoteReply *reply = gbinder_client_transact_sync_reply(m_client, POLL, req, &status); + gbinder_remote_reply_unref(reply); + gbinder_local_request_unref(req); + } + HybrisBackendBinder::cleanup(); +} + +bool HybrisBackendBinderHidl::needsReaderThread() +{ + if (m_sensorInterfaceEnum == SENSOR_INTERFACE_1_0) { + pollEvents(); + return false; + } + return true; +} + +int HybrisBackendBinderHidl::setActive(int handle, bool active) +{ + if (active && m_manager->getDelay(handle) != -1) { + int index = m_manager->indexForHandle(handle); + qCInfo(lcSensorFw, "HYBRIS CTL FORCE PRE UPDATE %i, %s", handle, + sensorTypeName(m_sensorArray[index].type)); + int delay_us = m_manager->getDelay(handle); + m_manager->setDelay(handle, delay_us, true); + } + + int error; + GBinderLocalRequest *req = gbinder_client_new_request2(m_client, ACTIVATE); + GBinderRemoteReply *reply; + GBinderReader reader; + GBinderWriter writer; + int32_t status; + + gbinder_local_request_init_writer(req, &writer); + + gbinder_writer_append_int32(&writer, handle); + gbinder_writer_append_int32(&writer, active); + + reply = gbinder_client_transact_sync_reply(m_client, ACTIVATE, req, &status); + gbinder_local_request_unref(req); + + if (status != GBINDER_STATUS_OK) { + qCWarning(lcSensorFw) << "Activate failed status " << status; + return false; + } + gbinder_remote_reply_init_reader(reply, &reader); + gbinder_reader_read_int32(&reader, &status); + gbinder_reader_read_int32(&reader, &error); + + gbinder_remote_reply_unref(reply); + + return error; +} + +int HybrisBackendBinderHidl::setDelay(int handle, int64_t delay_ns) +{ + int error; + GBinderLocalRequest *req = gbinder_client_new_request2(m_client, BATCH); + GBinderRemoteReply *reply; + GBinderReader reader; + GBinderWriter writer; + int32_t status; + + gbinder_local_request_init_writer(req, &writer); + + gbinder_writer_append_int32(&writer, handle); + gbinder_writer_append_int64(&writer, delay_ns); + gbinder_writer_append_int64(&writer, 0); + + reply = gbinder_client_transact_sync_reply(m_client, BATCH, req, &status); + gbinder_local_request_unref(req); + + if (status != GBINDER_STATUS_OK) { + qCWarning(lcSensorFw) << "Set delay failed status " << status; + return false; + } + gbinder_remote_reply_init_reader(reply, &reader); + gbinder_reader_read_int32(&reader, &status); + gbinder_reader_read_int32(&reader, &error); + + gbinder_remote_reply_unref(reply); + + return error; +} + +/** + * pollEvents is only called during initialization and after that from pollEventsCallback + * triggered by binder reply so there is only maximum of one active poll at all times + */ +void HybrisBackendBinderHidl::pollEvents() +{ + if (m_client) { + GBinderLocalRequest *req = gbinder_client_new_request2(m_client, POLL); + + req = gbinder_local_request_append_int32(req, 16); // Same number as for HAL + m_pollTransactId = gbinder_client_transact(m_client, POLL, 0, req, pollEventsCallback, 0, this); + gbinder_local_request_unref(req); + } +} + +void HybrisBackendBinderHidl::pollEventsCallback( + GBinderClient* /*client*/, + GBinderRemoteReply* reply, + int status, + void* userData) +{ + HybrisBackendBinderHidl *backend = static_cast(userData); + GBinderReader reader; + int32_t readerStatus; + int32_t result; + sensors_event_t *buffer; + + backend->m_pollTransactId = 0; + + if (status != GBINDER_STATUS_OK) { + qCWarning(lcSensorFw) << "Poll failed status " << status; + // In case of binder failure sleep a little before attempting a new poll + struct timespec ts = { 0, 50 * 1000 * 1000 }; // 50 ms + do { } while (nanosleep(&ts, &ts) == -1 && errno == EINTR); + } else { + // Read sensor events from reply + gbinder_remote_reply_init_reader(reply, &reader); + gbinder_reader_read_int32(&reader, &readerStatus); + gbinder_reader_read_int32(&reader, &result); + gsize structSize = 0; + gsize eventCount = 0; + + buffer = (sensors_event_t *)gbinder_reader_read_hidl_vec(&reader, &eventCount , &structSize); + backend->m_manager->queueEvents(buffer, eventCount); + } + // Initiate new poll + backend->pollEvents(); +} + +void HybrisBackendBinderHidl::eventReaderThreadImpl() +{ + sensors_event_t buffer[maxEvents]; + size_t availableEvents = gbinder_fmq_available_to_read(m_eventQueue); + + if (availableEvents <= 0) { + guint32 state = 0; + /* Async cancellation point */ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0); + gint32 ret = gbinder_fmq_wait(m_eventQueue, + EVENT_QUEUE_FLAG_READ_AND_PROCESS, &state); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); + + if (ret < 0) { + if (ret != -ETIMEDOUT && ret != -EAGAIN) { + qCWarning(lcSensorFw) << "Waiting for events failed" << strerror(-ret); + } + return; + } + availableEvents = gbinder_fmq_available_to_read(m_eventQueue); + } + size_t numEvents = std::min(availableEvents, maxEvents); + if (numEvents == 0) { + return; + } + if (gbinder_fmq_read(m_eventQueue, buffer, numEvents)) { + gbinder_fmq_wake(m_eventQueue, EVENT_QUEUE_FLAG_EVENTS_READ); + } else { + qCWarning(lcSensorFw) << "Reading events failed"; + return; + } + + // Queue received events for processing in main thread + int wakeupEventCount = m_manager->queueEvents(buffer, numEvents); + + // Acknowledge wakeup events + if (wakeupEventCount) { + if (gbinder_fmq_write(m_wakeLockQueue, &wakeupEventCount, 1)) { + gbinder_fmq_wake(m_wakeLockQueue, WAKE_LOCK_QUEUE_DATA_WRITTEN); + } else { + qCWarning(lcSensorFw) << "Write to wakelock queue failed"; + } + } +} + +GBinderLocalReply *HybrisBackendBinderHidl::sensorCallbackHandler( + GBinderLocalObject* obj, + GBinderRemoteRequest* req, + guint code, + guint flags, + int* status, + void* user_data) +{ + (void)flags; + (void)obj; + (void)user_data; + qCInfo(lcSensorFw) << "sensorCallbackHandler"; + const char *iface = gbinder_remote_request_interface(req); + if (iface && (!strcmp(iface, SENSOR_BINDER_SERVICE_IFACE_2_0) || + !strcmp(iface, SENSOR_BINDER_SERVICE_IFACE_2_1) + )) { + switch (code) { + case DYNAMIC_SENSORS_CONNECTED_2_0: + case DYNAMIC_SENSORS_CONNECTED_2_1: + qCInfo(lcSensorFw) << "Dynamic sensor connected"; + break; + case DYNAMIC_SENSORS_DISCONNECTED_2_0: + qCInfo(lcSensorFw) << "Dynamic sensor disconnected"; + break; + default: + qCWarning(lcSensorFw) << "Unknown code (" << code << ")"; + break; + } + *status = GBINDER_STATUS_OK; + qCInfo(lcSensorFw) << "sensorCallbackHandler valid sensor interface"; + } + return NULL; +} + +void HybrisBackendBinderHidl::getSensorList() +{ + qCInfo(lcSensorFw) << "Get sensor list"; + GBinderReader reader; + GBinderRemoteReply *reply; + int status; + + if (m_sensorInterfaceEnum == SENSOR_INTERFACE_2_1) { + reply = gbinder_client_transact_sync_reply(m_client, GET_SENSORS_LIST_2_1, NULL, &status); + } else { + reply = gbinder_client_transact_sync_reply(m_client, GET_SENSORS_LIST, NULL, &status); + } + + if (status != GBINDER_STATUS_OK) { + qCWarning(lcSensorFw) << "Unable to get sensor list: status " << status; + cleanup(); + sleep(1); + startConnect(); + return; + } + + gbinder_remote_reply_init_reader(reply, &reader); + gbinder_reader_read_int32(&reader, &status); + gsize count = 0; + gsize vecSize = 0; + sensor_t *vec = (sensor_t *)gbinder_reader_read_hidl_vec(&reader, &count, &vecSize); + + m_sensorCount = count; + m_sensorArray = new sensor_t[m_sensorCount]; + + for (int i = 0 ; i < m_sensorCount ; i++) { + memcpy(&m_sensorArray[i], &vec[i], sizeof(sensor_t)); + + // Read strings + GBinderBuffer *buffer = gbinder_reader_read_buffer(&reader); + m_sensorArray[i].name.data.str = g_strdup((const gchar *)buffer->data); + m_sensorArray[i].name.len = buffer->size; + m_sensorArray[i].name.owns_buffer = true; + gbinder_buffer_free(buffer); + + buffer = gbinder_reader_read_buffer(&reader); + m_sensorArray[i].vendor.data.str = g_strdup((const gchar *)buffer->data); + m_sensorArray[i].vendor.len = buffer->size; + m_sensorArray[i].vendor.owns_buffer = true; + gbinder_buffer_free(buffer); + + buffer = gbinder_reader_read_buffer(&reader); + m_sensorArray[i].typeAsString.data.str = g_strdup((const gchar *)buffer->data); + m_sensorArray[i].typeAsString.len = buffer->size; + m_sensorArray[i].typeAsString.owns_buffer = true; + gbinder_buffer_free(buffer); + + buffer = gbinder_reader_read_buffer(&reader); + m_sensorArray[i].requiredPermission.data.str = g_strdup((const gchar *)buffer->data); + m_sensorArray[i].requiredPermission.len = buffer->size; + m_sensorArray[i].requiredPermission.owns_buffer = true; + gbinder_buffer_free(buffer); + } + gbinder_remote_reply_unref(reply); + + m_manager->initManager(); + + qCWarning(lcSensorFw) << "Hybris sensor manager initialized"; +} + +void HybrisBackendBinderHidl::binderDied(GBinderRemoteObject *, void *user_data) +{ + HybrisBackendBinderHidl *conn = + static_cast(user_data); + qCWarning(lcSensorFw) << "Sensor service died! Trying to reconnect."; + conn->cleanup(); + conn->startConnect(); +} + +void HybrisBackendBinderHidl::startConnect() +{ + if (!m_serviceManager) { + m_serviceManager = gbinder_servicemanager_new(SENSOR_BINDER_SERVICE_DEVICE); + } + + if (gbinder_servicemanager_wait(m_serviceManager, -1)) { + finishConnect(); + } else { + qCWarning(lcSensorFw) << "Could not get service manager for sensor service"; + cleanup(); + } +} + +void HybrisBackendBinderHidl::finishConnect() +{ + int initializeCode; + m_remote = gbinder_servicemanager_get_service_sync(m_serviceManager, + SENSOR_BINDER_SERVICE_NAME_2_1, NULL); + + if (m_remote) { + qCInfo(lcSensorFw) << "Connected to sensor 2.1 service"; + m_sensorInterfaceEnum = SENSOR_INTERFACE_2_1; + initializeCode = INITIALIZE_2_1; + } else { + m_remote = gbinder_servicemanager_get_service_sync(m_serviceManager, + SENSOR_BINDER_SERVICE_NAME_2_0, NULL); + if (m_remote) { + qCInfo(lcSensorFw) << "Connected to sensor 2.0 service"; + m_sensorInterfaceEnum = SENSOR_INTERFACE_2_0; + initializeCode = INITIALIZE_2_0; + } + } + + if (m_remote) { + qCInfo(lcSensorFw) << "Initialize sensor service"; + m_deathId = gbinder_remote_object_add_death_handler(m_remote, binderDied, this); + m_client = gbinder_client_new2(m_remote, sensors_2_client_ifaces, G_N_ELEMENTS(sensors_2_client_ifaces)); + if (!m_client) { + qCInfo(lcSensorFw) << "Could not create client for sensor service. Trying to reconnect."; + } else { + GBinderRemoteReply *reply; + GBinderLocalRequest *req = gbinder_client_new_request2(m_client, initializeCode); + int32_t status; + GBinderWriter writer; + + gbinder_local_request_init_writer(req, &writer); + m_sensorCallback = gbinder_servicemanager_new_local_object2( + m_serviceManager, + sensors_2_callback_ifaces, + sensorCallbackHandler, + this); + + m_eventQueue = gbinder_fmq_new(sizeof(sensors_event_t), 128, + GBINDER_FMQ_TYPE_SYNC_READ_WRITE, GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG, -1, 0); + gbinder_writer_append_fmq_descriptor(&writer, m_eventQueue); + + m_wakeLockQueue = gbinder_fmq_new(sizeof(guint32), 128, + GBINDER_FMQ_TYPE_SYNC_READ_WRITE, GBINDER_FMQ_FLAG_CONFIGURE_EVENT_FLAG, -1, 0); + gbinder_writer_append_fmq_descriptor(&writer, m_wakeLockQueue); + + gbinder_writer_append_local_object(&writer, m_sensorCallback); + + reply = gbinder_client_transact_sync_reply(m_client, initializeCode, req, &status); + gbinder_local_request_unref(req); + + if (status != GBINDER_STATUS_OK) { + qCWarning(lcSensorFw) << "Initialize failed with status" << status << ". Trying to reconnect."; + gbinder_remote_reply_unref(reply); + } else { + int error; + GBinderReader reader; + gbinder_remote_reply_init_reader(reply, &reader); + gbinder_reader_read_int32(&reader, &status); + gbinder_reader_read_int32(&reader, &error); + + gbinder_remote_reply_unref(reply); + if (!error) { + getSensorList(); + return; + } else { + qCWarning(lcSensorFw) << "Initialize failed with error" << error << ". Trying to reconnect."; + } + } + } + } else { + m_remote = gbinder_servicemanager_get_service_sync(m_serviceManager, + SENSOR_BINDER_SERVICE_NAME_1_0, NULL); + if (!m_remote) { + qCInfo(lcSensorFw) << "Could not find remote object for sensor service. Trying to reconnect"; + } else { + m_sensorInterfaceEnum = SENSOR_INTERFACE_1_0; + qCInfo(lcSensorFw) << "Connected to sensor 1.0 service"; + m_deathId = gbinder_remote_object_add_death_handler(m_remote, binderDied, + this); + m_client = gbinder_client_new(m_remote, SENSOR_BINDER_SERVICE_IFACE_1_0); + if (!m_client) { + qCInfo(lcSensorFw) << "Could not create client for sensor service. Trying to reconnect."; + } else { + // Sometimes sensor service has lingering connetion from + // previous client which causes sensor service to restart + // and we need to test with poll if remote is really working. + GBinderRemoteReply *reply; + GBinderLocalRequest *req = gbinder_client_new_request2(m_client, POLL); + int32_t status; + + // Empty poll to test if remote is working + req = gbinder_local_request_append_int32(req, 0); + + reply = gbinder_client_transact_sync_reply(m_client, POLL, req, &status); + gbinder_local_request_unref(req); + gbinder_remote_reply_unref(reply); + + if (status != GBINDER_STATUS_OK) { + qCWarning(lcSensorFw) << "Poll failed with status" << status << ". Trying to reconnect."; + } else { + getSensorList(); + return; + } + } + } + } + // On failure cleanup and wait before reconnecting + cleanup(); + sleep(1); + startConnect(); +} + +#endif diff --git a/core/hybrisbackend_binder_hidl.h b/core/hybrisbackend_binder_hidl.h new file mode 100644 index 0000000..2237b0a --- /dev/null +++ b/core/hybrisbackend_binder_hidl.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (c) 2013 Jolla Ltd. +** Copyright (c) 2025 Jollyboys Ltd. +** Copyright (c) 2026 Jolla Mobile Ltd +** +** +** $QT_BEGIN_LICENSE:LGPL$ +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HybrisBackendBinderHidl_H +#define HybrisBackendBinderHidl_H + +#ifdef USE_BINDER +#include + +#include "hybrisbackend_binder.h" + +class HybrisBackendBinderHidl : public HybrisBackendBinder +{ + Q_OBJECT +public: + HybrisBackendBinderHidl(HybrisManager *manager, QObject *parent = 0); + ~HybrisBackendBinderHidl(); + void initialize(); + static bool isSupported(); + void cleanup(); + bool needsReaderThread(); + int setActive(int handle, bool active); + int setDelay(int handle, int64_t delay_ns); + void eventReaderThreadImpl(); + +protected: + static GBinderLocalReply *sensorCallbackHandler( + GBinderLocalObject* obj, + GBinderRemoteRequest* req, + guint code, + guint flags, + int* status, + void* user_data); + void getSensorList(); + void startConnect(); + void finishConnect(); + static void binderDied(GBinderRemoteObject *, void *user_data); + void pollEvents(); + static void pollEventsCallback( + GBinderClient* /*client*/, GBinderRemoteReply* reply, + int status, void* userData); + +private: + gulong m_pollTransactId; +}; + +#endif + +#endif // HybrisBackendBinderHidl_H diff --git a/core/hybrisbackend_hal.cpp b/core/hybrisbackend_hal.cpp new file mode 100644 index 0000000..9b5542e --- /dev/null +++ b/core/hybrisbackend_hal.cpp @@ -0,0 +1,295 @@ +/**************************************************************************** +** +** Copyright (c) 2013 Jolla Ltd. +** Copyright (c) 2025 Jollyboys Ltd. +** Copyright (c) 2026 Jolla Mobile Ltd +** +** +** $QT_BEGIN_LICENSE:LGPL$ +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "hybrisbackend_hal.h" + +#ifndef USE_BINDER + +#include "hybrisadaptor.h" +#include "logging.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +HybrisBackend *getBackend(HybrisManager *manager) +{ + return qobject_cast(new HybrisBackendHal(manager)); +} + +HybrisBackendHal::HybrisBackendHal(HybrisManager *manager, QObject *parent) + : HybrisBackend(manager, parent) + , m_halModule(NULL) + , m_halDevice(NULL) + , m_sensorArray(NULL) +{ +} + +HybrisBackendHal::~HybrisBackendHal() +{ +} + +void HybrisBackendHal::initialize() +{ + int err; + + /* Open android sensor plugin */ + for (int retries = 4; ;) { + // Try module loading in throwaway child process + // so that we can retry from clean slate if needed + fflush(nullptr); + pid_t child_pid = fork(); + + if (child_pid == 0) { + // Child process + const hw_module_t *dummyModule = nullptr; + err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, &dummyModule); + _exit(err ? EXIT_FAILURE : EXIT_SUCCESS); + } + + if (child_pid == -1) { + qCWarning(lcSensorFw) << "w_get_module() probe, fork failed:" << strerror(errno); + QCoreApplication::exit(EXIT_FAILURE); + return; + } + + int status = 0; + if (waitpid(child_pid, &status, 0) == -1) { + qCWarning(lcSensorFw) << "w_get_module() probe, waitpid failed:" << strerror(errno); + QCoreApplication::exit(EXIT_FAILURE); + return; + } + + // If probe in child process was successful, do it for real + if (WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS) { + err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, + (hw_module_t const **)&m_halModule); + if (err == 0) + break; + + qCWarning(lcSensorFw) << "hw_get_module() failed:" << strerror(-err); + m_halModule = nullptr; + QCoreApplication::exit(EXIT_FAILURE); + return; + } + + // Bailout or retry after brief delay + if (--retries < 0) { + qCWarning(lcSensorFw) << "hw_get_module() probe failed - giving up"; + QCoreApplication::exit(EXIT_FAILURE); + return; + } + + qCWarning(lcSensorFw) << "hw_get_module() probe failed"; + QThread::msleep(2000); + } + + /* Open android sensor device */ + err = sensors_open_1(&m_halModule->common, &m_halDevice); + if (err != 0) { + m_halDevice = 0; + qCWarning(lcSensorFw) << "sensors_open() failed:" << strerror(-err); + QCoreApplication::exit(EXIT_FAILURE); + return; + } + + /* Get static sensor information */ + m_sensorCount = m_halModule->get_sensors_list(m_halModule, &m_sensorArray); + if (m_sensorCount <= 0) { + qCWarning(lcSensorFw) << "no sensors found"; + QCoreApplication::exit(EXIT_FAILURE); + return; + } + + m_manager->initManager(); +} + +void HybrisBackendHal::cleanup() +{ + if (m_halDevice) { + qCInfo(lcSensorFw) << "close sensor device"; + int errorCode = sensors_close_1(m_halDevice); + if (errorCode != 0) { + qCWarning(lcSensorFw) << "sensors_close() failed:" << strerror(-errorCode); + } + m_halDevice = NULL; + } +} + +bool HybrisBackendHal::needsReaderThread() +{ + return true; +} + +bool HybrisBackendHal::needsWakeup(const sensors_event_t *eve) +{ + if (m_manager->typeRequiresWakeup(eve->type)) { + return true; + } + return false; +} + +bool HybrisBackendHal::isValid(const sensors_event_t *eve) +{ + if (eve->version != sizeof(sensors_event_t)) { + qCWarning(lcSensorFw) << QString("incorrect event version (version=%1, expected=%2").arg(eve->version).arg(sizeof(sensors_event_t)); + return false; + } + return true; +} + +int HybrisBackendHal::handle(int index) +{ + return m_sensorArray[index].handle; +} + +int HybrisBackendHal::type(int index) +{ + return m_sensorArray[index].type; +} + +bool HybrisBackendHal::isWakeupSensor(int index) +{ +#if defined(SENSORS_DEVICE_API_VERSION_1_3) + if (m_halDevice->common.version >= SENSORS_DEVICE_API_VERSION_1_3) { + if (m_sensorArray[index].flags & SENSOR_FLAG_WAKE_UP) + return true; + } else { + if (strstr(sensorName(index), "(WAKE_UP)")) + return true; + } +#else + if (strstr(sensorName(index), "(WAKE_UP)")) + return true; +#endif + return false; +} + +void HybrisBackendHal::initFallbackEvent(int index, sensors_event_t *eve) +{ + eve->version = sizeof *eve; + eve->sensor = m_sensorArray[index].handle; + eve->type = m_sensorArray[index].type; + switch (m_sensorArray[index].type) { + case SENSOR_TYPE_LIGHT: + // Roughly indoor lightning + eve->light = 400; + break; + case SENSOR_TYPE_PROXIMITY: + // Not-covered + eve->distance = m_sensorArray[index].maxRange; + break; + default: + eve->sensor = 0; + eve->type = 0; + break; + } +} + +const char *HybrisBackendHal::sensorName(int index) +{ + return m_sensorArray[index].name ?: "unknown"; +} + +int HybrisBackendHal::maxDelay(int index) +{ +#ifdef SENSORS_DEVICE_API_VERSION_1_3 + if (m_halDevice->common.version >= SENSORS_DEVICE_API_VERSION_1_3) + return m_sensorArray[index].maxDelay; +#endif + return -1; +} + +int HybrisBackendHal::minDelay(int index) +{ + return m_sensorArray[index].minDelay; +} + +float HybrisBackendHal::maxRange(int index) +{ + return m_sensorArray[index].maxRange; +} + +float HybrisBackendHal::resolution(int index) +{ + return m_sensorArray[index].resolution; +} + +int HybrisBackendHal::setActive(int handle, bool active) +{ + int error = m_halDevice->activate(&m_halDevice->v0, handle, active); + + if (!error) { + if (active && m_manager->getDelay(handle) != -1) { + qCInfo(lcSensorFw, "HYBRIS CTL FORCE DELAY UPDATE"); + int delay_us = m_manager->getDelay(handle); + m_manager->setDelay(handle, delay_us, false); + } + } + + return error; +} + +int HybrisBackendHal::setDelay(int handle, int64_t delay_ns) +{ + int error = EBADSLT; + if (m_halDevice->common.version >= SENSORS_DEVICE_API_VERSION_1_0) { + if (m_halDevice->batch) + error = m_halDevice->batch(m_halDevice, handle, 0, delay_ns, 0); + else if (m_halDevice->setDelay) + error = m_halDevice->setDelay(&m_halDevice->v0, handle, delay_ns); + } else { + if (m_halDevice->setDelay) + error = m_halDevice->setDelay(&m_halDevice->v0, handle, delay_ns); + else if (m_halDevice->batch) // Here be dragons + error = m_halDevice->batch(m_halDevice, handle, 0, delay_ns, 0); + } + + return error; +} + +void HybrisBackendHal::eventReaderThreadImpl() +{ + sensors_event_t buffer[maxEvents]; + + /* Async cancellation point at android hal poll() */ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0); + int numEvents = m_halDevice->poll(&m_halDevice->v0, buffer, maxEvents); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0); + /* Rate limit in poll() error situations */ + if (numEvents < 0) { + qCWarning(lcSensorFw) << "android device->poll() failed" << strerror(-numEvents); + struct timespec ts = { 1, 0 }; // 1000 ms + do { } while (nanosleep(&ts, &ts) == -1 && errno == EINTR); + return; + } + // Queue received events for processing in main thread + m_manager->queueEvents(buffer, numEvents); +} + +#endif diff --git a/core/hybrisbackend_hal.h b/core/hybrisbackend_hal.h new file mode 100644 index 0000000..9cdf006 --- /dev/null +++ b/core/hybrisbackend_hal.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (c) 2013 Jolla Ltd. +** Copyright (c) 2025 Jollyboys Ltd. +** Copyright (c) 2026 Jolla Mobile Ltd +** +** +** $QT_BEGIN_LICENSE:LGPL$ +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef HybrisBackendHal_H +#define HybrisBackendHal_H + +#ifndef USE_BINDER + +#include + +#include "hybrisbackend.h" + +class HybrisBackendHal : public HybrisBackend +{ + Q_OBJECT +public: + HybrisBackendHal(HybrisManager *manager, QObject *parent = 0); + ~HybrisBackendHal(); + void initialize(); + void cleanup(); + bool needsReaderThread(); + bool needsWakeup(const sensors_event_t *eve); + bool isValid(const sensors_event_t *eve); + void initFallbackEvent(int index, sensors_event_t *eve); + int handle(int index); + int type(int index); + bool isWakeupSensor(int index); + const char *sensorName(int index); + int maxDelay(int index); + int minDelay(int index); + float maxRange(int index); + float resolution(int index); + int setActive(int handle, bool active); + int setDelay(int handle, int64_t delay_ns); + void eventReaderThreadImpl(); + +private: + struct sensors_module_t *m_halModule; + sensors_poll_device_1_t *m_halDevice; + const struct sensor_t *m_sensorArray; // [m_sensorCount] +}; + +#endif + +#endif // HybrisBackendHal_H diff --git a/core/hybrisbindertypes.h b/core/hybrisbindertypes.h index 1d55eba..2ad02ba 100644 --- a/core/hybrisbindertypes.h +++ b/core/hybrisbindertypes.h @@ -30,6 +30,7 @@ typedef enum sensor_interface { SENSOR_INTERFACE_1_0, SENSOR_INTERFACE_2_0, SENSOR_INTERFACE_2_1, + SENSOR_INTERFACE_AIDL, SENSOR_INTERFACE_COUNT } SENSOR_INTERFACE; @@ -74,6 +75,25 @@ enum binder_callbacks_2 { DYNAMIC_SENSORS_CONNECTED_2_1 }; +enum binder_calls_aidl { + // MUST be in the same order as the interfaces in ISensors.aidl + ACTIVATE_AIDL = GBINDER_FIRST_CALL_TRANSACTION, + BATCH_AIDL, + CONFIG_DIRECT_REPORT_AIDL, + FLUSH_AIDL, + GET_SENSORS_LIST_AIDL, + INITIALIZE_AIDL, + INJECT_SENSOR_DATA_AIDL, + REGISTER_DIRECT_CHANNEL_AIDL, + SET_OPERATION_MODE_AIDL, + UNREGISTER_DIRECT_CHANNEL_AIDL, +}; + +enum binder_callbacks_aidl { + DYNAMIC_SENSORS_CONNECTED_AIDL = GBINDER_FIRST_CALL_TRANSACTION, + DYNAMIC_SENSORS_DISCONNECTED_AIDL, +}; + enum { RESULT_OK = 0, RESULT_PERMISSION_DENIED = -1, @@ -289,6 +309,102 @@ struct sensors_event_t { static_assert(sizeof(sensors_event_t) == 80, "wrong size"); +struct HeadTracker { + float rx ALIGNED(4); + float ry ALIGNED(4); + float rz ALIGNED(4); + float vx ALIGNED(4); + float vy ALIGNED(4); + float vz ALIGNED(4); + int discontinuityCount ALIGNED(4); +} ALIGNED(4); + +static_assert(sizeof(HeadTracker) == 28, "wrong size"); + +struct LimitedAxesImu { + float x ALIGNED(4); + float y ALIGNED(4); + float z ALIGNED(4); + float xSupported ALIGNED(4); + float ySupported ALIGNED(4); + float zSupported ALIGNED(4); +} ALIGNED(4); + +static_assert(sizeof(LimitedAxesImu) == 24, "wrong size"); + +struct LimitedAxesImuUncal { + float x ALIGNED(4); + float y ALIGNED(4); + float z ALIGNED(4); + float xBias ALIGNED(4); + float yBias ALIGNED(4); + float zBias ALIGNED(4); + float xSupported ALIGNED(4); + float ySupported ALIGNED(4); + float zSupported ALIGNED(4); +} ALIGNED(4); + +static_assert(sizeof(LimitedAxesImuUncal) == 36, "wrong size"); + +struct Heading { + float heading ALIGNED(4); + float accuracy ALIGNED(4); +} ALIGNED(4); + +static_assert(sizeof(Heading) == 8, "wrong size"); + +struct AdditionalInfoAidl { + union Payload { + int32_t data_int32[14] ALIGNED(4); + float data_float[14] ALIGNED(4); + } ALIGNED(4); + + static_assert(sizeof(AdditionalInfo::Payload) == 56, "wrong size"); + + AdditionalInfoType type ALIGNED(4); + int32_t serial ALIGNED(4); + int32_t tag ALIGNED(4); + AdditionalInfo::Payload u ALIGNED(4); +} ALIGNED(4); + +static_assert(sizeof(AdditionalInfoAidl) == 68, "wrong size"); + +union SensorEventPayloadAidl { + Vec3 vec3 ALIGNED(4); + Vec4 vec4 ALIGNED(4); + Uncal uncal ALIGNED(4); + MetaData meta ALIGNED(4); + float scalar ALIGNED(4); + uint64_t stepCount ALIGNED(8); + HeartRate heartRate ALIGNED(4); + float pose6DOF[15] ALIGNED(4); + Dynamicsensor_t dynamic ALIGNED(4); + AdditionalInfoAidl additional ALIGNED(4); + float data[16] ALIGNED(4); + HeadTracker headTracker ALIGNED(4); + LimitedAxesImu limitedAxesImu ALIGNED(4); + LimitedAxesImuUncal limitedAxesImuUncal ALIGNED(4); + Heading heading ALIGNED(4); +} ALIGNED(8); + +static_assert(sizeof(SensorEventPayloadAidl) == 72, "wrong size"); + +struct SensorEventPayloadAidlWrapper { + int32_t type ALIGNED(8); + SensorEventPayloadAidl data ALIGNED(8); +} ALIGNED(8); + +static_assert(sizeof(SensorEventPayloadAidlWrapper) == 80, "wrong size"); + +struct sensors_event_t_aidl { + int64_t timestamp ALIGNED(8); + int32_t sensor ALIGNED(4); + int32_t type ALIGNED(4); + SensorEventPayloadAidlWrapper u ALIGNED(8); +} ALIGNED(8); + +static_assert(sizeof(sensors_event_t_aidl) == 96, "wrong size"); + enum class RateLevel : int32_t { STOP = 0, NORMAL = 1,