Merge 6b3aea8578e45387a6bb5049bfc0231148dff670 on remote branch
Change-Id: I9f4e0a2488aaa9981ef05555b53fcbcea0c31451
diff --git a/include/hardware/keymaster_defs.h b/include/hardware/keymaster_defs.h
index c0b3800..930aceb 100644
--- a/include/hardware/keymaster_defs.h
+++ b/include/hardware/keymaster_defs.h
@@ -304,6 +304,7 @@
KM_EC_CURVE_P_256 = 1,
KM_EC_CURVE_P_384 = 2,
KM_EC_CURVE_P_521 = 3,
+ KM_EC_CURVE_CURVE_25519 = 4,
} keymaster_ec_curve_t;
/**
diff --git a/include/hardware/sensors-base.h b/include/hardware/sensors-base.h
index ef7eead..b88a8c2 100644
--- a/include/hardware/sensors-base.h
+++ b/include/hardware/sensors-base.h
@@ -52,6 +52,7 @@
SENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT = 34,
SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED = 35,
SENSOR_TYPE_HINGE_ANGLE = 36,
+ SENSOR_TYPE_HEAD_TRACKER = 37,
SENSOR_TYPE_DEVICE_PRIVATE_BASE = 65536 /* 0x10000 */,
};
diff --git a/include/hardware/sensors.h b/include/hardware/sensors.h
index a03a409..cef5dd6 100644
--- a/include/hardware/sensors.h
+++ b/include/hardware/sensors.h
@@ -186,6 +186,7 @@
#define SENSOR_STRING_TYPE_LOW_LATENCY_OFFBODY_DETECT "android.sensor.low_latency_offbody_detect"
#define SENSOR_STRING_TYPE_ACCELEROMETER_UNCALIBRATED "android.sensor.accelerometer_uncalibrated"
#define SENSOR_STRING_TYPE_HINGE_ANGLE "android.sensor.hinge_angle"
+#define SENSOR_STRING_TYPE_HEAD_TRACKER "android.sensor.head_tracker"
/**
* Values returned by the accelerometer in various locations in the universe.
diff --git a/modules/audio_remote_submix/OWNERS b/modules/audio_remote_submix/OWNERS
new file mode 100644
index 0000000..67da0f9
--- /dev/null
+++ b/modules/audio_remote_submix/OWNERS
@@ -0,0 +1,3 @@
+elaurent@google.com
+mnaganov@google.com
+jmtrivi@google.com
diff --git a/modules/audio_remote_submix/audio_hw.cpp b/modules/audio_remote_submix/audio_hw.cpp
index b43a44d..42d3b98 100644
--- a/modules/audio_remote_submix/audio_hw.cpp
+++ b/modules/audio_remote_submix/audio_hw.cpp
@@ -83,10 +83,7 @@
// multiple input streams from this device. If this option is enabled, each input stream returned
// is *the same stream* which means that readers will race to read data from these streams.
#define ENABLE_LEGACY_INPUT_OPEN 1
-// Whether channel conversion (16-bit signed PCM mono->stereo, stereo->mono) is enabled.
-#define ENABLE_CHANNEL_CONVERSION 1
-// Whether resampling is enabled.
-#define ENABLE_RESAMPLING 1
+
#if LOG_STREAMS_TO_FILES
// Folder to save stream log files to.
#define LOG_STREAM_FOLDER "/data/misc/audioserver"
@@ -130,11 +127,6 @@
// channel bitfields are not equivalent.
audio_channel_mask_t input_channel_mask;
audio_channel_mask_t output_channel_mask;
-#if ENABLE_RESAMPLING
- // Input stream and output stream sample rates.
- uint32_t input_sample_rate;
- uint32_t output_sample_rate;
-#endif // ENABLE_RESAMPLING
size_t pipe_frame_size; // Number of bytes in each audio frame in the pipe.
size_t buffer_size_frames; // Size of the audio pipe in frames.
// Maximum number of frames buffered by the input and output streams.
@@ -159,11 +151,6 @@
// destroyed if both and input and output streams are destroyed.
struct submix_stream_out *output;
struct submix_stream_in *input;
-#if ENABLE_RESAMPLING
- // Buffer used as temporary storage for resampled data prior to returning data to the output
- // stream.
- int16_t resampler_buffer[DEFAULT_PIPE_SIZE_IN_FRAMES];
-#endif // ENABLE_RESAMPLING
} route_config_t;
struct submix_audio_device {
@@ -325,7 +312,6 @@
static bool audio_config_compare(const audio_config * const input_config,
const audio_config * const output_config)
{
-#if !ENABLE_CHANNEL_CONVERSION
const uint32_t input_channels = audio_channel_count_from_in_mask(input_config->channel_mask);
const uint32_t output_channels = audio_channel_count_from_out_mask(output_config->channel_mask);
if (input_channels != output_channels) {
@@ -333,13 +319,8 @@
input_channels, output_channels);
return false;
}
-#endif // !ENABLE_CHANNEL_CONVERSION
-#if ENABLE_RESAMPLING
- if (input_config->sample_rate != output_config->sample_rate &&
- audio_channel_count_from_in_mask(input_config->channel_mask) != 1) {
-#else
+
if (input_config->sample_rate != output_config->sample_rate) {
-#endif // ENABLE_RESAMPLING
ALOGE("audio_config_compare() sample rate mismatch %ul vs. %ul",
input_config->sample_rate, output_config->sample_rate);
return false;
@@ -376,24 +357,11 @@
in->route_handle = route_idx;
rsxadev->routes[route_idx].input = in;
rsxadev->routes[route_idx].config.input_channel_mask = config->channel_mask;
-#if ENABLE_RESAMPLING
- rsxadev->routes[route_idx].config.input_sample_rate = config->sample_rate;
- // If the output isn't configured yet, set the output sample rate to the maximum supported
- // sample rate such that the smallest possible input buffer is created, and put a default
- // value for channel count
- if (!rsxadev->routes[route_idx].output) {
- rsxadev->routes[route_idx].config.output_sample_rate = 48000;
- rsxadev->routes[route_idx].config.output_channel_mask = AUDIO_CHANNEL_OUT_STEREO;
- }
-#endif // ENABLE_RESAMPLING
}
if (out) {
out->route_handle = route_idx;
rsxadev->routes[route_idx].output = out;
rsxadev->routes[route_idx].config.output_channel_mask = config->channel_mask;
-#if ENABLE_RESAMPLING
- rsxadev->routes[route_idx].config.output_sample_rate = config->sample_rate;
-#endif // ENABLE_RESAMPLING
}
// Save the address
strncpy(rsxadev->routes[route_idx].address, address, AUDIO_DEVICE_MAX_ADDRESS_LEN);
@@ -403,18 +371,14 @@
{
struct submix_config * const device_config = &rsxadev->routes[route_idx].config;
uint32_t channel_count;
- if (out)
+ if (out) {
channel_count = audio_channel_count_from_out_mask(config->channel_mask);
- else
+ } else {
channel_count = audio_channel_count_from_in_mask(config->channel_mask);
-#if ENABLE_CHANNEL_CONVERSION
- // If channel conversion is enabled, allocate enough space for the maximum number of
- // possible channels stored in the pipe for the situation when the number of channels in
- // the output stream don't match the number in the input stream.
- const uint32_t pipe_channel_count = max(channel_count, 2);
-#else
+ }
+
const uint32_t pipe_channel_count = channel_count;
-#endif // ENABLE_CHANNEL_CONVERSION
+
const NBAIO_Format format = Format_from_SR_C(config->sample_rate, pipe_channel_count,
config->format);
const NBAIO_Format offers[1] = {format};
@@ -444,11 +408,7 @@
buffer_period_count;
if (in) device_config->pipe_frame_size = audio_stream_in_frame_size(&in->stream);
if (out) device_config->pipe_frame_size = audio_stream_out_frame_size(&out->stream);
-#if ENABLE_CHANNEL_CONVERSION
- // Calculate the pipe frame size based upon the number of channels.
- device_config->pipe_frame_size = (device_config->pipe_frame_size * pipe_channel_count) /
- channel_count;
-#endif // ENABLE_CHANNEL_CONVERSION
+
SUBMIX_ALOGV("submix_audio_device_create_pipe_l(): pipe frame size %zd, pipe size %zd, "
"period size %zd", device_config->pipe_frame_size,
device_config->buffer_size_frames, device_config->buffer_period_size_frames);
@@ -473,10 +433,6 @@
rsxadev->routes[route_idx].rsxSource.clear();
}
memset(rsxadev->routes[route_idx].address, 0, AUDIO_DEVICE_MAX_ADDRESS_LEN);
-#if ENABLE_RESAMPLING
- memset(rsxadev->routes[route_idx].resampler_buffer, 0,
- sizeof(int16_t) * DEFAULT_PIPE_SIZE_IN_FRAMES);
-#endif
}
// Remove references to the specified input and output streams. When the device no longer
@@ -624,11 +580,7 @@
{
const struct submix_stream_out * const out = audio_stream_get_submix_stream_out(
const_cast<struct audio_stream *>(stream));
-#if ENABLE_RESAMPLING
- const uint32_t out_rate = out->dev->routes[out->route_handle].config.output_sample_rate;
-#else
const uint32_t out_rate = out->dev->routes[out->route_handle].config.common.sample_rate;
-#endif // ENABLE_RESAMPLING
SUBMIX_ALOGV("out_get_sample_rate() returns %u for addr %s",
out_rate, out->dev->routes[out->route_handle].address);
return out_rate;
@@ -637,17 +589,6 @@
static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
{
struct submix_stream_out * const out = audio_stream_get_submix_stream_out(stream);
-#if ENABLE_RESAMPLING
- // The sample rate of the stream can't be changed once it's set since this would change the
- // output buffer size and hence break playback to the shared pipe.
- if (rate != out->dev->routes[out->route_handle].config.output_sample_rate) {
- ALOGE("out_set_sample_rate() resampling enabled can't change sample rate from "
- "%u to %u for addr %s",
- out->dev->routes[out->route_handle].config.output_sample_rate, rate,
- out->dev->routes[out->route_handle].address);
- return -ENOSYS;
- }
-#endif // ENABLE_RESAMPLING
if (!sample_rate_supported(rate)) {
ALOGE("out_set_sample_rate(rate=%u) rate unsupported", rate);
return -ENOSYS;
@@ -994,11 +935,7 @@
{
const struct submix_stream_in * const in = audio_stream_get_submix_stream_in(
const_cast<struct audio_stream*>(stream));
-#if ENABLE_RESAMPLING
- const uint32_t rate = in->dev->routes[in->route_handle].config.input_sample_rate;
-#else
const uint32_t rate = in->dev->routes[in->route_handle].config.common.sample_rate;
-#endif // ENABLE_RESAMPLING
SUBMIX_ALOGV("in_get_sample_rate() returns %u", rate);
return rate;
}
@@ -1006,15 +943,6 @@
static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
{
const struct submix_stream_in * const in = audio_stream_get_submix_stream_in(stream);
-#if ENABLE_RESAMPLING
- // The sample rate of the stream can't be changed once it's set since this would change the
- // input buffer size and hence break recording from the shared pipe.
- if (rate != in->dev->routes[in->route_handle].config.input_sample_rate) {
- ALOGE("in_set_sample_rate() resampling enabled can't change sample rate from "
- "%u to %u", in->dev->routes[in->route_handle].config.input_sample_rate, rate);
- return -ENOSYS;
- }
-#endif // ENABLE_RESAMPLING
if (!sample_rate_supported(rate)) {
ALOGE("in_set_sample_rate(rate=%u) rate unsupported", rate);
return -ENOSYS;
@@ -1033,13 +961,6 @@
audio_stream_in_frame_size((const struct audio_stream_in *)stream);
size_t buffer_size_frames = calculate_stream_pipe_size_in_frames(
stream, config, config->buffer_period_size_frames, stream_frame_size);
-#if ENABLE_RESAMPLING
- // Scale the size of the buffer based upon the maximum number of frames that could be returned
- // given the ratio of output to input sample rate.
- buffer_size_frames = (size_t)(((float)buffer_size_frames *
- (float)config->input_sample_rate) /
- (float)config->output_sample_rate);
-#endif // ENABLE_RESAMPLING
const size_t buffer_size_bytes = buffer_size_frames * stream_frame_size;
SUBMIX_ALOGV("in_get_buffer_size() returns %zu bytes, %zu frames", buffer_size_bytes,
buffer_size_frames);
@@ -1168,65 +1089,10 @@
// read the data from the pipe (it's non blocking)
int attempts = 0;
char* buff = (char*)buffer;
-#if ENABLE_CHANNEL_CONVERSION
- // Determine whether channel conversion is required.
- const uint32_t input_channels = audio_channel_count_from_in_mask(
- rsxadev->routes[in->route_handle].config.input_channel_mask);
- const uint32_t output_channels = audio_channel_count_from_out_mask(
- rsxadev->routes[in->route_handle].config.output_channel_mask);
- if (input_channels != output_channels) {
- SUBMIX_ALOGV("in_read(): %d output channels will be converted to %d "
- "input channels", output_channels, input_channels);
- // Only support 16-bit PCM channel conversion from mono to stereo or stereo to mono.
- ALOG_ASSERT(rsxadev->routes[in->route_handle].config.common.format ==
- AUDIO_FORMAT_PCM_16_BIT);
- ALOG_ASSERT((input_channels == 1 && output_channels == 2) ||
- (input_channels == 2 && output_channels == 1));
- }
-#endif // ENABLE_CHANNEL_CONVERSION
-
-#if ENABLE_RESAMPLING
- const uint32_t input_sample_rate = in_get_sample_rate(&stream->common);
- const uint32_t output_sample_rate =
- rsxadev->routes[in->route_handle].config.output_sample_rate;
- const size_t resampler_buffer_size_frames =
- sizeof(rsxadev->routes[in->route_handle].resampler_buffer) /
- sizeof(rsxadev->routes[in->route_handle].resampler_buffer[0]);
- float resampler_ratio = 1.0f;
- // Determine whether resampling is required.
- if (input_sample_rate != output_sample_rate) {
- resampler_ratio = (float)output_sample_rate / (float)input_sample_rate;
- // Only support 16-bit PCM mono resampling.
- // NOTE: Resampling is performed after the channel conversion step.
- ALOG_ASSERT(rsxadev->routes[in->route_handle].config.common.format ==
- AUDIO_FORMAT_PCM_16_BIT);
- ALOG_ASSERT(audio_channel_count_from_in_mask(
- rsxadev->routes[in->route_handle].config.input_channel_mask) == 1);
- }
-#endif // ENABLE_RESAMPLING
while ((remaining_frames > 0) && (attempts < MAX_READ_ATTEMPTS)) {
ssize_t frames_read = -1977;
size_t read_frames = remaining_frames;
-#if ENABLE_RESAMPLING
- char* const saved_buff = buff;
- if (resampler_ratio != 1.0f) {
- // Calculate the number of frames from the pipe that need to be read to generate
- // the data for the input stream read.
- const size_t frames_required_for_resampler = (size_t)(
- (float)read_frames * (float)resampler_ratio);
- read_frames = min(frames_required_for_resampler, resampler_buffer_size_frames);
- // Read into the resampler buffer.
- buff = (char*)rsxadev->routes[in->route_handle].resampler_buffer;
- }
-#endif // ENABLE_RESAMPLING
-#if ENABLE_CHANNEL_CONVERSION
- if (output_channels == 1 && input_channels == 2) {
- // Need to read half the requested frames since the converted output
- // data will take twice the space (mono->stereo).
- read_frames /= 2;
- }
-#endif // ENABLE_CHANNEL_CONVERSION
SUBMIX_ALOGV("in_read(): frames available to read %zd", source->availableToRead());
@@ -1234,56 +1100,6 @@
SUBMIX_ALOGV("in_read(): frames read %zd", frames_read);
-#if ENABLE_CHANNEL_CONVERSION
- // Perform in-place channel conversion.
- // NOTE: In the following "input stream" refers to the data returned by this function
- // and "output stream" refers to the data read from the pipe.
- if (input_channels != output_channels && frames_read > 0) {
- int16_t *data = (int16_t*)buff;
- if (output_channels == 2 && input_channels == 1) {
- // Offset into the output stream data in samples.
- ssize_t output_stream_offset = 0;
- for (ssize_t input_stream_frame = 0; input_stream_frame < frames_read;
- input_stream_frame++, output_stream_offset += 2) {
- // Average the content from both channels.
- data[input_stream_frame] = ((int32_t)data[output_stream_offset] +
- (int32_t)data[output_stream_offset + 1]) / 2;
- }
- } else if (output_channels == 1 && input_channels == 2) {
- // Offset into the input stream data in samples.
- ssize_t input_stream_offset = (frames_read - 1) * 2;
- for (ssize_t output_stream_frame = frames_read - 1; output_stream_frame >= 0;
- output_stream_frame--, input_stream_offset -= 2) {
- const short sample = data[output_stream_frame];
- data[input_stream_offset] = sample;
- data[input_stream_offset + 1] = sample;
- }
- }
- }
-#endif // ENABLE_CHANNEL_CONVERSION
-
-#if ENABLE_RESAMPLING
- if (resampler_ratio != 1.0f) {
- SUBMIX_ALOGV("in_read(): resampling %zd frames", frames_read);
- const int16_t * const data = (int16_t*)buff;
- int16_t * const resampled_buffer = (int16_t*)saved_buff;
- // Resample with *no* filtering - if the data from the ouptut stream was really
- // sampled at a different rate this will result in very nasty aliasing.
- const float output_stream_frames = (float)frames_read;
- size_t input_stream_frame = 0;
- for (float output_stream_frame = 0.0f;
- output_stream_frame < output_stream_frames &&
- input_stream_frame < remaining_frames;
- output_stream_frame += resampler_ratio, input_stream_frame++) {
- resampled_buffer[input_stream_frame] = data[(size_t)output_stream_frame];
- }
- ALOG_ASSERT(input_stream_frame <= (ssize_t)resampler_buffer_size_frames);
- SUBMIX_ALOGV("in_read(): resampler produced %zd frames", input_stream_frame);
- frames_read = input_stream_frame;
- buff = saved_buff;
- }
-#endif // ENABLE_RESAMPLING
-
if (frames_read > 0) {
#if LOG_STREAMS_TO_FILES
if (in->log_fd >= 0) write(in->log_fd, buff, frames_read * frame_size);
@@ -1411,7 +1227,6 @@
struct submix_audio_device * const rsxadev = audio_hw_device_get_submix_audio_device(dev);
ALOGD("adev_open_output_stream(address=%s)", address);
struct submix_stream_out *out;
- bool force_pipe_creation = false;
(void)handle;
(void)devices;
(void)flags;
@@ -1464,17 +1279,10 @@
out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
out->stream.get_presentation_position = out_get_presentation_position;
-#if ENABLE_RESAMPLING
- // Recreate the pipe with the correct sample rate so that MonoPipe.write() rate limits
- // writes correctly.
- force_pipe_creation = rsxadev->routes[route_idx].config.common.sample_rate
- != config->sample_rate;
-#endif // ENABLE_RESAMPLING
-
// If the sink has been shutdown or pipe recreation is forced (see above), delete the pipe so
// that it's recreated.
if ((rsxadev->routes[route_idx].rsxSink != NULL
- && rsxadev->routes[route_idx].rsxSink->isShutdown()) || force_pipe_creation) {
+ && rsxadev->routes[route_idx].rsxSink->isShutdown())) {
submix_audio_device_release_pipe_l(rsxadev, route_idx);
}
@@ -1779,16 +1587,9 @@
int n = snprintf(msg, sizeof(msg), "\nReroute submix audio module:\n");
write(fd, &msg, n);
for (int i=0 ; i < MAX_ROUTES ; i++) {
-#if ENABLE_RESAMPLING
- n = snprintf(msg, sizeof(msg), " route[%d] rate in=%d out=%d, addr=[%s]\n", i,
- rsxadev->routes[i].config.input_sample_rate,
- rsxadev->routes[i].config.output_sample_rate,
- rsxadev->routes[i].address);
-#else
n = snprintf(msg, sizeof(msg), " route[%d], rate=%d addr=[%s]\n", i,
rsxadev->routes[i].config.common.sample_rate,
rsxadev->routes[i].address);
-#endif
write(fd, &msg, n);
}
return 0;
diff --git a/modules/gralloc/Android.mk b/modules/gralloc/Android.mk
index 439c95d..4c4899e 100644
--- a/modules/gralloc/Android.mk
+++ b/modules/gralloc/Android.mk
@@ -38,5 +38,8 @@
ifeq ($(TARGET_USE_PAN_DISPLAY),true)
LOCAL_CFLAGS += -DUSE_PAN_DISPLAY=1
endif
+ifneq ($(GRALLOC_FRAMEBUFFER_NUM),)
+LOCAL_CFLAGS += -DNUM_BUFFERS=$(GRALLOC_FRAMEBUFFER_NUM)
+endif
include $(BUILD_SHARED_LIBRARY)
diff --git a/modules/gralloc/framebuffer.cpp b/modules/gralloc/framebuffer.cpp
index b2ec3e4..fc220db 100644
--- a/modules/gralloc/framebuffer.cpp
+++ b/modules/gralloc/framebuffer.cpp
@@ -45,8 +45,10 @@
#define USE_PAN_DISPLAY 0
#endif
-// numbers of buffers for page flipping
+// Enabling page flipping by default
+#ifndef NUM_BUFFERS
#define NUM_BUFFERS 2
+#endif
enum {
@@ -157,7 +159,8 @@
info.activate = FB_ACTIVATE_NOW;
/*
- * Request NUM_BUFFERS screens (at lest 2 for page flipping)
+ * Request NUM_BUFFERS screens
+ * To enable page flipping, NUM_BUFFERS should be at least 2.
*/
info.yres_virtual = info.yres * NUM_BUFFERS;
diff --git a/modules/sensors/dynamic_sensor/ConnectionDetector.cpp b/modules/sensors/dynamic_sensor/ConnectionDetector.cpp
index c009a70..85b9901 100644
--- a/modules/sensors/dynamic_sensor/ConnectionDetector.cpp
+++ b/modules/sensors/dynamic_sensor/ConnectionDetector.cpp
@@ -156,6 +156,10 @@
void FileConnectionDetector::processExistingFiles() const {
auto dirp = ::opendir(mPath.c_str());
+ if(dirp == NULL) {
+ ALOGE("Problem open dir %s, errno: %s", mPath.c_str(), ::strerror(errno));
+ return;
+ }
struct dirent *dp;
while ((dp = ::readdir(dirp)) != NULL) {
const std::string name(dp->d_name);
diff --git a/modules/sensors/dynamic_sensor/HidRawSensor.cpp b/modules/sensors/dynamic_sensor/HidRawSensor.cpp
index f3c8a27..6654228 100644
--- a/modules/sensors/dynamic_sensor/HidRawSensor.cpp
+++ b/modules/sensors/dynamic_sensor/HidRawSensor.cpp
@@ -19,6 +19,8 @@
#include <utils/Errors.h>
#include "HidLog.h"
+#include <HidUtils.h>
+
#include <algorithm>
#include <cfloat>
#include <codecvt>
@@ -437,6 +439,7 @@
featureValue->reportModeFlag = SENSOR_FLAG_SPECIAL_REPORTING_MODE;
featureValue->isWakeUp = false;
+ featureValue->useUniqueIdForUuid = false;
memset(featureValue->uuid, 0, sizeof(featureValue->uuid));
featureValue->isAndroidCustom = false;
}
@@ -463,40 +466,23 @@
for (const auto & r : packet.reports) {
switch (r.usage) {
case FRIENDLY_NAME:
- if (!r.isByteAligned() || r.bitSize != 16 || r.count < 1) {
- // invalid friendly name
- break;
- }
if (decodeString(r, buffer, &str) && !str.empty()) {
featureValue->name = str;
}
break;
case SENSOR_MANUFACTURER:
- if (!r.isByteAligned() || r.bitSize != 16 || r.count < 1) {
- // invalid manufacturer
- break;
- }
if (decodeString(r, buffer, &str) && !str.empty()) {
featureValue->vendor = str;
}
break;
case PERSISTENT_UNIQUE_ID:
- if (!r.isByteAligned() || r.bitSize != 16 || r.count < 1) {
- // invalid unique id string
- break;
- }
if (decodeString(r, buffer, &str) && !str.empty()) {
featureValue->uniqueId = str;
}
break;
case SENSOR_DESCRIPTION:
- if (!r.isByteAligned() || r.bitSize != 16 || r.count < 1
- || (r.bitOffset / 8 + r.count * 2) > buffer.size() ) {
- // invalid description
- break;
- }
if (decodeString(r, buffer, &str)) {
- mFeatureInfo.isAndroidCustom = detectAndroidCustomSensor(str);
+ detectSensorFromDescription(str);
}
break;
default:
@@ -544,10 +530,19 @@
}
// initialize uuid field, use name, vendor and uniqueId
- if (mFeatureInfo.name.size() >= 4
- && mFeatureInfo.vendor.size() >= 4
- && mFeatureInfo.typeString.size() >= 4
- && mFeatureInfo.uniqueId.size() >= 4) {
+ // initialize uuid field using one of the following methods:
+ //
+ // 1. use uniqueId
+ // 2. use name, vendor and uniqueId
+ if (mFeatureInfo.useUniqueIdForUuid) {
+ if (mFeatureInfo.uniqueId.size() == sizeof(mFeatureInfo.uuid)) {
+ memcpy(mFeatureInfo.uuid, mFeatureInfo.uniqueId.c_str(),
+ sizeof(mFeatureInfo.uuid));
+ }
+ } else if (mFeatureInfo.name.size() >= 4
+ && mFeatureInfo.vendor.size() >= 4
+ && mFeatureInfo.typeString.size() >= 4
+ && mFeatureInfo.uniqueId.size() >= 4) {
uint32_t tmp[4], h;
std::hash<std::string> stringHash;
h = stringHash(mFeatureInfo.uniqueId);
@@ -581,26 +576,34 @@
bool HidRawSensor::decodeString(
const HidParser::ReportItem &report, const std::vector<uint8_t> &buffer, std::string *d) {
- if (!report.isByteAligned() || report.bitSize != 16 || report.count < 1) {
+ if (!report.isByteAligned() ||
+ (report.bitSize != 8 && report.bitSize != 16) || report.count < 1) {
return false;
}
+ size_t charSize = report.bitSize / 8;
size_t offset = report.bitOffset / 8;
- if (offset + report.count * 2 > buffer.size()) {
+ if (offset + report.count * charSize > buffer.size()) {
return false;
}
- std::vector<uint16_t> data(report.count);
- auto i = data.begin();
- auto j = buffer.begin() + offset;
- for ( ; i != data.end(); ++i, j += sizeof(uint16_t)) {
- // hid specified little endian
- *i = *j + (*(j + 1) << 8);
- }
- std::wstring wstr(data.begin(), data.end());
+ if (charSize == 1) {
+ *d = std::string(buffer.begin() + offset,
+ buffer.begin() + offset + report.count);
+ } else {
+ std::vector<uint16_t> data(report.count);
+ auto i = data.begin();
+ auto j = buffer.begin() + offset;
+ for ( ; i != data.end(); ++i, j += sizeof(uint16_t)) {
+ // hid specified little endian
+ *i = *j + (*(j + 1) << 8);
+ }
+ std::wstring wstr(data.begin(), data.end());
- std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
- *d = converter.to_bytes(wstr);
+ std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
+ *d = converter.to_bytes(wstr);
+ }
+
return true;
}
@@ -619,6 +622,33 @@
return tokens;
}
+void HidRawSensor::detectSensorFromDescription(const std::string &description) {
+ if (detectAndroidHeadTrackerSensor(description) ||
+ detectAndroidCustomSensor(description)) {
+ mFeatureInfo.isAndroidCustom = true;
+ }
+}
+
+bool HidRawSensor::detectAndroidHeadTrackerSensor(
+ const std::string &description) {
+ if (description.find("#AndroidHeadTracker#1.") != 0) {
+ return false;
+ }
+
+ mFeatureInfo.type = SENSOR_TYPE_DEVICE_PRIVATE_BASE;
+ mFeatureInfo.typeString = CUSTOM_TYPE_PREFIX + "headtracker";
+ mFeatureInfo.reportModeFlag = SENSOR_FLAG_CONTINUOUS_MODE;
+ mFeatureInfo.permission = "";
+ mFeatureInfo.isWakeUp = false;
+
+ // HID head tracker sensors must use the HID unique ID for the sensor UUID
+ // to permit association between the sensor and audio device (see
+ // specification for HEAD_TRACKER in SensorType).
+ mFeatureInfo.useUniqueIdForUuid = true;
+
+ return true;
+}
+
bool HidRawSensor::detectAndroidCustomSensor(const std::string &description) {
size_t nullPosition = description.find('\0');
if (nullPosition == std::string::npos) {
@@ -784,50 +814,83 @@
}
bool HidRawSensor::findSensorControlUsage(const std::vector<HidParser::ReportPacket> &packets) {
+ using namespace Hid::Sensor::PowerStateUsage;
using namespace Hid::Sensor::PropertyUsage;
- using namespace Hid::Sensor::RawMinMax;
+ using namespace Hid::Sensor::ReportingStateUsage;
//REPORTING_STATE
const HidParser::ReportItem *reportingState
= find(packets, REPORTING_STATE, HidParser::REPORT_TYPE_FEATURE);
- if (reportingState == nullptr
- || !reportingState->isByteAligned()
- || reportingState->bitSize != 8
- || reportingState->minRaw != REPORTING_STATE_MIN
- || reportingState->maxRaw != REPORTING_STATE_MAX) {
+ if (reportingState == nullptr) {
LOG_W << "Cannot find valid reporting state feature" << LOG_ENDL;
} else {
mReportingStateId = reportingState->id;
- mReportingStateOffset = reportingState->bitOffset / 8;
+ mReportingStateBitOffset = reportingState->bitOffset;
+ mReportingStateBitSize = reportingState->bitSize;
+
+ mReportingStateDisableIndex = -1;
+ mReportingStateEnableIndex = -1;
+ for (unsigned i = 0; i < reportingState->usageVector.size(); ++i) {
+ if (reportingState->usageVector[i] == REPORTING_STATE_NO_EVENTS) {
+ mReportingStateDisableIndex = i;
+ }
+ if (reportingState->usageVector[i] == REPORTING_STATE_ALL_EVENTS) {
+ mReportingStateEnableIndex = i;
+ }
+ }
+ if (mReportingStateDisableIndex < 0) {
+ LOG_W << "Cannot find reporting state to disable sensor"
+ << LOG_ENDL;
+ mReportingStateId = -1;
+ }
+ if (mReportingStateEnableIndex < 0) {
+ LOG_W << "Cannot find reporting state to enable sensor" << LOG_ENDL;
+ mReportingStateId = -1;
+ }
}
//POWER_STATE
const HidParser::ReportItem *powerState
= find(packets, POWER_STATE, HidParser::REPORT_TYPE_FEATURE);
- if (powerState == nullptr
- || !powerState->isByteAligned()
- || powerState->bitSize != 8
- || powerState->minRaw != POWER_STATE_MIN
- || powerState->maxRaw != POWER_STATE_MAX) {
+ if (powerState == nullptr) {
LOG_W << "Cannot find valid power state feature" << LOG_ENDL;
} else {
mPowerStateId = powerState->id;
- mPowerStateOffset = powerState->bitOffset / 8;
+ mPowerStateBitOffset = powerState->bitOffset;
+ mPowerStateBitSize = powerState->bitSize;
+
+ mPowerStateOffIndex = -1;
+ mPowerStateOnIndex = -1;
+ for (unsigned i = 0; i < powerState->usageVector.size(); ++i) {
+ if (powerState->usageVector[i] == POWER_STATE_D4_POWER_OFF) {
+ mPowerStateOffIndex = i;
+ }
+ if (powerState->usageVector[i] == POWER_STATE_D0_FULL_POWER) {
+ mPowerStateOnIndex = i;
+ }
+ }
+ if (mPowerStateOffIndex < 0) {
+ LOG_W << "Cannot find power state to power off sensor"
+ << LOG_ENDL;
+ mPowerStateId = -1;
+ }
+ if (mPowerStateOnIndex < 0) {
+ LOG_W << "Cannot find power state to power on sensor" << LOG_ENDL;
+ mPowerStateId = -1;
+ }
}
//REPORT_INTERVAL
const HidParser::ReportItem *reportInterval
= find(packets, REPORT_INTERVAL, HidParser::REPORT_TYPE_FEATURE);
if (reportInterval == nullptr
- || !reportInterval->isByteAligned()
- || reportInterval->minRaw < 0
- || (reportInterval->bitSize != 16 && reportInterval->bitSize != 32)) {
+ || reportInterval->minRaw < 0) {
LOG_W << "Cannot find valid report interval feature" << LOG_ENDL;
} else {
mReportIntervalId = reportInterval->id;
- mReportIntervalOffset = reportInterval->bitOffset / 8;
- mReportIntervalSize = reportInterval->bitSize / 8;
+ mReportIntervalBitOffset = reportInterval->bitOffset;
+ mReportIntervalBitSize = reportInterval->bitSize;
mFeatureInfo.minDelay = std::max(static_cast<int64_t>(1), reportInterval->minRaw) * 1000;
mFeatureInfo.maxDelay = std::min(static_cast<int64_t>(1000000),
@@ -846,7 +909,6 @@
}
int HidRawSensor::enable(bool enable) {
- using namespace Hid::Sensor::StateValue;
SP(HidDevice) device = PROMOTE(mDevice);
if (device == nullptr) {
@@ -863,8 +925,11 @@
setPowerOk = false;
uint8_t id = static_cast<uint8_t>(mPowerStateId);
if (device->getFeature(id, &buffer)
- && buffer.size() > mPowerStateOffset) {
- buffer[mPowerStateOffset] = enable ? POWER_STATE_FULL_POWER : POWER_STATE_POWER_OFF;
+ && (8 * buffer.size()) >=
+ (mPowerStateBitOffset + mPowerStateBitSize)) {
+ uint8_t index = enable ? mPowerStateOnIndex : mPowerStateOffIndex;
+ HidUtil::copyBits(&index, &(buffer[0]), buffer.size(),
+ 0, mPowerStateBitOffset, mPowerStateBitSize);
setPowerOk = device->setFeature(id, buffer);
} else {
LOG_E << "enable: changing POWER STATE failed" << LOG_ENDL;
@@ -876,9 +941,12 @@
setReportingOk = false;
uint8_t id = static_cast<uint8_t>(mReportingStateId);
if (device->getFeature(id, &buffer)
- && buffer.size() > mReportingStateOffset) {
- buffer[mReportingStateOffset]
- = enable ? REPORTING_STATE_ALL_EVENT : REPORTING_STATE_NO_EVENT;
+ && (8 * buffer.size()) >
+ (mReportingStateBitOffset + mReportingStateBitSize)) {
+ uint8_t index = enable ? mReportingStateEnableIndex :
+ mReportingStateDisableIndex;
+ HidUtil::copyBits(&index, &(buffer[0]), buffer.size(),0,
+ mReportingStateBitOffset, mReportingStateBitSize);
setReportingOk = device->setFeature(id, buffer);
} else {
LOG_E << "enable: changing REPORTING STATE failed" << LOG_ENDL;
@@ -911,22 +979,15 @@
ok = false;
uint8_t id = static_cast<uint8_t>(mReportIntervalId);
if (device->getFeature(id, &buffer)
- && buffer.size() >= mReportIntervalOffset + mReportIntervalSize) {
+ && (8 * buffer.size()) >=
+ (mReportIntervalBitOffset + mReportIntervalBitSize)) {
int64_t periodMs = samplingPeriod / 1000000; //ns -> ms
- switch (mReportIntervalSize) {
- case sizeof(uint16_t):
- periodMs = std::min(periodMs, static_cast<int64_t>(UINT16_MAX));
- buffer[mReportIntervalOffset] = periodMs & 0xFF;
- buffer[mReportIntervalOffset + 1] = (periodMs >> 8) & 0xFF;
- break;
- case sizeof(uint32_t):
- periodMs = std::min(periodMs, static_cast<int64_t>(UINT32_MAX));
- buffer[mReportIntervalOffset] = periodMs & 0xFF;
- buffer[mReportIntervalOffset + 1] = (periodMs >> 8) & 0xFF;
- buffer[mReportIntervalOffset + 2] = (periodMs >> 16) & 0xFF;
- buffer[mReportIntervalOffset + 3] = (periodMs >> 24) & 0xFF;
- break;
- }
+ int64_t maxPeriodMs =
+ (1LL << std::min(mReportIntervalBitSize, 63U)) - 1;
+ periodMs = std::min(periodMs, maxPeriodMs);
+ HidUtil::copyBits(&periodMs, &(buffer[0]), buffer.size(),
+ 0, mReportIntervalBitOffset,
+ mReportIntervalBitSize);
ok = device->setFeature(id, buffer);
}
}
@@ -997,11 +1058,15 @@
<< " fifoSize: " << mFeatureInfo.fifoSize << LOG_ENDL
<< " fifoMaxSize: " << mFeatureInfo.fifoMaxSize << LOG_ENDL
<< " reportModeFlag: " << mFeatureInfo.reportModeFlag << LOG_ENDL
- << " isWakeUp: " << (mFeatureInfo.isWakeUp ? "true" : "false") << LOG_ENDL
- << " uniqueId: " << mFeatureInfo.uniqueId << LOG_ENDL
- << " uuid: ";
+ << " isWakeUp: " << (mFeatureInfo.isWakeUp ? "true" : "false") << LOG_ENDL;
- ss << std::hex << std::setfill('0');
+ ss << " uniqueId: " << std::hex << std::setfill('0');
+ for (auto d : mFeatureInfo.uniqueId) {
+ ss << std::setw(2) << static_cast<int>(d) << " ";
+ }
+ ss << std::dec << std::setfill(' ') << LOG_ENDL;
+
+ ss << " uuid: " << std::hex << std::setfill('0');
for (auto d : mFeatureInfo.uuid) {
ss << std::setw(2) << static_cast<int>(d) << " ";
}
@@ -1019,7 +1084,11 @@
ss << " Power state ";
if (mPowerStateId >= 0) {
ss << "found, id: " << mPowerStateId
- << " offset: " << mPowerStateOffset << LOG_ENDL;
+ << " bit offset: " << mPowerStateBitOffset
+ << " bit size: " << mPowerStateBitSize
+ << " power off index: " << mPowerStateOffIndex
+ << " power on index: " << mPowerStateOnIndex
+ << LOG_ENDL;
} else {
ss << "not found" << LOG_ENDL;
}
@@ -1027,7 +1096,11 @@
ss << " Reporting state ";
if (mReportingStateId >= 0) {
ss << "found, id: " << mReportingStateId
- << " offset: " << mReportingStateOffset << LOG_ENDL;
+ << " bit offset: " << mReportingStateBitOffset
+ << " bit size: " << mReportingStateBitSize
+ << " disable index: " << mReportingStateDisableIndex
+ << " enable index: " << mReportingStateEnableIndex
+ << LOG_ENDL;
} else {
ss << "not found" << LOG_ENDL;
}
@@ -1035,8 +1108,8 @@
ss << " Report interval ";
if (mReportIntervalId >= 0) {
ss << "found, id: " << mReportIntervalId
- << " offset: " << mReportIntervalOffset
- << " size: " << mReportIntervalSize << LOG_ENDL;
+ << " bit offset: " << mReportIntervalBitOffset
+ << " bit size: " << mReportIntervalBitSize << LOG_ENDL;
} else {
ss << "not found" << LOG_ENDL;
}
diff --git a/modules/sensors/dynamic_sensor/HidRawSensor.h b/modules/sensors/dynamic_sensor/HidRawSensor.h
index 2dd32b6..f6d13b5 100644
--- a/modules/sensors/dynamic_sensor/HidRawSensor.h
+++ b/modules/sensors/dynamic_sensor/HidRawSensor.h
@@ -86,6 +86,7 @@
size_t fifoMaxSize;
uint32_t reportModeFlag;
bool isWakeUp;
+ bool useUniqueIdForUuid;
// dynamic sensor specific
std::string uniqueId;
@@ -121,6 +122,14 @@
// helper function to find sensor control feature usage from packets
bool findSensorControlUsage(const std::vector<HidParser::ReportPacket> &packets);
+ // try to parse sensor description feature value to see if it matches any
+ // known sensors
+ void detectSensorFromDescription(const std::string &description);
+
+ // try to parse sensor description feature value to see if it matches the
+ // Android header tracker sensor
+ bool detectAndroidHeadTrackerSensor(const std::string &description);
+
// try to parse sensor description feature value to see if it matches
// android specified custom sensor definition.
bool detectAndroidCustomSensor(const std::string &description);
@@ -137,14 +146,20 @@
// Features for control sensor
int mReportingStateId;
- unsigned int mReportingStateOffset;
+ unsigned int mReportingStateBitOffset;
+ unsigned int mReportingStateBitSize;
+ int mReportingStateDisableIndex;
+ int mReportingStateEnableIndex;
int mPowerStateId;
- unsigned int mPowerStateOffset;
+ unsigned int mPowerStateBitOffset;
+ unsigned int mPowerStateBitSize;
+ int mPowerStateOffIndex;
+ int mPowerStateOnIndex;
int mReportIntervalId;
- unsigned int mReportIntervalOffset;
- unsigned int mReportIntervalSize;
+ unsigned int mReportIntervalBitOffset;
+ unsigned int mReportIntervalBitSize;
// Input report translate table
std::vector<ReportTranslateRecord> mTranslateTable;
diff --git a/modules/sensors/dynamic_sensor/HidSensorDef.h b/modules/sensors/dynamic_sensor/HidSensorDef.h
index 2728b28..8f47a85 100644
--- a/modules/sensors/dynamic_sensor/HidSensorDef.h
+++ b/modules/sensors/dynamic_sensor/HidSensorDef.h
@@ -77,24 +77,28 @@
};
} // namespace ReportUsage
-namespace RawMinMax {
+namespace ReportingStateUsage {
enum {
- REPORTING_STATE_MIN = 0,
- REPORTING_STATE_MAX = 5,
- POWER_STATE_MIN = 0,
- POWER_STATE_MAX = 5,
+ REPORTING_STATE_NO_EVENTS = 0x0840,
+ REPORTING_STATE_ALL_EVENTS = 0x0841,
+ REPORTING_STATE_REPORT_THRESHOLD_EVENTS = 0x0842,
+ REPORTING_STATE_REPORT_WAKE_ON_NO_EVENTS = 0x0843,
+ REPORTING_STATE_REPORT_WAKE_ON_ALL_EVENTS = 0x0844,
+ REPORTING_STATE_REPORT_WAKE_ON_THRESHOLD_EVENTS = 0x0845,
};
-} // namespace RawMinMax
+} // namespace ReportingStateUsage
-namespace StateValue {
+namespace PowerStateUsage {
enum {
- POWER_STATE_FULL_POWER = 1,
- POWER_STATE_POWER_OFF = 5,
-
- REPORTING_STATE_ALL_EVENT = 1,
- REPORTING_STATE_NO_EVENT = 0,
+ POWER_STATE_UNDEFINED = 0x0850,
+ POWER_STATE_D0_FULL_POWER = 0x0851,
+ POWER_STATE_D1_LOW_POWER = 0x0852,
+ POWER_STATE_D2_STANDBY_POWER_WITH_WAKEUP = 0x0853,
+ POWER_STATE_D3_SLEEP_WITH_WAKEUP = 0x0854,
+ POWER_STATE_D4_POWER_OFF = 0x0855,
};
-} // StateValue
+} // namespace PowerStateUsage
+
} // namespace Sensor
} // namespace Hid
#endif // HID_SENSOR_DEF_H_
diff --git a/modules/sensors/dynamic_sensor/HidUtils/Android.bp b/modules/sensors/dynamic_sensor/HidUtils/Android.bp
index bbed032..5823c79 100644
--- a/modules/sensors/dynamic_sensor/HidUtils/Android.bp
+++ b/modules/sensors/dynamic_sensor/HidUtils/Android.bp
@@ -45,6 +45,7 @@
"HidParser.cpp",
"HidReport.cpp",
"HidTree.cpp",
+ "HidUtils.cpp",
],
export_include_dirs: ["."],
@@ -99,3 +100,20 @@
local_include_dirs: ["test"],
}
+
+//
+// Test for HidUtils
+//
+cc_test_host {
+ name: "hid_utils_test",
+ defaults: ["hid_defaults"],
+
+ srcs: ["test/CopyBitsTest.cpp"],
+
+ shared_libs: [
+ "libhidparser",
+ ],
+
+ local_include_dirs: ["test"],
+}
+
diff --git a/modules/sensors/dynamic_sensor/HidUtils/HidParser.cpp b/modules/sensors/dynamic_sensor/HidUtils/HidParser.cpp
index 264f13c..19aa429 100644
--- a/modules/sensors/dynamic_sensor/HidUtils/HidParser.cpp
+++ b/modules/sensors/dynamic_sensor/HidUtils/HidParser.cpp
@@ -240,14 +240,17 @@
auto logical = r.getLogicalRange();
auto physical = r.getPhysicalRange();
- int64_t offset = physical.first - logical.first;
double scale = static_cast<double>((physical.second - physical.first))
/ (logical.second - logical.first);
scale *= r.getExponentValue();
+ int64_t offset =
+ (physical.first * r.getExponentValue() / scale) -
+ logical.first;
ReportItem digest = {
.usage = r.getFullUsage(),
.id = id,
+ .usageVector = r.getUsageVector(),
.minRaw = logical.first,
.maxRaw = logical.second,
.a = scale,
@@ -316,4 +319,5 @@
os << LOG_ENDL;
return os;
}
+
} // namespace HidUtil
diff --git a/modules/sensors/dynamic_sensor/HidUtils/HidParser.h b/modules/sensors/dynamic_sensor/HidUtils/HidParser.h
index 4ef5ec6..cb4a92a 100644
--- a/modules/sensors/dynamic_sensor/HidUtils/HidParser.h
+++ b/modules/sensors/dynamic_sensor/HidUtils/HidParser.h
@@ -89,6 +89,7 @@
unsigned int usage;
unsigned int id;
int type; // feature, input or output
+ std::vector<unsigned int> usageVector;
int64_t minRaw;
int64_t maxRaw;
@@ -173,6 +174,7 @@
};
std::ostream& operator<<(std::ostream &os, const HidParser::DigestVector &digest2);
+
} // namespace HidUtil
#endif // HIDUTIL_HIDPARSER_H_
diff --git a/modules/sensors/dynamic_sensor/HidUtils/HidUtils.cpp b/modules/sensors/dynamic_sensor/HidUtils/HidUtils.cpp
new file mode 100644
index 0000000..0cce2a3
--- /dev/null
+++ b/modules/sensors/dynamic_sensor/HidUtils/HidUtils.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2021 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 "HidUtils.h"
+#include <stdint.h>
+#include <algorithm>
+
+namespace HidUtil {
+
+void copyBits(const void *src, void *dst, size_t dst_size,
+ unsigned int src_bit_offset, unsigned int dst_bit_offset,
+ unsigned int bit_count) {
+ const uint8_t *p_src;
+ uint8_t *p_dst;
+ uint8_t dst_mask;
+ unsigned int bits_rem;
+ unsigned int bit_block_count;
+
+ // Do nothing if copying past the end of the destination buffer.
+ if ((static_cast<size_t>(dst_bit_offset) > (8 * dst_size)) ||
+ (static_cast<size_t>(bit_count) > (8 * dst_size)) ||
+ (static_cast<size_t>(dst_bit_offset + bit_count) > (8 * dst_size))) {
+ return;
+ }
+
+ // Copy bits from source to destination buffer.
+ p_src = static_cast<const uint8_t*>(src) + (src_bit_offset / 8);
+ src_bit_offset = src_bit_offset % 8;
+ p_dst = static_cast<uint8_t*>(dst) + (dst_bit_offset / 8);
+ dst_bit_offset = dst_bit_offset % 8;
+ bits_rem = bit_count;
+ while (bits_rem > 0) {
+ // Determine the size of the next block of bits to copy. The block must
+ // not cross a source or desintation byte boundary.
+ bit_block_count = std::min(bits_rem, 8 - src_bit_offset);
+ bit_block_count = std::min(bit_block_count, 8 - dst_bit_offset);
+
+ // Determine the destination bit block mask.
+ dst_mask = ((1 << bit_block_count) - 1) << dst_bit_offset;
+
+ // Copy the block of bits.
+ *p_dst = (*p_dst & ~dst_mask) |
+ (((*p_src >> src_bit_offset) << dst_bit_offset) & dst_mask);
+
+ // Advance past the block of copied bits in the source.
+ src_bit_offset += bit_block_count;
+ p_src += src_bit_offset / 8;
+ src_bit_offset = src_bit_offset % 8;
+
+ // Advance past the block of copied bits in the destination.
+ dst_bit_offset += bit_block_count;
+ p_dst += dst_bit_offset / 8;
+ dst_bit_offset = dst_bit_offset % 8;
+
+ // Decrement the number of bits remaining.
+ bits_rem -= bit_block_count;
+ }
+}
+
+} // namespace HidUtil
diff --git a/modules/sensors/dynamic_sensor/HidUtils/HidUtils.h b/modules/sensors/dynamic_sensor/HidUtils/HidUtils.h
new file mode 100644
index 0000000..54aa31e
--- /dev/null
+++ b/modules/sensors/dynamic_sensor/HidUtils/HidUtils.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+#ifndef HIDUTIL_HIDUTILS_H_
+#define HIDUTIL_HIDUTILS_H_
+
+#include <stddef.h>
+
+namespace HidUtil {
+
+void copyBits(const void *src, void *dst, size_t dst_size,
+ unsigned int src_bit_offset, unsigned int dst_bit_offset,
+ unsigned int bit_count);
+
+} // namespace HidUtil
+
+#endif // HIDUTIL_HIDUTILS_H_
diff --git a/modules/sensors/dynamic_sensor/HidUtils/test/CopyBitsTest.cpp b/modules/sensors/dynamic_sensor/HidUtils/test/CopyBitsTest.cpp
new file mode 100644
index 0000000..1b1ca70
--- /dev/null
+++ b/modules/sensors/dynamic_sensor/HidUtils/test/CopyBitsTest.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 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 "HidUtils.h"
+#include <gtest/gtest.h>
+
+using HidUtil::copyBits;
+
+TEST(CopyBitsTest, CopyBits) {
+ const struct {
+ uint32_t src;
+ uint32_t dst;
+ int src_bit_offset;
+ int dst_bit_offset;
+ int bit_count;
+ uint32_t expected_dst;
+ } kTestVectorList[] = {
+ { 0x00000005, 0x00000000, 0, 0, 8, 0x00000005 },
+ { 0x00000005, 0x00000000, 0, 4, 8, 0x00000050 },
+ { 0x0000000C, 0x00000020, 0, 4, 8, 0x000000C0 },
+ { 0x00000005, 0x0000F02F, 0, 4, 8, 0x0000F05F },
+ { 0x12345678, 0x87654321, 5, 11, 17, 0x8D159B21 },
+ { 0x12345678, 0x87654321, 11, 5, 17, 0x8748D141 },
+ };
+
+ for (auto test_vector : kTestVectorList) {
+ uint32_t dst = test_vector.dst;
+ copyBits(&(test_vector.src), &dst, sizeof(dst),
+ test_vector.src_bit_offset, test_vector.dst_bit_offset,
+ test_vector.bit_count);
+ EXPECT_EQ(test_vector.expected_dst, dst);
+ }
+}
+
+TEST(CopyBitsTest, Overflow) {
+ const struct {
+ uint32_t src;
+ uint32_t dst;
+ unsigned int src_bit_offset;
+ unsigned int dst_bit_offset;
+ unsigned int bit_count;
+ uint32_t expected_dst;
+ } kTestVectorList[] = {
+ { 0x000000FF, 0x00000000, 0, 0, 8, 0x000000FF },
+ { 0x000000FF, 0x00000000, 0, 24, 8, 0xFF000000 },
+ { 0x000000FF, 0x00000000, 0, 25, 8, 0x00000000 },
+ { 0x000000FF, 0x00000000, 0, 32, 8, 0x00000000 },
+ { 0x000000FF, 0x00000000, 0, UINT_MAX, 8, 0x00000000 },
+ { 0x000000FF, 0x00000000, 0, 8, UINT_MAX, 0x00000000 },
+ };
+
+ for (auto test_vector : kTestVectorList) {
+ uint32_t dst = test_vector.dst;
+ copyBits(&(test_vector.src), &dst, sizeof(dst),
+ test_vector.src_bit_offset, test_vector.dst_bit_offset,
+ test_vector.bit_count);
+ EXPECT_EQ(test_vector.expected_dst, dst);
+ }
+}
+
diff --git a/modules/sensors/dynamic_sensor/README.md b/modules/sensors/dynamic_sensor/README.md
new file mode 100644
index 0000000..49e541e
--- /dev/null
+++ b/modules/sensors/dynamic_sensor/README.md
@@ -0,0 +1,152 @@
+# Dynamic Sensors
+
+[TOC]
+
+## Links
+
+* [Sensor HAL dynamic sensor support](https://source.android.com/devices/sensors/sensors-hal2#dynamic-sensors)
+* [Sensors Multi-HAL](https://source.android.com/devices/sensors/sensors-multihal)
+
+## Adding dynamic sensor support to a device
+
+A few files need to be modified to add dynamic sensor support to a device. The
+dynamic sensor HAL must be enabled in the device product makefile and in the
+sensor sub-HAL configuration file, raw HID devices must be configured, and raw
+HID device and dynamic sensor property permissions must be set up in the SELinux
+policy files.
+
+```shell
+acme-co$ git -C device/acme/rocket-phone diff
+diff --git a/sensor_hal/hals.conf b/sensor_hal/hals.conf
+index a1f4b8b..d112546 100644
+--- a/sensor_hal/hals.conf
++++ b/sensor_hal/hals.conf
+@@ -1 +1,2 @@
++sensors.dynamic_sensor_hal.so
+ sensors.rocket-phone.so
+diff --git a/rocket-phone.mk b/rocket-phone.mk
+index 3fc8538..b1bd8a1 100644
+--- a/rocket-phone.mk
++++ b/rocket-phone.mk
+@@ -73,6 +73,9 @@
+ PRODUCT_PACKAGES += sensors.rocket-phone
+ PRODUCT_PACKAGES += thruster_stats
+
++# Add the dynamic sensor HAL.
++PRODUCT_PACKAGES += sensors.dynamic_sensor_hal
++
+ # Only install test tools in debug build or eng build.
+ ifneq ($(filter userdebug eng,$(TARGET_BUILD_VARIANT)),)
+ PRODUCT_PACKAGES += thruster_test
+diff --git a/conf/ueventd.rc b/conf/ueventd.rc
+index 88ee00b..2f03009 100644
+--- a/conf/ueventd.rc
++++ b/conf/ueventd.rc
+@@ -209,3 +209,7 @@
+
+ # Thrusters
+ /dev/thruster* 0600 system system
++
++# Raw HID devices
++/dev/hidraw* 0660 system system
++
+diff --git a/sepolicy/sensor_hal.te b/sepolicy/sensor_hal.te
+index 0797253..22a4208 100644
+--- a/sepolicy/sensor_hal.te
++++ b/sepolicy/sensor_hal.te
+@@ -52,6 +52,9 @@
+ # Allow sensor HAL to read thruster state.
+ allow hal_sensors_default thruster_state:file r_file_perms;
+
++# Allow access for dynamic sensor properties.
++get_prop(hal_sensors_default, vendor_dynamic_sensor_prop)
++
++# Allow access to raw HID devices for dynamic sensors.
++allow hal_sensors_default hidraw_device:chr_file rw_file_perms;
++
+ #
+ # Thruster sensor enforcements.
+ #
+diff --git a/sepolicy/device.te b/sepolicy/device.te
+index bc3c947..bad0be0 100644
+--- a/sepolicy/device.te
++++ b/sepolicy/device.te
+@@ -55,3 +55,7 @@
+
+ # Thruster
+ type thruster_device, dev_type;
++
++# Raw HID device
++type hidraw_device, dev_type;
++
+diff --git a/sepolicy/property.te b/sepolicy/property.te
+index 4b671a4..bb0894f 100644
+--- a/sepolicy/property.te
++++ b/sepolicy/property.te
+@@ -49,3 +49,7 @@
+
+ # Thruster
+ vendor_internal_prop(vendor_thruster_debug_prop)
++
++# Dynamic sensor
++vendor_internal_prop(vendor_dynamic_sensor_prop)
++
+diff --git a/sepolicy/file_contexts b/sepolicy/file_contexts
+index bc03a78..ff401dc 100644
+--- a/sepolicy/file_contexts
++++ b/sepolicy/file_contexts
+@@ -441,3 +441,7 @@
+ /dev/thruster-fuel u:object_r:thruster_device:s0
+ /dev/thruster-output u:object_r:thruster_device:s0
+ /dev/thruster-telemetry u:object_r:thruster_device:s0
++
++# Raw HID device
++/dev/hidraw[0-9]* u:object_r:hidraw_device:s0
++
+diff --git a/sepolicy/property_contexts b/sepolicy/property_contexts
+index 5d2f018..18a6059 100644
+--- a/sepolicy/property_contexts
++++ b/sepolicy/property_contexts
+@@ -104,3 +104,7 @@
+
+ # Thruster
+ vendor.thruster.debug u:object_r:vendor_thruster_debug_prop:s0
++
++# Dynamic sensor
++vendor.dynamic_sensor. u:object_r:vendor_dynamic_sensor_prop:s0
++
+acme-co$
+```
+
+Once the file modifications are made, rebuild and flash. The dynamic sensor HAL
+should be initialized and appear in the sensor service.
+
+```shell
+acme-co$ make -j28 && fastboot flashall
+.
+.
+.
+acme-co$ adb logcat -d | grep DynamicSensorHal
+12-15 18:18:45.735 791 791 D DynamicSensorHal: DynamicSensorsSubHal::getSensorsList_2_1 invoked.
+12-15 18:18:47.474 791 791 D DynamicSensorHal: DynamicSensorsSubHal::initialize invoked.
+acme-co$ adb shell dumpsys sensorservice | grep Dynamic
+0000000000) Dynamic Sensor Manager | Google | ver: 1 | type: android.sensor.dynamic_sensor_meta(32) | perm: n/a | flags: 0x00000007
+Dynamic Sensor Manager (handle=0x00000000, connections=1)
+ Dynamic Sensor Manager 0x00000000 | status: active | pending flush events 0
+acme-co$ adb logcat -c
+acme-co$
+```
+
+When a dynamic sensor is paired with the device (e.g., Bluetooth rocket buds),
+it will appear in the sensor service.
+
+```shell
+acme-co$ adb logcat -d | grep "DynamicSensorHal\|hidraw\|Rocket"
+12-15 18:19:55.268 157 157 I hid-generic 0003: 1234:5678.0001: hidraw0: BLUETOOTH HID v0.00 Device [RocketBuds] on
+12-15 18:19:55.235 791 809 E DynamicSensorHal: return 1 sensors
+12-15 18:19:56.239 1629 1787 I SensorService: Dynamic sensor handle 0x1 connected, type 65536, name RocketBuds
+acme-co$ adb shell dumpsys sensorservice | grep Rocket
+0x00000001) RocketBuds | BLUETOOTH 1234:1234 | ver: 1 | type: com.google.hardware.sensor.hid_dynamic.headtracker(65536) | perm: n/a | flags: 0x00000020
+acme-co$
+```
+