From 16b56bc01104b46ea5fcccc04ca32b9e1ffc6cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matti=20Lehtim=C3=A4ki?= Date: Sat, 22 Nov 2025 22:19:16 +0200 Subject: [PATCH 1/2] [hybrisadaptor] Split hybris backends to separate classes. JB#61406 Don't wait for hwbinder servicemanager when checking if hidl backend is supported. One new devices hwbinder servicemanager is not present anymore and waiting for servicemanager would cause the service to wait forever. --- core/hybris.pro | 12 +- core/hybrisadaptor.cpp | 846 +++-------------------------- core/hybrisadaptor.h | 53 +- core/hybrisbackend.cpp | 34 ++ core/hybrisbackend.h | 75 +++ core/hybrisbackend_binder.cpp | 167 ++++++ core/hybrisbackend_binder.h | 69 +++ core/hybrisbackend_binder_hidl.cpp | 544 +++++++++++++++++++ core/hybrisbackend_binder_hidl.h | 67 +++ core/hybrisbackend_hal.cpp | 295 ++++++++++ core/hybrisbackend_hal.h | 63 +++ 11 files changed, 1402 insertions(+), 823 deletions(-) create mode 100644 core/hybrisbackend.cpp create mode 100644 core/hybrisbackend.h create mode 100644 core/hybrisbackend_binder.cpp create mode 100644 core/hybrisbackend_binder.h create mode 100644 core/hybrisbackend_binder_hidl.cpp create mode 100644 core/hybrisbackend_binder_hidl.h create mode 100644 core/hybrisbackend_hal.cpp create mode 100644 core/hybrisbackend_hal.h diff --git a/core/hybris.pro b/core/hybris.pro index a9c87dc4..552d79a6 100644 --- a/core/hybris.pro +++ b/core/hybris.pro @@ -13,8 +13,16 @@ SENSORFW_INCLUDEPATHS = .. \ DEPENDPATH += $$SENSORFW_INCLUDEPATHS INCLUDEPATH += $$SENSORFW_INCLUDEPATHS -SOURCES += hybrisadaptor.cpp -HEADERS += hybrisadaptor.h +SOURCES += hybrisadaptor.cpp \ + hybrisbackend.cpp \ + hybrisbackend_binder.cpp \ + hybrisbackend_binder_hidl.cpp \ + hybrisbackend_hal.cpp +HEADERS += hybrisadaptor.h \ + hybrisbackend.h \ + hybrisbackend_binder.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 3c78febd..a6bbaf84 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 69958eca..455d4350 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 00000000..801c5860 --- /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 00000000..5e5e35aa --- /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 00000000..e842d136 --- /dev/null +++ b/core/hybrisbackend_binder.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** 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_hidl.h" +#include "hybrisadaptor.h" + +#include + +HybrisBackend *getBackend(HybrisManager *manager) +{ + HybrisBackend *backend = NULL; + for (int i = 0; i < 5; ++i) { + 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 00000000..9755a56a --- /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_hidl.cpp b/core/hybrisbackend_binder_hidl.cpp new file mode 100644 index 00000000..d51d0a54 --- /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 00000000..2237b0ad --- /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 00000000..9b5542ed --- /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 00000000..9cdf006e --- /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 From fabd2acd7ffd9d27d04a031bdee6b7a527f788a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matti=20Lehtim=C3=A4ki?= Date: Sun, 23 Nov 2025 04:10:27 +0200 Subject: [PATCH 2/2] [hybrisadaptor] Add support for AIDL binder interface. JB#61406 --- core/hybris.pro | 2 + core/hybrisbackend_binder.cpp | 6 +- core/hybrisbackend_binder_aidl.cpp | 400 +++++++++++++++++++++++++++++ core/hybrisbackend_binder_aidl.h | 60 +++++ core/hybrisbindertypes.h | 116 +++++++++ 5 files changed, 583 insertions(+), 1 deletion(-) create mode 100644 core/hybrisbackend_binder_aidl.cpp create mode 100644 core/hybrisbackend_binder_aidl.h diff --git a/core/hybris.pro b/core/hybris.pro index 552d79a6..4804826b 100644 --- a/core/hybris.pro +++ b/core/hybris.pro @@ -16,11 +16,13 @@ INCLUDEPATH += $$SENSORFW_INCLUDEPATHS 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} diff --git a/core/hybrisbackend_binder.cpp b/core/hybrisbackend_binder.cpp index e842d136..def27960 100644 --- a/core/hybrisbackend_binder.cpp +++ b/core/hybrisbackend_binder.cpp @@ -22,6 +22,7 @@ #ifdef USE_BINDER #include "hybrisbackend_binder.h" +#include "hybrisbackend_binder_aidl.h" #include "hybrisbackend_binder_hidl.h" #include "hybrisadaptor.h" @@ -31,7 +32,10 @@ HybrisBackend *getBackend(HybrisManager *manager) { HybrisBackend *backend = NULL; for (int i = 0; i < 5; ++i) { - if (HybrisBackendBinderHidl::isSupported()) { + if (HybrisBackendBinderAidl::isSupported()) { + backend = qobject_cast(new HybrisBackendBinderAidl(manager)); + break; + } else if (HybrisBackendBinderHidl::isSupported()) { backend = qobject_cast(new HybrisBackendBinderHidl(manager)); break; } diff --git a/core/hybrisbackend_binder_aidl.cpp b/core/hybrisbackend_binder_aidl.cpp new file mode 100644 index 00000000..1f05cd0d --- /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 00000000..f041eb3b --- /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/hybrisbindertypes.h b/core/hybrisbindertypes.h index 1d55ebad..2ad02ba1 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,