Automatically reconnect sensors
Automatically reenable sensor connections for static sensors after a
Sensors HAL crash.
Bug: 111070257
Test: Request sensor events via a_sns_test, kill the sensors HAL,
verify that events are no longer received, restart the HAL and
verify that a_sns_test receives new sensor events.
Change-Id: I2baa7745cf07e29c186ac4b80679393d6e48bd56
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index f813fe5..f2336cb 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -59,11 +59,22 @@
}
}
+template<typename EnumType>
+constexpr typename std::underlying_type<EnumType>::type asBaseType(EnumType value) {
+ return static_cast<typename std::underlying_type<EnumType>::type>(value);
+}
+
+// Used internally by the framework to wake the Event FMQ. These values must start after
+// the last value of EventQueueFlagBits
+enum EventQueueFlagBitsInternal : uint32_t {
+ INTERNAL_WAKE = 1 << 16,
+};
+
void SensorsHalDeathReceivier::serviceDied(
uint64_t /* cookie */,
const wp<::android::hidl::base::V1_0::IBase>& /* service */) {
ALOGW("Sensors HAL died, attempting to reconnect.");
- // TODO: Attempt reconnect
+ SensorDevice::getInstance().prepareForReconnect();
}
struct SensorsCallback : public ISensorsCallback {
@@ -81,11 +92,20 @@
};
SensorDevice::SensorDevice()
- : mHidlTransportErrors(20), mRestartWaiter(new HidlServiceRegistrationWaiter()) {
+ : mHidlTransportErrors(20),
+ mRestartWaiter(new HidlServiceRegistrationWaiter()),
+ mReconnecting(false) {
if (!connectHidlService()) {
return;
}
+ initializeSensorList();
+
+ mIsDirectReportSupported =
+ (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);
+}
+
+void SensorDevice::initializeSensorList() {
float minPowerMa = 0.001; // 1 microAmp
checkReturn(mSensors->getSensorsList(
@@ -110,9 +130,6 @@
checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
}
}));
-
- mIsDirectReportSupported =
- (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);
}
SensorDevice::~SensorDevice() {
@@ -204,6 +221,108 @@
return connectionStatus;
}
+void SensorDevice::prepareForReconnect() {
+ mReconnecting = true;
+
+ // Wake up the polling thread so it returns and allows the SensorService to initiate
+ // a reconnect.
+ mEventQueueFlag->wake(asBaseType(INTERNAL_WAKE));
+}
+
+void SensorDevice::reconnect() {
+ Mutex::Autolock _l(mLock);
+ mSensors = nullptr;
+
+ auto previousActivations = mActivationCount;
+ auto previousSensorList = mSensorList;
+
+ mActivationCount.clear();
+ mSensorList.clear();
+
+ if (connectHidlServiceV2_0() == HalConnectionStatus::CONNECTED) {
+ initializeSensorList();
+
+ if (sensorHandlesChanged(previousSensorList, mSensorList)) {
+ LOG_ALWAYS_FATAL("Sensor handles changed, cannot re-enable sensors.");
+ } else {
+ reactivateSensors(previousActivations);
+ }
+ }
+ mReconnecting = false;
+}
+
+bool SensorDevice::sensorHandlesChanged(const Vector<sensor_t>& oldSensorList,
+ const Vector<sensor_t>& newSensorList) {
+ bool didChange = false;
+
+ if (oldSensorList.size() != newSensorList.size()) {
+ didChange = true;
+ }
+
+ for (size_t i = 0; i < newSensorList.size() && !didChange; i++) {
+ bool found = false;
+ const sensor_t& newSensor = newSensorList[i];
+ for (size_t j = 0; j < oldSensorList.size() && !found; j++) {
+ const sensor_t& prevSensor = oldSensorList[j];
+ if (prevSensor.handle == newSensor.handle) {
+ found = true;
+ if (!sensorIsEquivalent(prevSensor, newSensor)) {
+ didChange = true;
+ }
+ }
+ }
+
+ if (!found) {
+ // Could not find the new sensor in the old list of sensors, the lists must
+ // have changed.
+ didChange = true;
+ }
+ }
+ return didChange;
+}
+
+bool SensorDevice::sensorIsEquivalent(const sensor_t& prevSensor, const sensor_t& newSensor) {
+ bool equivalent = true;
+ if (prevSensor.handle != newSensor.handle ||
+ (strcmp(prevSensor.vendor, newSensor.vendor) != 0) ||
+ (strcmp(prevSensor.stringType, newSensor.stringType) != 0) ||
+ (strcmp(prevSensor.requiredPermission, newSensor.requiredPermission) != 0) ||
+ (prevSensor.version != newSensor.version) ||
+ (prevSensor.type != newSensor.type) ||
+ (std::abs(prevSensor.maxRange - newSensor.maxRange) > 0.001f) ||
+ (std::abs(prevSensor.resolution - newSensor.resolution) > 0.001f) ||
+ (std::abs(prevSensor.power - newSensor.power) > 0.001f) ||
+ (prevSensor.minDelay != newSensor.minDelay) ||
+ (prevSensor.fifoReservedEventCount != newSensor.fifoReservedEventCount) ||
+ (prevSensor.fifoMaxEventCount != newSensor.fifoMaxEventCount) ||
+ (prevSensor.maxDelay != newSensor.maxDelay) ||
+ (prevSensor.flags != newSensor.flags)) {
+ equivalent = false;
+ }
+ return equivalent;
+}
+
+void SensorDevice::reactivateSensors(const DefaultKeyedVector<int, Info>& previousActivations) {
+ for (size_t i = 0; i < mSensorList.size(); i++) {
+ int handle = mSensorList[i].handle;
+ ssize_t activationIndex = previousActivations.indexOfKey(handle);
+ if (activationIndex < 0 || previousActivations[activationIndex].numActiveClients() <= 0) {
+ continue;
+ }
+
+ const Info& info = previousActivations[activationIndex];
+ for (size_t j = 0; j < info.batchParams.size(); j++) {
+ const BatchParams& batchParams = info.batchParams[j];
+ status_t res = batchLocked(info.batchParams.keyAt(j), handle, 0 /* flags */,
+ batchParams.mTSample, batchParams.mTBatch);
+
+ if (res == NO_ERROR) {
+ activateLocked(info.batchParams.keyAt(j), handle, true /* enabled */);
+ }
+ }
+ }
+}
+
void SensorDevice::handleDynamicSensorConnection(int handle, bool connected) {
// not need to check mSensors because this is is only called after successful poll()
if (connected) {
@@ -261,6 +380,8 @@
}
ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
+ if (mSensors == nullptr) return NO_INIT;
+
ssize_t eventsRead = 0;
if (mSensors->supportsMessageQueues()) {
eventsRead = pollFmq(buffer, count);
@@ -274,8 +395,6 @@
}
ssize_t SensorDevice::pollHal(sensors_event_t* buffer, size_t count) {
- if (mSensors == nullptr) return NO_INIT;
-
ssize_t err;
int numHidlTransportErrors = 0;
bool hidlTransportError = false;
@@ -320,10 +439,6 @@
}
ssize_t SensorDevice::pollFmq(sensors_event_t* buffer, size_t maxNumEventsToRead) {
- if (mSensors == nullptr) {
- return NO_INIT;
- }
-
ssize_t eventsRead = 0;
size_t availableEvents = mEventQueue->availableToRead();
@@ -334,13 +449,19 @@
// able to be called with the correct number of events to read. If the specified number of
// events is not available, then read() would return no events, possibly introducing
// additional latency in delivering events to applications.
- mEventQueueFlag->wait(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
- &eventFlagState);
+ mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS) |
+ asBaseType(INTERNAL_WAKE), &eventFlagState);
availableEvents = mEventQueue->availableToRead();
- if (availableEvents == 0) {
+ if ((eventFlagState & asBaseType(EventQueueFlagBits::READ_AND_PROCESS)) &&
+ availableEvents == 0) {
ALOGW("Event FMQ wake without any events");
}
+
+ if ((eventFlagState & asBaseType(INTERNAL_WAKE)) && mReconnecting) {
+ ALOGD("Event FMQ internal wake, returning from poll with no events");
+ return DEAD_OBJECT;
+ }
}
size_t eventsToRead = std::min({availableEvents, maxNumEventsToRead, mEventBuffer.size()});
@@ -387,7 +508,8 @@
}
void SensorDevice::writeWakeLockHandled(uint32_t count) {
- if (mSensors->supportsMessageQueues() && !mWakeLockQueue->write(&count)) {
+ if (mSensors != nullptr && mSensors->supportsMessageQueues() &&
+ !mWakeLockQueue->write(&count)) {
ALOGW("Failed to write wake lock handled");
}
}
@@ -406,10 +528,15 @@
status_t SensorDevice::activate(void* ident, int handle, int enabled) {
if (mSensors == nullptr) return NO_INIT;
- status_t err(NO_ERROR);
+ Mutex::Autolock _l(mLock);
+ return activateLocked(ident, handle, enabled);
+}
+
+status_t SensorDevice::activateLocked(void* ident, int handle, int enabled) {
bool actuateHardware = false;
- Mutex::Autolock _l(mLock);
+ status_t err(NO_ERROR);
+
ssize_t activationIndex = mActivationCount.indexOfKey(handle);
if (activationIndex < 0) {
ALOGW("Handle %d cannot be found in activation record", handle);
@@ -509,6 +636,11 @@
ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
Mutex::Autolock _l(mLock);
+ return batchLocked(ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs);
+}
+
+status_t SensorDevice::batchLocked(void* ident, int handle, int flags, int64_t samplingPeriodNs,
+ int64_t maxBatchReportLatencyNs) {
ssize_t activationIndex = mActivationCount.indexOfKey(handle);
if (activationIndex < 0) {
ALOGW("Handle %d cannot be found in activation record", handle);
@@ -739,7 +871,7 @@
// ---------------------------------------------------------------------------
-int SensorDevice::Info::numActiveClients() {
+int SensorDevice::Info::numActiveClients() const {
SensorDevice& device(SensorDevice::getInstance());
int num = 0;
for (size_t i = 0; i < batchParams.size(); ++i) {
@@ -838,8 +970,12 @@
}
void SensorDevice::handleHidlDeath(const std::string & detail) {
- // restart is the only option at present.
- LOG_ALWAYS_FATAL("Abort due to ISensors hidl service failure, detail: %s.", detail.c_str());
+ if (!SensorDevice::getInstance().mSensors->supportsMessageQueues()) {
+ // restart is the only option at present.
+ LOG_ALWAYS_FATAL("Abort due to ISensors hidl service failure, detail: %s.", detail.c_str());
+ } else {
+ ALOGD("ISensors HAL died, death recipient will attempt reconnect");
+ }
}
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 2da60b6..e1024ac 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -77,6 +77,8 @@
};
~SensorDevice();
+ void prepareForReconnect();
+ void reconnect();
ssize_t getSensorList(sensor_t const** list);
@@ -114,6 +116,10 @@
hardware::Return<void> onDynamicSensorsDisconnected(
const hardware::hidl_vec<int32_t> &dynamicSensorHandlesRemoved);
+ bool isReconnecting() const {
+ return mReconnecting;
+ }
+
// Dumpable
virtual std::string dump() const;
private:
@@ -167,7 +173,7 @@
// the removed ident. If index >=0, ident is present and successfully removed.
ssize_t removeBatchParamsForIdent(void* ident);
- int numActiveClients();
+ int numActiveClients() const;
};
DefaultKeyedVector<int, Info> mActivationCount;
@@ -179,6 +185,11 @@
SortedVector<void *> mDisabledClients;
SensorDevice();
bool connectHidlService();
+ void initializeSensorList();
+ void reactivateSensors(const DefaultKeyedVector<int, Info>& previousActivations);
+ static bool sensorHandlesChanged(const Vector<sensor_t>& oldSensorList,
+ const Vector<sensor_t>& newSensorList);
+ static bool sensorIsEquivalent(const sensor_t& prevSensor, const sensor_t& newSensor);
enum HalConnectionStatus {
CONNECTED, // Successfully connected to the HAL
@@ -191,6 +202,9 @@
ssize_t pollHal(sensors_event_t* buffer, size_t count);
ssize_t pollFmq(sensors_event_t* buffer, size_t count);
+ status_t activateLocked(void* ident, int handle, int enabled);
+ status_t batchLocked(void* ident, int handle, int flags, int64_t samplingPeriodNs,
+ int64_t maxBatchReportLatencyNs);
static void handleHidlDeath(const std::string &detail);
template<typename T>
@@ -228,6 +242,7 @@
std::array<Event, SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer;
sp<SensorsHalDeathReceivier> mSensorsHalDeathReceiver;
+ std::atomic_bool mReconnecting;
};
// ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index f4e728b..1b9b945 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -633,8 +633,13 @@
do {
ssize_t count = device.poll(mSensorEventBuffer, numEventMax);
if (count < 0) {
- ALOGE("sensor poll failed (%s)", strerror(-count));
- break;
+ if(count == DEAD_OBJECT && device.isReconnecting()) {
+ device.reconnect();
+ continue;
+ } else {
+ ALOGE("sensor poll failed (%s)", strerror(-count));
+ break;
+ }
}
// Reset sensors_event_t.flags to zero for all events in the buffer.