Merge "Add Sensors Multihal support for Hal 2.0"

This commit is contained in:
Treehugger Robot
2019-10-31 15:32:44 +00:00
committed by Gerrit Code Review
17 changed files with 3399 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
//
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
cc_defaults {
name: "android.hardware.sensors@2.0-multihal-defaults",
header_libs: [
"android.hardware.sensors@2.0-multihal.header",
],
shared_libs: [
"android.hardware.sensors@1.0",
"android.hardware.sensors@2.0",
"libbase",
"libcutils",
"libfmq",
"libhidlbase",
"liblog",
"libpower",
"libutils",
],
cflags: ["-DLOG_TAG=\"SensorsMultiHal\""],
}
cc_binary {
name: "android.hardware.sensors@2.0-service.multihal",
defaults: [
"hidl_defaults",
"android.hardware.sensors@2.0-multihal-defaults",
],
vendor: true,
relative_install_path: "hw",
srcs: [
"service.cpp",
"HalProxy.cpp",
"ScopedWakelock.cpp",
],
init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"],
vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"],
}
cc_library_headers {
name: "android.hardware.sensors@2.0-multihal.header",
vendor_available: true,
export_include_dirs: ["include"],
}
// The below targets should only be used for testing.
cc_test_library {
name: "android.hardware.sensors@2.0-HalProxy",
defaults: ["android.hardware.sensors@2.0-multihal-defaults"],
vendor_available: true,
srcs: [
"HalProxy.cpp",
"ScopedWakelock.cpp",
],
export_header_lib_headers: [
"android.hardware.sensors@2.0-multihal.header",
],
shared_libs: [
"libutils",
],
}

View File

@@ -0,0 +1,686 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "HalProxy.h"
#include "SubHal.h"
#include <android/hardware/sensors/2.0/types.h>
#include <android-base/file.h>
#include "hardware_legacy/power.h"
#include <dlfcn.h>
#include <cinttypes>
#include <cmath>
#include <fstream>
#include <functional>
#include <thread>
namespace android {
namespace hardware {
namespace sensors {
namespace V2_0 {
namespace implementation {
using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
using ::android::hardware::sensors::V2_0::implementation::getTimeNow;
using ::android::hardware::sensors::V2_0::implementation::kWakelockTimeoutNs;
typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*);
static constexpr int32_t kBitsAfterSubHalIndex = 24;
/**
* Set the subhal index as first byte of sensor handle and return this modified version.
*
* @param sensorHandle The sensor handle to modify.
* @param subHalIndex The index in the hal proxy of the sub hal this sensor belongs to.
*
* @return The modified sensor handle.
*/
int32_t setSubHalIndex(int32_t sensorHandle, size_t subHalIndex) {
return sensorHandle | (static_cast<int32_t>(subHalIndex) << kBitsAfterSubHalIndex);
}
/**
* Extract the subHalIndex from sensorHandle.
*
* @param sensorHandle The sensorHandle to extract from.
*
* @return The subhal index.
*/
size_t extractSubHalIndex(int32_t sensorHandle) {
return static_cast<size_t>(sensorHandle >> kBitsAfterSubHalIndex);
}
/**
* Convert nanoseconds to milliseconds.
*
* @param nanos The nanoseconds input.
*
* @return The milliseconds count.
*/
int64_t msFromNs(int64_t nanos) {
constexpr int64_t nanosecondsInAMillsecond = 1000000;
return nanos / nanosecondsInAMillsecond;
}
HalProxy::HalProxy() {
const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf";
initializeSubHalListFromConfigFile(kMultiHalConfigFile);
init();
}
HalProxy::HalProxy(std::vector<ISensorsSubHal*>& subHalList) : mSubHalList(subHalList) {
init();
}
HalProxy::~HalProxy() {
stopThreads();
}
Return<void> HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) {
std::vector<SensorInfo> sensors;
for (const auto& iter : mSensors) {
sensors.push_back(iter.second);
}
_hidl_cb(sensors);
return Void();
}
Return<Result> HalProxy::setOperationMode(OperationMode mode) {
Result result = Result::OK;
size_t subHalIndex;
for (subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
ISensorsSubHal* subHal = mSubHalList[subHalIndex];
result = subHal->setOperationMode(mode);
if (result != Result::OK) {
ALOGE("setOperationMode failed for SubHal: %s", subHal->getName().c_str());
break;
}
}
if (result != Result::OK) {
// Reset the subhal operation modes that have been flipped
for (size_t i = 0; i < subHalIndex; i++) {
ISensorsSubHal* subHal = mSubHalList[i];
subHal->setOperationMode(mCurrentOperationMode);
}
} else {
mCurrentOperationMode = mode;
}
return result;
}
Return<Result> HalProxy::activate(int32_t sensorHandle, bool enabled) {
if (!isSubHalIndexValid(sensorHandle)) {
return Result::BAD_VALUE;
}
return getSubHalForSensorHandle(sensorHandle)
->activate(clearSubHalIndex(sensorHandle), enabled);
}
Return<Result> HalProxy::initialize(
const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
const sp<ISensorsCallback>& sensorsCallback) {
Result result = Result::OK;
stopThreads();
resetSharedWakelock();
// So that the pending write events queue can be cleared safely and when we start threads
// again we do not get new events until after initialize resets the subhals.
disableAllSensors();
// Clears the queue if any events were pending write before.
mPendingWriteEventsQueue = std::queue<std::pair<std::vector<Event>, size_t>>();
// Clears previously connected dynamic sensors
mDynamicSensors.clear();
mDynamicSensorsCallback = sensorsCallback;
// Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions.
mEventQueue =
std::make_unique<EventMessageQueue>(eventQueueDescriptor, true /* resetPointers */);
// Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP
// events have been successfully read and handled by the framework.
mWakeLockQueue =
std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */);
if (mEventQueueFlag != nullptr) {
EventFlag::deleteEventFlag(&mEventQueueFlag);
}
if (mWakelockQueueFlag != nullptr) {
EventFlag::deleteEventFlag(&mWakelockQueueFlag);
}
if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
result = Result::BAD_VALUE;
}
if (EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakelockQueueFlag) != OK) {
result = Result::BAD_VALUE;
}
if (!mDynamicSensorsCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
result = Result::BAD_VALUE;
}
mThreadsRun.store(true);
mPendingWritesThread = std::thread(startPendingWritesThread, this);
mWakelockThread = std::thread(startWakelockThread, this);
for (size_t i = 0; i < mSubHalList.size(); i++) {
auto subHal = mSubHalList[i];
const auto& subHalCallback = mSubHalCallbacks[i];
Result currRes = subHal->initialize(subHalCallback);
if (currRes != Result::OK) {
result = currRes;
ALOGE("Subhal '%s' failed to initialize.", subHal->getName().c_str());
break;
}
}
mCurrentOperationMode = OperationMode::NORMAL;
return result;
}
Return<Result> HalProxy::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
int64_t maxReportLatencyNs) {
if (!isSubHalIndexValid(sensorHandle)) {
return Result::BAD_VALUE;
}
return getSubHalForSensorHandle(sensorHandle)
->batch(clearSubHalIndex(sensorHandle), samplingPeriodNs, maxReportLatencyNs);
}
Return<Result> HalProxy::flush(int32_t sensorHandle) {
if (!isSubHalIndexValid(sensorHandle)) {
return Result::BAD_VALUE;
}
return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle));
}
Return<Result> HalProxy::injectSensorData(const Event& event) {
Result result = Result::OK;
if (mCurrentOperationMode == OperationMode::NORMAL &&
event.sensorType != V1_0::SensorType::ADDITIONAL_INFO) {
ALOGE("An event with type != ADDITIONAL_INFO passed to injectSensorData while operation"
" mode was NORMAL.");
result = Result::BAD_VALUE;
}
if (result == Result::OK) {
Event subHalEvent = event;
if (!isSubHalIndexValid(event.sensorHandle)) {
return Result::BAD_VALUE;
}
subHalEvent.sensorHandle = clearSubHalIndex(event.sensorHandle);
result = getSubHalForSensorHandle(event.sensorHandle)->injectSensorData(subHalEvent);
}
return result;
}
Return<void> HalProxy::registerDirectChannel(const SharedMemInfo& mem,
registerDirectChannel_cb _hidl_cb) {
if (mDirectChannelSubHal == nullptr) {
_hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
} else {
mDirectChannelSubHal->registerDirectChannel(mem, _hidl_cb);
}
return Return<void>();
}
Return<Result> HalProxy::unregisterDirectChannel(int32_t channelHandle) {
Result result;
if (mDirectChannelSubHal == nullptr) {
result = Result::INVALID_OPERATION;
} else {
result = mDirectChannelSubHal->unregisterDirectChannel(channelHandle);
}
return result;
}
Return<void> HalProxy::configDirectReport(int32_t sensorHandle, int32_t channelHandle,
RateLevel rate, configDirectReport_cb _hidl_cb) {
if (mDirectChannelSubHal == nullptr) {
_hidl_cb(Result::INVALID_OPERATION, -1 /* reportToken */);
} else {
mDirectChannelSubHal->configDirectReport(clearSubHalIndex(sensorHandle), channelHandle,
rate, _hidl_cb);
}
return Return<void>();
}
Return<void> HalProxy::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /*args*/) {
if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
ALOGE("%s: missing fd for writing", __FUNCTION__);
return Void();
}
android::base::borrowed_fd writeFd = dup(fd->data[0]);
std::ostringstream stream;
stream << "===HalProxy===" << std::endl;
stream << "Internal values:" << std::endl;
stream << " Threads are running: " << (mThreadsRun.load() ? "true" : "false") << std::endl;
int64_t now = getTimeNow();
stream << " Wakelock timeout start time: " << msFromNs(now - mWakelockTimeoutStartTime)
<< " ms ago" << std::endl;
stream << " Wakelock timeout reset time: " << msFromNs(now - mWakelockTimeoutResetTime)
<< " ms ago" << std::endl;
// TODO(b/142969448): Add logging for history of wakelock acquisition per subhal.
stream << " Wakelock ref count: " << mWakelockRefCount << std::endl;
stream << " Size of pending write events queue: " << mPendingWriteEventsQueue.size()
<< std::endl;
if (!mPendingWriteEventsQueue.empty()) {
stream << " Size of events list on front of pending writes queue: "
<< mPendingWriteEventsQueue.front().first.size() << std::endl;
}
stream << " # of non-dynamic sensors across all subhals: " << mSensors.size() << std::endl;
stream << " # of dynamic sensors across all subhals: " << mDynamicSensors.size() << std::endl;
stream << "SubHals (" << mSubHalList.size() << "):" << std::endl;
for (ISensorsSubHal* subHal : mSubHalList) {
stream << " Name: " << subHal->getName() << std::endl;
stream << " Debug dump: " << std::endl;
android::base::WriteStringToFd(stream.str(), writeFd);
subHal->debug(fd, {});
stream.str("");
stream << std::endl;
}
android::base::WriteStringToFd(stream.str(), writeFd);
return Return<void>();
}
Return<void> HalProxy::onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
int32_t subHalIndex) {
std::vector<SensorInfo> sensors;
{
std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
for (SensorInfo sensor : dynamicSensorsAdded) {
if (!subHalIndexIsClear(sensor.sensorHandle)) {
ALOGE("Dynamic sensor added %s had sensorHandle with first byte not 0.",
sensor.name.c_str());
} else {
sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
mDynamicSensors[sensor.sensorHandle] = sensor;
sensors.push_back(sensor);
}
}
}
mDynamicSensorsCallback->onDynamicSensorsConnected(sensors);
return Return<void>();
}
Return<void> HalProxy::onDynamicSensorsDisconnected(
const hidl_vec<int32_t>& dynamicSensorHandlesRemoved, int32_t subHalIndex) {
// TODO(b/143302327): Block this call until all pending events are flushed from queue
std::vector<int32_t> sensorHandles;
{
std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
for (int32_t sensorHandle : dynamicSensorHandlesRemoved) {
if (!subHalIndexIsClear(sensorHandle)) {
ALOGE("Dynamic sensorHandle removed had first byte not 0.");
} else {
sensorHandle = setSubHalIndex(sensorHandle, subHalIndex);
if (mDynamicSensors.find(sensorHandle) != mDynamicSensors.end()) {
mDynamicSensors.erase(sensorHandle);
sensorHandles.push_back(sensorHandle);
}
}
}
}
mDynamicSensorsCallback->onDynamicSensorsDisconnected(sensorHandles);
return Return<void>();
}
void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) {
std::ifstream subHalConfigStream(configFileName);
if (!subHalConfigStream) {
ALOGE("Failed to load subHal config file: %s", configFileName);
} else {
std::string subHalLibraryFile;
while (subHalConfigStream >> subHalLibraryFile) {
void* handle = dlopen(subHalLibraryFile.c_str(), RTLD_NOW);
if (handle == nullptr) {
ALOGE("dlopen failed for library: %s", subHalLibraryFile.c_str());
} else {
SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr =
(SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal");
if (sensorsHalGetSubHalPtr == nullptr) {
ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s",
subHalLibraryFile.c_str());
} else {
std::function<SensorsHalGetSubHalFunc> sensorsHalGetSubHal =
*sensorsHalGetSubHalPtr;
uint32_t version;
ISensorsSubHal* subHal = sensorsHalGetSubHal(&version);
if (version != SUB_HAL_2_0_VERSION) {
ALOGE("SubHal version was not 2.0 for library: %s",
subHalLibraryFile.c_str());
} else {
ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str());
mSubHalList.push_back(subHal);
}
}
}
}
}
}
void HalProxy::initializeSubHalCallbacks() {
for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
sp<IHalProxyCallback> callback = new HalProxyCallback(this, subHalIndex);
mSubHalCallbacks.push_back(callback);
}
}
void HalProxy::initializeSensorList() {
for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
ISensorsSubHal* subHal = mSubHalList[subHalIndex];
auto result = subHal->getSensorsList([&](const auto& list) {
for (SensorInfo sensor : list) {
if (!subHalIndexIsClear(sensor.sensorHandle)) {
ALOGE("SubHal sensorHandle's first byte was not 0");
} else {
ALOGV("Loaded sensor: %s", sensor.name.c_str());
sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
setDirectChannelFlags(&sensor, subHal);
mSensors[sensor.sensorHandle] = sensor;
}
}
});
if (!result.isOk()) {
ALOGE("getSensorsList call failed for SubHal: %s", subHal->getName().c_str());
}
}
}
void HalProxy::init() {
initializeSubHalCallbacks();
initializeSensorList();
}
void HalProxy::stopThreads() {
mThreadsRun.store(false);
if (mEventQueueFlag != nullptr && mEventQueue != nullptr) {
size_t numToRead = mEventQueue->availableToRead();
std::vector<Event> events(numToRead);
mEventQueue->read(events.data(), numToRead);
mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ));
}
if (mWakelockQueueFlag != nullptr && mWakeLockQueue != nullptr) {
uint32_t kZero = 0;
mWakeLockQueue->write(&kZero);
mWakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
}
mWakelockCV.notify_one();
mEventQueueWriteCV.notify_one();
if (mPendingWritesThread.joinable()) {
mPendingWritesThread.join();
}
if (mWakelockThread.joinable()) {
mWakelockThread.join();
}
}
void HalProxy::disableAllSensors() {
for (const auto& sensorEntry : mSensors) {
int32_t sensorHandle = sensorEntry.first;
activate(sensorHandle, false /* enabled */);
}
std::lock_guard<std::mutex> dynamicSensorsLock(mDynamicSensorsMutex);
for (const auto& sensorEntry : mDynamicSensors) {
int32_t sensorHandle = sensorEntry.first;
activate(sensorHandle, false /* enabled */);
}
}
void HalProxy::startPendingWritesThread(HalProxy* halProxy) {
halProxy->handlePendingWrites();
}
void HalProxy::handlePendingWrites() {
// TODO(b/143302327): Find a way to optimize locking strategy maybe using two mutexes instead of
// one.
std::unique_lock<std::mutex> lock(mEventQueueWriteMutex);
while (mThreadsRun.load()) {
mEventQueueWriteCV.wait(
lock, [&] { return !mPendingWriteEventsQueue.empty() || !mThreadsRun.load(); });
if (mThreadsRun.load()) {
std::vector<Event>& pendingWriteEvents = mPendingWriteEventsQueue.front().first;
size_t numWakeupEvents = mPendingWriteEventsQueue.front().second;
size_t eventQueueSize = mEventQueue->getQuantumCount();
size_t numToWrite = std::min(pendingWriteEvents.size(), eventQueueSize);
lock.unlock();
if (!mEventQueue->writeBlocking(
pendingWriteEvents.data(), numToWrite,
static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
kPendingWriteTimeoutNs, mEventQueueFlag)) {
ALOGE("Dropping %zu events after blockingWrite failed.", numToWrite);
if (numWakeupEvents > 0) {
if (pendingWriteEvents.size() > eventQueueSize) {
decrementRefCountAndMaybeReleaseWakelock(
countNumWakeupEvents(pendingWriteEvents, eventQueueSize));
} else {
decrementRefCountAndMaybeReleaseWakelock(numWakeupEvents);
}
}
}
lock.lock();
if (pendingWriteEvents.size() > eventQueueSize) {
// TODO(b/143302327): Check if this erase operation is too inefficient. It will copy
// all the events ahead of it down to fill gap off array at front after the erase.
pendingWriteEvents.erase(pendingWriteEvents.begin(),
pendingWriteEvents.begin() + eventQueueSize);
} else {
mPendingWriteEventsQueue.pop();
}
}
}
}
void HalProxy::startWakelockThread(HalProxy* halProxy) {
halProxy->handleWakelocks();
}
void HalProxy::handleWakelocks() {
std::unique_lock<std::recursive_mutex> lock(mWakelockMutex);
while (mThreadsRun.load()) {
mWakelockCV.wait(lock, [&] { return mWakelockRefCount > 0 || !mThreadsRun.load(); });
if (mThreadsRun.load()) {
int64_t timeLeft;
if (sharedWakelockDidTimeout(&timeLeft)) {
resetSharedWakelock();
} else {
uint32_t numWakeLocksProcessed;
lock.unlock();
bool success = mWakeLockQueue->readBlocking(
&numWakeLocksProcessed, 1, 0,
static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN), timeLeft);
lock.lock();
if (success) {
decrementRefCountAndMaybeReleaseWakelock(
static_cast<size_t>(numWakeLocksProcessed));
}
}
}
}
resetSharedWakelock();
}
bool HalProxy::sharedWakelockDidTimeout(int64_t* timeLeft) {
bool didTimeout;
int64_t duration = getTimeNow() - mWakelockTimeoutStartTime;
if (duration > kWakelockTimeoutNs) {
didTimeout = true;
} else {
didTimeout = false;
*timeLeft = kWakelockTimeoutNs - duration;
}
return didTimeout;
}
void HalProxy::resetSharedWakelock() {
std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
decrementRefCountAndMaybeReleaseWakelock(mWakelockRefCount);
mWakelockTimeoutResetTime = getTimeNow();
}
void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
ScopedWakelock wakelock) {
size_t numToWrite = 0;
std::lock_guard<std::mutex> lock(mEventQueueWriteMutex);
if (wakelock.isLocked()) {
incrementRefCountAndMaybeAcquireWakelock(numWakeupEvents);
}
if (mPendingWriteEventsQueue.empty()) {
numToWrite = std::min(events.size(), mEventQueue->availableToWrite());
if (numToWrite > 0) {
if (mEventQueue->write(events.data(), numToWrite)) {
// TODO(b/143302327): While loop if mEventQueue->avaiableToWrite > 0 to possibly fit
// in more writes immediately
mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
} else {
numToWrite = 0;
}
}
}
if (numToWrite < events.size()) {
// TODO(b/143302327): Bound the mPendingWriteEventsQueue so that we do not trigger OOMs if
// framework stalls
std::vector<Event> eventsLeft(events.begin() + numToWrite, events.end());
mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents});
mEventQueueWriteCV.notify_one();
}
}
bool HalProxy::incrementRefCountAndMaybeAcquireWakelock(size_t delta,
int64_t* timeoutStart /* = nullptr */) {
if (!mThreadsRun.load()) return false;
std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
if (mWakelockRefCount == 0) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakelockName);
mWakelockCV.notify_one();
}
mWakelockTimeoutStartTime = getTimeNow();
mWakelockRefCount += delta;
if (timeoutStart != nullptr) {
*timeoutStart = mWakelockTimeoutStartTime;
}
return true;
}
void HalProxy::decrementRefCountAndMaybeReleaseWakelock(size_t delta,
int64_t timeoutStart /* = -1 */) {
if (!mThreadsRun.load()) return;
std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
if (timeoutStart == -1) timeoutStart = mWakelockTimeoutResetTime;
if (mWakelockRefCount == 0 || timeoutStart < mWakelockTimeoutResetTime) return;
mWakelockRefCount -= std::min(mWakelockRefCount, delta);
if (mWakelockRefCount == 0) {
release_wake_lock(kWakelockName);
}
}
void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal) {
bool sensorSupportsDirectChannel =
(sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL)) != 0;
if (mDirectChannelSubHal == nullptr && sensorSupportsDirectChannel) {
mDirectChannelSubHal = subHal;
} else if (mDirectChannelSubHal != nullptr && subHal != mDirectChannelSubHal) {
// disable direct channel capability for sensors in subHals that are not
// the only one we will enable
sensorInfo->flags &= ~(V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
}
}
ISensorsSubHal* HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) {
return mSubHalList[extractSubHalIndex(sensorHandle)];
}
bool HalProxy::isSubHalIndexValid(int32_t sensorHandle) {
return extractSubHalIndex(sensorHandle) < mSubHalList.size();
}
size_t HalProxy::countNumWakeupEvents(const std::vector<Event>& events, size_t n) {
size_t numWakeupEvents = 0;
for (size_t i = 0; i < n; i++) {
int32_t sensorHandle = events[i].sensorHandle;
if (mSensors[sensorHandle].flags & static_cast<uint32_t>(V1_0::SensorFlagBits::WAKE_UP)) {
numWakeupEvents++;
}
}
return numWakeupEvents;
}
int32_t HalProxy::clearSubHalIndex(int32_t sensorHandle) {
return sensorHandle & (~kSensorHandleSubHalIndexMask);
}
bool HalProxy::subHalIndexIsClear(int32_t sensorHandle) {
return (sensorHandle & kSensorHandleSubHalIndexMask) == 0;
}
void HalProxyCallback::postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) {
if (events.empty() || !mHalProxy->areThreadsRunning()) return;
size_t numWakeupEvents;
std::vector<Event> processedEvents = processEvents(events, &numWakeupEvents);
if (numWakeupEvents > 0) {
ALOG_ASSERT(wakelock.isLocked(),
"Wakeup events posted while wakelock unlocked for subhal"
" w/ index %zu.",
mSubHalIndex);
} else {
ALOG_ASSERT(!wakelock.isLocked(),
"No Wakeup events posted but wakelock locked for subhal"
" w/ index %zu.",
mSubHalIndex);
}
mHalProxy->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock));
}
ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) {
ScopedWakelock wakelock(mHalProxy, lock);
return wakelock;
}
std::vector<Event> HalProxyCallback::processEvents(const std::vector<Event>& events,
size_t* numWakeupEvents) const {
*numWakeupEvents = 0;
std::vector<Event> eventsOut;
for (Event event : events) {
event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex);
eventsOut.push_back(event);
const SensorInfo& sensor = mHalProxy->getSensorInfo(event.sensorHandle);
if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) {
(*numWakeupEvents)++;
}
}
return eventsOut;
}
} // namespace implementation
} // namespace V2_0
} // namespace sensors
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,3 @@
arthuri@google.com
bduddie@google.com
stange@google.com

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ScopedWakelock.h"
namespace android {
namespace hardware {
namespace sensors {
namespace V2_0 {
namespace implementation {
int64_t getTimeNow() {
return std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
}
ScopedWakelock::ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked)
: mRefCounter(refCounter), mLocked(locked) {
if (mLocked) {
mLocked = mRefCounter->incrementRefCountAndMaybeAcquireWakelock(1, &mCreatedAtTimeNs);
}
}
ScopedWakelock::~ScopedWakelock() {
if (mLocked) {
mRefCounter->decrementRefCountAndMaybeReleaseWakelock(1, mCreatedAtTimeNs);
}
}
} // namespace implementation
} // namespace V2_0
} // namespace sensors
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,11 @@
<manifest version="1.0" type="device">
<hal format="hidl">
<name>android.hardware.sensors</name>
<transport>hwbinder</transport>
<version>2.0</version>
<interface>
<name>ISensors</name>
<instance>multihal</instance>
</interface>
</hal>
</manifest>

View File

@@ -0,0 +1,7 @@
service vendor.sensors-hal-2-0-multihal /vendor/bin/hw/android.hardware.sensors@2.0-service.multihal
class hal
user system
group system wakelock
writepid /dev/cpuset/system-background/tasks
capabilities BLOCK_SUSPEND
rlimit rtprio 10 10

View File

@@ -0,0 +1,396 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "ScopedWakelock.h"
#include "SubHal.h"
#include <android/hardware/sensors/2.0/ISensors.h>
#include <android/hardware/sensors/2.0/types.h>
#include <fmq/MessageQueue.h>
#include <hardware_legacy/power.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <atomic>
#include <condition_variable>
#include <map>
#include <mutex>
#include <queue>
#include <thread>
#include <utility>
namespace android {
namespace hardware {
namespace sensors {
namespace V2_0 {
namespace implementation {
using ::android::sp;
using ::android::hardware::EventFlag;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::MessageQueue;
using ::android::hardware::MQDescriptor;
using ::android::hardware::Return;
using ::android::hardware::Void;
class HalProxy : public ISensors, public IScopedWakelockRefCounter {
public:
using Event = ::android::hardware::sensors::V1_0::Event;
using OperationMode = ::android::hardware::sensors::V1_0::OperationMode;
using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
using Result = ::android::hardware::sensors::V1_0::Result;
using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo;
using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
using ISensorsSubHal = ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal;
explicit HalProxy();
// Test only constructor.
explicit HalProxy(std::vector<ISensorsSubHal*>& subHalList);
~HalProxy();
// Methods from ::android::hardware::sensors::V2_0::ISensors follow.
Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
Return<Result> setOperationMode(OperationMode mode) override;
Return<Result> activate(int32_t sensorHandle, bool enabled) override;
Return<Result> initialize(
const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
const sp<ISensorsCallback>& sensorsCallback) override;
Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
int64_t maxReportLatencyNs) override;
Return<Result> flush(int32_t sensorHandle) override;
Return<Result> injectSensorData(const Event& event) override;
Return<void> registerDirectChannel(const SharedMemInfo& mem,
registerDirectChannel_cb _hidl_cb) override;
Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
configDirectReport_cb _hidl_cb) override;
Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
// Below methods from ::android::hardware::sensors::V2_0::ISensorsCallback with a minor change
// to pass in the sub-HAL index. While the above methods are invoked from the sensors framework
// via the binder, these methods are invoked from a callback provided to sub-HALs inside the
// same process as the HalProxy, but potentially running on different threads.
Return<void> onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
int32_t subHalIndex);
Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& dynamicSensorHandlesRemoved,
int32_t subHalIndex);
// Below methods are for HalProxyCallback
/**
* Post events to the event message queue if there is room to write them. Otherwise post the
* remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs
* timeout.
*
* @param events The list of events to post to the message queue.
* @param numWakeupEvents The number of wakeup events in events.
* @param wakelock The wakelock associated with this post of events.
*/
void postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
ScopedWakelock wakelock);
/**
* Get the sensor info associated with that sensorHandle.
*
* @param sensorHandle The sensor handle.
*
* @return The sensor info object in the mapping.
*/
const SensorInfo& getSensorInfo(int32_t sensorHandle) { return mSensors[sensorHandle]; }
bool areThreadsRunning() { return mThreadsRun.load(); }
// Below methods are from IScopedWakelockRefCounter interface
bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
int64_t* timeoutStart = nullptr) override;
void decrementRefCountAndMaybeReleaseWakelock(size_t delta, int64_t timeoutStart = -1) override;
private:
using EventMessageQueue = MessageQueue<Event, kSynchronizedReadWrite>;
using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>;
/**
* The Event FMQ where sensor events are written
*/
std::unique_ptr<EventMessageQueue> mEventQueue;
/**
* The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events
*/
std::unique_ptr<WakeLockMessageQueue> mWakeLockQueue;
/**
* Event Flag to signal to the framework when sensor events are available to be read and to
* interrupt event queue blocking write.
*/
EventFlag* mEventQueueFlag = nullptr;
//! Event Flag to signal internally that the wakelock queue should stop its blocking read.
EventFlag* mWakelockQueueFlag = nullptr;
/**
* Callback to the sensors framework to inform it that new sensors have been added or removed.
*/
sp<ISensorsCallback> mDynamicSensorsCallback;
/**
* SubHal object pointers that have been saved from vendor dynamic libraries.
*/
std::vector<ISensorsSubHal*> mSubHalList;
//! The list of subhal callbacks for each subhal where the indices correlate with mSubHalList
std::vector<const sp<IHalProxyCallback>> mSubHalCallbacks;
/**
* Map of sensor handles to SensorInfo objects that contains the sensor info from subhals as
* well as the modified sensor handle for the framework.
*
* The subhal index is encoded in the first byte of the sensor handle and the remaining
* bytes are generated by the subhal to identify the sensor.
*/
std::map<int32_t, SensorInfo> mSensors;
//! Map of the dynamic sensors that have been added to halproxy.
std::map<int32_t, SensorInfo> mDynamicSensors;
//! The current operation mode for all subhals.
OperationMode mCurrentOperationMode = OperationMode::NORMAL;
//! The single subHal that supports directChannel reporting.
ISensorsSubHal* mDirectChannelSubHal = nullptr;
//! The timeout for each pending write on background thread for events.
static const int64_t kPendingWriteTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */;
//! The bit mask used to get the subhal index from a sensor handle.
static constexpr int32_t kSensorHandleSubHalIndexMask = 0xFF000000;
/**
* A FIFO queue of pairs of vector of events and the number of wakeup events in that vector
* which are waiting to be written to the events fmq in the background thread.
*/
std::queue<std::pair<std::vector<Event>, size_t>> mPendingWriteEventsQueue;
//! The mutex protecting writing to the fmq and the pending events queue
std::mutex mEventQueueWriteMutex;
//! The condition variable waiting on pending write events to stack up
std::condition_variable mEventQueueWriteCV;
//! The thread object ptr that handles pending writes
std::thread mPendingWritesThread;
//! The thread object that handles wakelocks
std::thread mWakelockThread;
//! The bool indicating whether to end the threads started in initialize
std::atomic_bool mThreadsRun = true;
//! The mutex protecting access to the dynamic sensors added and removed methods.
std::mutex mDynamicSensorsMutex;
// WakelockRefCount membar vars below
//! The mutex protecting the wakelock refcount and subsequent wakelock releases and
//! acquisitions
std::recursive_mutex mWakelockMutex;
std::condition_variable_any mWakelockCV;
//! The refcount of how many ScopedWakelocks and pending wakeup events are active
size_t mWakelockRefCount = 0;
int64_t mWakelockTimeoutStartTime = getTimeNow();
int64_t mWakelockTimeoutResetTime = getTimeNow();
const char* kWakelockName = "SensorsHAL_WAKEUP";
/**
* Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries
* listed in a config file.
*/
void initializeSubHalListFromConfigFile(const char* configFileName);
/**
* Initialize the HalProxyCallback vector using the list of subhals.
*/
void initializeSubHalCallbacks();
/**
* Initialize the list of SensorInfo objects in mSensorList by getting sensors from each
* subhal.
*/
void initializeSensorList();
/**
* Calls the helper methods that all ctors use.
*/
void init();
/**
* Stops all threads by setting the threads running flag to false and joining to them.
*/
void stopThreads();
/**
* Disable all the sensors observed by the HalProxy.
*/
void disableAllSensors();
/**
* Starts the thread that handles pending writes to event fmq.
*
* @param halProxy The HalProxy object pointer.
*/
static void startPendingWritesThread(HalProxy* halProxy);
//! Handles the pending writes on events to eventqueue.
void handlePendingWrites();
/**
* Starts the thread that handles decrementing the ref count on wakeup events processed by the
* framework and timing out wakelocks.
*
* @param halProxy The HalProxy object pointer.
*/
static void startWakelockThread(HalProxy* halProxy);
//! Handles the wakelocks.
void handleWakelocks();
/**
* @param timeLeft The variable that should be set to the timeleft before timeout will occur or
* unmodified if timeout occurred.
*
* @return true if the shared wakelock has been held passed the timeout and should be released
*/
bool sharedWakelockDidTimeout(int64_t* timeLeft);
/**
* Reset all the member variables associated with the wakelock ref count and maybe release
* the shared wakelock.
*/
void resetSharedWakelock();
/**
* Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel
* subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first
* direct channel enabled sensor seen.
*
* @param sensorInfo The SensorInfo object that may be altered to have direct channel support
* disabled.
* @param subHal The subhal pointer that the current sensorInfo object came from.
*/
void setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal);
/*
* Get the subhal pointer which can be found by indexing into the mSubHalList vector
* using the index from the first byte of sensorHandle.
*
* @param sensorHandle The handle used to identify a sensor in one of the subhals.
*/
ISensorsSubHal* getSubHalForSensorHandle(int32_t sensorHandle);
/**
* Checks that sensorHandle's subhal index byte is within bounds of mSubHalList.
*
* @param sensorHandle The sensor handle to check.
*
* @return true if sensorHandles's subhal index byte is valid.
*/
bool isSubHalIndexValid(int32_t sensorHandle);
/**
* Count the number of wakeup events in the first n events of the vector.
*
* @param events The vector of Event objects.
* @param n The end index not inclusive of events to consider.
*
* @return The number of wakeup events of the considered events.
*/
size_t countNumWakeupEvents(const std::vector<Event>& events, size_t n);
/*
* Clear out the subhal index bytes from a sensorHandle.
*
* @param sensorHandle The sensor handle to modify.
*
* @return The modified version of the sensor handle.
*/
static int32_t clearSubHalIndex(int32_t sensorHandle);
/**
* @param sensorHandle The sensor handle to modify.
*
* @return true if subHalIndex byte of sensorHandle is zeroed.
*/
static bool subHalIndexIsClear(int32_t sensorHandle);
};
/**
* Callback class used to provide the HalProxy with the index of which subHal is invoking
*/
class HalProxyCallback : public IHalProxyCallback {
using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo;
public:
HalProxyCallback(HalProxy* halProxy, int32_t subHalIndex)
: mHalProxy(halProxy), mSubHalIndex(subHalIndex) {}
Return<void> onDynamicSensorsConnected(
const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
return mHalProxy->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex);
}
Return<void> onDynamicSensorsDisconnected(
const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
return mHalProxy->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex);
}
void postEvents(const std::vector<Event>& events, ScopedWakelock wakelock);
ScopedWakelock createScopedWakelock(bool lock);
private:
HalProxy* mHalProxy;
int32_t mSubHalIndex;
std::vector<Event> processEvents(const std::vector<Event>& events,
size_t* numWakeupEvents) const;
};
} // namespace implementation
} // namespace V2_0
} // namespace sensors
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <android/hardware/sensors/2.0/types.h>
namespace android {
namespace hardware {
namespace sensors {
namespace V2_0 {
namespace implementation {
using ::android::hardware::sensors::V2_0::SensorTimeout;
const int64_t kWakelockTimeoutNs =
static_cast<int64_t>(SensorTimeout::WAKE_LOCK_SECONDS) * INT64_C(1000000000);
int64_t getTimeNow();
class IScopedWakelockRefCounter : public RefBase {
public:
/**
* Increment the wakelock ref count and maybe acquire the shared wakelock if incrementing
* from 0 then return the time of incrementing back to caller.
*
* @param delta The amount to change ref count by.
* @param timeoutStart The ptr to the timestamp in ns that the increment occurred which will be
* set in the function or nullptr if not specified.
*
* @return true if successfully incremented the wakelock ref count.
*/
virtual bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
int64_t* timeoutStart = nullptr) = 0;
/**
* Decrement the wakelock ref count and maybe release wakelock if ref count ends up 0.
*
* @param delta The amount to change ref count by.
* @param timeoutStart The timestamp in ns that the calling context kept track of when
* incrementing the ref count or -1 by default
*/
virtual void decrementRefCountAndMaybeReleaseWakelock(size_t delta,
int64_t timeoutStart = -1) = 0;
// Virtual dtor needed for compilation success
virtual ~IScopedWakelockRefCounter(){};
};
/**
* Wrapper around wake lock acquisition functions (acquire/release_wake_lock) that provides a
* RAII-style mechanism for keeping a wake lock held for the duration of a scoped block.
* When a ScopedWakelock is created, it increments the reference count stored in the HalProxy
* for the sub-HALs specific wake lock, acquiring the wake lock if necessary. When the object goes
* out of scope, the ref count is decremented, potentially releasing the wake lock if no other
* references to the wake lock exist.
*
* This class is allocated through the createScopedWakelock callback inside the IHalProxyCallback
* provided to sub-HALs during initialization and should be used for all wake lock acquisition
* inside of the sub-HAL to ensure wake locks are not held indefinitely.
*
* The most prevalent use case for this class will be for posting events to the framework through
* the postEvents HalProxy callback. The expectation is that sub-HALs will create this
* ScopedWakelock through the createScopedWakelock upon receiving a sensor events. The lock boolean
* provided to createScopedWakelock will be set the according to whether the sensor events are
* from wakeup sensors. Then, the sub-HAL will perform any processing necessary before invoking the
* postEvents callback passing in the previously created ScopedWakelock. At this point, ownership
* of the object will be passed to the HalProxy that will then be responsible for ensuring any
* wake locks continue to be held, if necessary.
*/
class ScopedWakelock {
public:
ScopedWakelock(ScopedWakelock&&) = default;
ScopedWakelock& operator=(ScopedWakelock&&) = default;
virtual ~ScopedWakelock();
bool isLocked() const { return mLocked; }
private:
friend class HalProxyCallback;
IScopedWakelockRefCounter* mRefCounter;
int64_t mCreatedAtTimeNs;
bool mLocked;
ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked);
ScopedWakelock(const ScopedWakelock&) = delete;
ScopedWakelock& operator=(const ScopedWakelock&) = delete;
};
} // namespace implementation
} // namespace V2_0
} // namespace sensors
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,170 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "ScopedWakelock.h"
#include <android/hardware/sensors/1.0/types.h>
#include <android/hardware/sensors/2.0/ISensors.h>
#include <vector>
// Indicates the current version of the multiHAL interface formatted as (HAL major version) << 24 |
// (HAL minor version) << 16 | (multiHAL version)
#define SUB_HAL_2_0_VERSION 0x02000000
namespace android {
namespace hardware {
namespace sensors {
namespace V2_0 {
namespace implementation {
using ::android::hardware::sensors::V1_0::Event;
using ::android::hardware::sensors::V1_0::Result;
using ::android::hardware::sensors::V1_0::SensorInfo;
/**
* Interface that contains several callbacks into the HalProxy class to communicate dynamic sensor
* changes and sensor events to the framework and acquire wake locks. The HalProxy will ensure
* callbacks occurring at the same time from multiple sub-HALs are synchronized in a safe, efficient
* manner.
*/
class IHalProxyCallback : public ISensorsCallback {
public:
/**
* Thread-safe callback used to post events to the HalProxy. Sub-HALs should invoke this
* whenever new sensor events need to be delivered to the sensors framework. Once invoked, the
* HalProxy will attempt to send events to the sensors framework using a blocking write with a
* 5 second timeout. This write may be done asynchronously if the queue used to communicate
* with the framework is full to avoid blocking sub-HALs for the length of the timeout. If the
* write fails, the events will be dropped and any wake locks held will be released.
*
* The provided ScopedWakelock must be locked if the events are from wakeup sensors. If it's
* not locked accordingly, the HalProxy will crash as this indicates the sub-HAL isn't compliant
* with the sensors HAL 2.0 specification. Additionally, since ScopedWakelock isn't copyable,
* the HalProxy will take ownership of the wake lock given when this method is invoked. Once the
* method returns, the HalProxy will handle holding the wake lock, if necessary, until the
* framework has successfully processed any wakeup events.
*
* No return type is used for this callback to avoid sub-HALs trying to resend events when
* writes fail. Writes should only fail when the framework is under inordinate stress which will
* likely result in a framework restart so retrying will likely only result in overloading the
* HalProxy. Sub-HALs should always assume that the write was a success and perform any
* necessary cleanup. Additionally, the HalProxy will ensure it logs any errors (through ADB and
* bug reports) it encounters during delivery to ensure it's obvious that a failure occurred.
*
* @param events the events that should be sent to the sensors framework
* @param wakelock ScopedWakelock that should be locked to send events from wake sensors and
* unlocked otherwise.
*/
virtual void postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) = 0;
/**
* Initializes a ScopedWakelock on the stack that, when locked, will increment the reference
* count for the sub-HAL's wake lock managed inside the HalProxy. See the ScopedWakelock class
* definition for how it should be used.
*
* @param lock whether the ScopedWakelock should be locked before it's returned.
* @return the created ScopedWakelock
*/
virtual ScopedWakelock createScopedWakelock(bool lock) = 0;
};
/**
* ISensorsSubHal is an interface that sub-HALs must implement in order to be compliant with
* multihal 2.0 and in order for the HalProxy to successfully load and communicate with the sub-HAL.
*
* Any vendor wishing to implement this interface and support multihal 2.0 will need to create a
* dynamic library that exposes sensorsHalGetSubHal (defined below). This library will be loaded by
* the HalProxy when the sensors HAL is initialized and then the HalProxy will retrieve the vendor's
* implementation of sensorsHalGetSubHal.
*
* With the exception of the initialize method, ISensorsSubHal will implement the ISensors.hal spec.
* Any sensor handles given to the HalProxy, either through getSensorsList() or the
* onDynamicSensors(Dis)Connected callbacks, will be translated to avoid clashing with other sub-HAL
* handles. To achieve this, the HalProxy will use the upper byte to store the sub-HAL index and
* sub-HALs can continue to use the lower 3 bytes of the handle.
*/
class ISensorsSubHal : public ISensors {
public:
// The ISensors version of initialize isn't used for multihal. Instead, sub-HALs must implement
// the version below to allow communciation logic to centralized in the HalProxy
Return<Result> initialize(
const ::android::hardware::MQDescriptorSync<Event>& /* eventQueueDescriptor */,
const ::android::hardware::MQDescriptorSync<uint32_t>& /* wakeLockDescriptor */,
const sp<ISensorsCallback>& /* sensorsCallback */) final {
return Result::INVALID_OPERATION;
}
/**
* Method defined in ::android::hidl::base::V1_0::IBase.
*
* This method should write debug information to hidl_handle that is useful for debugging
* issues. Suggestions include:
* - Sensor info including handle values and any other state available in the SensorInfo class
* - List of active sensors and their current sampling period and reporting latency
* - Information about pending flush requests
* - Current operating mode
* - Currently registered direct channel info
* - A history of any of the above
*/
virtual Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) = 0;
/**
* @return A human-readable name for use in wake locks and logging.
*/
virtual const std::string getName() = 0;
/**
* This is the first method invoked on the sub-HAL after it's allocated through
* sensorsHalGetSubHal() by the HalProxy. Sub-HALs should use this to initialize any state and
* retain the callback given in order to communicate with the HalProxy. Method will be called
* anytime the sensors framework restarts. Therefore, this method will be responsible for
* reseting the state of the subhal and cleaning up and reallocating any previously allocated
* data. Initialize should ensure that the subhal has reset its operation mode to NORMAL state
* as well.
*
* @param halProxyCallback callback used to inform the HalProxy when a dynamic sensor's state
* changes, new sensor events should be sent to the framework, and when a new ScopedWakelock
* should be created.
* @return result OK on success
*/
virtual Return<Result> initialize(const sp<IHalProxyCallback>& halProxyCallback) = 0;
};
} // namespace implementation
} // namespace V2_0
} // namespace sensors
} // namespace hardware
} // namespace android
using ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal;
/**
* Function that must be exported so the HalProxy class can invoke it on the sub-HAL dynamic
* library. This function will only be invoked once at initialization time.
*
* NOTE: The supported sensors HAL version must match SUB_HAL_2_0_VERSION exactly or the HalProxy
* will fail to initialize.
*
* @param uint32_t when this function returns, this parameter must contain the HAL version that
* this sub-HAL supports. To support this version of multi-HAL, this must be set to
* SUB_HAL_2_0_VERSION.
* @return A statically allocated, valid ISensorsSubHal implementation.
*/
__attribute__((visibility("default"))) extern "C" ISensorsSubHal* sensorsHalGetSubHal(
uint32_t* version);

View File

@@ -0,0 +1,39 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <android/hardware/sensors/2.0/ISensors.h>
#include <hidl/HidlTransportSupport.h>
#include <log/log.h>
#include <utils/StrongPointer.h>
#include "HalProxy.h"
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::hardware::sensors::V2_0::ISensors;
using android::hardware::sensors::V2_0::implementation::HalProxy;
int main(int /* argc */, char** /* argv */) {
configureRpcThreadpool(1, true);
android::sp<ISensors> halProxy = new HalProxy();
if (halProxy->registerAsService() != ::android::OK) {
ALOGE("Failed to register Sensors HAL instance");
return -1;
}
joinRpcThreadpool();
return 1; // joinRpcThreadpool shouldn't exit
}

View File

@@ -0,0 +1,99 @@
//
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
cc_defaults {
name: "android.hardware.sensors@2.0-fakesubhal-defaults",
srcs: [
"fake_subhal/*.cpp",
],
header_libs: [
"android.hardware.sensors@2.0-multihal.header",
],
export_include_dirs: ["fake_subhal"],
shared_libs: [
"android.hardware.sensors@1.0",
"android.hardware.sensors@2.0",
"libcutils",
"libfmq",
"libhardware",
"libhidlbase",
"liblog",
"libpower",
"libutils",
],
static_libs: [
"android.hardware.sensors@2.0-HalProxy",
],
cflags: [
"-DLOG_TAG=\"FakeSubHal\""
],
}
cc_library {
name: "android.hardware.sensors@2.0-fakesubhal-config1",
vendor: true,
defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
cflags: [
"-DSUPPORT_CONTINUOUS_SENSORS",
"-DSUB_HAL_NAME=\"FakeSubHal-Continuous\"",
],
}
cc_library {
name: "android.hardware.sensors@2.0-fakesubhal-config2",
vendor: true,
defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
cflags: [
"-DSUPPORT_ON_CHANGE_SENSORS",
"-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"",
],
}
cc_test_library {
name: "android.hardware.sensors@2.0-fakesubhal-unittest",
vendor_available: true,
defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
cflags: [
"-DSUPPORT_ON_CHANGE_SENSORS",
"-DSUPPORT_CONTINUOUS_SENSORS",
"-DSUB_HAL_NAME=\"FakeSubHal-Test\"",
],
}
cc_test {
name: "android.hardware.sensors@2.0-halproxy-unit-tests",
srcs: ["HalProxy_test.cpp"],
vendor: true,
static_libs: [
"android.hardware.sensors@2.0-HalProxy",
"android.hardware.sensors@2.0-fakesubhal-unittest",
],
shared_libs: [
"android.hardware.sensors@1.0",
"android.hardware.sensors@2.0",
"libbase",
"libcutils",
"libfmq",
"libhardware",
"libhidlbase",
"liblog",
"libpower",
"libutils",
],
test_suites: ["device-tests"],
cflags: [
"-DLOG_TAG=\"HalProxyUnitTests\"",
],
}

View File

@@ -0,0 +1,833 @@
//
// Copyright (C) 2019 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <android/hardware/sensors/2.0/types.h>
#include <fmq/MessageQueue.h>
#include "HalProxy.h"
#include "ScopedWakelock.h"
#include "SensorsSubHal.h"
#include <chrono>
#include <set>
#include <thread>
#include <vector>
namespace {
using ::android::hardware::EventFlag;
using ::android::hardware::hidl_vec;
using ::android::hardware::MessageQueue;
using ::android::hardware::Return;
using ::android::hardware::sensors::V1_0::EventPayload;
using ::android::hardware::sensors::V1_0::SensorFlagBits;
using ::android::hardware::sensors::V1_0::SensorInfo;
using ::android::hardware::sensors::V1_0::SensorType;
using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
using ::android::hardware::sensors::V2_0::ISensorsCallback;
using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
using ::android::hardware::sensors::V2_0::implementation::HalProxy;
using ::android::hardware::sensors::V2_0::implementation::HalProxyCallback;
using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal;
using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal;
using ::android::hardware::sensors::V2_0::subhal::implementation::
AllSupportDirectChannelSensorsSubHal;
using ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal;
using ::android::hardware::sensors::V2_0::subhal::implementation::
DoesNotSupportDirectChannelSensorsSubHal;
using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal;
using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal;
using ::android::hardware::sensors::V2_0::subhal::implementation::
SetOperationModeFailingSensorsSubHal;
using EventMessageQueue = MessageQueue<Event, ::android::hardware::kSynchronizedReadWrite>;
using WakeupMessageQueue = MessageQueue<uint32_t, ::android::hardware::kSynchronizedReadWrite>;
// The barebones sensors callback class passed into halproxy initialize calls
class SensorsCallback : public ISensorsCallback {
public:
Return<void> onDynamicSensorsConnected(
const hidl_vec<SensorInfo>& /*dynamicSensorsAdded*/) override {
// Nothing yet
return Return<void>();
}
Return<void> onDynamicSensorsDisconnected(
const hidl_vec<int32_t>& /*dynamicSensorHandlesRemoved*/) override {
// Nothing yet
return Return<void>();
}
};
// The sensors callback that expects a variable list of sensors to be added
class TestSensorsCallback : public ISensorsCallback {
public:
Return<void> onDynamicSensorsConnected(
const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
mSensorsConnected.insert(mSensorsConnected.end(), dynamicSensorsAdded.begin(),
dynamicSensorsAdded.end());
return Return<void>();
}
Return<void> onDynamicSensorsDisconnected(
const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
mSensorHandlesDisconnected.insert(mSensorHandlesDisconnected.end(),
dynamicSensorHandlesRemoved.begin(),
dynamicSensorHandlesRemoved.end());
return Return<void>();
}
const std::vector<SensorInfo>& getSensorsConnected() const { return mSensorsConnected; }
const std::vector<int32_t>& getSensorHandlesDisconnected() const {
return mSensorHandlesDisconnected;
}
private:
std::vector<SensorInfo> mSensorsConnected;
std::vector<int32_t> mSensorHandlesDisconnected;
};
// Helper declarations follow
/**
* Tests that for each SensorInfo object from a proxy getSensorsList call each corresponding
* object from a subhal getSensorsList call has the same type and its last 3 bytes are the
* same for sensorHandle field.
*
* @param proxySensorsList The list of SensorInfo objects from the proxy.getSensorsList callback.
* @param subHalSenosrsList The list of SensorInfo objects from the subHal.getSensorsList callback.
*/
void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
const std::vector<SensorInfo>& subHalSensorsList);
/**
* Tests that there is exactly one subhal that allows its sensors to have direct channel enabled.
* Therefore, all SensorInfo objects that are not from the enabled subhal should be disabled for
* direct channel.
*
* @param sensorsList The SensorInfo object list from proxy.getSensorsList call.
* @param enabledSubHalIndex The index of the subhal in the halproxy that is expected to be
* enabled.
*/
void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
size_t enabledSubHalIndex);
void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
EventFlag* wakelockQueueFlag);
bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueue>& eventQueue,
EventFlag* eventQueueFlag);
std::unique_ptr<EventMessageQueue> makeEventFMQ(size_t size);
std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size);
/**
* Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
* which is a wakeup type sensor.
*
* @return A proximity event.
*/
Event makeProximityEvent();
/**
* Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
* which is a wakeup type sensor.
*
* @return A proximity event.
*/
Event makeAccelerometerEvent();
/**
* Make a certain number of proximity type events with the sensorHandle field set to
* the proper number for AllSensorsSubHal subhal type.
*
* @param numEvents The number of events to make.
*
* @return The created list of events.
*/
std::vector<Event> makeMultipleProximityEvents(size_t numEvents);
/**
* Make a certain number of accelerometer type events with the sensorHandle field set to
* the proper number for AllSensorsSubHal subhal type.
*
* @param numEvents The number of events to make.
*
* @return The created list of events.
*/
std::vector<Event> makeMultipleAccelerometerEvents(size_t numEvents);
/**
* Given a SensorInfo vector and a sensor handles vector populate 'sensors' with SensorInfo
* objects that have the sensorHandle property set to int32_ts from start to start + size
* (exclusive) and push those sensorHandles also onto 'sensorHandles'.
*
* @param start The starting sensorHandle value.
* @param size The ending (not included) sensorHandle value.
* @param sensors The SensorInfo object vector reference to push_back to.
* @param sensorHandles The sensor handles int32_t vector reference to push_back to.
*/
void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size,
std::vector<SensorInfo>& sensors,
std::vector<int32_t>& sensorHandles);
// Tests follow
TEST(HalProxyTest, GetSensorsListOneSubHalTest) {
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> fakeSubHals{&subHal};
HalProxy proxy(fakeSubHals);
proxy.getSensorsList([&](const auto& proxySensorsList) {
subHal.getSensorsList([&](const auto& subHalSensorsList) {
testSensorsListFromProxyAndSubHal(proxySensorsList, subHalSensorsList);
});
});
}
TEST(HalProxyTest, GetSensorsListTwoSubHalTest) {
ContinuousSensorsSubHal continuousSubHal;
OnChangeSensorsSubHal onChangeSubHal;
std::vector<ISensorsSubHal*> fakeSubHals;
fakeSubHals.push_back(&continuousSubHal);
fakeSubHals.push_back(&onChangeSubHal);
HalProxy proxy(fakeSubHals);
std::vector<SensorInfo> proxySensorsList, combinedSubHalSensorsList;
proxy.getSensorsList([&](const auto& list) { proxySensorsList = list; });
continuousSubHal.getSensorsList([&](const auto& list) {
combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
});
onChangeSubHal.getSensorsList([&](const auto& list) {
combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
});
testSensorsListFromProxyAndSubHal(proxySensorsList, combinedSubHalSensorsList);
}
TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) {
ContinuousSensorsSubHal subHal1;
OnChangeSensorsSubHal subHal2;
std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
HalProxy proxy(fakeSubHals);
EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);
EXPECT_EQ(result, Result::OK);
EXPECT_EQ(subHal1.getOperationMode(), OperationMode::DATA_INJECTION);
EXPECT_EQ(subHal2.getOperationMode(), OperationMode::DATA_INJECTION);
}
TEST(HalProxyTest, SetOperationModeTwoSubHalFailTest) {
AllSensorsSubHal subHal1;
SetOperationModeFailingSensorsSubHal subHal2;
std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
HalProxy proxy(fakeSubHals);
EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);
EXPECT_NE(result, Result::OK);
EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
}
TEST(HalProxyTest, InitDirectChannelTwoSubHalsUnitTest) {
AllSupportDirectChannelSensorsSubHal subHal1;
AllSupportDirectChannelSensorsSubHal subHal2;
std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
HalProxy proxy(fakeSubHals);
proxy.getSensorsList([&](const auto& sensorsList) {
testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 0);
});
}
TEST(HalProxyTest, InitDirectChannelThreeSubHalsUnitTest) {
DoesNotSupportDirectChannelSensorsSubHal subHal1;
AllSupportDirectChannelSensorsSubHal subHal2, subHal3;
std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2, &subHal3};
HalProxy proxy(fakeSubHals);
proxy.getSensorsList([&](const auto& sensorsList) {
testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 1);
});
}
TEST(HalProxyTest, PostSingleNonWakeupEvent) {
constexpr size_t kQueueSize = 5;
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
std::vector<Event> events{makeAccelerometerEvent()};
subHal.postEvents(events, false /* wakeup */);
EXPECT_EQ(eventQueue->availableToRead(), 1);
}
TEST(HalProxyTest, PostMultipleNonWakeupEvent) {
constexpr size_t kQueueSize = 5;
constexpr size_t kNumEvents = 3;
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
subHal.postEvents(events, false /* wakeup */);
EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
}
TEST(HalProxyTest, PostSingleWakeupEvent) {
constexpr size_t kQueueSize = 5;
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
EventFlag* eventQueueFlag;
EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
EventFlag* wakelockQueueFlag;
EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
std::vector<Event> events{makeProximityEvent()};
subHal.postEvents(events, true /* wakeup */);
EXPECT_EQ(eventQueue->availableToRead(), 1);
readEventsOutOfQueue(1, eventQueue, eventQueueFlag);
ackWakeupEventsToHalProxy(1, wakeLockQueue, wakelockQueueFlag);
}
TEST(HalProxyTest, PostMultipleWakeupEvents) {
constexpr size_t kQueueSize = 5;
constexpr size_t kNumEvents = 3;
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
EventFlag* eventQueueFlag;
EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
EventFlag* wakelockQueueFlag;
EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
std::vector<Event> events = makeMultipleProximityEvents(kNumEvents);
subHal.postEvents(events, true /* wakeup */);
EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
readEventsOutOfQueue(kNumEvents, eventQueue, eventQueueFlag);
ackWakeupEventsToHalProxy(kNumEvents, wakeLockQueue, wakelockQueueFlag);
}
TEST(HalProxyTest, PostEventsMultipleSubhals) {
constexpr size_t kQueueSize = 5;
constexpr size_t kNumEvents = 2;
AllSensorsSubHal subHal1, subHal2;
std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
HalProxy proxy(subHals);
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
subHal1.postEvents(events, false /* wakeup */);
EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
subHal2.postEvents(events, false /* wakeup */);
EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
}
TEST(HalProxyTest, PostEventsDelayedWrite) {
constexpr size_t kQueueSize = 5;
constexpr size_t kNumEvents = 6;
AllSensorsSubHal subHal1, subHal2;
std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
HalProxy proxy(subHals);
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
EventFlag* eventQueueFlag;
EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
subHal1.postEvents(events, false /* wakeup */);
EXPECT_EQ(eventQueue->availableToRead(), kQueueSize);
// readblock a full queue size worth of events out of queue, timeout for half a second
EXPECT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag));
// proxy background thread should have wrote remaining events when it saw space
EXPECT_TRUE(readEventsOutOfQueue(kNumEvents - kQueueSize, eventQueue, eventQueueFlag));
EXPECT_EQ(eventQueue->availableToRead(), 0);
}
TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) {
constexpr size_t kQueueSize = 5;
constexpr size_t kNumEvents = 2;
AllSensorsSubHal subHal1, subHal2;
std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
HalProxy proxy(subHals);
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, events, false);
std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, events, false);
t1.join();
t2.join();
EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
}
TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThread) {
constexpr size_t kQueueSize = 5;
constexpr size_t kNumEvents = 6;
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
HalProxy proxy(subHals);
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
subHal.postEvents(events, false /* wakeup */);
// Destructing HalProxy object with events on the background thread
}
TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) {
constexpr size_t kQueueSize = 5;
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
HalProxy proxy(subHals);
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
std::vector<Event> events{makeProximityEvent()};
subHal.postEvents(events, true /* wakeup */);
// Not sending any acks back through wakeLockQueue
// Destructing HalProxy object with unacked wakeup events posted
}
TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) {
constexpr size_t kQueueSize = 5;
constexpr size_t kNumEvents = 10;
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
HalProxy proxy(subHals);
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
subHal.postEvents(events, false /* wakeup */);
eventQueue = makeEventFMQ(kQueueSize);
wakeLockQueue = makeWakelockFMQ(kQueueSize);
Result secondInitResult =
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
EXPECT_EQ(secondInitResult, Result::OK);
// Small sleep so that pending writes thread has a change to hit writeBlocking call.
std::this_thread::sleep_for(std::chrono::milliseconds(5));
Event eventOut;
EXPECT_FALSE(eventQueue->read(&eventOut));
}
TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) {
constexpr size_t kQueueSize = 5;
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
HalProxy proxy(subHals);
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
std::vector<Event> events{makeProximityEvent()};
subHal.postEvents(events, true /* wakeup */);
// Not sending any acks back through wakeLockQueue
eventQueue = makeEventFMQ(kQueueSize);
wakeLockQueue = makeWakelockFMQ(kQueueSize);
Result secondInitResult =
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
EXPECT_EQ(secondInitResult, Result::OK);
}
TEST(HalProxyTest, InitializeManyTimesInARow) {
constexpr size_t kQueueSize = 5;
constexpr size_t kNumTimesToInit = 100;
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
HalProxy proxy(subHals);
for (size_t i = 0; i < kNumTimesToInit; i++) {
Result secondInitResult =
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
EXPECT_EQ(secondInitResult, Result::OK);
}
}
TEST(HalProxyTest, OperationModeResetOnInitialize) {
constexpr size_t kQueueSize = 5;
AllSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
HalProxy proxy(subHals);
proxy.setOperationMode(OperationMode::DATA_INJECTION);
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
Event event = makeAccelerometerEvent();
// Should not be able to inject a non AdditionInfo type event because operation mode should
// have been reset to NORMAL
EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE);
}
TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) {
constexpr size_t kQueueSize = 5;
constexpr size_t kNumSensors = 5;
AddAndRemoveDynamicSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
HalProxy proxy(subHals);
std::vector<SensorInfo> sensorsToConnect;
std::vector<int32_t> sensorHandlesToAttemptToRemove;
makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
sensorHandlesToAttemptToRemove);
std::vector<int32_t> nonDynamicSensorHandles;
for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
nonDynamicSensorHandles.push_back(sensorHandle);
}
TestSensorsCallback* callback = new TestSensorsCallback();
::android::sp<ISensorsCallback> callbackPtr = callback;
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
subHal.addDynamicSensors(sensorsToConnect);
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);
std::vector<int32_t> sensorHandlesActuallyRemoved = callback->getSensorHandlesDisconnected();
// Should not have received the sensorHandles for any dynamic sensors that were removed since
// all of them should have been removed in the second initialize call.
EXPECT_TRUE(sensorHandlesActuallyRemoved.empty());
}
TEST(HalProxyTest, DynamicSensorsConnectedTest) {
constexpr size_t kNumSensors = 3;
AddAndRemoveDynamicSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(0);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
std::vector<SensorInfo> sensorsToConnect;
std::vector<int32_t> sensorHandlesToExpect;
makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
sensorHandlesToExpect);
TestSensorsCallback* callback = new TestSensorsCallback();
::android::sp<ISensorsCallback> callbackPtr = callback;
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
subHal.addDynamicSensors(sensorsToConnect);
std::vector<SensorInfo> sensorsSeen = callback->getSensorsConnected();
EXPECT_EQ(kNumSensors, sensorsSeen.size());
for (size_t i = 0; i < kNumSensors; i++) {
auto sensorHandleSeen = sensorsSeen[i].sensorHandle;
// Note since only one subhal we do not need to change first byte for expected
auto sensorHandleExpected = sensorHandlesToExpect[i];
EXPECT_EQ(sensorHandleSeen, sensorHandleExpected);
}
}
TEST(HalProxyTest, DynamicSensorsDisconnectedTest) {
constexpr size_t kNumSensors = 3;
AddAndRemoveDynamicSensorsSubHal subHal;
std::vector<ISensorsSubHal*> subHals{&subHal};
HalProxy proxy(subHals);
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(0);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
std::vector<SensorInfo> sensorsToConnect;
std::vector<int32_t> sensorHandlesToExpect;
makeSensorsAndSensorHandlesStartingAndOfSize(20, kNumSensors, sensorsToConnect,
sensorHandlesToExpect);
std::vector<int32_t> nonDynamicSensorHandles;
for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
nonDynamicSensorHandles.push_back(sensorHandle);
}
std::set<int32_t> nonDynamicSensorHandlesSet(nonDynamicSensorHandles.begin(),
nonDynamicSensorHandles.end());
std::vector<int32_t> sensorHandlesToAttemptToRemove;
sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
sensorHandlesToExpect.begin(),
sensorHandlesToExpect.end());
sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
nonDynamicSensorHandles.begin(),
nonDynamicSensorHandles.end());
TestSensorsCallback* callback = new TestSensorsCallback();
::android::sp<ISensorsCallback> callbackPtr = callback;
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
subHal.addDynamicSensors(sensorsToConnect);
subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);
std::vector<int32_t> sensorHandlesSeen = callback->getSensorHandlesDisconnected();
EXPECT_EQ(kNumSensors, sensorHandlesSeen.size());
for (size_t i = 0; i < kNumSensors; i++) {
auto sensorHandleSeen = sensorHandlesSeen[i];
// Note since only one subhal we do not need to change first byte for expected
auto sensorHandleExpected = sensorHandlesToExpect[i];
EXPECT_EQ(sensorHandleSeen, sensorHandleExpected);
EXPECT_TRUE(nonDynamicSensorHandlesSet.find(sensorHandleSeen) ==
nonDynamicSensorHandlesSet.end());
}
}
TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) {
constexpr size_t kNumSubHals = 3;
constexpr size_t kQueueSize = 5;
int32_t kNumSubHalsInt32 = static_cast<int32_t>(kNumSubHals);
std::vector<AllSensorsSubHal> subHalObjs(kNumSubHals);
std::vector<ISensorsSubHal*> subHals;
for (const auto& subHal : subHalObjs) {
subHals.push_back((ISensorsSubHal*)(&subHal));
}
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
HalProxy proxy(subHals);
// Initialize for the injectSensorData call so callback postEvents is valid
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
// For testing proxy.injectSensorData properly
proxy.setOperationMode(OperationMode::DATA_INJECTION);
// kNumSubHalsInt32 index is one off the end of mSubHalList in proxy object
EXPECT_EQ(proxy.activate(0x00000001 | (kNumSubHalsInt32 << 24), true), Result::BAD_VALUE);
EXPECT_EQ(proxy.batch(0x00000001 | (kNumSubHalsInt32 << 24), 0, 0), Result::BAD_VALUE);
EXPECT_EQ(proxy.flush(0x00000001 | (kNumSubHalsInt32 << 24)), Result::BAD_VALUE);
Event event;
event.sensorHandle = 0x00000001 | (kNumSubHalsInt32 << 24);
EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE);
}
TEST(HalProxyTest, PostedEventSensorHandleSubHalIndexValid) {
constexpr size_t kQueueSize = 5;
constexpr int32_t subhal1Index = 0;
constexpr int32_t subhal2Index = 1;
AllSensorsSubHal subhal1;
AllSensorsSubHal subhal2;
std::vector<ISensorsSubHal*> subHals{&subhal1, &subhal2};
std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
::android::sp<ISensorsCallback> callback = new SensorsCallback();
HalProxy proxy(subHals);
proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
int32_t sensorHandleToPost = 0x00000001;
Event eventIn = makeAccelerometerEvent();
eventIn.sensorHandle = sensorHandleToPost;
std::vector<Event> eventsToPost{eventIn};
subhal1.postEvents(eventsToPost, false);
Event eventOut;
EXPECT_TRUE(eventQueue->read(&eventOut));
EXPECT_EQ(eventOut.sensorHandle, (subhal1Index << 24) | sensorHandleToPost);
subhal2.postEvents(eventsToPost, false);
EXPECT_TRUE(eventQueue->read(&eventOut));
EXPECT_EQ(eventOut.sensorHandle, (subhal2Index << 24) | sensorHandleToPost);
}
// Helper implementations follow
void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
const std::vector<SensorInfo>& subHalSensorsList) {
EXPECT_EQ(proxySensorsList.size(), subHalSensorsList.size());
for (size_t i = 0; i < proxySensorsList.size(); i++) {
const SensorInfo& proxySensor = proxySensorsList[i];
const SensorInfo& subHalSensor = subHalSensorsList[i];
EXPECT_EQ(proxySensor.type, subHalSensor.type);
EXPECT_EQ(proxySensor.sensorHandle & 0x00FFFFFF, subHalSensor.sensorHandle);
}
}
void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
size_t enabledSubHalIndex) {
for (const SensorInfo& sensor : sensorsList) {
size_t subHalIndex = static_cast<size_t>(sensor.sensorHandle >> 24);
if (subHalIndex == enabledSubHalIndex) {
// First subhal should have been picked as the direct channel subhal
// and so have direct channel enabled on all of its sensors
EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
} else {
// All other subhals should have direct channel disabled for all sensors
EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
}
}
}
void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
EventFlag* wakelockQueueFlag) {
uint32_t numEventsUInt32 = static_cast<uint32_t>(numEvents);
wakelockQueue->write(&numEventsUInt32);
wakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
}
bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueue>& eventQueue,
EventFlag* eventQueueFlag) {
constexpr int64_t kReadBlockingTimeout = INT64_C(500000000);
std::vector<Event> events(numEvents);
return eventQueue->readBlocking(events.data(), numEvents,
static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
kReadBlockingTimeout, eventQueueFlag);
}
std::unique_ptr<EventMessageQueue> makeEventFMQ(size_t size) {
return std::make_unique<EventMessageQueue>(size, true);
}
std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size) {
return std::make_unique<WakeupMessageQueue>(size, true);
}
Event makeProximityEvent() {
Event event;
event.timestamp = 0xFF00FF00;
// This is the sensorhandle of proximity, which is wakeup type
event.sensorHandle = 0x00000008;
event.sensorType = SensorType::PROXIMITY;
event.u = EventPayload();
return event;
}
Event makeAccelerometerEvent() {
Event event;
event.timestamp = 0xFF00FF00;
// This is the sensorhandle of proximity, which is wakeup type
event.sensorHandle = 0x00000001;
event.sensorType = SensorType::ACCELEROMETER;
event.u = EventPayload();
return event;
}
std::vector<Event> makeMultipleProximityEvents(size_t numEvents) {
std::vector<Event> events;
for (size_t i = 0; i < numEvents; i++) {
events.push_back(makeProximityEvent());
}
return events;
}
std::vector<Event> makeMultipleAccelerometerEvents(size_t numEvents) {
std::vector<Event> events;
for (size_t i = 0; i < numEvents; i++) {
events.push_back(makeAccelerometerEvent());
}
return events;
}
void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size,
std::vector<SensorInfo>& sensors,
std::vector<int32_t>& sensorHandles) {
for (int32_t sensorHandle = start; sensorHandle < start + static_cast<int32_t>(size);
sensorHandle++) {
SensorInfo sensor;
// Just set the sensorHandle field to the correct value so as to not have
// to compare every field
sensor.sensorHandle = sensorHandle;
sensors.push_back(sensor);
sensorHandles.push_back(sensorHandle);
}
}
} // namespace

