V2: Use resolution to round sensor event values
Add method to utilize a sensor's specified resolution value to ensure
data isn't provided that is more fine-grained than expected. This
helps mitigate sensor calibration fingerprinting attacks.
Bug: 147725937
Test: Verify accel sensor data isn't more fine grained than its
specified resolution
Test: Verify that the max range specified is a multiple of the
resolution
Change-Id: I30ff66d9deb10c84319a63f9964477d8e469650d
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 3b68e0e..d20674c 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -143,6 +143,25 @@
for (size_t i=0 ; i < count; i++) {
sensor_t sensor;
convertToSensor(convertToOldSensorInfo(list[i]), &sensor);
+
+ if (sensor.type < static_cast<int>(SensorType::DEVICE_PRIVATE_BASE)) {
+ if(sensor.resolution == 0) {
+ // Don't crash here or the device will go into a crashloop.
+ ALOGW("%s must have a non-zero resolution", sensor.name);
+ // For simple algos, map their resolution to 1 if it's not specified
+ sensor.resolution =
+ SensorDeviceUtils::defaultResolutionForType(sensor.type);
+ }
+
+ double promotedResolution = sensor.resolution;
+ double promotedMaxRange = sensor.maxRange;
+ if (fmod(promotedMaxRange, promotedResolution) != 0) {
+ ALOGW("%s's max range %f is not a multiple of the resolution %f",
+ sensor.name, sensor.maxRange, sensor.resolution);
+ SensorDeviceUtils::quantizeValue(&sensor.maxRange, promotedResolution);
+ }
+ }
+
// Sanity check and clamp power if it is 0 (or close)
if (sensor.power < minPowerMa) {
ALOGI("Reported power %f not deemed sane, clamping to %f",
@@ -508,7 +527,7 @@
const auto &events,
const auto &dynamicSensorsAdded) {
if (result == Result::OK) {
- convertToSensorEvents(convertToNewEvents(events),
+ convertToSensorEventsAndQuantize(convertToNewEvents(events),
convertToNewSensorInfos(dynamicSensorsAdded), buffer);
err = (ssize_t)events.size();
} else {
@@ -571,6 +590,8 @@
for (size_t i = 0; i < eventsToRead; i++) {
convertToSensorEvent(mEventBuffer[i], &buffer[i]);
+ android::SensorDeviceUtils::quantizeSensorEventValues(&buffer[i],
+ getResolutionForSensor(buffer[i].sensor));
}
eventsRead = eventsToRead;
} else {
@@ -1077,7 +1098,7 @@
}
}
-void SensorDevice::convertToSensorEvents(
+void SensorDevice::convertToSensorEventsAndQuantize(
const hidl_vec<Event> &src,
const hidl_vec<SensorInfo> &dynamicSensorsAdded,
sensors_event_t *dst) {
@@ -1088,9 +1109,26 @@
for (size_t i = 0; i < src.size(); ++i) {
V2_1::implementation::convertToSensorEvent(src[i], &dst[i]);
+ android::SensorDeviceUtils::quantizeSensorEventValues(&dst[i],
+ getResolutionForSensor(dst[i].sensor));
}
}
+float SensorDevice::getResolutionForSensor(int sensorHandle) {
+ for (size_t i = 0; i < mSensorList.size(); i++) {
+ if (sensorHandle == mSensorList[i].handle) {
+ return mSensorList[i].resolution;
+ }
+ }
+
+ auto it = mConnectedDynamicSensors.find(sensorHandle);
+ if (it != mConnectedDynamicSensors.end()) {
+ return it->second->resolution;
+ }
+
+ return 0;
+}
+
void SensorDevice::handleHidlDeath(const std::string & detail) {
if (!mSensors->supportsMessageQueues()) {
// restart is the only option at present.
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 24d03c6..04e6031 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -233,11 +233,13 @@
void convertToSensorEvent(const Event &src, sensors_event_t *dst);
- void convertToSensorEvents(
+ void convertToSensorEventsAndQuantize(
const hardware::hidl_vec<Event> &src,
const hardware::hidl_vec<SensorInfo> &dynamicSensorsAdded,
sensors_event_t *dst);
+ float getResolutionForSensor(int sensorHandle);
+
bool mIsDirectReportSupported;
typedef hardware::MessageQueue<uint32_t, hardware::kSynchronizedReadWrite> WakeLockQueue;
diff --git a/services/sensorservice/SensorDeviceUtils.cpp b/services/sensorservice/SensorDeviceUtils.cpp
index dbafffe..0dcf8c0 100644
--- a/services/sensorservice/SensorDeviceUtils.cpp
+++ b/services/sensorservice/SensorDeviceUtils.cpp
@@ -17,17 +17,101 @@
#include "SensorDeviceUtils.h"
#include <android/hardware/sensors/1.0/ISensors.h>
+#include <android/hardware/sensors/2.1/ISensors.h>
#include <utils/Log.h>
#include <chrono>
#include <thread>
using ::android::hardware::Void;
+using SensorTypeV2_1 = android::hardware::sensors::V2_1::SensorType;
using namespace android::hardware::sensors::V1_0;
namespace android {
namespace SensorDeviceUtils {
+void quantizeSensorEventValues(sensors_event_t *event, float resolution) {
+ LOG_FATAL_IF(resolution == 0, "Resolution must be specified for all sensors!");
+ if (resolution == 0) {
+ return;
+ }
+
+ size_t axes = 0;
+ switch ((SensorTypeV2_1)event->type) {
+ case SensorTypeV2_1::ACCELEROMETER:
+ case SensorTypeV2_1::MAGNETIC_FIELD:
+ case SensorTypeV2_1::ORIENTATION:
+ case SensorTypeV2_1::GYROSCOPE:
+ case SensorTypeV2_1::GRAVITY:
+ case SensorTypeV2_1::LINEAR_ACCELERATION:
+ case SensorTypeV2_1::MAGNETIC_FIELD_UNCALIBRATED:
+ case SensorTypeV2_1::GYROSCOPE_UNCALIBRATED:
+ case SensorTypeV2_1::ACCELEROMETER_UNCALIBRATED:
+ axes = 3;
+ break;
+ case SensorTypeV2_1::GAME_ROTATION_VECTOR:
+ axes = 4;
+ break;
+ case SensorTypeV2_1::ROTATION_VECTOR:
+ case SensorTypeV2_1::GEOMAGNETIC_ROTATION_VECTOR:
+ axes = 5;
+ break;
+ case SensorTypeV2_1::DEVICE_ORIENTATION:
+ case SensorTypeV2_1::LIGHT:
+ case SensorTypeV2_1::PRESSURE:
+ case SensorTypeV2_1::TEMPERATURE:
+ case SensorTypeV2_1::PROXIMITY:
+ case SensorTypeV2_1::RELATIVE_HUMIDITY:
+ case SensorTypeV2_1::AMBIENT_TEMPERATURE:
+ case SensorTypeV2_1::SIGNIFICANT_MOTION:
+ case SensorTypeV2_1::STEP_DETECTOR:
+ case SensorTypeV2_1::TILT_DETECTOR:
+ case SensorTypeV2_1::WAKE_GESTURE:
+ case SensorTypeV2_1::GLANCE_GESTURE:
+ case SensorTypeV2_1::PICK_UP_GESTURE:
+ case SensorTypeV2_1::WRIST_TILT_GESTURE:
+ case SensorTypeV2_1::STATIONARY_DETECT:
+ case SensorTypeV2_1::MOTION_DETECT:
+ case SensorTypeV2_1::HEART_BEAT:
+ case SensorTypeV2_1::LOW_LATENCY_OFFBODY_DETECT:
+ case SensorTypeV2_1::HINGE_ANGLE:
+ axes = 1;
+ break;
+ case SensorTypeV2_1::POSE_6DOF:
+ axes = 15;
+ break;
+ default:
+ // No other sensors have data that needs to be rounded.
+ break;
+ }
+
+ // sensor_event_t is a union so we're able to perform the same quanitization action for most
+ // sensors by only knowing the number of axes their output data has.
+ for (size_t i = 0; i < axes; i++) {
+ quantizeValue(&event->data[i], resolution);
+ }
+}
+
+float defaultResolutionForType(int type) {
+ switch ((SensorTypeV2_1)type) {
+ case SensorTypeV2_1::SIGNIFICANT_MOTION:
+ case SensorTypeV2_1::STEP_DETECTOR:
+ case SensorTypeV2_1::STEP_COUNTER:
+ case SensorTypeV2_1::TILT_DETECTOR:
+ case SensorTypeV2_1::WAKE_GESTURE:
+ case SensorTypeV2_1::GLANCE_GESTURE:
+ case SensorTypeV2_1::PICK_UP_GESTURE:
+ case SensorTypeV2_1::WRIST_TILT_GESTURE:
+ case SensorTypeV2_1::STATIONARY_DETECT:
+ case SensorTypeV2_1::MOTION_DETECT:
+ return 1.0f;
+ default:
+ // fall through and return 0 for all other types
+ break;
+ }
+ return 0.0f;
+}
+
HidlServiceRegistrationWaiter::HidlServiceRegistrationWaiter() {
}
diff --git a/services/sensorservice/SensorDeviceUtils.h b/services/sensorservice/SensorDeviceUtils.h
index e2eb606..d7e621c 100644
--- a/services/sensorservice/SensorDeviceUtils.h
+++ b/services/sensorservice/SensorDeviceUtils.h
@@ -18,7 +18,9 @@
#define ANDROID_SENSOR_DEVICE_UTIL
#include <android/hidl/manager/1.0/IServiceNotification.h>
+#include <hardware/sensors.h>
+#include <cmath>
#include <condition_variable>
#include <thread>
@@ -29,6 +31,21 @@
namespace android {
namespace SensorDeviceUtils {
+// Quantizes a single value using a sensor's resolution.
+inline void quantizeValue(float *value, double resolution) {
+ // Increase the value of the sensor's nominal resolution to ensure that
+ // sensor accuracy improvements, like runtime calibration, are not masked
+ // during requantization.
+ double incRes = 0.25 * resolution;
+ *value = round(static_cast<double>(*value) / incRes) * incRes;
+}
+
+// Ensures a sensor event doesn't provide values finer grained than its sensor resolution allows.
+void quantizeSensorEventValues(sensors_event_t *event, float resolution);
+
+// Provides a default resolution for simple sensor types if one wasn't provided by the HAL.
+float defaultResolutionForType(int type);
+
class HidlServiceRegistrationWaiter : public IServiceNotification {
public: