==== Summary ==== android.frameworks.sensorservice@1.0 is a package that mimics the sensors API in NDK (sensor.h). It includes a subset of these APIs and introduces a few adaptations. === Design Details === - ISensorManager ISensorMangaer includes member functions that adapts the ASensorManager_* series in NDK. An instance of ISensorManager must be able to - retrieve sensors - create direct report channel - create event queue - IDirectReportChannel IDirectReportChannel corresponds to a channel ID, an integer obtained in ASensorManager_createSharedMemoryDirectChannel and ASensorManager_createHardwareBufferDirectChannel. An instance of IDirectReportChannel must also destroy it against the sensor manager. An IDirectReportChannel must be able to configure itself (an adaptation to ASensorManager_configureDirectReport). The implementation must also call ASensorManager_destroyEventQueue on destruction of IDirectReportChannel. Usage typically looks like this (transaction errors are not handled): sp manager = ISensorManager::getService(); int32_t sensorHandle; manager->getDefaultSensor(SensorType::GYROSCOPE, [&sensorHandle] (const auto &info) { sensorHandle = info.sensorHandle; }); hidl_memory mem; const uint64_t size = 4096; ::android::hidl::memory::V1_0::IAllocator::getService()->allocate(size, [&](auto, const auto &m) { mem = m; }); if (!mem.handle()) { /* error handling */ } sp chan; Result res; manager->createAshmemDirectChannel(mem, size, [&chan, &res] (const auto &c, auto r) { chan = c; res = r; }); if (res != Result::OK) { /* error handling */ } chan->configure(sensorHandle, RateLevel::FAST, [&](auto token, auto result) { if (result != Result::OK) { /* error handling */ } }); /* obtain sensor events from shared memory */ chan->configure(sensorHandle, RateLevel::STOP, [&](auto token, auto result) { if (result != Result::OK) { /* error handling */ } }); /* * Free the channel. * kernel calls decStrong() on server side implementation of IDirectChannel, * hence resources are freed as well. */ chan = nullptr; - IEventQueue, IEventQueueCallback IEventQueue includes member functions that adapts some of the ASensorEventQueue_* seeries in NDK. An instance of IEventQueue must be able to - enable selected sensors (adapts ASensorEventQueue_registerSensor) - disable selected sensors (adapts ASensorEventQueue_disableSensor) The implementation must free all resources related to this IEventQueue instance and call ASensorManager_destroyEventQueue on destruction of IEventQueue. Unlike NDK ASensorEventQueue_hasEvents and ASensorEventQueue_getEvents, which implies a poll model for sensor events, IEventQueue uses a push model by using callbacks. When creating an event queue, client must provide an instance of IEventQueueCallback. The implementation of IEventQueue must either use a global looper or create a new looper to call on ASensorManager_createEventQueue. The server implementation must use this looper to constantly poll for events, then invoke the callback when any event is fired. IEventQueueCallback.onEvent is designed to be oneway, because the server should not wait for the client to finish handling the event. The callback should finish in a predictably short time, and should not block or run for an extended period of time. The callbacks can be invoked in a very high frequency; a long running callback means delay in handling of subsequent events and filling up the (kernel binder buffer) memory space of the client process, eventually the server sees a transaction error when issuing the callback. It is up to the client to be configured single-threaded or multi-threaded to handle these callbacks. - Single-threaded clients receive events in the correct order in the same thread. - Multi-threaded clients receive events in the correct order but in different threads; it is the clients' responsibility to deal with concurrency issues and handle events in the expected order to avoid race conditions. Usage typically looks like this (transaction errors are not handled): struct Callback : IEventQueueCallback { Return onEvent(const Event &e) { /* handle sensor event e */ } }; sp manager = ISensorManager::getService(); int32_t sensorHandle; manager->getDefaultSensor(SensorType::GYROSCOPE, [&sensorHandle] (const auto &info) { sensorHandle = info.sensorHandle; }); sp queue; Result res; manager->createEventQueue(new Callback(), [&queue, &res] (const auto &q, auto r) { queue = q; res = r; }); /* Server side implementation of IEventQueue holds a strong reference to * the callback. */ if (res != Result::OK) { /* error handling */ } if (q->enableSensor(sensorHandle, 20000 /* sample period */, 0 /* latency */) != Result::OK) { /* error handling */ } /* start receiving events via onEvent */ if (q->disableSensor(sensorHandle) != Result::OK) { /* error handling */ } /* * Free the event queue. * kernel calls decStrong() on server side implementation of IEventQueue, * hence resources (including the callback) are freed as well. */ queue = nullptr;