View File

@@ -0,0 +1,19 @@
This directory contains a modified version of the default implementation
provided for sensors HAL 2.0 to support multi-HAL 2.0. It should be used as a
means to verify the multi-HAL 2.0 implementation can successfully load and
interact with sub-HALs.
This sub-HAL implementation has two macros that can be used to configure support
for different sets of sensors. One "SUPPORT_CONTINUOUS_SENSORS", enables
support for continuous sensors like accel, and gyro whereas the other
"SUPPORT_ON_CHANGE_SENSORS" enables support for on change sensors like the
light and proximity sensor. A build target is defined for each of these macros,
but more targets could be added to support both in one sub-HAL or none at all,
if necessary.
When built, the library will be written to
out/target/product/<device>/vendor/lib64/android.hardware.sensors@2.0-fakesubhal.so
Take this .so and place it where the multi-HAL config will cause the HalProxy to
look and then restart the system server with adb shell stop / adb shell start
to cause the multi-HAL to restart and attempt to load in the sub-HAL.

View File

@@ -0,0 +1,349 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "Sensor.h"
#include <hardware/sensors.h>
#include <utils/SystemClock.h>
#include <cmath>
namespace android {
namespace hardware {
namespace sensors {
namespace V2_0 {
namespace subhal {
namespace implementation {
using ::android::hardware::sensors::V1_0::MetaDataEventType;
using ::android::hardware::sensors::V1_0::SensorFlagBits;
using ::android::hardware::sensors::V1_0::SensorStatus;
Sensor::Sensor(int32_t sensorHandle, ISensorsEventCallback* callback)
: mIsEnabled(false),
mSamplingPeriodNs(0),
mLastSampleTimeNs(0),
mCallback(callback),
mMode(OperationMode::NORMAL) {
mSensorInfo.sensorHandle = sensorHandle;
mSensorInfo.vendor = "Vendor String";
mSensorInfo.version = 1;
constexpr float kDefaultMaxDelayUs = 1000 * 1000;
mSensorInfo.maxDelay = kDefaultMaxDelayUs;
mSensorInfo.fifoReservedEventCount = 0;
mSensorInfo.fifoMaxEventCount = 0;
mSensorInfo.requiredPermission = "";
mSensorInfo.flags = 0;
mRunThread = std::thread(startThread, this);
}
Sensor::~Sensor() {
// Ensure that lock is unlocked before calling mRunThread.join() or a
// deadlock will occur.
{
std::unique_lock<std::mutex> lock(mRunMutex);
mStopThread = true;
mIsEnabled = false;
mWaitCV.notify_all();
}
mRunThread.join();
}
const SensorInfo& Sensor::getSensorInfo() const {
return mSensorInfo;
}
void Sensor::batch(int32_t samplingPeriodNs) {
samplingPeriodNs =
std::clamp(samplingPeriodNs, mSensorInfo.minDelay * 1000, mSensorInfo.maxDelay * 1000);
if (mSamplingPeriodNs != samplingPeriodNs) {
mSamplingPeriodNs = samplingPeriodNs;
// Wake up the 'run' thread to check if a new event should be generated now
mWaitCV.notify_all();
}
}
void Sensor::activate(bool enable) {
if (mIsEnabled != enable) {
std::unique_lock<std::mutex> lock(mRunMutex);
mIsEnabled = enable;
mWaitCV.notify_all();
}
}
Result Sensor::flush() {
// Only generate a flush complete event if the sensor is enabled and if the sensor is not a
// one-shot sensor.
if (!mIsEnabled || (mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::ONE_SHOT_MODE))) {
return Result::BAD_VALUE;
}
// Note: If a sensor supports batching, write all of the currently batched events for the sensor
// to the Event FMQ prior to writing the flush complete event.
Event ev;
ev.sensorHandle = mSensorInfo.sensorHandle;
ev.sensorType = SensorType::META_DATA;
ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE;
std::vector<Event> evs{ev};
mCallback->postEvents(evs, isWakeUpSensor());
return Result::OK;
}
void Sensor::startThread(Sensor* sensor) {
sensor->run();
}
void Sensor::run() {
std::unique_lock<std::mutex> runLock(mRunMutex);
constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000;
while (!mStopThread) {
if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) {
mWaitCV.wait(runLock, [&] {
return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread);
});
} else {
timespec curTime;
clock_gettime(CLOCK_REALTIME, &curTime);
int64_t now = (curTime.tv_sec * kNanosecondsInSeconds) + curTime.tv_nsec;
int64_t nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
if (now >= nextSampleTime) {
mLastSampleTimeNs = now;
nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
mCallback->postEvents(readEvents(), isWakeUpSensor());
}
mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now));
}
}
}
bool Sensor::isWakeUpSensor() {
return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
}
std::vector<Event> Sensor::readEvents() {
std::vector<Event> events;
Event event;
event.sensorHandle = mSensorInfo.sensorHandle;
event.sensorType = mSensorInfo.type;
event.timestamp = ::android::elapsedRealtimeNano();
event.u.vec3.x = 0;
event.u.vec3.y = 0;
event.u.vec3.z = 0;
event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
events.push_back(event);
return events;
}
void Sensor::setOperationMode(OperationMode mode) {
if (mMode != mode) {
std::unique_lock<std::mutex> lock(mRunMutex);
mMode = mode;
mWaitCV.notify_all();
}
}
bool Sensor::supportsDataInjection() const {
return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION);
}
Result Sensor::injectEvent(const Event& event) {
Result result = Result::OK;
if (event.sensorType == SensorType::ADDITIONAL_INFO) {
// When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation
// environment data into the device.
} else if (!supportsDataInjection()) {
result = Result::INVALID_OPERATION;
} else if (mMode == OperationMode::DATA_INJECTION) {
mCallback->postEvents(std::vector<Event>{event}, isWakeUpSensor());
} else {
result = Result::BAD_VALUE;
}
return result;
}
OnChangeSensor::OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
: Sensor(sensorHandle, callback), mPreviousEventSet(false) {
mSensorInfo.flags |= SensorFlagBits::ON_CHANGE_MODE;
}
void OnChangeSensor::activate(bool enable) {
Sensor::activate(enable);
if (!enable) {
mPreviousEventSet = false;
}
}
std::vector<Event> OnChangeSensor::readEvents() {
std::vector<Event> events = Sensor::readEvents();
std::vector<Event> outputEvents;
for (auto iter = events.begin(); iter != events.end(); ++iter) {
Event ev = *iter;
if (ev.u.vec3 != mPreviousEvent.u.vec3 || !mPreviousEventSet) {
outputEvents.push_back(ev);
mPreviousEvent = ev;
mPreviousEventSet = true;
}
}
return outputEvents;
}
ContinuousSensor::ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
: Sensor(sensorHandle, callback) {
mSensorInfo.flags |= SensorFlagBits::CONTINUOUS_MODE;
}
AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
: ContinuousSensor(sensorHandle, callback) {
mSensorInfo.name = "Accel Sensor";
mSensorInfo.type = SensorType::ACCELEROMETER;
mSensorInfo.typeAsString = SENSOR_STRING_TYPE_ACCELEROMETER;
mSensorInfo.maxRange = 78.4f; // +/- 8g
mSensorInfo.resolution = 1.52e-5;
mSensorInfo.power = 0.001f; // mA
mSensorInfo.minDelay = 20 * 1000; // microseconds
mSensorInfo.flags |= SensorFlagBits::DATA_INJECTION;
}
std::vector<Event> AccelSensor::readEvents() {
std::vector<Event> events;
Event event;
event.sensorHandle = mSensorInfo.sensorHandle;
event.sensorType = mSensorInfo.type;
event.timestamp = ::android::elapsedRealtimeNano();
event.u.vec3.x = 0;
event.u.vec3.y = 0;
event.u.vec3.z = -9.815;
event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
events.push_back(event);
return events;
}
PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
: ContinuousSensor(sensorHandle, callback) {
mSensorInfo.name = "Pressure Sensor";
mSensorInfo.type = SensorType::PRESSURE;
mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PRESSURE;
mSensorInfo.maxRange = 1100.0f; // hPa
mSensorInfo.resolution = 0.005f; // hPa
mSensorInfo.power = 0.001f; // mA
mSensorInfo.minDelay = 100 * 1000; // microseconds
}
MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
: ContinuousSensor(sensorHandle, callback) {
mSensorInfo.name = "Magnetic Field Sensor";
mSensorInfo.type = SensorType::MAGNETIC_FIELD;
mSensorInfo.typeAsString = SENSOR_STRING_TYPE_MAGNETIC_FIELD;
mSensorInfo.maxRange = 1300.0f;
mSensorInfo.resolution = 0.01f;
mSensorInfo.power = 0.001f; // mA
mSensorInfo.minDelay = 20 * 1000; // microseconds
}
LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
: OnChangeSensor(sensorHandle, callback) {
mSensorInfo.name = "Light Sensor";
mSensorInfo.type = SensorType::LIGHT;
mSensorInfo.typeAsString = SENSOR_STRING_TYPE_LIGHT;
mSensorInfo.maxRange = 43000.0f;
mSensorInfo.resolution = 10.0f;
mSensorInfo.power = 0.001f; // mA
mSensorInfo.minDelay = 200 * 1000; // microseconds
}
ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback)
: OnChangeSensor(sensorHandle, callback) {
mSensorInfo.name = "Proximity Sensor";
mSensorInfo.type = SensorType::PROXIMITY;
mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PROXIMITY;
mSensorInfo.maxRange = 5.0f;
mSensorInfo.resolution = 1.0f;
mSensorInfo.power = 0.012f; // mA
mSensorInfo.minDelay = 200 * 1000; // microseconds
mSensorInfo.flags |= SensorFlagBits::WAKE_UP;
}
GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
: ContinuousSensor(sensorHandle, callback) {
mSensorInfo.name = "Gyro Sensor";
mSensorInfo.type = SensorType::GYROSCOPE;
mSensorInfo.typeAsString = SENSOR_STRING_TYPE_GYROSCOPE;
mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f;
mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f);
mSensorInfo.power = 0.001f;
mSensorInfo.minDelay = 2.5f * 1000; // microseconds
}
std::vector<Event> GyroSensor::readEvents() {
std::vector<Event> events;
Event event;
event.sensorHandle = mSensorInfo.sensorHandle;
event.sensorType = mSensorInfo.type;
event.timestamp = ::android::elapsedRealtimeNano();
event.u.vec3.x = 0;
event.u.vec3.y = 0;
event.u.vec3.z = 0;
event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
events.push_back(event);
return events;
}
AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
: OnChangeSensor(sensorHandle, callback) {
mSensorInfo.name = "Ambient Temp Sensor";
mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE;
mSensorInfo.typeAsString = SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE;
mSensorInfo.maxRange = 80.0f;
mSensorInfo.resolution = 0.01f;
mSensorInfo.power = 0.001f;
mSensorInfo.minDelay = 40 * 1000; // microseconds
}
DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
: ContinuousSensor(sensorHandle, callback) {
mSensorInfo.name = "Device Temp Sensor";
mSensorInfo.type = SensorType::TEMPERATURE;
mSensorInfo.typeAsString = SENSOR_STRING_TYPE_TEMPERATURE;
mSensorInfo.maxRange = 80.0f;
mSensorInfo.resolution = 0.01f;
mSensorInfo.power = 0.001f;
mSensorInfo.minDelay = 40 * 1000; // microseconds
}
RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
ISensorsEventCallback* callback)
: OnChangeSensor(sensorHandle, callback) {
mSensorInfo.name = "Relative Humidity Sensor";
mSensorInfo.type = SensorType::RELATIVE_HUMIDITY;
mSensorInfo.typeAsString = SENSOR_STRING_TYPE_RELATIVE_HUMIDITY;
mSensorInfo.maxRange = 100.0f;
mSensorInfo.resolution = 0.1f;
mSensorInfo.power = 0.001f;
mSensorInfo.minDelay = 40 * 1000; // microseconds
}
} // namespace implementation
} // namespace subhal
} // namespace V2_0
} // namespace sensors
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,157 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <android/hardware/sensors/1.0/types.h>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <thread>
#include <vector>
using ::android::hardware::sensors::V1_0::Event;
using ::android::hardware::sensors::V1_0::OperationMode;
using ::android::hardware::sensors::V1_0::Result;
using ::android::hardware::sensors::V1_0::SensorInfo;
using ::android::hardware::sensors::V1_0::SensorType;
namespace android {
namespace hardware {
namespace sensors {
namespace V2_0 {
namespace subhal {
namespace implementation {
class ISensorsEventCallback {
public:
virtual ~ISensorsEventCallback(){};
virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0;
};
class Sensor {
public:
Sensor(int32_t sensorHandle, ISensorsEventCallback* callback);
virtual ~Sensor();
const SensorInfo& getSensorInfo() const;
void batch(int32_t samplingPeriodNs);
virtual void activate(bool enable);
Result flush();
void setOperationMode(OperationMode mode);
bool supportsDataInjection() const;
Result injectEvent(const Event& event);
protected:
void run();
virtual std::vector<Event> readEvents();
static void startThread(Sensor* sensor);
bool isWakeUpSensor();
bool mIsEnabled;
int64_t mSamplingPeriodNs;
int64_t mLastSampleTimeNs;
SensorInfo mSensorInfo;
std::atomic_bool mStopThread;
std::condition_variable mWaitCV;
std::mutex mRunMutex;
std::thread mRunThread;
ISensorsEventCallback* mCallback;
OperationMode mMode;
};
class OnChangeSensor : public Sensor {
public:
OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
virtual void activate(bool enable) override;
protected:
virtual std::vector<Event> readEvents() override;
protected:
Event mPreviousEvent;
bool mPreviousEventSet;
};
class ContinuousSensor : public Sensor {
public:
ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
};
class AccelSensor : public ContinuousSensor {
public:
AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
protected:
std::vector<Event> readEvents() override;
};
class GyroSensor : public ContinuousSensor {
public:
GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
protected:
std::vector<Event> readEvents() override;
};
class DeviceTempSensor : public ContinuousSensor {
public:
DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
};
class PressureSensor : public ContinuousSensor {
public:
PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
};
class MagnetometerSensor : public ContinuousSensor {
public:
MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
};
class AmbientTempSensor : public OnChangeSensor {
public:
AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
};
class LightSensor : public OnChangeSensor {
public:
LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
};
class ProximitySensor : public OnChangeSensor {
public:
ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
};
class RelativeHumiditySensor : public OnChangeSensor {
public:
RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
};
} // namespace implementation
} // namespace subhal
} // namespace V2_0
} // namespace sensors
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,240 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "SensorsSubHal.h"
#include <android/hardware/sensors/2.0/types.h>
#include <log/log.h>
ISensorsSubHal* sensorsHalGetSubHal(uint32_t* version) {
#if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
static ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal subHal;
#elif defined SUPPORT_CONTINUOUS_SENSORS
static ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal
subHal;
#elif defined SUPPORT_ON_CHANGE_SENSORS
static ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal subHal;
#else
static ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal subHal;
#endif // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
*version = SUB_HAL_2_0_VERSION;
return &subHal;
}
namespace android {
namespace hardware {
namespace sensors {
namespace V2_0 {
namespace subhal {
namespace implementation {
using ::android::hardware::Void;
using ::android::hardware::sensors::V1_0::Event;
using ::android::hardware::sensors::V1_0::OperationMode;
using ::android::hardware::sensors::V1_0::RateLevel;
using ::android::hardware::sensors::V1_0::Result;
using ::android::hardware::sensors::V1_0::SharedMemInfo;
using ::android::hardware::sensors::V2_0::SensorTimeout;
using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock;
SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {}
// Methods from ::android::hardware::sensors::V2_0::ISensors follow.
Return<void> SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
std::vector<SensorInfo> sensors;
for (const auto& sensor : mSensors) {
sensors.push_back(sensor.second->getSensorInfo());
}
_hidl_cb(sensors);
return Void();
}
Return<Result> SensorsSubHal::setOperationMode(OperationMode mode) {
for (auto sensor : mSensors) {
sensor.second->setOperationMode(mode);
}
mCurrentOperationMode = mode;
return Result::OK;
}
Return<Result> SensorsSubHal::activate(int32_t sensorHandle, bool enabled) {
auto sensor = mSensors.find(sensorHandle);
if (sensor != mSensors.end()) {
sensor->second->activate(enabled);
return Result::OK;
}
return Result::BAD_VALUE;
}
Return<Result> SensorsSubHal::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
int64_t /* maxReportLatencyNs */) {
auto sensor = mSensors.find(sensorHandle);
if (sensor != mSensors.end()) {
sensor->second->batch(samplingPeriodNs);
return Result::OK;
}
return Result::BAD_VALUE;
}
Return<Result> SensorsSubHal::flush(int32_t sensorHandle) {
auto sensor = mSensors.find(sensorHandle);
if (sensor != mSensors.end()) {
return sensor->second->flush();
}
return Result::BAD_VALUE;
}
Return<Result> SensorsSubHal::injectSensorData(const Event& event) {
auto sensor = mSensors.find(event.sensorHandle);
if (sensor != mSensors.end()) {
return sensor->second->injectEvent(event);
}
return Result::BAD_VALUE;
}
Return<void> SensorsSubHal::registerDirectChannel(const SharedMemInfo& /* mem */,
registerDirectChannel_cb _hidl_cb) {
_hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
return Return<void>();
}
Return<Result> SensorsSubHal::unregisterDirectChannel(int32_t /* channelHandle */) {
return Result::INVALID_OPERATION;
}
Return<void> SensorsSubHal::configDirectReport(int32_t /* sensorHandle */,
int32_t /* channelHandle */, RateLevel /* rate */,
configDirectReport_cb _hidl_cb) {
_hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */);
return Return<void>();
}
Return<void> SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) {
if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
ALOGE("%s: missing fd for writing", __FUNCTION__);
return Void();
}
FILE* out = fdopen(dup(fd->data[0]), "w");
if (args.size() != 0) {
fprintf(out,
"Note: sub-HAL %s currently does not support args. Input arguments are "
"ignored.\n",
getName().c_str());
}
std::ostringstream stream;
stream << "Available sensors:" << std::endl;
for (auto sensor : mSensors) {
SensorInfo info = sensor.second->getSensorInfo();
stream << "Name: " << info.name << std::endl;
stream << "Min delay: " << info.minDelay << std::endl;
stream << "Flags: " << info.flags << std::endl;
}
stream << std::endl;
fprintf(out, "%s", stream.str().c_str());
fclose(out);
return Return<void>();
}
Return<Result> SensorsSubHal::initialize(const sp<IHalProxyCallback>& halProxyCallback) {
mCallback = halProxyCallback;
setOperationMode(OperationMode::NORMAL);
return Result::OK;
}
void SensorsSubHal::postEvents(const std::vector<Event>& events, bool wakeup) {
ScopedWakelock wakelock = mCallback->createScopedWakelock(wakeup);
mCallback->postEvents(events, std::move(wakelock));
}
ContinuousSensorsSubHal::ContinuousSensorsSubHal() {
AddSensor<AccelSensor>();
AddSensor<GyroSensor>();
AddSensor<MagnetometerSensor>();
AddSensor<PressureSensor>();
AddSensor<DeviceTempSensor>();
}
OnChangeSensorsSubHal::OnChangeSensorsSubHal() {
AddSensor<AmbientTempSensor>();
AddSensor<LightSensor>();
AddSensor<ProximitySensor>();
AddSensor<RelativeHumiditySensor>();
}
AllSensorsSubHal::AllSensorsSubHal() {
AddSensor<AccelSensor>();
AddSensor<GyroSensor>();
AddSensor<MagnetometerSensor>();
AddSensor<PressureSensor>();
AddSensor<DeviceTempSensor>();
AddSensor<AmbientTempSensor>();
AddSensor<LightSensor>();
AddSensor<ProximitySensor>();
AddSensor<RelativeHumiditySensor>();
}
Return<Result> SetOperationModeFailingSensorsSubHal::setOperationMode(OperationMode /*mode*/) {
return Result::BAD_VALUE;
}
Return<void> AllSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
std::vector<SensorInfo> sensors;
for (const auto& sensor : mSensors) {
SensorInfo sensorInfo = sensor.second->getSensorInfo();
sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL;
sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_REPORT;
sensors.push_back(sensorInfo);
}
_hidl_cb(sensors);
return Void();
}
Return<void> DoesNotSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
std::vector<SensorInfo> sensors;
for (const auto& sensor : mSensors) {
SensorInfo sensorInfo = sensor.second->getSensorInfo();
sensorInfo.flags &= ~static_cast<uint32_t>(V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
sensorInfo.flags &= ~static_cast<uint32_t>(V1_0::SensorFlagBits::MASK_DIRECT_REPORT);
sensors.push_back(sensorInfo);
}
_hidl_cb(sensors);
return Void();
}
void AddAndRemoveDynamicSensorsSubHal::addDynamicSensors(
const std::vector<SensorInfo>& sensorsAdded) {
mCallback->onDynamicSensorsConnected(sensorsAdded);
}
void AddAndRemoveDynamicSensorsSubHal::removeDynamicSensors(
const std::vector<int32_t>& sensorHandlesRemoved) {
mCallback->onDynamicSensorsDisconnected(sensorHandlesRemoved);
}
} // namespace implementation
} // namespace subhal
} // namespace V2_0
} // namespace sensors
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,165 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "SubHal.h"
#include "Sensor.h"
#include <vector>
namespace android {
namespace hardware {
namespace sensors {
namespace V2_0 {
namespace subhal {
namespace implementation {
using ::android::hardware::sensors::V1_0::OperationMode;
using ::android::hardware::sensors::V1_0::Result;
using ::android::hardware::sensors::V2_0::implementation::IHalProxyCallback;
/**
* Implementation of a ISensorsSubHal that can be used to test the implementation of multihal 2.0.
* See the README file for more details on how this class can be used for testing.
*/
class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback {
using Event = ::android::hardware::sensors::V1_0::Event;
using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
public:
SensorsSubHal();
// Methods from ::android::hardware::sensors::V2_0::ISensors follow.
virtual Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
virtual Return<Result> setOperationMode(OperationMode mode) override;
OperationMode getOperationMode() const { return mCurrentOperationMode; }
Return<Result> activate(int32_t sensorHandle, bool enabled) override;
Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
int64_t maxReportLatencyNs) override;
Return<Result> flush(int32_t sensorHandle) override;
Return<Result> injectSensorData(const Event& event) override;
Return<void> registerDirectChannel(const SharedMemInfo& mem,
registerDirectChannel_cb _hidl_cb) override;
Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
configDirectReport_cb _hidl_cb) override;
Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
// Methods from ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal follow.
const std::string getName() override {
#ifdef SUB_HAL_NAME
return SUB_HAL_NAME;
#else // SUB_HAL_NAME
return "FakeSubHal";
#endif // SUB_HAL_NAME
}
Return<Result> initialize(const sp<IHalProxyCallback>& halProxyCallback) override;
// Method from ISensorsEventCallback.
void postEvents(const std::vector<Event>& events, bool wakeup) override;
protected:
template <class SensorType>
void AddSensor() {
std::shared_ptr<SensorType> sensor =
std::make_shared<SensorType>(mNextHandle++ /* sensorHandle */, this /* callback */);
mSensors[sensor->getSensorInfo().sensorHandle] = sensor;
}
/**
* A map of the available sensors
*/
std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
/**
* Callback used to communicate to the HalProxy when dynamic sensors are connected /
* disconnected, sensor events need to be sent to the framework, and when a wakelock should be
* acquired.
*/
sp<IHalProxyCallback> mCallback;
private:
/**
* The current operation mode of the multihal framework. Ensures that all subhals are set to
* the same operation mode.
*/
OperationMode mCurrentOperationMode = OperationMode::NORMAL;
/**
* The next available sensor handle
*/
int32_t mNextHandle;
};
// SubHal that has continuous sensors for testing purposes.
class ContinuousSensorsSubHal : public SensorsSubHal {
public:
ContinuousSensorsSubHal();
};
// SubHal that has on-change sensors for testing purposes.
class OnChangeSensorsSubHal : public SensorsSubHal {
public:
OnChangeSensorsSubHal();
};
// SubHal that has both continuous and on-change sensors for testing purposes.
class AllSensorsSubHal : public SensorsSubHal {
public:
AllSensorsSubHal();
};
class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal {
public:
Return<Result> setOperationMode(OperationMode mode) override;
};
class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal {
public:
Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
};
class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal {
public:
Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
};
class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal {
public:
void addDynamicSensors(const std::vector<SensorInfo>& sensorsAdded);
void removeDynamicSensors(const std::vector<int32_t>& sensorHandlesAdded);
};
} // namespace implementation
} // namespace subhal
} // namespace V2_0
} // namespace sensors
} // namespace hardware
} // namespace android