Merge "Add navigation methods to IGnss AIDL HAL (hardware/interfaces)"
diff --git a/automotive/can/1.0/tools/libprotocan/Android.bp b/automotive/can/1.0/tools/libprotocan/Android.bp
index 76c238b..4c23fad 100644
--- a/automotive/can/1.0/tools/libprotocan/Android.bp
+++ b/automotive/can/1.0/tools/libprotocan/Android.bp
@@ -25,7 +25,7 @@
cc_library_static {
name: "libprotocan",
- defaults: ["android.hardware.automotive.vehicle@2.0-protocan-defaults"],
+ defaults: ["android.hardware.automotive.can@defaults"],
vendor: true,
srcs: [
"Checksum.cpp",
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
index 63eb747..49b33d5 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
@@ -213,7 +213,7 @@
::ndk::ScopedAStatus toScopedAStatus(
const ::android::base::Result<T>& result,
::aidl::android::hardware::automotive::vehicle::StatusCode status,
- std::string additionalErrorMsg) {
+ const std::string& additionalErrorMsg) {
if (result.ok()) {
return ::ndk::ScopedAStatus::ok();
}
@@ -236,10 +236,50 @@
template <class T>
::ndk::ScopedAStatus toScopedAStatus(const ::android::base::Result<T>& result,
- std::string additionalErrorMsg) {
+ const std::string& additionalErrorMsg) {
return toScopedAStatus(result, getErrorCode(result), additionalErrorMsg);
}
+// Check whether the value is valid according to config.
+// We check for the following:
+// * If the type is INT32, {@code value.int32Values} must contain one element.
+// * If the type is INT32_VEC, {@code value.int32Values} must contain at least one element.
+// * If the type is INT64, {@code value.int64Values} must contain one element.
+// * If the type is INT64_VEC, {@code value.int64Values} must contain at least one element.
+// * If the type is FLOAT, {@code value.floatValues} must contain one element.
+// * If the type is FLOAT_VEC, {@code value.floatValues} must contain at least one element.
+// * If the type is MIXED, see checkVendorMixedPropValue.
+::android::base::Result<void> checkPropValue(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig* config);
+
+// Check whether the Mixed type value is valid according to config.
+// We check for the following:
+// * configArray[1] + configArray[2] + configArray[3] must be equal to the number of
+// {@code value.int32Values} elements.
+// * configArray[4] + configArray[5] must be equal to the number of {@code value.int64Values}
+// elements.
+// * configArray[6] + configArray[7] must be equal to the number of {@code value.floatValues}
+// elements.
+// * configArray[8] must be equal to the number of {@code value.byteValues} elements.
+::android::base::Result<void> checkVendorMixedPropValue(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig* config);
+
+// Check whether the value is within the configured range.
+// We check for the following types:
+// * If type is INT32 or INT32_VEC, all {@code value.int32Values} elements must be within
+// {@code minInt32Value} and {@code maxInt32Value} if either of them is not 0.
+// * If type is INT64 or INT64_VEC, all {@code value.int64Values} elements must be within
+// {@code minInt64Value} and {@code maxInt64Value} if either of them is not 0.
+// * If type is FLOAT or FLOAT_VEC, all {@code value.floatValues} elements must be within
+// {@code minFloatValues} and {@code maxFloatValues} if either of them is not 0.
+// We don't check other types. If more checks are required, they should be added in VehicleHardware
+// implementation.
+::android::base::Result<void> checkValueRange(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
+ const ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* config);
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
new file mode 100644
index 0000000..5abde8d
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
@@ -0,0 +1,210 @@
+/*
+ * 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 "VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::android::base::Error;
+using ::android::base::Result;
+using ::ndk::ScopedAStatus;
+
+Result<void> checkPropValue(const VehiclePropValue& value, const VehiclePropConfig* config) {
+ int32_t property = value.prop;
+ VehiclePropertyType type = getPropType(property);
+ switch (type) {
+ case VehiclePropertyType::BOOLEAN:
+ [[fallthrough]];
+ case VehiclePropertyType::INT32:
+ if (value.value.int32Values.size() != 1) {
+ return Error() << "expect 1 int32Values for INT32 type";
+ }
+ break;
+ case VehiclePropertyType::INT32_VEC:
+ if (value.value.int32Values.size() < 1) {
+ return Error() << "expect >=1 int32Values for INT32_VEC type";
+ }
+ break;
+ case VehiclePropertyType::INT64:
+ if (value.value.int64Values.size() != 1) {
+ return Error() << "expect 1 int64Values for INT64 type";
+ }
+ break;
+ case VehiclePropertyType::INT64_VEC:
+ if (value.value.int64Values.size() < 1) {
+ return Error() << "expect >=1 int64Values for INT64_VEC type";
+ }
+ break;
+ case VehiclePropertyType::FLOAT:
+ if (value.value.floatValues.size() != 1) {
+ return Error() << "expect 1 floatValues for FLOAT type";
+ }
+ break;
+ case VehiclePropertyType::FLOAT_VEC:
+ if (value.value.floatValues.size() < 1) {
+ return Error() << "expect >=1 floatValues for FLOAT_VEC type";
+ }
+ break;
+ case VehiclePropertyType::BYTES:
+ // We allow setting an empty bytes array.
+ break;
+ case VehiclePropertyType::STRING:
+ // We allow setting an empty string.
+ break;
+ case VehiclePropertyType::MIXED:
+ if (getPropGroup(property) == VehiclePropertyGroup::VENDOR) {
+ // We only checks vendor mixed properties.
+ return checkVendorMixedPropValue(value, config);
+ }
+ break;
+ default:
+ return Error() << "unknown property type: " << toInt(type);
+ }
+ return {};
+}
+
+Result<void> checkVendorMixedPropValue(const VehiclePropValue& value,
+ const VehiclePropConfig* config) {
+ auto configArray = config->configArray;
+ // configArray[0], 1 indicates the property has a String value, we allow the string value to
+ // be empty.
+
+ size_t int32Count = 0;
+ // configArray[1], 1 indicates the property has a Boolean value.
+ if (configArray[1] == 1) {
+ int32Count++;
+ }
+ // configArray[2], 1 indicates the property has an Integer value.
+ if (configArray[2] == 1) {
+ int32Count++;
+ }
+ // configArray[3], the number indicates the size of Integer[] in the property.
+ int32Count += static_cast<size_t>(configArray[3]);
+ size_t int32Size = value.value.int32Values.size();
+ if (int32Size != int32Count) {
+ return Error() << "invalid mixed property, got " << int32Size << " int32Values, expect "
+ << int32Count;
+ }
+
+ size_t int64Count = 0;
+ // configArray[4], 1 indicates the property has a Long value.
+ if (configArray[4] == 1) {
+ int64Count++;
+ }
+ // configArray[5], the number indicates the size of Long[] in the property.
+ int64Count += static_cast<size_t>(configArray[5]);
+ size_t int64Size = value.value.int64Values.size();
+ if (int64Size != int64Count) {
+ return Error() << "invalid mixed property, got " << int64Size << " int64Values, expect "
+ << int64Count;
+ }
+
+ size_t floatCount = 0;
+ // configArray[6], 1 indicates the property has a Float value.
+ if (configArray[6] == 1) {
+ floatCount++;
+ }
+ // configArray[7], the number indicates the size of Float[] in the property.
+ floatCount += static_cast<size_t>(configArray[7]);
+ size_t floatSize = value.value.floatValues.size();
+ if (floatSize != floatCount) {
+ return Error() << "invalid mixed property, got " << floatSize << " floatValues, expect "
+ << floatCount;
+ }
+
+ // configArray[8], the number indicates the size of byte[] in the property.
+ size_t byteSize = value.value.byteValues.size();
+ size_t byteCount = static_cast<size_t>(configArray[8]);
+ if (byteCount != 0 && byteSize != byteCount) {
+ return Error() << "invalid mixed property, got " << byteSize << " byteValues, expect "
+ << byteCount;
+ }
+ return {};
+}
+
+Result<void> checkValueRange(const VehiclePropValue& value, const VehicleAreaConfig* areaConfig) {
+ if (areaConfig == nullptr) {
+ return {};
+ }
+ int32_t property = value.prop;
+ VehiclePropertyType type = getPropType(property);
+ switch (type) {
+ case VehiclePropertyType::INT32:
+ [[fallthrough]];
+ case VehiclePropertyType::INT32_VEC:
+ if (areaConfig->minInt32Value == 0 && areaConfig->maxInt32Value == 0) {
+ break;
+ }
+ for (int32_t int32Value : value.value.int32Values) {
+ if (int32Value < areaConfig->minInt32Value ||
+ int32Value > areaConfig->maxInt32Value) {
+ return Error() << "int32Value: " << int32Value
+ << " out of range, min: " << areaConfig->minInt32Value
+ << " max: " << areaConfig->maxInt32Value;
+ }
+ }
+ break;
+ case VehiclePropertyType::INT64:
+ [[fallthrough]];
+ case VehiclePropertyType::INT64_VEC:
+ if (areaConfig->minInt64Value == 0 && areaConfig->maxInt64Value == 0) {
+ break;
+ }
+ for (int64_t int64Value : value.value.int64Values) {
+ if (int64Value < areaConfig->minInt64Value ||
+ int64Value > areaConfig->maxInt64Value) {
+ return Error() << "int64Value: " << int64Value
+ << " out of range, min: " << areaConfig->minInt64Value
+ << " max: " << areaConfig->maxInt64Value;
+ }
+ }
+ break;
+ case VehiclePropertyType::FLOAT:
+ [[fallthrough]];
+ case VehiclePropertyType::FLOAT_VEC:
+ if (areaConfig->minFloatValue == 0.f && areaConfig->maxFloatValue == 0.f) {
+ break;
+ }
+ for (float floatValue : value.value.floatValues) {
+ if (floatValue < areaConfig->minFloatValue ||
+ floatValue > areaConfig->maxFloatValue) {
+ return Error() << "floatValue: " << floatValue
+ << " out of range, min: " << areaConfig->minFloatValue
+ << " max: " << areaConfig->maxFloatValue;
+ }
+ }
+ break;
+ default:
+ // We don't check the rest of property types. Additional logic needs to be added if
+ // required in VehicleHardware, e.g. you might want to check the range for mixed
+ // property.
+ break;
+ }
+ return {};
+}
+
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/Android.bp b/automotive/vehicle/aidl/impl/utils/common/test/Android.bp
index dd43712..250b331 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/Android.bp
@@ -27,6 +27,7 @@
"libgtest",
"libgmock",
],
+ header_libs: ["VehicleHalTestUtilHeaders"],
defaults: ["VehicleHalDefaults"],
test_suites: ["device-tests"],
}
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
index 131eb3b..de8b26d 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
@@ -16,6 +16,7 @@
#include <ConcurrentQueue.h>
#include <PropertyUtils.h>
+#include <TestPropertyUtils.h>
#include <VehicleUtils.h>
#include <gtest/gtest.h>
@@ -29,6 +30,8 @@
namespace automotive {
namespace vehicle {
+namespace {
+
using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
@@ -37,6 +40,427 @@
using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+struct InvalidPropValueTestCase {
+ std::string name;
+ VehiclePropValue value;
+ bool valid = false;
+ VehiclePropConfig config;
+};
+
+constexpr int32_t int32Prop = toInt(VehicleProperty::INFO_MODEL_YEAR);
+constexpr int32_t int32VecProp = toInt(VehicleProperty::INFO_FUEL_TYPE);
+constexpr int32_t int64Prop = toInt(VehicleProperty::ANDROID_EPOCH_TIME);
+constexpr int32_t int64VecProp = toInt(VehicleProperty::WHEEL_TICK);
+constexpr int32_t floatProp = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE);
+constexpr int32_t floatVecProp = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION);
+
+std::vector<InvalidPropValueTestCase> getInvalidPropValuesTestCases() {
+ return std::vector<InvalidPropValueTestCase>(
+ {
+ InvalidPropValueTestCase{
+ .name = "int32_normal",
+ .value =
+ {
+ .prop = int32Prop,
+ .value.int32Values = {0},
+ },
+ .valid = true,
+ },
+ InvalidPropValueTestCase{
+ .name = "int32_no_value",
+ .value =
+ {
+ .prop = int32Prop,
+ },
+ },
+ InvalidPropValueTestCase{
+ .name = "int32_more_than_one_value",
+ .value =
+ {
+ .prop = int32Prop,
+ .value.int32Values = {0, 1},
+ },
+ },
+ InvalidPropValueTestCase{
+ .name = "int32_vec_normal",
+ .value =
+ {
+ .prop = int32VecProp,
+ .value.int32Values = {0, 1},
+ },
+ .valid = true,
+ },
+ InvalidPropValueTestCase{
+ .name = "int32_vec_no_value",
+ .value =
+ {
+ .prop = int32VecProp,
+ },
+ },
+ InvalidPropValueTestCase{
+ .name = "int64_normal",
+ .value =
+ {
+ .prop = int64Prop,
+ .value.int64Values = {0},
+ },
+ .valid = true,
+ },
+ InvalidPropValueTestCase{
+ .name = "int64_no_value",
+ .value =
+ {
+ .prop = int64Prop,
+ },
+ },
+ InvalidPropValueTestCase{
+ .name = "int64_more_than_one_value",
+ .value =
+ {
+ .prop = int64Prop,
+ .value.int64Values = {0, 1},
+ },
+ },
+ InvalidPropValueTestCase{
+ .name = "int64_vec_normal",
+ .value =
+ {
+ .prop = int64VecProp,
+ .value.int64Values = {0, 1},
+ },
+ .valid = true,
+ },
+ InvalidPropValueTestCase{
+ .name = "int64_vec_no_value",
+ .value =
+ {
+ .prop = int64VecProp,
+ },
+ },
+ InvalidPropValueTestCase{
+ .name = "float_normal",
+ .value =
+ {
+ .prop = floatProp,
+ .value.floatValues = {0.0},
+ },
+ .valid = true,
+ },
+ InvalidPropValueTestCase{
+ .name = "float_no_value",
+ .value =
+ {
+ .prop = floatProp,
+ },
+ },
+ InvalidPropValueTestCase{
+ .name = "float_more_than_one_value",
+ .value =
+ {
+ .prop = floatProp,
+ .value.floatValues = {0.0, 1.0},
+ },
+ },
+ InvalidPropValueTestCase{
+ .name = "float_vec_normal",
+ .value =
+ {
+ .prop = floatVecProp,
+ .value.floatValues = {0.0, 1.0},
+ },
+ .valid = true,
+ },
+ InvalidPropValueTestCase{
+ .name = "float_vec_no_value",
+ .value =
+ {
+ .prop = floatVecProp,
+ },
+ },
+ InvalidPropValueTestCase{
+ .name = "mixed_normal",
+ .value =
+ {
+ .prop = kMixedTypePropertyForTest,
+ // Expect 3 values.
+ .value.int32Values = {0, 1, 2},
+ // Expect 2 values.
+ .value.int64Values = {0, 1},
+ // Expect 2 values.
+ .value.floatValues = {0.0, 1.0},
+ // Expect 1 value.
+ .value.byteValues = {static_cast<uint8_t>(0)},
+ },
+ .config =
+ {
+ .prop = kMixedTypePropertyForTest,
+ .configArray = {0, 1, 1, 1, 1, 1, 1, 1, 1},
+ },
+ .valid = true,
+ },
+ InvalidPropValueTestCase{
+ .name = "mixed_mismatch_int32_values_count",
+ .value =
+ {
+ .prop = kMixedTypePropertyForTest,
+ // Expect 3 values.
+ .value.int32Values = {0, 1},
+ // Expect 2 values.
+ .value.int64Values = {0, 1},
+ // Expect 2 values.
+ .value.floatValues = {0.0, 1.0},
+ // Expect 1 value.
+ .value.byteValues = {static_cast<uint8_t>(0)},
+ },
+ .config =
+ {
+ .prop = kMixedTypePropertyForTest,
+ .configArray = {0, 1, 1, 1, 1, 1, 1, 1, 1},
+ },
+ },
+ InvalidPropValueTestCase{
+ .name = "mixed_mismatch_int64_values_count",
+ .value =
+ {
+ .prop = kMixedTypePropertyForTest,
+ // Expect 3 values.
+ .value.int32Values = {0, 1, 2},
+ // Expect 2 values.
+ .value.int64Values = {0},
+ // Expect 2 values.
+ .value.floatValues = {0.0, 1.0},
+ // Expect 1 value.
+ .value.byteValues = {static_cast<uint8_t>(0)},
+ },
+ .config =
+ {
+ .prop = kMixedTypePropertyForTest,
+ .configArray = {0, 1, 1, 1, 1, 1, 1, 1, 1},
+ },
+ },
+ InvalidPropValueTestCase{
+ .name = "mixed_mismatch_float_values_count",
+ .value =
+ {
+ .prop = kMixedTypePropertyForTest,
+ // Expect 3 values.
+ .value.int32Values = {0, 1, 2},
+ // Expect 2 values.
+ .value.int64Values = {0, 1},
+ // Expect 2 values.
+ .value.floatValues = {0.0},
+ // Expect 1 value.
+ .value.byteValues = {static_cast<uint8_t>(0)},
+ },
+ .config =
+ {
+ .prop = kMixedTypePropertyForTest,
+ .configArray = {0, 1, 1, 1, 1, 1, 1, 1, 1},
+ },
+ },
+ InvalidPropValueTestCase{
+ .name = "mixed_mismatch_byte_values_count",
+ .value =
+ {
+ .prop = kMixedTypePropertyForTest,
+ // Expect 3 values.
+ .value.int32Values = {0, 1, 2},
+ // Expect 2 values.
+ .value.int64Values = {0, 1},
+ // Expect 2 values.
+ .value.floatValues = {0.0, 1.0},
+ // Expect 1 value.
+ .value.byteValues = {static_cast<uint8_t>(0),
+ static_cast<uint8_t>(1)},
+ },
+ .config =
+ {
+ .prop = kMixedTypePropertyForTest,
+ .configArray = {0, 1, 1, 1, 1, 1, 1, 1, 1},
+ },
+ },
+ });
+}
+
+struct InvalidValueRangeTestCase {
+ std::string name;
+ VehiclePropValue value;
+ bool valid = false;
+ VehicleAreaConfig config;
+};
+
+std::vector<InvalidValueRangeTestCase> getInvalidValueRangeTestCases() {
+ return std::vector<InvalidValueRangeTestCase>({{
+ InvalidValueRangeTestCase{
+ .name = "int32_normal",
+ .value =
+ {
+ .prop = int32Prop,
+ .value.int32Values = {0},
+ },
+ .valid = true,
+ .config =
+ {
+ .minInt32Value = 0,
+ .maxInt32Value = 10,
+ },
+ },
+ InvalidValueRangeTestCase{
+ .name = "int32_vec_normal",
+ .value =
+ {
+ .prop = int32VecProp,
+ .value.int32Values = {0, 1},
+ },
+ .valid = true,
+ .config =
+ {
+ .minInt32Value = 0,
+ .maxInt32Value = 10,
+ },
+ },
+ InvalidValueRangeTestCase{
+ .name = "int32_vec_underflow",
+ .value =
+ {
+ .prop = int32VecProp,
+ .value.int32Values = {-1, 1},
+ },
+
+ .config =
+ {
+ .minInt32Value = 0,
+ .maxInt32Value = 10,
+ },
+ },
+ InvalidValueRangeTestCase{
+ .name = "int32_vec_overflow",
+ .value =
+ {
+ .prop = int32VecProp,
+ .value.int32Values = {0, 100},
+ },
+ .config =
+ {
+ .minInt32Value = 0,
+ .maxInt32Value = 10,
+ },
+ },
+ InvalidValueRangeTestCase{
+ .name = "int64_normal",
+ .value =
+ {
+ .prop = int64Prop,
+ .value.int64Values = {0},
+ },
+ .valid = true,
+ .config =
+ {
+ .minInt64Value = 0,
+ .maxInt64Value = 10,
+ },
+ },
+ InvalidValueRangeTestCase{
+ .name = "int64_vec_normal",
+ .value =
+ {
+ .prop = int64VecProp,
+ .value.int64Values = {0, 1},
+ },
+ .valid = true,
+ .config =
+ {
+ .minInt64Value = 0,
+ .maxInt64Value = 10,
+ },
+ },
+ InvalidValueRangeTestCase{
+ .name = "int64_vec_underflow",
+ .value =
+ {
+ .prop = int64VecProp,
+ .value.int64Values = {-1, 1},
+ },
+
+ .config =
+ {
+ .minInt64Value = 0,
+ .maxInt64Value = 10,
+ },
+ },
+ InvalidValueRangeTestCase{
+ .name = "int64_vec_overflow",
+ .value =
+ {
+ .prop = int64VecProp,
+ .value.int64Values = {0, 100},
+ },
+ .config =
+ {
+ .minInt64Value = 0,
+ .maxInt64Value = 10,
+ },
+ },
+ InvalidValueRangeTestCase{
+ .name = "float_normal",
+ .value =
+ {
+ .prop = floatProp,
+ .value.floatValues = {0.0},
+ },
+ .valid = true,
+ .config =
+ {
+ .minFloatValue = 0.0,
+ .maxFloatValue = 10.0,
+ },
+ },
+ InvalidValueRangeTestCase{
+ .name = "float_vec_normal",
+ .value =
+ {
+ .prop = floatVecProp,
+ .value.floatValues = {0.0, 10.0},
+ },
+ .valid = true,
+ .config =
+ {
+ .minFloatValue = 0.0,
+ .maxFloatValue = 10.0,
+ },
+ },
+ InvalidValueRangeTestCase{
+ .name = "float_vec_underflow",
+ .value =
+ {
+ .prop = floatVecProp,
+ .value.floatValues = {-0.1, 1.1},
+ },
+
+ .config =
+ {
+ .minFloatValue = 0.0,
+ .maxFloatValue = 10.0,
+ },
+ },
+ InvalidValueRangeTestCase{
+ .name = "float_vec_overflow",
+ .value =
+ {
+ .prop = floatVecProp,
+ .value.floatValues = {0.0, 10.1},
+ },
+ .config =
+ {
+ .minFloatValue = 0.0,
+ .maxFloatValue = 10.0,
+ },
+ },
+ }});
+}
+
+} // namespace
+
TEST(VehicleUtilsTest, testToInt) {
int areaGlobal = toInt(VehicleArea::GLOBAL);
@@ -335,6 +759,40 @@
t.join();
}
+class InvalidPropValueTest : public testing::TestWithParam<InvalidPropValueTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(InvalidPropValueTests, InvalidPropValueTest,
+ testing::ValuesIn(getInvalidPropValuesTestCases()),
+ [](const testing::TestParamInfo<InvalidPropValueTest::ParamType>& info) {
+ return info.param.name;
+ });
+
+TEST_P(InvalidPropValueTest, testCheckPropValue) {
+ InvalidPropValueTestCase tc = GetParam();
+
+ // Config is not used for non-mixed types.
+ auto result = checkPropValue(tc.value, &tc.config);
+
+ ASSERT_EQ(tc.valid, result.ok());
+}
+
+class InvalidValueRangeTest : public testing::TestWithParam<InvalidValueRangeTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(InvalidValueRangeTests, InvalidValueRangeTest,
+ testing::ValuesIn(getInvalidValueRangeTestCases()),
+ [](const testing::TestParamInfo<InvalidValueRangeTest::ParamType>& info) {
+ return info.param.name;
+ });
+
+TEST_P(InvalidValueRangeTest, testCheckValueRange) {
+ InvalidValueRangeTestCase tc = GetParam();
+
+ // Config is not used for non-mixed types.
+ auto result = checkValueRange(tc.value, &tc.config);
+
+ ASSERT_EQ(tc.valid, result.ok());
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index 43bdca2..4ee3ee9 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -17,10 +17,14 @@
#ifndef android_hardware_automotive_vehicle_aidl_impl_vhal_include_DefaultVehicleHal_H_
#define android_hardware_automotive_vehicle_aidl_impl_vhal_include_DefaultVehicleHal_H_
+#include "ConnectedClient.h"
+#include "ParcelableUtils.h"
+
#include <IVehicleHardware.h>
-#include <LargeParcelableBase.h>
#include <VehicleUtils.h>
#include <aidl/android/hardware/automotive/vehicle/BnVehicle.h>
+#include <android-base/expected.h>
+#include <android-base/thread_annotations.h>
#include <android/binder_auto_utils.h>
#include <memory>
@@ -37,59 +41,24 @@
constexpr int INVALID_MEMORY_FD = -1;
-template <class T>
-::ndk::ScopedAStatus toScopedAStatus(
- const ::android::base::Result<T>& result,
- ::aidl::android::hardware::automotive::vehicle::StatusCode status) {
- if (result.ok()) {
- return ::ndk::ScopedAStatus::ok();
- }
- return ::ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(toInt(status),
- getErrorMsg(result).c_str());
-}
-
-template <class T>
-::ndk::ScopedAStatus toScopedAStatus(const ::android::base::Result<T>& result) {
- return toScopedAStatus(result, getErrorCode(result));
-}
-
-template <class T1, class T2>
-::ndk::ScopedAStatus vectorToStableLargeParcelable(std::vector<T1>& values, T2* output) {
- auto result = ::android::automotive::car_binder_lib::LargeParcelableBase::
- parcelableVectorToStableLargeParcelable(values);
- if (!result.ok()) {
- return toScopedAStatus(
- result, ::aidl::android::hardware::automotive::vehicle::StatusCode::INTERNAL_ERROR);
- }
- auto& fd = result.value();
- if (fd == nullptr) {
- output->payloads = values;
- } else {
- // Move the returned ScopedFileDescriptor pointer to ScopedFileDescriptor value in
- // 'sharedMemoryFd' field.
- output->sharedMemoryFd.set(fd->get());
- *(fd->getR()) = INVALID_MEMORY_FD;
- }
- return ::ndk::ScopedAStatus::ok();
-}
-
} // namespace defaultvehiclehal_impl
class DefaultVehicleHal final : public ::aidl::android::hardware::automotive::vehicle::BnVehicle {
public:
+ using CallbackType =
+ std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
+
explicit DefaultVehicleHal(std::unique_ptr<IVehicleHardware> hardware);
::ndk::ScopedAStatus getAllPropConfigs(
::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
override;
::ndk::ScopedAStatus getValues(
- const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>&
- callback,
+ const CallbackType& callback,
const ::aidl::android::hardware::automotive::vehicle::GetValueRequests& requests)
override;
::ndk::ScopedAStatus setValues(
- const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>&
- callback,
+ const CallbackType& callback,
const ::aidl::android::hardware::automotive::vehicle::SetValueRequests& requests)
override;
::ndk::ScopedAStatus getPropConfigs(
@@ -97,27 +66,49 @@
::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs* returnConfigs)
override;
::ndk::ScopedAStatus subscribe(
- const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>&
- callback,
+ const CallbackType& callback,
const std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions>&
options,
int32_t maxSharedMemoryFileCount) override;
- ::ndk::ScopedAStatus unsubscribe(
- const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>&
- callback,
- const std::vector<int32_t>& propIds) override;
- ::ndk::ScopedAStatus returnSharedMemory(
- const std::shared_ptr<::aidl::android::hardware::automotive::vehicle::IVehicleCallback>&
- callback,
- int64_t sharedMemoryId) override;
+ ::ndk::ScopedAStatus unsubscribe(const CallbackType& callback,
+ const std::vector<int32_t>& propIds) override;
+ ::ndk::ScopedAStatus returnSharedMemory(const CallbackType& callback,
+ int64_t sharedMemoryId) override;
IVehicleHardware* getHardware();
private:
+ // friend class for unit testing.
+ friend class DefaultVehicleHalTest;
+
+ using GetValuesClient =
+ GetSetValuesClient<::aidl::android::hardware::automotive::vehicle::GetValueResult,
+ ::aidl::android::hardware::automotive::vehicle::GetValueResults>;
+ using SetValuesClient =
+ GetSetValuesClient<::aidl::android::hardware::automotive::vehicle::SetValueResult,
+ ::aidl::android::hardware::automotive::vehicle::SetValueResults>;
+
const std::unique_ptr<IVehicleHardware> mVehicleHardware;
+
+ // mConfigsByPropId and mConfigFile are only modified during initialization, so no need to
+ // lock guard them.
std::unordered_map<int32_t, ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig>
mConfigsByPropId;
std::unique_ptr<::ndk::ScopedFileDescriptor> mConfigFile;
+
+ std::mutex mLock;
+ std::unordered_map<CallbackType, std::shared_ptr<GetValuesClient>> mGetValuesClients
+ GUARDED_BY(mLock);
+ std::unordered_map<CallbackType, std::shared_ptr<SetValuesClient>> mSetValuesClients
+ GUARDED_BY(mLock);
+
+ template <class T>
+ std::shared_ptr<T> getOrCreateClient(
+ std::unordered_map<CallbackType, std::shared_ptr<T>>* clients,
+ const CallbackType& callback) REQUIRES(mLock);
+
+ ::android::base::Result<void> checkProperty(
+ const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& propValue);
};
} // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index fd9e331..e98f021 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -21,6 +21,7 @@
#include <LargeParcelableBase.h>
#include <VehicleHalTypes.h>
#include <VehicleUtils.h>
+
#include <android-base/result.h>
#include <utils/Log.h>
@@ -29,14 +30,24 @@
namespace automotive {
namespace vehicle {
+using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
using ::aidl::android::hardware::automotive::vehicle::GetValueRequests;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResults;
using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
+using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
using ::aidl::android::hardware::automotive::vehicle::SetValueRequests;
+using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
using ::aidl::android::hardware::automotive::vehicle::StatusCode;
using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
using ::android::automotive::car_binder_lib::LargeParcelableBase;
+using ::android::base::Error;
+using ::android::base::expected;
using ::android::base::Result;
using ::ndk::ScopedAStatus;
@@ -70,15 +81,141 @@
return ScopedAStatus::ok();
}
-ScopedAStatus DefaultVehicleHal::getValues(const std::shared_ptr<IVehicleCallback>&,
- const GetValueRequests&) {
- // TODO(b/200737967): implement this.
+template <class T>
+std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient(
+ std::unordered_map<CallbackType, std::shared_ptr<T>>* clients,
+ const CallbackType& callback) {
+ if (clients->find(callback) == clients->end()) {
+ // TODO(b/204943359): Remove client from clients when linkToDeath is implemented.
+ (*clients)[callback] = std::make_shared<T>(callback);
+ }
+ return (*clients)[callback];
+}
+
+template std::shared_ptr<DefaultVehicleHal::GetValuesClient>
+DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::GetValuesClient>(
+ std::unordered_map<CallbackType, std::shared_ptr<GetValuesClient>>* clients,
+ const CallbackType& callback);
+
+template std::shared_ptr<DefaultVehicleHal::SetValuesClient>
+DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::SetValuesClient>(
+ std::unordered_map<CallbackType, std::shared_ptr<SetValuesClient>>* clients,
+ const CallbackType& callback);
+
+Result<void> DefaultVehicleHal::checkProperty(const VehiclePropValue& propValue) {
+ int32_t propId = propValue.prop;
+ auto it = mConfigsByPropId.find(propId);
+ if (it == mConfigsByPropId.end()) {
+ return Error() << "no config for property, ID: " << propId;
+ }
+ const VehiclePropConfig& config = it->second;
+ const VehicleAreaConfig* areaConfig = getAreaConfig(propValue, config);
+ if (!isGlobalProp(propId) && areaConfig == nullptr) {
+ // Ignore areaId for global property. For non global property, check whether areaId is
+ // allowed. areaId must appear in areaConfig.
+ return Error() << "invalid area ID: " << propValue.areaId << " for prop ID: " << propId
+ << ", not listed in config";
+ }
+ if (auto result = checkPropValue(propValue, &config); !result.ok()) {
+ return Error() << "invalid property value: " << propValue.toString()
+ << ", error: " << result.error().message();
+ }
+ if (auto result = checkValueRange(propValue, areaConfig); !result.ok()) {
+ return Error() << "property value out of range: " << propValue.toString()
+ << ", error: " << result.error().message();
+ }
+ return {};
+}
+
+ScopedAStatus DefaultVehicleHal::getValues(const CallbackType& callback,
+ const GetValueRequests& requests) {
+ // TODO(b/203713317): check for duplicate properties and duplicate request IDs.
+
+ const std::vector<GetValueRequest>* getValueRequests;
+ // Define deserializedResults here because we need it to have the same lifetime as
+ // getValueRequests.
+ expected<std::vector<GetValueRequest>, ScopedAStatus> deserializedResults;
+ if (!requests.payloads.empty()) {
+ getValueRequests = &requests.payloads;
+ } else {
+ deserializedResults = stableLargeParcelableToVector<GetValueRequest>(requests);
+ if (!deserializedResults.ok()) {
+ ALOGE("failed to parse getValues requests");
+ return std::move(deserializedResults.error());
+ }
+ getValueRequests = &deserializedResults.value();
+ }
+
+ std::shared_ptr<GetValuesClient> client;
+ {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ client = getOrCreateClient(&mGetValuesClients, callback);
+ }
+
+ if (StatusCode status =
+ mVehicleHardware->getValues(client->getResultCallback(), *getValueRequests);
+ status != StatusCode::OK) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ toInt(status), "failed to get value from VehicleHardware");
+ }
+
return ScopedAStatus::ok();
}
-ScopedAStatus DefaultVehicleHal::setValues(const std::shared_ptr<IVehicleCallback>&,
- const SetValueRequests&) {
- // TODO(b/200737967): implement this.
+ScopedAStatus DefaultVehicleHal::setValues(const CallbackType& callback,
+ const SetValueRequests& requests) {
+ // TODO(b/203713317): check for duplicate properties and duplicate request IDs.
+
+ const std::vector<SetValueRequest>* setValueRequests;
+ // Define deserializedResults here because we need it to have the same lifetime as
+ // setValueRequests.
+ expected<std::vector<SetValueRequest>, ScopedAStatus> deserializedResults;
+ if (!requests.payloads.empty()) {
+ setValueRequests = &requests.payloads;
+ } else {
+ deserializedResults = stableLargeParcelableToVector<SetValueRequest>(requests);
+ if (!deserializedResults.ok()) {
+ ALOGE("failed to parse setValues requests");
+ return std::move(deserializedResults.error());
+ }
+ setValueRequests = &deserializedResults.value();
+ }
+
+ // A list of failed result we already know before sending to hardware.
+ std::vector<SetValueResult> failedResults;
+ // The list of requests that we would send to hardware.
+ std::vector<SetValueRequest> hardwareRequests;
+
+ for (auto& request : *setValueRequests) {
+ int64_t requestId = request.requestId;
+ if (auto result = checkProperty(request.value); !result.ok()) {
+ ALOGW("property not valid: %s", result.error().message().c_str());
+ failedResults.push_back(SetValueResult{
+ .requestId = requestId,
+ .status = StatusCode::INVALID_ARG,
+ });
+ continue;
+ }
+ hardwareRequests.push_back(request);
+ }
+
+ std::shared_ptr<SetValuesClient> client;
+ {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ client = getOrCreateClient(&mSetValuesClients, callback);
+ }
+
+ if (!failedResults.empty()) {
+ client->sendResults(failedResults);
+ }
+
+ if (StatusCode status =
+ mVehicleHardware->setValues(client->getResultCallback(), hardwareRequests);
+ status != StatusCode::OK) {
+ return ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ toInt(status), "failed to set value to VehicleHardware");
+ }
+
return ScopedAStatus::ok();
}
@@ -90,23 +227,21 @@
configs.push_back(mConfigsByPropId[prop]);
}
}
- return defaultvehiclehal_impl::vectorToStableLargeParcelable(configs, output);
+ return vectorToStableLargeParcelable(std::move(configs), output);
}
-ScopedAStatus DefaultVehicleHal::subscribe(const std::shared_ptr<IVehicleCallback>&,
+ScopedAStatus DefaultVehicleHal::subscribe(const CallbackType&,
const std::vector<SubscribeOptions>&, int32_t) {
// TODO(b/200737967): implement this.
return ScopedAStatus::ok();
}
-ScopedAStatus DefaultVehicleHal::unsubscribe(const std::shared_ptr<IVehicleCallback>&,
- const std::vector<int32_t>&) {
+ScopedAStatus DefaultVehicleHal::unsubscribe(const CallbackType&, const std::vector<int32_t>&) {
// TODO(b/200737967): implement this.
return ScopedAStatus::ok();
}
-ScopedAStatus DefaultVehicleHal::returnSharedMemory(const std::shared_ptr<IVehicleCallback>&,
- int64_t) {
+ScopedAStatus DefaultVehicleHal::returnSharedMemory(const CallbackType&, int64_t) {
// TODO(b/200737967): implement this.
return ScopedAStatus::ok();
}
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index 2b5ca70..8934a7b 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -15,17 +15,24 @@
*/
#include "DefaultVehicleHal.h"
+#include "MockVehicleCallback.h"
#include <IVehicleHardware.h>
#include <LargeParcelableBase.h>
#include <aidl/android/hardware/automotive/vehicle/IVehicle.h>
-#include <android-base/thread_annotations.h>
+#include <aidl/android/hardware/automotive/vehicle/IVehicleCallback.h>
+#include <android-base/thread_annotations.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <utils/Log.h>
+#include <list>
#include <memory>
+#include <mutex>
#include <optional>
+#include <thread>
+#include <unordered_map>
#include <vector>
namespace android {
@@ -36,38 +43,77 @@
namespace {
using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::GetValueRequests;
using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::GetValueResults;
using ::aidl::android::hardware::automotive::vehicle::IVehicle;
+using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
+using ::aidl::android::hardware::automotive::vehicle::SetValueRequests;
using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
+using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
using ::android::automotive::car_binder_lib::LargeParcelableBase;
using ::android::base::Result;
+using ::ndk::ScopedAStatus;
+using ::ndk::ScopedFileDescriptor;
+
using ::testing::Eq;
using ::testing::WhenSortedBy;
+constexpr int32_t INVALID_PROP_ID = 0;
+// VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
+constexpr int32_t INT32_WINDOW_PROP = 10001 + 0x10000000 + 0x03000000 + 0x00400000;
+
+template <class T>
+std::optional<T> pop(std::list<T>& items) {
+ if (items.size() > 0) {
+ auto item = std::move(items.front());
+ items.pop_front();
+ return item;
+ }
+ return std::nullopt;
+}
+
+int32_t testInt32VecProp(size_t i) {
+ // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32_VEC
+ return static_cast<int32_t>(i) + 0x10000000 + 0x01000000 + 0x00410000;
+}
+
class MockVehicleHardware final : public IVehicleHardware {
public:
+ ~MockVehicleHardware() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ for (auto& thread : mThreads) {
+ thread.join();
+ }
+ }
+
std::vector<VehiclePropConfig> getAllPropertyConfigs() const override {
std::scoped_lock<std::mutex> lockGuard(mLock);
return mPropertyConfigs;
}
- StatusCode setValues(std::shared_ptr<const SetValuesCallback>,
- const std::vector<SetValueRequest>&) override {
- // TODO(b/200737967): mock this.
- return StatusCode::OK;
+ StatusCode setValues(std::shared_ptr<const SetValuesCallback> callback,
+ const std::vector<SetValueRequest>& requests) override {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return handleRequests(__func__, callback, requests, &mSetValueRequests,
+ &mSetValueResponses);
}
- StatusCode getValues(std::shared_ptr<const GetValuesCallback>,
- const std::vector<GetValueRequest>&) const override {
- // TODO(b/200737967): mock this.
- return StatusCode::OK;
+ StatusCode getValues(std::shared_ptr<const GetValuesCallback> callback,
+ const std::vector<GetValueRequest>& requests) const override {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ return handleRequests(__func__, callback, requests, &mGetValueRequests,
+ &mGetValueResponses);
}
DumpResult dump(const std::vector<std::string>&) override {
@@ -94,20 +140,316 @@
mPropertyConfigs = configs;
}
+ void addGetValueResponses(const std::vector<GetValueResult>& responses) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mGetValueResponses.push_back(responses);
+ }
+
+ void addSetValueResponses(const std::vector<SetValueResult>& responses) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mSetValueResponses.push_back(responses);
+ }
+
+ std::vector<GetValueRequest> nextGetValueRequests() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ std::optional<std::vector<GetValueRequest>> request = pop(mGetValueRequests);
+ if (!request.has_value()) {
+ return std::vector<GetValueRequest>();
+ }
+ return std::move(request.value());
+ }
+
+ std::vector<SetValueRequest> nextSetValueRequests() {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ std::optional<std::vector<SetValueRequest>> request = pop(mSetValueRequests);
+ if (!request.has_value()) {
+ return std::vector<SetValueRequest>();
+ }
+ return std::move(request.value());
+ }
+
+ void setStatus(const char* functionName, StatusCode status) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mStatusByFunctions[functionName] = status;
+ }
+
+ void setSleepTime(int64_t timeInNano) {
+ std::scoped_lock<std::mutex> lockGuard(mLock);
+ mSleepTime = timeInNano;
+ }
+
private:
mutable std::mutex mLock;
std::vector<VehiclePropConfig> mPropertyConfigs GUARDED_BY(mLock);
+ mutable std::list<std::vector<GetValueRequest>> mGetValueRequests GUARDED_BY(mLock);
+ mutable std::list<std::vector<GetValueResult>> mGetValueResponses GUARDED_BY(mLock);
+ mutable std::list<std::vector<SetValueRequest>> mSetValueRequests GUARDED_BY(mLock);
+ mutable std::list<std::vector<SetValueResult>> mSetValueResponses GUARDED_BY(mLock);
+ std::unordered_map<const char*, StatusCode> mStatusByFunctions GUARDED_BY(mLock);
+ int64_t mSleepTime GUARDED_BY(mLock) = 0;
+ mutable std::vector<std::thread> mThreads GUARDED_BY(mLock);
+
+ template <class ResultType>
+ StatusCode returnResponse(
+ std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+ std::list<std::vector<ResultType>>* storedResponses) const;
+
+ template <class RequestType, class ResultType>
+ StatusCode handleRequests(
+ const char* functionName,
+ std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+ const std::vector<RequestType>& requests,
+ std::list<std::vector<RequestType>>* storedRequests,
+ std::list<std::vector<ResultType>>* storedResponses) const REQUIRES(mLock);
};
+template <class ResultType>
+StatusCode MockVehicleHardware::returnResponse(
+ std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+ std::list<std::vector<ResultType>>* storedResponses) const {
+ if (storedResponses->size() > 0) {
+ (*callback)(std::move(storedResponses->front()));
+ storedResponses->pop_front();
+ return StatusCode::OK;
+ } else {
+ ALOGE("no more response");
+ return StatusCode::INTERNAL_ERROR;
+ }
+}
+
+template StatusCode MockVehicleHardware::returnResponse<GetValueResult>(
+ std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
+ std::list<std::vector<GetValueResult>>* storedResponses) const;
+
+template StatusCode MockVehicleHardware::returnResponse<SetValueResult>(
+ std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
+ std::list<std::vector<SetValueResult>>* storedResponses) const;
+
+template <class RequestType, class ResultType>
+StatusCode MockVehicleHardware::handleRequests(
+ const char* functionName,
+ std::shared_ptr<const std::function<void(std::vector<ResultType>)>> callback,
+ const std::vector<RequestType>& requests,
+ std::list<std::vector<RequestType>>* storedRequests,
+ std::list<std::vector<ResultType>>* storedResponses) const {
+ storedRequests->push_back(requests);
+ if (auto it = mStatusByFunctions.find(functionName); it != mStatusByFunctions.end()) {
+ if (StatusCode status = it->second; status != StatusCode::OK) {
+ return status;
+ }
+ }
+
+ if (mSleepTime != 0) {
+ int64_t sleepTime = mSleepTime;
+ mThreads.emplace_back([this, callback, sleepTime, storedResponses]() {
+ std::this_thread::sleep_for(std::chrono::nanoseconds(sleepTime));
+ returnResponse(callback, storedResponses);
+ });
+ return StatusCode::OK;
+
+ } else {
+ return returnResponse(callback, storedResponses);
+ }
+}
+
+template StatusCode MockVehicleHardware::handleRequests<GetValueRequest, GetValueResult>(
+ const char* functionName,
+ std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>> callback,
+ const std::vector<GetValueRequest>& requests,
+ std::list<std::vector<GetValueRequest>>* storedRequests,
+ std::list<std::vector<GetValueResult>>* storedResponses) const;
+
+template StatusCode MockVehicleHardware::handleRequests<SetValueRequest, SetValueResult>(
+ const char* functionName,
+ std::shared_ptr<const std::function<void(std::vector<SetValueResult>)>> callback,
+ const std::vector<SetValueRequest>& requests,
+ std::list<std::vector<SetValueRequest>>* storedRequests,
+ std::list<std::vector<SetValueResult>>* storedResponses) const;
+
struct PropConfigCmp {
bool operator()(const VehiclePropConfig& a, const VehiclePropConfig& b) const {
return (a.prop < b.prop);
}
} propConfigCmp;
+struct SetValuesInvalidRequestTestCase {
+ std::string name;
+ VehiclePropValue request;
+ StatusCode expectedStatus;
+};
+
+std::vector<SetValuesInvalidRequestTestCase> getSetValuesInvalidRequestTestCases() {
+ return {{
+ .name = "config_not_found",
+ .request =
+ {
+ // No config for INVALID_PROP_ID.
+ .prop = INVALID_PROP_ID,
+ },
+ .expectedStatus = StatusCode::INVALID_ARG,
+ },
+ {
+ .name = "invalid_prop_value",
+ .request =
+ {
+ .prop = testInt32VecProp(0),
+ // No int32Values for INT32_VEC property.
+ .value.int32Values = {},
+ },
+ .expectedStatus = StatusCode::INVALID_ARG,
+ },
+ {
+ .name = "value_out_of_range",
+ .request =
+ {
+ .prop = testInt32VecProp(0),
+ // We configured the range to be 0-100.
+ .value.int32Values = {0, -1},
+ },
+ .expectedStatus = StatusCode::INVALID_ARG,
+ },
+ {
+ .name = "invalid_area",
+ .request =
+ {
+ .prop = INT32_WINDOW_PROP,
+ .value.int32Values = {0},
+ // Only ROW_1_LEFT is allowed.
+ .areaId = toInt(VehicleAreaWindow::ROW_1_RIGHT),
+ },
+ .expectedStatus = StatusCode::INVALID_ARG,
+ }};
+}
+
} // namespace
-TEST(DefaultVehicleHalTest, testGetAllPropConfigsSmall) {
+class DefaultVehicleHalTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ auto hardware = std::make_unique<MockVehicleHardware>();
+ std::vector<VehiclePropConfig> testConfigs;
+ for (size_t i = 0; i < 10000; i++) {
+ testConfigs.push_back(VehiclePropConfig{
+ .prop = testInt32VecProp(i),
+ .areaConfigs =
+ {
+ {
+ .areaId = 0,
+ .minInt32Value = 0,
+ .maxInt32Value = 100,
+ },
+ },
+ });
+ }
+ testConfigs.push_back(
+ VehiclePropConfig{.prop = INT32_WINDOW_PROP,
+ .areaConfigs = {{
+ .areaId = toInt(VehicleAreaWindow::ROW_1_LEFT),
+ .minInt32Value = 0,
+ .maxInt32Value = 100,
+ }}});
+ hardware->setPropertyConfigs(testConfigs);
+ mHardwarePtr = hardware.get();
+ mVhal = ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
+ mVhalClient = IVehicle::fromBinder(mVhal->asBinder());
+ mCallback = ndk::SharedRefBase::make<MockVehicleCallback>();
+ mCallbackClient = IVehicleCallback::fromBinder(mCallback->asBinder());
+ }
+
+ MockVehicleHardware* getHardware() { return mHardwarePtr; }
+
+ std::shared_ptr<IVehicle> getClient() { return mVhal; }
+
+ std::shared_ptr<IVehicleCallback> getCallbackClient() { return mCallbackClient; }
+
+ MockVehicleCallback* getCallback() { return mCallback.get(); }
+
+ static Result<void> getValuesTestCases(size_t size, GetValueRequests& requests,
+ std::vector<GetValueResult>& expectedResults,
+ std::vector<GetValueRequest>& expectedHardwareRequests) {
+ expectedHardwareRequests.clear();
+ for (size_t i = 0; i < size; i++) {
+ int64_t requestId = static_cast<int64_t>(i);
+ int32_t propId = testInt32VecProp(i);
+ expectedHardwareRequests.push_back(GetValueRequest{
+ .prop =
+ VehiclePropValue{
+ .prop = propId,
+ },
+ .requestId = requestId,
+ });
+ expectedResults.push_back(GetValueResult{
+ .requestId = requestId,
+ .status = StatusCode::OK,
+ .prop =
+ VehiclePropValue{
+ .prop = propId,
+ .value.int32Values = {1, 2, 3, 4},
+ },
+ });
+ }
+
+ auto result = LargeParcelableBase::parcelableVectorToStableLargeParcelable(
+ expectedHardwareRequests);
+ if (!result.ok()) {
+ return result.error();
+ }
+ if (result.value() == nullptr) {
+ requests.payloads = expectedHardwareRequests;
+ } else {
+ requests.sharedMemoryFd = std::move(*result.value());
+ }
+ return {};
+ }
+
+ static Result<void> setValuesTestCases(size_t size, SetValueRequests& requests,
+ std::vector<SetValueResult>& expectedResults,
+ std::vector<SetValueRequest>& expectedHardwareRequests) {
+ expectedHardwareRequests.clear();
+ for (size_t i = 0; i < size; i++) {
+ int64_t requestId = static_cast<int64_t>(i);
+ int32_t propId = testInt32VecProp(i);
+ expectedHardwareRequests.push_back(SetValueRequest{
+ .value =
+ VehiclePropValue{
+ .prop = propId,
+ .value.int32Values = {1, 2, 3, 4},
+ },
+ .requestId = requestId,
+ });
+ expectedResults.push_back(SetValueResult{
+ .requestId = requestId,
+ .status = StatusCode::OK,
+ });
+ }
+
+ auto result = LargeParcelableBase::parcelableVectorToStableLargeParcelable(
+ expectedHardwareRequests);
+ if (!result.ok()) {
+ return result.error();
+ }
+ if (result.value() == nullptr) {
+ requests.payloads = expectedHardwareRequests;
+ } else {
+ requests.sharedMemoryFd = std::move(*result.value());
+ }
+ return {};
+ }
+
+ size_t countClients() {
+ std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
+ return mVhal->mGetValuesClients.size() + mVhal->mSetValuesClients.size();
+ }
+
+ private:
+ std::shared_ptr<DefaultVehicleHal> mVhal;
+ std::shared_ptr<IVehicle> mVhalClient;
+ MockVehicleHardware* mHardwarePtr;
+ std::shared_ptr<MockVehicleCallback> mCallback;
+ std::shared_ptr<IVehicleCallback> mCallbackClient;
+};
+
+TEST_F(DefaultVehicleHalTest, testGetAllPropConfigsSmall) {
auto testConfigs = std::vector<VehiclePropConfig>({
VehiclePropConfig{
.prop = 1,
@@ -125,14 +467,14 @@
VehiclePropConfigs output;
auto status = client->getAllPropConfigs(&output);
- ASSERT_TRUE(status.isOk());
+ ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
ASSERT_THAT(output.payloads, WhenSortedBy(propConfigCmp, Eq(testConfigs)));
}
-TEST(DefaultVehicleHalTest, testGetAllPropConfigsLarge) {
+TEST_F(DefaultVehicleHalTest, testGetAllPropConfigsLarge) {
std::vector<VehiclePropConfig> testConfigs;
- // 10000 VehiclePropConfig exceeds 4k memory limit, so it would be sent through shared memory.
- for (size_t i = 0; i < 10000; i++) {
+ // 5000 VehiclePropConfig exceeds 4k memory limit, so it would be sent through shared memory.
+ for (size_t i = 0; i < 5000; i++) {
testConfigs.push_back(VehiclePropConfig{
.prop = static_cast<int32_t>(i),
});
@@ -146,16 +488,202 @@
VehiclePropConfigs output;
auto status = client->getAllPropConfigs(&output);
- ASSERT_TRUE(status.isOk());
+ ASSERT_TRUE(status.isOk()) << "getAllPropConfigs failed: " << status.getMessage();
ASSERT_TRUE(output.payloads.empty());
Result<std::optional<std::vector<VehiclePropConfig>>> result =
LargeParcelableBase::stableLargeParcelableToParcelableVector<VehiclePropConfig>(
output.sharedMemoryFd);
- ASSERT_TRUE(result.ok());
- ASSERT_TRUE(result.value().has_value());
+ ASSERT_TRUE(result.ok()) << "failed to parse result shared memory file: "
+ << result.error().message();
+ ASSERT_TRUE(result.value().has_value()) << "empty parsed value";
ASSERT_EQ(result.value().value(), testConfigs);
}
+TEST_F(DefaultVehicleHalTest, testGetValuesSmall) {
+ GetValueRequests requests;
+ std::vector<GetValueResult> expectedResults;
+ std::vector<GetValueRequest> expectedHardwareRequests;
+
+ ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+ getHardware()->addGetValueResponses(expectedResults);
+
+ auto status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+ EXPECT_EQ(getHardware()->nextGetValueRequests(), expectedHardwareRequests)
+ << "requests to hardware mismatch";
+
+ auto maybeGetValueResults = getCallback()->nextGetValueResults();
+ ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
+ EXPECT_EQ(maybeGetValueResults.value().payloads, expectedResults) << "results mismatch";
+ EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesLarge) {
+ GetValueRequests requests;
+ std::vector<GetValueResult> expectedResults;
+ std::vector<GetValueRequest> expectedHardwareRequests;
+
+ ASSERT_TRUE(getValuesTestCases(5000, requests, expectedResults, expectedHardwareRequests).ok())
+ << "requests to hardware mismatch";
+ ;
+
+ getHardware()->addGetValueResponses(expectedResults);
+
+ auto status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_TRUE(status.isOk()) << "getValues failed: " << status.getMessage();
+
+ EXPECT_EQ(getHardware()->nextGetValueRequests(), expectedHardwareRequests);
+
+ auto maybeGetValueResults = getCallback()->nextGetValueResults();
+ ASSERT_TRUE(maybeGetValueResults.has_value()) << "no results in callback";
+ const GetValueResults& getValueResults = maybeGetValueResults.value();
+ ASSERT_TRUE(getValueResults.payloads.empty())
+ << "payload should be empty, shared memory file should be used";
+
+ auto result = LargeParcelableBase::stableLargeParcelableToParcelableVector<GetValueResult>(
+ getValueResults.sharedMemoryFd);
+ ASSERT_TRUE(result.ok()) << "failed to parse shared memory file";
+ ASSERT_TRUE(result.value().has_value()) << "no parsed value";
+ ASSERT_EQ(result.value().value(), expectedResults) << "results mismatch";
+ EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesErrorFromHardware) {
+ GetValueRequests requests;
+ std::vector<GetValueResult> expectedResults;
+ std::vector<GetValueRequest> expectedHardwareRequests;
+
+ ASSERT_TRUE(getValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+ getHardware()->setStatus("getValues", StatusCode::INTERNAL_ERROR);
+
+ auto status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_FALSE(status.isOk()) << "expect getValues to fail when hardware returns error";
+ ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INTERNAL_ERROR));
+}
+
+TEST_F(DefaultVehicleHalTest, testGetValuesInvalidLargeParcelableInput) {
+ GetValueRequests requests;
+ requests.sharedMemoryFd = ScopedFileDescriptor(0);
+
+ auto status = getClient()->getValues(getCallbackClient(), requests);
+
+ ASSERT_FALSE(status.isOk()) << "expect getValues to fail when input parcelable is not valid";
+ ASSERT_EQ(status.getServiceSpecificError(), toInt(StatusCode::INVALID_ARG));
+}
+
+TEST_F(DefaultVehicleHalTest, testSetValuesSmall) {
+ SetValueRequests requests;
+ std::vector<SetValueResult> expectedResults;
+ std::vector<SetValueRequest> expectedHardwareRequests;
+
+ ASSERT_TRUE(setValuesTestCases(10, requests, expectedResults, expectedHardwareRequests).ok());
+
+ getHardware()->addSetValueResponses(expectedResults);
+
+ auto status = getClient()->setValues(getCallbackClient(), requests);
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ EXPECT_EQ(getHardware()->nextSetValueRequests(), expectedHardwareRequests)
+ << "requests to hardware mismatch";
+
+ auto maybeSetValueResults = getCallback()->nextSetValueResults();
+ ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
+ ASSERT_EQ(maybeSetValueResults.value().payloads, expectedResults) << "results mismatch";
+ EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+TEST_F(DefaultVehicleHalTest, testSetValuesLarge) {
+ SetValueRequests requests;
+ std::vector<SetValueResult> expectedResults;
+ std::vector<SetValueRequest> expectedHardwareRequests;
+
+ ASSERT_TRUE(setValuesTestCases(5000, requests, expectedResults, expectedHardwareRequests).ok());
+
+ getHardware()->addSetValueResponses(expectedResults);
+
+ auto status = getClient()->setValues(getCallbackClient(), requests);
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ EXPECT_EQ(getHardware()->nextSetValueRequests(), expectedHardwareRequests)
+ << "requests to hardware mismatch";
+
+ auto maybeSetValueResults = getCallback()->nextSetValueResults();
+ ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
+ const SetValueResults& setValueResults = maybeSetValueResults.value();
+ ASSERT_TRUE(setValueResults.payloads.empty())
+ << "payload should be empty, shared memory file should be used";
+
+ auto result = LargeParcelableBase::stableLargeParcelableToParcelableVector<SetValueResult>(
+ setValueResults.sharedMemoryFd);
+ ASSERT_TRUE(result.ok()) << "failed to parse shared memory file";
+ ASSERT_TRUE(result.value().has_value()) << "no parsed value";
+ ASSERT_EQ(result.value().value(), expectedResults) << "results mismatch";
+ EXPECT_EQ(countClients(), static_cast<size_t>(1));
+}
+
+class SetValuesInvalidRequestTest
+ : public DefaultVehicleHalTest,
+ public testing::WithParamInterface<SetValuesInvalidRequestTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(
+ SetValuesInvalidRequestTests, SetValuesInvalidRequestTest,
+ ::testing::ValuesIn(getSetValuesInvalidRequestTestCases()),
+ [](const testing::TestParamInfo<SetValuesInvalidRequestTest::ParamType>& info) {
+ return info.param.name;
+ });
+
+TEST_P(SetValuesInvalidRequestTest, testSetValuesInvalidRequest) {
+ SetValuesInvalidRequestTestCase tc = GetParam();
+ std::vector<SetValueResult> expectedHardwareResults{
+ SetValueResult{
+ .requestId = 1,
+ .status = StatusCode::OK,
+ },
+ };
+ getHardware()->addSetValueResponses(expectedHardwareResults);
+
+ SetValueRequests requests;
+ SetValueRequest invalidRequest{
+ .requestId = 0,
+ .value = tc.request,
+ };
+ SetValueRequest normalRequest{.requestId = 1,
+ .value = {
+ .prop = testInt32VecProp(0),
+ .value.int32Values = {0},
+ }};
+ requests.payloads = {invalidRequest, normalRequest};
+ auto status = getClient()->setValues(getCallbackClient(), requests);
+
+ ASSERT_TRUE(status.isOk()) << "setValues failed: " << status.getMessage();
+
+ EXPECT_EQ(getHardware()->nextSetValueRequests(), std::vector<SetValueRequest>({normalRequest}))
+ << "requests to hardware mismatch";
+
+ auto maybeSetValueResults = getCallback()->nextSetValueResults();
+ ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results in callback";
+ EXPECT_EQ(maybeSetValueResults.value().payloads, std::vector<SetValueResult>({
+ {
+ .requestId = 0,
+ .status = tc.expectedStatus,
+ },
+ }))
+ << "invalid argument result mismatch";
+
+ maybeSetValueResults = getCallback()->nextSetValueResults();
+ ASSERT_TRUE(maybeSetValueResults.has_value()) << "no results from hardware in callback";
+ EXPECT_EQ(maybeSetValueResults.value().payloads, expectedHardwareResults)
+ << "results from hardware mismatch";
+}
+
} // namespace vehicle
} // namespace automotive
} // namespace hardware
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index c480c13..3809561 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -393,6 +393,7 @@
<interface>
<name>IRemotelyProvisionedComponent</name>
<instance>default</instance>
+ <instance>strongbox</instance>
</interface>
</hal>
<hal format="aidl" optional="true">
@@ -626,6 +627,13 @@
<instance>strongbox</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.sensors</name>
+ <interface>
+ <name>ISensors</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.sensors</name>
<version>1.0</version>
diff --git a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
index 24d6f9c..9c4a54b 100644
--- a/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
+++ b/gnss/aidl/aidl_api/android.hardware.gnss/current/android/hardware/gnss/IGnssMeasurementInterface.aidl
@@ -36,4 +36,11 @@
interface IGnssMeasurementInterface {
void setCallback(in android.hardware.gnss.IGnssMeasurementCallback callback, in boolean enableFullTracking, in boolean enableCorrVecOutputs);
void close();
+ void setCallbackWithOptions(in android.hardware.gnss.IGnssMeasurementCallback callback, in android.hardware.gnss.IGnssMeasurementInterface.Options options);
+ @VintfStability
+ parcelable Options {
+ boolean enableFullTracking;
+ boolean enableCorrVecOutputs;
+ int intervalMs;
+ }
}
diff --git a/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
index 08c83a4..102cdcd 100644
--- a/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
+++ b/gnss/aidl/android/hardware/gnss/IGnssMeasurementInterface.aidl
@@ -24,6 +24,48 @@
@VintfStability
interface IGnssMeasurementInterface {
/**
+ * Options specifying the GnssMeasurement request.
+ */
+ @VintfStability
+ parcelable Options {
+ /**
+ * Enable full tracking mode.
+ *
+ * If true, GNSS chipset must switch off duty cycling. In such mode no clock discontinuities
+ * are expected and, when supported, carrier phase should be continuous in good signal
+ * conditions. All non-blocklisted, healthy constellations, satellites and frequency bands
+ * that the chipset supports must be reported in this mode. The GNSS chipset is allowed to
+ * consume more power in this mode. If false, API must optimize power via duty cycling,
+ * constellations and frequency limits, etc.
+ */
+ boolean enableFullTracking;
+
+ /**
+ * Enable Correlation Vector outputs.
+ *
+ * If true, enable correlation vectors as part of the raw GNSS measurements outputs. If
+ * false, disable correlation vectors.
+ */
+ boolean enableCorrVecOutputs;
+
+ /**
+ * Time interval between the reported measurements in milliseconds.
+ *
+ * The GNSS chipset must not report measurements with a rate slower than requested. All the
+ * available measurements must be reported to the framework.
+ *
+ * For cases where concurrently serving the location and the measurement requests would not
+ * consume more power than only the measurement request, the faster rate of the 2 requests
+ * must be chosen. Otherwise, it is recommended that the GNSS chipset minimizes the power
+ * consumption with appropriate location and measurement intervals to satisfy both requests.
+ * For example, for 2-sec measurement interval request and 7-sec location interval request,
+ * the GNSS chipset is recommended to run the measurement engine with 2-sec interval and the
+ * location engine with 6-sec interval.
+ */
+ int intervalMs;
+ }
+
+ /**
* Initializes the interface and registers the callback routines with the HAL. After a
* successful call to 'setCallback' the HAL must begin to provide updates at an average
* output rate of 1Hz (occasional intra-measurement time offsets in the range from 0-2000msec
@@ -39,13 +81,9 @@
*
* @param enableCorrVecOutputs If true, enable correlation vectors as part of the raw GNSS
* measurements outputs. If false, disable correlation vectors.
- *
- * Returns ok() if successful. Returns ERROR_ALREADY_INIT if a callback has already been
- * registered without a corresponding call to 'close'. Returns ERROR_GENERIC for any other
- * error. The HAL must not generate any other updates upon returning this error code.
*/
void setCallback(in IGnssMeasurementCallback callback, in boolean enableFullTracking,
- in boolean enableCorrVecOutputs);
+ in boolean enableCorrVecOutputs);
/**
* Stops updates from the HAL, and unregisters the callback routines. After a call to close(),
@@ -55,4 +93,11 @@
* no work.
*/
void close();
-}
\ No newline at end of file
+
+ /**
+ * Initializes the interface and registers the callback routines with the HAL.
+ *
+ * @param options See Options definition.
+ */
+ void setCallbackWithOptions(in IGnssMeasurementCallback callback, in Options options);
+}
diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp
index 9e4f7c7..2c7241b 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.cpp
+++ b/gnss/aidl/default/GnssMeasurementInterface.cpp
@@ -56,11 +56,29 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus GnssMeasurementInterface::setCallbackWithOptions(
+ const std::shared_ptr<IGnssMeasurementCallback>& callback, const Options& options) {
+ ALOGD("setCallbackWithOptions: fullTracking:%d, corrVec:%d, intervalMs:%d",
+ (int)options.enableFullTracking, (int)options.enableCorrVecOutputs, options.intervalMs);
+ std::unique_lock<std::mutex> lock(mMutex);
+ sCallback = callback;
+
+ if (mIsActive) {
+ ALOGW("GnssMeasurement callback already set. Resetting the callback...");
+ stop();
+ }
+ mMinIntervalMillis = options.intervalMs;
+ start(options.enableCorrVecOutputs);
+
+ return ndk::ScopedAStatus::ok();
+}
+
ndk::ScopedAStatus GnssMeasurementInterface::close() {
ALOGD("close");
stop();
std::unique_lock<std::mutex> lock(mMutex);
sCallback = nullptr;
+ mMinIntervalMillis = 1000;
return ndk::ScopedAStatus::ok();
}
diff --git a/gnss/aidl/default/GnssMeasurementInterface.h b/gnss/aidl/default/GnssMeasurementInterface.h
index db63515..bf77806 100644
--- a/gnss/aidl/default/GnssMeasurementInterface.h
+++ b/gnss/aidl/default/GnssMeasurementInterface.h
@@ -32,6 +32,9 @@
const bool enableFullTracking,
const bool enableCorrVecOutputs) override;
ndk::ScopedAStatus close() override;
+ ndk::ScopedAStatus setCallbackWithOptions(
+ const std::shared_ptr<IGnssMeasurementCallback>& callback,
+ const Options& options) override;
private:
void start(const bool enableCorrVecOutputs);
diff --git a/gnss/aidl/vts/gnss_hal_test_cases.cpp b/gnss/aidl/vts/gnss_hal_test_cases.cpp
index 3aa308f..9acef8b 100644
--- a/gnss/aidl/vts/gnss_hal_test_cases.cpp
+++ b/gnss/aidl/vts/gnss_hal_test_cases.cpp
@@ -927,3 +927,42 @@
status = iGnssVisibilityControl->enableNfwLocationAccess(proxyApps);
ASSERT_TRUE(status.isOk());
}
+
+/*
+ * TestGnssMeasurementSetCallbackWithOptions:
+ * 1. Gets the GnssMeasurementExtension and verifies that it returns a non-null extension.
+ * 2. Sets a GnssMeasurementCallback with intervalMillis option, waits for measurements reported,
+ * and verifies mandatory fields are valid.
+ */
+TEST_P(GnssHalTest, TestGnssMeasurementSetCallbackWithOptions) {
+ if (aidl_gnss_hal_->getInterfaceVersion() == 1) {
+ return;
+ }
+ const int kFirstGnssMeasurementTimeoutSeconds = 10;
+ const int kNumMeasurementEvents = 5;
+
+ sp<IGnssMeasurementInterface> iGnssMeasurement;
+ auto status = aidl_gnss_hal_->getExtensionGnssMeasurement(&iGnssMeasurement);
+ ASSERT_TRUE(status.isOk());
+ ASSERT_TRUE(iGnssMeasurement != nullptr);
+
+ auto callback = sp<GnssMeasurementCallbackAidl>::make();
+ IGnssMeasurementInterface::Options options;
+ options.intervalMs = 2000;
+ status = iGnssMeasurement->setCallbackWithOptions(callback, options);
+ ASSERT_TRUE(status.isOk());
+
+ for (int i = 0; i < kNumMeasurementEvents; i++) {
+ GnssData lastMeasurement;
+ ASSERT_TRUE(callback->gnss_data_cbq_.retrieve(lastMeasurement,
+ kFirstGnssMeasurementTimeoutSeconds));
+ EXPECT_EQ(callback->gnss_data_cbq_.calledCount(), i + 1);
+ ASSERT_TRUE(lastMeasurement.measurements.size() > 0);
+
+ // Validity check GnssData fields
+ CheckGnssMeasurementClockFields(lastMeasurement);
+ }
+
+ status = iGnssMeasurement->close();
+ ASSERT_TRUE(status.isOk());
+}
diff --git a/health/aidl/default/Android.bp b/health/aidl/default/Android.bp
index 8aa7638..8eab997 100644
--- a/health/aidl/default/Android.bp
+++ b/health/aidl/default/Android.bp
@@ -120,6 +120,15 @@
},
}
+// Users of libhealth_aidl_impl should use this defaults.
+cc_defaults {
+ name: "libhealth_aidl_impl_user",
+ defaults: [
+ "libhealth_aidl_common_defaults",
+ "libhealth_aidl_charger_defaults",
+ ],
+}
+
// AIDL version of android.hardware.health@2.1-service.
// Default binder service of the health HAL.
cc_defaults {
@@ -127,8 +136,7 @@
relative_install_path: "hw",
vintf_fragments: ["android.hardware.health-service.example.xml"],
defaults: [
- "libhealth_aidl_common_defaults",
- "libhealth_aidl_charger_defaults",
+ "libhealth_aidl_impl_user",
],
static_libs: [
"libhealth_aidl_impl",
diff --git a/neuralnetworks/OWNERS b/neuralnetworks/OWNERS
index def3ea9..04c5d72 100644
--- a/neuralnetworks/OWNERS
+++ b/neuralnetworks/OWNERS
@@ -1,10 +1,2 @@
# Bug component: 195575
-# Neuralnetworks team
-butlermichael@google.com
-dgross@google.com
-galarragas@google.com
-ianhua@google.com
-jeanluc@google.com
-miaowang@google.com
-pszczepaniak@google.com
-xusongw@google.com
+include platform/packages/modules/NeuralNetworks:/NNAPI_OWNERS # Neuralnetworks team
diff --git a/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl b/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
index a1c3c27..b5cf633 100644
--- a/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
+++ b/radio/aidl/android/hardware/radio/config/SimSlotStatus.aidl
@@ -42,7 +42,13 @@
*/
String eid;
/**
- * PortInfo contains the ICCID, logical slot ID, and port state
+ * PortInfo contains the ICCID, logical slot ID, and port state.
+ * Cardstate has no relationship with whether the slot is active or inactive. Should always
+ * report up at least 1 port otherwise the logicalSlotIndex and portActive info will be lost.
+ * For example, the pSIM can be removed, but the slot can still be active. In that case, the
+ * SIM_STATUS reported for the corresponding logical stack will show CARDSTATE_ABSENT.
+ * Similarly, even if there is no profile enabled on the eSIM, that port can still be the
+ * active port in the slot mapping.
*/
SimPortInfo[] portInfo;
}
diff --git a/radio/aidl/android/hardware/radio/sim/IRadioSim.aidl b/radio/aidl/android/hardware/radio/sim/IRadioSim.aidl
index c731caf..7923b14 100644
--- a/radio/aidl/android/hardware/radio/sim/IRadioSim.aidl
+++ b/radio/aidl/android/hardware/radio/sim/IRadioSim.aidl
@@ -205,6 +205,12 @@
* Open a new logical channel and select the given application. This command
* reflects TS 27.007 "open logical channel" operation (+CCHO).
*
+ * For MEP-A(Multiple enabled profile), only dedicated port 0 is ISDR selectable.
+ * e.g., Port0 - for ISDR access and Port1/Port2 - the currently active ports/subscriptions.
+ * Port 0 should be transparent to AP and iccLogicalChannel API should remain the same.
+ * Even if the ISDR request comes over port1 or port2, Modem would just internally convert the
+ * portID to port0 and add the real port index as the payload of MANAGE_CHANNEL command.
+ *
* @param serial Serial number of request.
* @param aid AID value, See ETSI 102.221 and 101.220.
* @param p2 P2 value, described in ISO 7816-4. Ignore if equal to RadioConst:P2_CONSTANT_NO_P2
diff --git a/sensors/aidl/Android.bp b/sensors/aidl/Android.bp
new file mode 100644
index 0000000..fd1ac44
--- /dev/null
+++ b/sensors/aidl/Android.bp
@@ -0,0 +1,25 @@
+// This is the expected build file, but it may not be right in all cases
+
+aidl_interface {
+ name: "android.hardware.sensors",
+ vendor_available: true,
+ srcs: ["android/hardware/sensors/*.aidl"],
+ imports: [
+ "android.hardware.common-V2",
+ "android.hardware.common.fmq-V1",
+ ],
+ stability: "vintf",
+ backend: {
+ cpp: {
+ enabled: false,
+ },
+ java: {
+ enabled: false,
+ },
+ ndk: {
+ vndk: {
+ enabled: true,
+ },
+ },
+ },
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/AdditionalInfo.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/AdditionalInfo.aidl
new file mode 100644
index 0000000..5184723
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/AdditionalInfo.aidl
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.sensors;
+@FixedSize @VintfStability
+parcelable AdditionalInfo {
+ android.hardware.sensors.AdditionalInfo.AdditionalInfoType type;
+ int serial;
+ android.hardware.sensors.AdditionalInfo.AdditionalInfoPayload payload;
+ @FixedSize @VintfStability
+ union AdditionalInfoPayload {
+ android.hardware.sensors.AdditionalInfo.AdditionalInfoPayload.Int32Values dataInt32;
+ android.hardware.sensors.AdditionalInfo.AdditionalInfoPayload.FloatValues dataFloat;
+ @FixedSize @VintfStability
+ parcelable Int32Values {
+ int[14] values;
+ }
+ @FixedSize @VintfStability
+ parcelable FloatValues {
+ float[14] values;
+ }
+ }
+ @Backing(type="int") @VintfStability
+ enum AdditionalInfoType {
+ AINFO_BEGIN = 0,
+ AINFO_END = 1,
+ AINFO_UNTRACKED_DELAY = 65536,
+ AINFO_INTERNAL_TEMPERATURE = 65537,
+ AINFO_VEC3_CALIBRATION = 65538,
+ AINFO_SENSOR_PLACEMENT = 65539,
+ AINFO_SAMPLING = 65540,
+ AINFO_CHANNEL_NOISE = 131072,
+ AINFO_CHANNEL_SAMPLER = 131073,
+ AINFO_CHANNEL_FILTER = 131074,
+ AINFO_CHANNEL_LINEAR_TRANSFORM = 131075,
+ AINFO_CHANNEL_NONLINEAR_MAP = 131076,
+ AINFO_CHANNEL_RESAMPLER = 131077,
+ AINFO_LOCAL_GEOMAGNETIC_FIELD = 196608,
+ AINFO_LOCAL_GRAVITY = 196609,
+ AINFO_DOCK_STATE = 196610,
+ AINFO_HIGH_PERFORMANCE_MODE = 196611,
+ AINFO_MAGNETIC_FIELD_CALIBRATION = 196612,
+ AINFO_CUSTOM_START = 268435456,
+ AINFO_DEBUGGING_START = 1073741824,
+ }
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/DynamicSensorInfo.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/DynamicSensorInfo.aidl
new file mode 100644
index 0000000..0c9a493
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/DynamicSensorInfo.aidl
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.sensors;
+@FixedSize @VintfStability
+parcelable DynamicSensorInfo {
+ boolean connected;
+ int sensorHandle;
+ android.hardware.sensors.DynamicSensorInfo.Uuid uuid;
+ @FixedSize @VintfStability
+ parcelable Uuid {
+ byte[16] values;
+ }
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/Event.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/Event.aidl
new file mode 100644
index 0000000..186b2be
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/Event.aidl
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.sensors;
+@FixedSize @VintfStability
+parcelable Event {
+ long timestamp;
+ int sensorHandle;
+ android.hardware.sensors.SensorType sensorType;
+ android.hardware.sensors.Event.EventPayload payload;
+ @FixedSize @VintfStability
+ union EventPayload {
+ android.hardware.sensors.Event.EventPayload.Vec3 vec3;
+ android.hardware.sensors.Event.EventPayload.Vec4 vec4;
+ android.hardware.sensors.Event.EventPayload.Uncal uncal;
+ android.hardware.sensors.Event.EventPayload.MetaData meta;
+ float scalar;
+ long stepCount;
+ android.hardware.sensors.Event.EventPayload.HeartRate heartRate;
+ android.hardware.sensors.Event.EventPayload.Pose6Dof pose6DOF;
+ android.hardware.sensors.DynamicSensorInfo dynamic;
+ android.hardware.sensors.AdditionalInfo additional;
+ android.hardware.sensors.Event.EventPayload.Data data;
+ @FixedSize @VintfStability
+ parcelable Vec4 {
+ float x;
+ float y;
+ float z;
+ float w;
+ }
+ @FixedSize @VintfStability
+ parcelable Vec3 {
+ float x;
+ float y;
+ float z;
+ android.hardware.sensors.SensorStatus status;
+ }
+ @FixedSize @VintfStability
+ parcelable Uncal {
+ float x;
+ float y;
+ float z;
+ float xBias;
+ float yBias;
+ float zBias;
+ }
+ @FixedSize @VintfStability
+ parcelable HeartRate {
+ float bpm;
+ android.hardware.sensors.SensorStatus status;
+ }
+ @FixedSize @VintfStability
+ parcelable MetaData {
+ android.hardware.sensors.Event.EventPayload.MetaData.MetaDataEventType what;
+ @Backing(type="int") @VintfStability
+ enum MetaDataEventType {
+ META_DATA_FLUSH_COMPLETE = 1,
+ }
+ }
+ @FixedSize @VintfStability
+ parcelable Pose6Dof {
+ float[15] values;
+ }
+ @FixedSize @VintfStability
+ parcelable Data {
+ float[16] values;
+ }
+ }
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl
new file mode 100644
index 0000000..f60f5bb
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.sensors;
+@VintfStability
+interface ISensors {
+ void activate(in int sensorHandle, in boolean enabled);
+ void batch(in int sensorHandle, in long samplingPeriodNs, in long maxReportLatencyNs);
+ int configDirectReport(in int sensorHandle, in int channelHandle, in android.hardware.sensors.ISensors.RateLevel rate);
+ void flush(in int sensorHandle);
+ android.hardware.sensors.SensorInfo[] getSensorsList();
+ void initialize(in android.hardware.common.fmq.MQDescriptor<android.hardware.sensors.Event,android.hardware.common.fmq.SynchronizedReadWrite> eventQueueDescriptor, in android.hardware.common.fmq.MQDescriptor<int,android.hardware.common.fmq.SynchronizedReadWrite> wakeLockDescriptor, in android.hardware.sensors.ISensorsCallback sensorsCallback);
+ void injectSensorData(in android.hardware.sensors.Event event);
+ int registerDirectChannel(in android.hardware.sensors.ISensors.SharedMemInfo mem);
+ void setOperationMode(in android.hardware.sensors.ISensors.OperationMode mode);
+ void unregisterDirectChannel(in int channelHandle);
+ const int ERROR_NO_MEMORY = -12;
+ const int ERROR_BAD_VALUE = -22;
+ const int WAKE_LOCK_TIMEOUT_SECONDS = 1;
+ const int EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS = 1;
+ const int EVENT_QUEUE_FLAG_BITS_EVENTS_READ = 2;
+ const int WAKE_LOCK_QUEUE_FLAG_BITS_DATA_WRITTEN = 1;
+ const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_FIELD = 0;
+ const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_REPORT_TOKEN = 4;
+ const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_SENSOR_TYPE = 8;
+ const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_ATOMIC_COUNTER = 12;
+ const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_TIMESTAMP = 16;
+ const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_DATA = 24;
+ const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_RESERVED = 88;
+ const int DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH = 104;
+ @Backing(type="int") @VintfStability
+ enum RateLevel {
+ STOP = 0,
+ NORMAL = 1,
+ FAST = 2,
+ VERY_FAST = 3,
+ }
+ @Backing(type="int") @VintfStability
+ enum OperationMode {
+ NORMAL = 0,
+ DATA_INJECTION = 1,
+ }
+ @VintfStability
+ parcelable SharedMemInfo {
+ android.hardware.sensors.ISensors.SharedMemInfo.SharedMemType type;
+ android.hardware.sensors.ISensors.SharedMemInfo.SharedMemFormat format;
+ int size;
+ android.hardware.common.NativeHandle memoryHandle;
+ @Backing(type="int") @VintfStability
+ enum SharedMemFormat {
+ SENSORS_EVENT = 1,
+ }
+ @Backing(type="int") @VintfStability
+ enum SharedMemType {
+ ASHMEM = 1,
+ GRALLOC = 2,
+ }
+ }
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensorsCallback.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensorsCallback.aidl
new file mode 100644
index 0000000..78ab567
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensorsCallback.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.sensors;
+@VintfStability
+interface ISensorsCallback {
+ void onDynamicSensorsConnected(in android.hardware.sensors.SensorInfo[] sensorInfos);
+ void onDynamicSensorsDisconnected(in int[] sensorHandles);
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorInfo.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorInfo.aidl
new file mode 100644
index 0000000..996be3d
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorInfo.aidl
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.sensors;
+@VintfStability
+parcelable SensorInfo {
+ int sensorHandle;
+ String name;
+ String vendor;
+ int version;
+ android.hardware.sensors.SensorType type;
+ String typeAsString;
+ float maxRange;
+ float resolution;
+ float power;
+ int minDelayUs;
+ int fifoReservedEventCount;
+ int fifoMaxEventCount;
+ String requiredPermission;
+ int maxDelayUs;
+ int flags;
+ const int SENSOR_FLAG_BITS_WAKE_UP = 1;
+ const int SENSOR_FLAG_BITS_CONTINUOUS_MODE = 0;
+ const int SENSOR_FLAG_BITS_ON_CHANGE_MODE = 2;
+ const int SENSOR_FLAG_BITS_ONE_SHOT_MODE = 4;
+ const int SENSOR_FLAG_BITS_SPECIAL_REPORTING_MODE = 6;
+ const int SENSOR_FLAG_BITS_DATA_INJECTION = 16;
+ const int SENSOR_FLAG_BITS_DYNAMIC_SENSOR = 32;
+ const int SENSOR_FLAG_BITS_ADDITIONAL_INFO = 64;
+ const int SENSOR_FLAG_BITS_DIRECT_CHANNEL_ASHMEM = 1024;
+ const int SENSOR_FLAG_BITS_DIRECT_CHANNEL_GRALLOC = 2048;
+ const int SENSOR_FLAG_BITS_MASK_REPORTING_MODE = 14;
+ const int SENSOR_FLAG_BITS_MASK_DIRECT_REPORT = 896;
+ const int SENSOR_FLAG_BITS_MASK_DIRECT_CHANNEL = 3072;
+ const int SENSOR_FLAG_SHIFT_REPORTING_MODE = 1;
+ const int SENSOR_FLAG_SHIFT_DATA_INJECTION = 4;
+ const int SENSOR_FLAG_SHIFT_DYNAMIC_SENSOR = 5;
+ const int SENSOR_FLAG_SHIFT_ADDITIONAL_INFO = 6;
+ const int SENSOR_FLAG_SHIFT_DIRECT_REPORT = 7;
+ const int SENSOR_FLAG_SHIFT_DIRECT_CHANNEL = 10;
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorStatus.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorStatus.aidl
new file mode 100644
index 0000000..4521710
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorStatus.aidl
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.sensors;
+@Backing(type="byte") @VintfStability
+enum SensorStatus {
+ NO_CONTACT = -1,
+ UNRELIABLE = 0,
+ ACCURACY_LOW = 1,
+ ACCURACY_MEDIUM = 2,
+ ACCURACY_HIGH = 3,
+}
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorType.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorType.aidl
new file mode 100644
index 0000000..4f3b5b2
--- /dev/null
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/SensorType.aidl
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.sensors;
+@Backing(type="int") @VintfStability
+enum SensorType {
+ META_DATA = 0,
+ ACCELEROMETER = 1,
+ MAGNETIC_FIELD = 2,
+ ORIENTATION = 3,
+ GYROSCOPE = 4,
+ LIGHT = 5,
+ PRESSURE = 6,
+ PROXIMITY = 8,
+ GRAVITY = 9,
+ LINEAR_ACCELERATION = 10,
+ ROTATION_VECTOR = 11,
+ RELATIVE_HUMIDITY = 12,
+ AMBIENT_TEMPERATURE = 13,
+ MAGNETIC_FIELD_UNCALIBRATED = 14,
+ GAME_ROTATION_VECTOR = 15,
+ GYROSCOPE_UNCALIBRATED = 16,
+ SIGNIFICANT_MOTION = 17,
+ STEP_DETECTOR = 18,
+ STEP_COUNTER = 19,
+ GEOMAGNETIC_ROTATION_VECTOR = 20,
+ HEART_RATE = 21,
+ TILT_DETECTOR = 22,
+ WAKE_GESTURE = 23,
+ GLANCE_GESTURE = 24,
+ PICK_UP_GESTURE = 25,
+ WRIST_TILT_GESTURE = 26,
+ DEVICE_ORIENTATION = 27,
+ POSE_6DOF = 28,
+ STATIONARY_DETECT = 29,
+ MOTION_DETECT = 30,
+ HEART_BEAT = 31,
+ DYNAMIC_SENSOR_META = 32,
+ ADDITIONAL_INFO = 33,
+ LOW_LATENCY_OFFBODY_DETECT = 34,
+ ACCELEROMETER_UNCALIBRATED = 35,
+ HINGE_ANGLE = 36,
+ DEVICE_PRIVATE_BASE = 65536,
+}
diff --git a/sensors/aidl/android/hardware/sensors/AdditionalInfo.aidl b/sensors/aidl/android/hardware/sensors/AdditionalInfo.aidl
new file mode 100644
index 0000000..9fe2d39
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/AdditionalInfo.aidl
@@ -0,0 +1,234 @@
+/*
+ * 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.
+ */
+
+package android.hardware.sensors;
+
+@FixedSize
+@VintfStability
+parcelable AdditionalInfo {
+ /**
+ * type of payload data, see AdditionalInfoType
+ */
+ AdditionalInfoType type;
+
+ /**
+ * sequence number of this frame for this type
+ */
+ int serial;
+
+ AdditionalInfoPayload payload;
+
+ @FixedSize
+ @VintfStability
+ union AdditionalInfoPayload {
+ Int32Values dataInt32;
+ FloatValues dataFloat;
+
+ @FixedSize
+ @VintfStability
+ parcelable Int32Values {
+ int[14] values;
+ }
+
+ @FixedSize
+ @VintfStability
+ parcelable FloatValues {
+ float[14] values;
+ }
+ }
+
+ @VintfStability
+ @Backing(type="int")
+ enum AdditionalInfoType {
+ /**
+ * Marks the beginning of additional information frames
+ */
+ AINFO_BEGIN = 0,
+
+ /**
+ * Marks the end of additional information frames
+ */
+ AINFO_END = 1,
+
+ /**
+ * Estimation of the delay that is not tracked by sensor timestamps. This
+ * includes delay introduced by sensor front-end filtering, data transport,
+ * etc.
+ * float[2]: delay in seconds, standard deviation of estimated value
+ */
+ AINFO_UNTRACKED_DELAY = 0x10000,
+
+ /**
+ * float: Celsius temperature
+ */
+ AINFO_INTERNAL_TEMPERATURE,
+
+ /**
+ * First three rows of a homogeneous matrix, which represents calibration to
+ * a three-element vector raw sensor reading.
+ * float[12]: 3x4 matrix in row major order
+ */
+ AINFO_VEC3_CALIBRATION,
+
+ /**
+ * Provides the orientation and location of the sensor element in terms of
+ * the Android coordinate system. This data is given as a 3x4 matrix
+ * consisting of a 3x3 rotation matrix (R) concatenated with a 3x1 location
+ * vector (t). The rotation matrix provides the orientation of the Android
+ * device coordinate frame relative to the local coordinate frame of the
+ * sensor. Note that assuming the axes conventions of the sensor are the
+ * same as Android, this is the inverse of the matrix applied to raw
+ * samples read from the sensor to convert them into the Android
+ * representation. The location vector represents the translation from the
+ * origin of the Android sensor coordinate system to the geometric center
+ * of the sensor, specified in millimeters (mm).
+ *
+ * float[12]: 3x4 matrix in row major order [R; t]
+ *
+ * Example:
+ * This raw buffer: {0, 1, 0, 0, -1, 0, 0, 10, 0, 0, 1, -2.5}
+ * Corresponds to this 3x4 matrix:
+ * 0 1 0 0
+ * -1 0 0 10
+ * 0 0 1 -2.5
+ * The sensor is oriented such that:
+ * - the device X axis corresponds to the sensor's local -Y axis
+ * - the device Y axis corresponds to the sensor's local X axis
+ * - the device Z axis and sensor's local Z axis are equivalent
+ * In other words, if viewing the origin of the Android coordinate
+ * system from the positive Z direction, the device coordinate frame is
+ * to be rotated 90 degrees counter-clockwise about the Z axis to align
+ * with the sensor's local coordinate frame. Equivalently, a vector in
+ * the Android coordinate frame may be multiplied with R to rotate it
+ * 90 degrees clockwise (270 degrees counter-clockwise), yielding its
+ * representation in the sensor's coordinate frame.
+ * Relative to the origin of the Android coordinate system, the physical
+ * center of the sensor is located 10mm in the positive Y direction, and
+ * 2.5mm in the negative Z direction.
+ */
+ AINFO_SENSOR_PLACEMENT,
+
+ /**
+ * float[2]: raw sample period in seconds,
+ * standard deviation of sampling period
+ */
+ AINFO_SAMPLING,
+
+ /**
+ * int32_t: noise type
+ * float[n]: parameters
+ */
+ AINFO_CHANNEL_NOISE = 0x20000,
+
+ /**
+ * float[3]: sample period, standard deviation of sample period,
+ * quantization unit
+ */
+ AINFO_CHANNEL_SAMPLER,
+
+ /**
+ * Represents a filter:
+ * \sum_j a_j y[n-j] == \sum_i b_i x[n-i]
+ *
+ * int32_t[3]: number of feedforward coeffients M,
+ * number of feedback coefficients N (for FIR filter, N = 1).
+ * bit mask that represents which element the filter is applied
+ * to. (bit 0==1 means this filter applies to vector element 0).
+ * float[M+N]: filter coefficients (b0, b1, ..., b_{M-1}), then
+ * (a0, a1, ..., a_{N-1}), a0 is always 1.
+ *
+ * Multiple frames may be needed for higher number of taps.
+ */
+ AINFO_CHANNEL_FILTER,
+
+ /**
+ * int32_t[2]: size in (row, column) ... 1st frame
+ * float[n]: matrix element values in row major order.
+ */
+ AINFO_CHANNEL_LINEAR_TRANSFORM,
+
+ /**
+ * int32_t[2]: extrapolate method, interpolate method
+ * float[n]: mapping key points in pairs, (in, out)...
+ * (may be used to model saturation).
+ */
+ AINFO_CHANNEL_NONLINEAR_MAP,
+
+ /**
+ * int32_t: resample method (0-th order, 1st order...)
+ * float[1]: resample ratio (upsampling if < 1.0, downsampling if > 1.0).
+ */
+ AINFO_CHANNEL_RESAMPLER,
+
+ /**
+ * Operation environment parameters section
+ * Types in the following section is sent down (instead of reported from)
+ * device as additional information to aid sensor operation. Data is sent
+ * via injectSensorData() function to sensor handle -1 denoting all sensors
+ * in device.
+ *
+ *
+ * Local geomagnetic field information based on device geo location. This
+ * type is primarily for for magnetic field calibration and rotation vector
+ * sensor fusion.
+ * float[3]: strength (uT), declination and inclination angle (rad).
+ */
+ AINFO_LOCAL_GEOMAGNETIC_FIELD = 0x30000,
+
+ /**
+ * Local gravitational acceleration strength at device geo location.
+ * float: gravitational acceleration norm in m/s^2.
+ */
+ AINFO_LOCAL_GRAVITY,
+
+ /**
+ * Device dock state.
+ * int32_t: dock state following Android API Intent.EXTRA_DOCK_STATE
+ * definition, undefined value is ignored.
+ */
+ AINFO_DOCK_STATE,
+
+ /**
+ * High performance mode hint. Device is able to use up more power and take
+ * more resources to improve throughput and latency in high performance mode.
+ * One possible use case is virtual reality, when sensor latency need to be
+ * carefully controlled.
+ * int32_t: 1 or 0, denote if device is in/out of high performance mode,
+ * other values is ignored.
+ */
+ AINFO_HIGH_PERFORMANCE_MODE,
+
+ /**
+ * Magnetic field calibration hint. Device is notified when manually
+ * triggered magnetic field calibration procedure is started or stopped. The
+ * calibration procedure is assumed timed out after 1 minute from start,
+ * even if an explicit stop is not received.
+ *
+ * int32_t: 1 for start, 0 for stop, other value is ignored.
+ */
+ AINFO_MAGNETIC_FIELD_CALIBRATION,
+
+ /**
+ * Custom information
+ */
+ AINFO_CUSTOM_START = 0x10000000,
+
+ /**
+ * Debugging
+ */
+ AINFO_DEBUGGING_START = 0x40000000,
+ }
+}
diff --git a/sensors/aidl/android/hardware/sensors/DynamicSensorInfo.aidl b/sensors/aidl/android/hardware/sensors/DynamicSensorInfo.aidl
new file mode 100644
index 0000000..4b14ed0
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/DynamicSensorInfo.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+package android.hardware.sensors;
+
+@VintfStability
+@FixedSize
+parcelable DynamicSensorInfo {
+ boolean connected;
+
+ int sensorHandle;
+
+ /**
+ * UUID of a dynamic sensor (using RFC 4122 byte order)
+ * For UUID 12345678-90AB-CDEF-1122-334455667788 the uuid field is
+ * initialized as:
+ * {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x11, ...}
+ */
+ Uuid uuid;
+
+ @FixedSize
+ @VintfStability
+ parcelable Uuid {
+ byte[16] values;
+ }
+}
diff --git a/sensors/aidl/android/hardware/sensors/Event.aidl b/sensors/aidl/android/hardware/sensors/Event.aidl
new file mode 100644
index 0000000..6ef9acb
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/Event.aidl
@@ -0,0 +1,198 @@
+/*
+ * 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.
+ */
+
+package android.hardware.sensors;
+
+import android.hardware.sensors.AdditionalInfo;
+import android.hardware.sensors.DynamicSensorInfo;
+import android.hardware.sensors.SensorStatus;
+import android.hardware.sensors.SensorType;
+
+@VintfStability
+@FixedSize
+parcelable Event {
+ /**
+ * Time measured in nanoseconds, in "elapsedRealtimeNano()'s" timebase.
+ */
+ long timestamp;
+
+ /**
+ * sensor identifier
+ */
+ int sensorHandle;
+
+ SensorType sensorType;
+
+ /**
+ * Union discriminated on sensorType
+ */
+ EventPayload payload;
+
+ /*
+ * acceleration values are in meter per second per second (m/s^2)
+ * magnetic vector values are in micro-Tesla (uT)
+ * orientation values are in degrees
+ * gyroscope values are in rad/s
+ * temperature is in degrees centigrade (Celsius)
+ * distance in centimeters
+ * light in SI lux units
+ * pressure in hectopascal (hPa)
+ * relative humidity in percent
+ */
+ @VintfStability
+ @FixedSize
+ union EventPayload {
+ /**
+ * SensorType::ACCELEROMETER, SensorType::MAGNETIC_FIELD,
+ * SensorType::ORIENTATION, SensorType::GYROSCOPE, SensorType::GRAVITY,
+ * SensorType::LINEAR_ACCELERATION
+ */
+ Vec3 vec3;
+
+ /**
+ * SensorType::GAME_ROTATION_VECTOR
+ */
+ Vec4 vec4;
+
+ /**
+ * SensorType::MAGNETIC_FIELD_UNCALIBRATED,
+ * SensorType::GYROSCOPE_UNCALIBRATED
+ * SensorType::ACCELEROMETER_UNCALIBRATED
+ */
+ Uncal uncal;
+
+ /**
+ * SensorType::META_DATA
+ */
+ MetaData meta;
+
+ /**
+ * SensorType::DEVICE_ORIENTATION, SensorType::LIGHT, SensorType::PRESSURE,
+ * SensorType::TEMPERATURE, SensorType::PROXIMITY,
+ * SensorType::RELATIVE_HUMIDITY, SensorType::AMBIENT_TEMPERATURE,
+ * SensorType::SIGNIFICANT_MOTION, SensorType::STEP_DETECTOR,
+ * SensorType::TILT_DETECTOR, SensorType::WAKE_GESTURE,
+ * SensorType::GLANCE_GESTURE, SensorType::PICK_UP_GESTURE,
+ * SensorType::WRIST_TILT_GESTURE, SensorType::STATIONARY_DETECT,
+ * SensorType::MOTION_DETECT, SensorType::HEART_BEAT,
+ * SensorType::LOW_LATENCY_OFFBODY_DETECT
+ */
+ float scalar;
+
+ /**
+ * SensorType::STEP_COUNTER
+ */
+ long stepCount;
+
+ /**
+ * SensorType::HEART_RATE
+ */
+ HeartRate heartRate;
+
+ /**
+ * SensorType::POSE_6DOF
+ */
+ Pose6Dof pose6DOF;
+
+ /**
+ * SensorType::DYNAMIC_SENSOR_META
+ */
+ DynamicSensorInfo dynamic;
+
+ /**
+ * SensorType::ADDITIONAL_INFO
+ */
+ AdditionalInfo additional;
+
+ /**
+ * The following sensors should use the data field:
+ * - Undefined/custom sensor type >= SensorType::DEVICE_PRIVATE_BASE
+ * - SensorType::ROTATION_VECTOR, SensorType::GEOMAGNETIC_ROTATION_VECTOR:
+ * - These are Vec4 types with an additional float accuracy field,
+ * where data[4] is the estimated heading accuracy in radians
+ * (-1 if unavailable, and invalid if not in the range (0, 2 * pi]).
+ */
+ Data data;
+
+ @FixedSize
+ @VintfStability
+ parcelable Vec4 {
+ float x;
+ float y;
+ float z;
+ float w;
+ }
+
+ @FixedSize
+ @VintfStability
+ parcelable Vec3 {
+ float x;
+ float y;
+ float z;
+ SensorStatus status;
+ }
+
+ @FixedSize
+ @VintfStability
+ parcelable Uncal {
+ float x;
+ float y;
+ float z;
+ float xBias;
+ float yBias;
+ float zBias;
+ }
+
+ @FixedSize
+ @VintfStability
+ parcelable HeartRate {
+ /**
+ * Heart rate in beats per minute.
+ * Set to 0 when status is SensorStatus::UNRELIABLE or
+ * SensorStatus::NO_CONTACT
+ */
+ float bpm;
+ /**
+ * Status of the heart rate sensor for this reading.
+ */
+ SensorStatus status;
+ }
+
+ @FixedSize
+ @VintfStability
+ parcelable MetaData {
+ MetaDataEventType what;
+
+ @VintfStability
+ @Backing(type="int")
+ enum MetaDataEventType {
+ META_DATA_FLUSH_COMPLETE = 1,
+ }
+ }
+
+ @FixedSize
+ @VintfStability
+ parcelable Pose6Dof {
+ float[15] values;
+ }
+
+ @FixedSize
+ @VintfStability
+ parcelable Data {
+ float[16] values;
+ }
+ }
+}
diff --git a/sensors/aidl/android/hardware/sensors/ISensors.aidl b/sensors/aidl/android/hardware/sensors/ISensors.aidl
new file mode 100644
index 0000000..2ac1884
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/ISensors.aidl
@@ -0,0 +1,375 @@
+/*
+ * 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.
+ */
+
+package android.hardware.sensors;
+
+import android.hardware.common.NativeHandle;
+import android.hardware.common.fmq.MQDescriptor;
+import android.hardware.common.fmq.SynchronizedReadWrite;
+import android.hardware.sensors.Event;
+import android.hardware.sensors.ISensorsCallback;
+import android.hardware.sensors.SensorInfo;
+
+@VintfStability
+interface ISensors {
+ /**
+ * Activate/de-activate one sensor.
+ *
+ * After sensor de-activation, existing sensor events that have not
+ * been written to the event queue must be abandoned immediately so that
+ * subsequent activations do not get stale sensor events (events
+ * that are generated prior to the latter activation).
+ *
+ * @param sensorHandle is the handle of the sensor to change.
+ * @param enabled set to true to enable, or false to disable the sensor.
+ * @return Status::ok on success
+ * EX_ILLEGAL_ARGUMENT if the sensorHandle is invalid.
+ */
+ void activate(in int sensorHandle, in boolean enabled);
+
+ /**
+ * Sets a sensor’s parameters, including sampling frequency and maximum
+ * report latency. This function can be called while the sensor is
+ * activated, in which case it must not cause any sensor measurements to
+ * be lost: transitioning from one sampling rate to the other cannot cause
+ * lost events, nor can transitioning from a high maximum report latency to
+ * a low maximum report latency.
+ *
+ * @param sensorHandle handle of sensor to be changed.
+ * @param samplingPeriodNs specifies sensor sample period in nanoseconds.
+ * @param maxReportLatencyNs allowed delay time before an event is sampled
+ * to time of report.
+ * @return Status::ok on success
+ * EX_ILLEGAL_ARGUMENT if any parameters are invalid.
+ */
+ void batch(in int sensorHandle, in long samplingPeriodNs, in long maxReportLatencyNs);
+
+ /**
+ * Configure direct sensor event report in direct channel.
+ *
+ * This function start, modify rate or stop direct report of a sensor in a
+ * certain direct channel.
+ *
+ * @param sensorHandle handle of sensor to be configured. When combined
+ * with STOP rate, sensorHandle can be -1 to denote all active sensors
+ * in the direct channel specified by channel Handle.
+ * @param channelHandle handle of direct channel to be configured.
+ * @param rate rate level, see RateLevel enum.
+ * @param out reportToken The report token, ignored if rate is STOP.
+ * See SharedMemFormat.
+ * @return The direct report token to identify multiple sensors of the same type in a single
+ * direct channel.
+ * @return Status::ok on success
+ * EX_ILLEGAL_ARGUMENT if the parameter is invalid (e.g. unsupported rate level
+ * for sensor, channelHandle does not exist, etc).
+ * EX_UNSUPPORTED_OPERATION if this functionality is unsupported.
+ */
+ int configDirectReport(in int sensorHandle, in int channelHandle, in RateLevel rate);
+
+ /**
+ * Trigger a flush of internal FIFO.
+ *
+ * Flush adds a FLUSH_COMPLETE metadata event to the end of the "batch mode"
+ * FIFO for the specified sensor and flushes the FIFO. If the FIFO is empty
+ * or if the sensor doesn't support batching (FIFO size zero), return
+ * SUCCESS and add a trivial FLUSH_COMPLETE event added to the event stream.
+ * This applies to all sensors other than one-shot sensors. If the sensor
+ * is a one-shot sensor, flush must return EX_ILLEGAL_ARGUMENT and not generate any
+ * flush complete metadata. If the sensor is not active at the time flush()
+ * is called, flush() return EX_ILLEGAL_ARGUMENT.
+ *
+ * @param sensorHandle handle of sensor to be flushed.
+ * @return Status::ok on success
+ * EX_ILLEGAL_ARGUMENT if the sensorHandle is invalid.
+ */
+ void flush(in int sensorHandle);
+
+ /**
+ * Enumerate all available (static) sensors.
+ *
+ * The SensorInfo for each sensor returned by getSensorsList must be stable
+ * from the initial call to getSensorsList after a device boot until the
+ * entire system restarts. The SensorInfo for each sensor must not change
+ * between subsequent calls to getSensorsList, even across restarts of the
+ * HAL and its dependencies (for example, the sensor handle for a given
+ * sensor must not change across HAL restarts).
+ */
+ SensorInfo[] getSensorsList();
+
+ /**
+ * Initialize the Sensors HAL's Fast Message Queues (FMQ) and callback.
+ *
+ * The Fast Message Queues (FMQ) that are used to send data between the
+ * framework and the HAL. The callback is used by the HAL to notify the
+ * framework of asynchronous events, such as a dynamic sensor connection.
+ *
+ * The Event FMQ is used to transport sensor events from the HAL to the
+ * framework. The Event FMQ is created using the eventQueueDescriptor.
+ * Data may only be written to the Event FMQ. Data must not be read from
+ * the Event FMQ since the framework is the only reader. Upon receiving
+ * sensor events, the HAL writes the sensor events to the Event FMQ.
+ *
+ * Once the HAL is finished writing sensor events to the Event FMQ, the HAL
+ * must notify the framework that sensor events are available to be read and
+ * processed. This is accomplished by either:
+ * 1) Calling the Event FMQ’s EventFlag::wake() function with
+ * EventQueueFlagBits::READ_AND_PROCESS
+ * 2) Setting the write notification in the Event FMQ’s writeBlocking()
+ * function to EventQueueFlagBits::READ_AND_PROCESS.
+ *
+ * If the Event FMQ’s writeBlocking() function is used, the read
+ * notification must be set to EventQueueFlagBits::EVENTS_READ in order to
+ * be notified and unblocked when the framework has successfully read events
+ * from the Event FMQ.
+ *
+ * The Wake Lock FMQ is used by the framework to notify the HAL when it is
+ * safe to release its wake_lock. When the framework receives WAKE_UP events
+ * from the Event FMQ and the framework has acquired a wake_lock, the
+ * framework must write the number of WAKE_UP events processed to the Wake
+ * Lock FMQ. When the HAL reads the data from the Wake Lock FMQ, the HAL
+ * decrements its current count of unprocessed WAKE_UP events and releases
+ * its wake_lock if the current count of unprocessed WAKE_UP events is
+ * zero. It is important to note that the HAL must acquire the wake lock and
+ * update its internal state regarding the number of outstanding WAKE_UP
+ * events _before_ posting the event to the Wake Lock FMQ, in order to avoid
+ * a race condition that can lead to loss of wake lock synchronization with
+ * the framework.
+ *
+ * The framework must use the WAKE_LOCK_QUEUE_FLAG_BITS_DATA_WRITTEN value to
+ * notify the HAL that data has been written to the Wake Lock FMQ and must
+ * be read by HAL.
+ *
+ * The ISensorsCallback is used by the HAL to notify the framework of
+ * asynchronous events, such as a dynamic sensor connection.
+ *
+ * The name of any wake_lock acquired by the Sensors HAL for WAKE_UP events
+ * must begin with "SensorsHAL_WAKEUP".
+ *
+ * If WAKE_LOCK_TIMEOUT_SECONDS has elapsed since the most recent WAKE_UP
+ * event was written to the Event FMQ without receiving a message on the
+ * Wake Lock FMQ, then any held wake_lock for WAKE_UP events must be
+ * released.
+ *
+ * If either the Event FMQ or the Wake Lock FMQ is already initialized when
+ * initialize is invoked, then both existing FMQs must be discarded and the
+ * new descriptors must be used to create new FMQs within the HAL. The
+ * number of outstanding WAKE_UP events should also be reset to zero, and
+ * any outstanding wake_locks held as a result of WAKE_UP events should be
+ * released.
+ *
+ * All active sensor requests and direct channels must be closed and
+ * properly cleaned up when initialize is called in order to ensure that the
+ * HAL and framework's state is consistent (e.g. after a runtime restart).
+ *
+ * initialize must be thread safe and prevent concurrent calls
+ * to initialize from simultaneously modifying state.
+ *
+ * @param eventQueueDescriptor Fast Message Queue descriptor that is used to
+ * create the Event FMQ which is where sensor events are written. The
+ * descriptor is obtained from the framework's FMQ that is used to read
+ * sensor events.
+ * @param wakeLockDescriptor Fast Message Queue descriptor that is used to
+ * create the Wake Lock FMQ which is where wake_lock events are read
+ * from. The descriptor is obtained from the framework's FMQ that is
+ * used to write wake_lock events.
+ * @param sensorsCallback sensors callback that receives asynchronous data
+ * from the Sensors HAL.
+ * @return Status::ok on success
+ * EX_ILLEGAL_ARGUMENT if the descriptor is invalid (such as null).
+ */
+ void initialize(in MQDescriptor<Event, SynchronizedReadWrite> eventQueueDescriptor,
+ in MQDescriptor<int, SynchronizedReadWrite> wakeLockDescriptor,
+ in ISensorsCallback sensorsCallback);
+
+ /**
+ * Inject a single sensor event or push operation environment parameters to
+ * device.
+ *
+ * When device is in NORMAL mode, this function is called to push operation
+ * environment data to device. In this operation, Event is always of
+ * SensorType::AdditionalInfo type. See operation environment parameters
+ * section in AdditionalInfoType.
+ *
+ * When device is in DATA_INJECTION mode, this function is also used for
+ * injecting sensor events.
+ *
+ * Regardless of OperationMode, injected SensorType::ADDITIONAL_INFO
+ * type events should not be routed back to the sensor event queue.
+ *
+ * @see AdditionalInfoType
+ * @see OperationMode
+ * @param event sensor event to be injected
+ * @return Status::ok on success
+ * EX_UNSUPPORTED_OPERATION if this functionality is unsupported.
+ * EX_SECURITY if the operation is not allowed.
+ * EX_SERVICE_SPECIFIC on error
+ * - ERROR_BAD_VALUE if the sensor event cannot be injected.
+ */
+ void injectSensorData(in Event event);
+
+ /**
+ * Register direct report channel.
+ *
+ * Register a direct channel with supplied shared memory information. Upon
+ * return, the sensor hardware is responsible for resetting the memory
+ * content to initial value (depending on memory format settings).
+ *
+ * @param mem shared memory info data structure.
+ * @param out channelHandle The registered channel handle.
+ * @return The direct channel handle, which is positive if successfully registered, and -1
+ * otherwise.
+ * @return Status::ok on success
+ * EX_ILLEGAL_ARGUMENT if the shared memory information is not consistent.
+ * EX_UNSUPPORTED_OPERATION if this functionality is unsupported.
+ * EX_SERVICE_SPECIFIC on error
+ * - ERROR_NO_MEMORY if shared memory cannot be used by sensor system.
+ */
+ int registerDirectChannel(in SharedMemInfo mem);
+
+ /**
+ * Place the module in a specific mode.
+ *
+ * @see OperationMode
+ * @param mode The operation mode.
+ * @return Status::ok on success
+ * EX_UNSUPPORTED_OPERATION if requested mode is not supported.
+ * EX_SECURITY if the operation is not allowed.
+ */
+ void setOperationMode(in OperationMode mode);
+
+ /**
+ * Unregister direct report channel.
+ *
+ * Unregister a direct channel previously registered using
+ * registerDirectChannel, and remove all active sensor report configured in
+ * still active sensor report configured in the direct channel.
+ *
+ * @param channelHandle handle of direct channel to be unregistered.
+ * @return Status::ok on success
+ * EX_UNSUPPORTED_OPERATION if direct report is not supported.
+ */
+ void unregisterDirectChannel(in int channelHandle);
+
+ /**
+ * Direct report rate level definition. Except for SENSOR_DIRECT_RATE_STOP, each
+ * rate level covers the range (55%, 220%] * nominal report rate. For example,
+ * if config direct report specify a rate level SENSOR_DIRECT_RATE_FAST, it is
+ * legal for sensor hardware to report event at a rate greater than 110Hz, and
+ * less or equal to 440Hz. Note that rate has to remain steady without variation
+ * before new rate level is configured, i.e. if a sensor is configured to
+ * SENSOR_DIRECT_RATE_FAST and starts to report event at 256Hz, it cannot
+ * change rate to 128Hz after a few seconds of running even if 128Hz is also in
+ * the legal range of SENSOR_DIRECT_RATE_FAST. Thus, it is recommended to
+ * associate report rate with RateLvel statically for single sensor.
+ */
+ @VintfStability
+ @Backing(type="int")
+ enum RateLevel {
+ STOP,
+ NORMAL,
+ FAST,
+ VERY_FAST,
+ }
+
+ @VintfStability
+ @Backing(type="int")
+ enum OperationMode {
+ // Normal operation. Default state of the module.
+ NORMAL = 0,
+ // Loopback mode. Data is injected for the supported sensors by the sensor service in this
+ // mode.
+ DATA_INJECTION = 1,
+ }
+
+ @VintfStability
+ parcelable SharedMemInfo {
+ SharedMemType type;
+ SharedMemFormat format;
+ int size;
+ NativeHandle memoryHandle;
+
+ @VintfStability
+ @Backing(type="int")
+ enum SharedMemFormat {
+ SENSORS_EVENT = 1,
+ }
+
+ @VintfStability
+ @Backing(type="int")
+ enum SharedMemType {
+ ASHMEM = 1,
+ GRALLOC,
+ }
+ }
+
+ /**
+ * Error codes that are used as service specific errors with the AIDL return
+ * value EX_SERVICE_SPECIFIC.
+ */
+ const int ERROR_NO_MEMORY = -12;
+ const int ERROR_BAD_VALUE = -22;
+
+ /**
+ * The maximum number of seconds to wait for a message on the Wake Lock FMQ
+ * before automatically releasing any wake_lock held for a WAKE_UP event.
+ */
+ const int WAKE_LOCK_TIMEOUT_SECONDS = 1;
+
+ /**
+ * Used to notify the Event FMQ that events should be read and processed.
+ */
+ const int EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS = 1 << 0;
+
+ /**
+ * Used by the framework to signal to the HAL when events have been
+ * successfully read from the Event FMQ.
+ *
+ * If the MessageQueue::writeBlocking function is being used to write sensor
+ * events to the Event FMQ, then the readNotification parameter must be set
+ * to EVENTS_READ.
+ */
+ const int EVENT_QUEUE_FLAG_BITS_EVENTS_READ = 1 << 1;
+
+ /**
+ * Used to notify the HAL that the framework has written data to the Wake
+ * Lock FMQ.
+ */
+ const int WAKE_LOCK_QUEUE_FLAG_BITS_DATA_WRITTEN = 1 << 0;
+
+ /**
+ * Constants related to direct sensor events. The following table illustrates the
+ * data format.
+ *
+ * Offset Type Name
+ * -----------------------------------
+ * 0x0000 int32_t Size (always DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH)
+ * 0x0004 int32_t Sensor report token
+ * 0x0008 int32_t Type (see SensorType.aidl)
+ * 0x000C uint32_t Atomic counter
+ * 0x0010 int64_t Timestamp (see Event.aidl)
+ * 0x0018 float[16]/ Data
+ * int64_t[8]
+ * 0x0058 int32_t[4] Reserved (set to zero)
+ */
+ const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_FIELD = 0x0;
+ const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_REPORT_TOKEN = 0x4;
+ const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_SENSOR_TYPE = 0x8;
+ const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_ATOMIC_COUNTER = 0xC;
+ const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_TIMESTAMP = 0x10;
+ const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_DATA = 0x18;
+ const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_RESERVED = 0x58;
+ const int DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH = 104;
+}
diff --git a/sensors/aidl/android/hardware/sensors/ISensorsCallback.aidl b/sensors/aidl/android/hardware/sensors/ISensorsCallback.aidl
new file mode 100644
index 0000000..01bae52
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/ISensorsCallback.aidl
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package android.hardware.sensors;
+
+import android.hardware.sensors.SensorInfo;
+
+@VintfStability
+interface ISensorsCallback {
+ /**
+ * Notify the framework that new dynamic sensors have been connected.
+ *
+ * If a dynamic sensor was previously connected and has not been
+ * disconnected, then that sensor must not be included in sensorInfos.
+ *
+ * @param sensorInfos vector of SensorInfo for each dynamic sensor that
+ * was connected.
+ */
+ void onDynamicSensorsConnected(in SensorInfo[] sensorInfos);
+
+ /**
+ * Notify the framework that previously connected dynamic sensors have been
+ * disconnected.
+ *
+ * If a dynamic sensor was previously disconnected and has not been
+ * reconnected, then that sensor must not be included in sensorHandles.
+ *
+ * The HAL must ensure that all sensor events from departing dynamic
+ * sensors have been written to the Event FMQ before calling
+ * onDynamicSensorsDisconnected.
+ *
+ * @param sensorHandles vector of sensor handles for each dynamic sensors
+ * that was disconnected.
+ */
+ void onDynamicSensorsDisconnected(in int[] sensorHandles);
+}
diff --git a/sensors/aidl/android/hardware/sensors/SensorInfo.aidl b/sensors/aidl/android/hardware/sensors/SensorInfo.aidl
new file mode 100644
index 0000000..35caf8b
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/SensorInfo.aidl
@@ -0,0 +1,217 @@
+/*
+ * 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.
+ */
+
+package android.hardware.sensors;
+
+import android.hardware.sensors.SensorType;
+
+@VintfStability
+parcelable SensorInfo {
+ /**
+ * handle that identifies this sensors. This handle is used to reference
+ * this sensor throughout the HAL API.
+ */
+ int sensorHandle;
+
+ /**
+ * Name of this sensor.
+ * All sensors of the same "type" must have a different "name".
+ */
+ String name;
+
+ /**
+ * vendor of the hardware part
+ */
+ String vendor;
+
+ /**
+ * version of the hardware part + driver. The value of this field
+ * must increase when the driver is updated in a way that changes the
+ * output of this sensor. This is important for fused sensors when the
+ * fusion algorithm is updated.
+ */
+ int version;
+
+ /**
+ * this sensor's type.
+ */
+ SensorType type;
+
+ /**
+ * type of this sensor as a string.
+ *
+ * When defining an OEM specific sensor or sensor manufacturer specific
+ * sensor, use your reserve domain name as a prefix.
+ * e.g. com.google.glass.onheaddetector
+ *
+ * For sensors of known type defined in SensorType (value <
+ * SensorType::DEVICE_PRIVATE_BASE), this can be an empty string.
+ */
+ String typeAsString;
+
+ /**
+ * maximum range of this sensor's value in SI units
+ */
+ float maxRange;
+
+ /**
+ * smallest difference between two values reported by this sensor
+ */
+ float resolution;
+
+ /**
+ * rough estimate of this sensor's power consumption in mA
+ */
+ float power;
+
+ /**
+ * this value depends on the reporting mode:
+ *
+ * continuous: minimum sample period allowed in microseconds
+ * on-change : 0
+ * one-shot :-1
+ * special : 0, unless otherwise noted
+ */
+ int minDelayUs;
+
+ /**
+ * number of events reserved for this sensor in the batch mode FIFO.
+ * If there is a dedicated FIFO for this sensor, then this is the
+ * size of this FIFO. If the FIFO is shared with other sensors,
+ * this is the size reserved for that sensor and it can be zero.
+ */
+ int fifoReservedEventCount;
+
+ /**
+ * maximum number of events of this sensor that could be batched.
+ * This is especially relevant when the FIFO is shared between
+ * several sensors; this value is then set to the size of that FIFO.
+ */
+ int fifoMaxEventCount;
+
+ /**
+ * permission required to see this sensor, register to it and receive data.
+ * Set to "" if no permission is required. Some sensor types like the
+ * heart rate monitor have a mandatory require_permission.
+ * For sensors that always require a specific permission, like the heart
+ * rate monitor, the android framework might overwrite this string
+ * automatically.
+ */
+ String requiredPermission;
+
+ /**
+ * This value is defined only for continuous mode and on-change sensors.
+ * It is the delay between two sensor events corresponding to the lowest
+ * frequency that this sensor supports. When lower frequencies are requested
+ * through batch()/setDelay() the events will be generated at this frequency
+ * instead.
+ * It can be used by the framework or applications to estimate when the
+ * batch FIFO may be full.
+ *
+ * continuous, on-change: maximum sampling period allowed in microseconds.
+ * one-shot, special : 0
+ */
+ int maxDelayUs;
+
+ /**
+ * Bitmasks defined in SENSOR_FLAG_BITS_* below.
+ */
+ int flags;
+
+ /**
+ * Whether this sensor wakes up the AP from suspend mode when data is
+ * available. Whenever sensor events are delivered from a wake_up sensor,
+ * the driver needs to hold a wake_lock till the events are read by the
+ * SensorService i.e. till ISensors::poll() is called the next time.
+ * Once poll is called again it means events have been read by the
+ * SensorService, the driver can safely release the wake_lock. SensorService
+ * will continue to hold a wake_lock till the app actually reads the events.
+ */
+ const int SENSOR_FLAG_BITS_WAKE_UP = 1;
+
+ /**
+ * Reporting modes for various sensors. Each sensor will have exactly one of
+ * these modes set.
+ * The least significant 2nd, 3rd and 4th bits are used to represent four
+ * possible reporting modes.
+ */
+ const int SENSOR_FLAG_BITS_CONTINUOUS_MODE = 0;
+ const int SENSOR_FLAG_BITS_ON_CHANGE_MODE = 2;
+ const int SENSOR_FLAG_BITS_ONE_SHOT_MODE = 4;
+ const int SENSOR_FLAG_BITS_SPECIAL_REPORTING_MODE = 6;
+
+ /**
+ * Set this flag if the sensor supports data_injection mode and allows data
+ * to be injected from the SensorService. When in data_injection ONLY
+ * sensors with this flag set are injected sensor data and only sensors with
+ * this flag set are activated. Eg: Accelerometer and Step Counter sensors
+ * can be set with this flag and SensorService will inject accelerometer
+ * data and read the corresponding step counts.
+ */
+ const int SENSOR_FLAG_BITS_DATA_INJECTION = 0x10;
+
+ /**
+ * Set this flag if the sensor is a dynamically connected sensor. See
+ * DynamicSensorInfo and DYNAMIC_SENSOR_META for details.
+ */
+ const int SENSOR_FLAG_BITS_DYNAMIC_SENSOR = 0x20;
+
+ /**
+ * Set this flag if sensor additional information is supported.
+ * See ADDITIONAL_INFO and AdditionalInfo for details.
+ */
+ const int SENSOR_FLAG_BITS_ADDITIONAL_INFO = 0x40;
+
+ /**
+ * Set this flag if sensor suppor direct channel backed by ashmem.
+ * See SharedMemType and registerDirectChannel for more details.
+ */
+ const int SENSOR_FLAG_BITS_DIRECT_CHANNEL_ASHMEM = 0x400;
+
+ /**
+ * Set this flag if sensor suppor direct channel backed by gralloc HAL memory.
+ * See SharedMemType and registerDirectChannel for more details.
+ */
+ const int SENSOR_FLAG_BITS_DIRECT_CHANNEL_GRALLOC = 0x800;
+
+ /**
+ * Flags mask for reporting mode of sensor.
+ */
+ const int SENSOR_FLAG_BITS_MASK_REPORTING_MODE = 0xE;
+
+ /**
+ * Flags mask for direct report maximum rate level support.
+ * See RateLevel.
+ */
+ const int SENSOR_FLAG_BITS_MASK_DIRECT_REPORT = 0x380;
+
+ /**
+ * Flags mask for all direct channel support bits.
+ * See SharedMemType.
+ */
+ const int SENSOR_FLAG_BITS_MASK_DIRECT_CHANNEL = 0xC00;
+
+ /**
+ * Defines the number of bits different pieces of information are shifted in the
+ * SENSOR_FLAG_BITS_* bitmask.
+ */
+ const int SENSOR_FLAG_SHIFT_REPORTING_MODE = 1;
+ const int SENSOR_FLAG_SHIFT_DATA_INJECTION = 4;
+ const int SENSOR_FLAG_SHIFT_DYNAMIC_SENSOR = 5;
+ const int SENSOR_FLAG_SHIFT_ADDITIONAL_INFO = 6;
+ const int SENSOR_FLAG_SHIFT_DIRECT_REPORT = 7;
+ const int SENSOR_FLAG_SHIFT_DIRECT_CHANNEL = 10;
+}
diff --git a/sensors/aidl/android/hardware/sensors/SensorStatus.aidl b/sensors/aidl/android/hardware/sensors/SensorStatus.aidl
new file mode 100644
index 0000000..0fd8697
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/SensorStatus.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package android.hardware.sensors;
+
+@VintfStability
+@Backing(type="byte")
+enum SensorStatus {
+ NO_CONTACT = -1,
+ UNRELIABLE = 0,
+ ACCURACY_LOW = 1,
+ ACCURACY_MEDIUM = 2,
+ ACCURACY_HIGH = 3,
+}
diff --git a/sensors/aidl/android/hardware/sensors/SensorType.aidl b/sensors/aidl/android/hardware/sensors/SensorType.aidl
new file mode 100644
index 0000000..95c7a6a
--- /dev/null
+++ b/sensors/aidl/android/hardware/sensors/SensorType.aidl
@@ -0,0 +1,641 @@
+/*
+ * 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.
+ */
+
+package android.hardware.sensors;
+
+@VintfStability
+@Backing(type="int")
+enum SensorType {
+ /**
+ * META_DATA is a special event type used to populate the MetaData
+ * structure. It doesn't correspond to a physical sensor. Events of this
+ * type exist only inside the HAL, their primary purpose is to signal the
+ * completion of a flush request.
+ */
+ META_DATA = 0,
+
+ /**
+ * ACCELEROMETER
+ * reporting-mode: continuous
+ *
+ * All values are in SI units (m/s^2) and measure the acceleration of the
+ * device minus the acceleration due to gravity.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ ACCELEROMETER = 1,
+
+ /**
+ * MAGNETIC_FIELD
+ * reporting-mode: continuous
+ *
+ * All values are in micro-Tesla (uT) and measure the geomagnetic
+ * field in the X, Y and Z axis.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ MAGNETIC_FIELD = 2,
+
+ /**
+ * ORIENTATION
+ * reporting-mode: continuous
+ *
+ * All values are angles in degrees.
+ *
+ * Orientation sensors return sensor events for all 3 axes at a constant
+ * rate defined by setDelay().
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ ORIENTATION = 3,
+
+ /**
+ * GYROSCOPE
+ * reporting-mode: continuous
+ *
+ * All values are in radians/second and measure the rate of rotation
+ * around the X, Y and Z axis.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ GYROSCOPE = 4,
+
+ /**
+ * LIGHT
+ * reporting-mode: on-change
+ *
+ * The light sensor value is returned in SI lux units.
+ *
+ * Both wake-up and non wake-up versions are useful.
+ */
+ LIGHT = 5,
+
+ /**
+ * PRESSURE
+ * reporting-mode: continuous
+ *
+ * The pressure sensor return the athmospheric pressure in hectopascal (hPa)
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ PRESSURE = 6,
+
+ /**
+ * PROXIMITY
+ * reporting-mode: on-change
+ *
+ * The proximity sensor which turns the screen off and back on during calls
+ * is the wake-up proximity sensor. Implement wake-up proximity sensor
+ * before implementing a non wake-up proximity sensor. For the wake-up
+ * proximity sensor set the flag SENSOR_FLAG_WAKE_UP.
+ * The value corresponds to the distance to the nearest object in
+ * centimeters.
+ */
+ PROXIMITY = 8,
+
+ /**
+ * GRAVITY
+ * reporting-mode: continuous
+ *
+ * A gravity output indicates the direction of and magnitude of gravity in
+ * the devices's coordinates.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ GRAVITY = 9,
+
+ /**
+ * LINEAR_ACCELERATION
+ * reporting-mode: continuous
+ *
+ * Indicates the linear acceleration of the device in device coordinates,
+ * not including gravity.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ LINEAR_ACCELERATION = 10,
+
+ /**
+ * ROTATION_VECTOR
+ * reporting-mode: continuous
+ *
+ * The rotation vector symbolizes the orientation of the device relative to
+ * the East-North-Up coordinates frame.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ ROTATION_VECTOR = 11,
+
+ /**
+ * RELATIVE_HUMIDITY
+ * reporting-mode: on-change
+ *
+ * A relative humidity sensor measures relative ambient air humidity and
+ * returns a value in percent.
+ *
+ * Both wake-up and non wake-up versions are useful.
+ */
+ RELATIVE_HUMIDITY = 12,
+
+ /**
+ * AMBIENT_TEMPERATURE
+ * reporting-mode: on-change
+ *
+ * The ambient (room) temperature in degree Celsius.
+ *
+ * Both wake-up and non wake-up versions are useful.
+ */
+ AMBIENT_TEMPERATURE = 13,
+
+ /**
+ * MAGNETIC_FIELD_UNCALIBRATED
+ * reporting-mode: continuous
+ *
+ * Similar to MAGNETIC_FIELD, but the hard iron calibration is
+ * reported separately instead of being included in the measurement.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ MAGNETIC_FIELD_UNCALIBRATED = 14,
+
+ /**
+ * GAME_ROTATION_VECTOR
+ * reporting-mode: continuous
+ *
+ * Similar to ROTATION_VECTOR, but not using the geomagnetic
+ * field.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ GAME_ROTATION_VECTOR = 15,
+
+ /**
+ * GYROSCOPE_UNCALIBRATED
+ * reporting-mode: continuous
+ *
+ * All values are in radians/second and measure the rate of rotation
+ * around the X, Y and Z axis.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ GYROSCOPE_UNCALIBRATED = 16,
+
+ /**
+ * SIGNIFICANT_MOTION
+ * reporting-mode: one-shot
+ *
+ * A sensor of this type triggers an event each time significant motion
+ * is detected and automatically disables itself.
+ * For Significant Motion sensor to be useful, it must be defined as a
+ * wake-up sensor. (set SENSOR_FLAG_WAKE_UP). Implement the wake-up
+ * significant motion sensor. A non wake-up version is not useful.
+ * The only allowed value to return is 1.0.
+ */
+ SIGNIFICANT_MOTION = 17,
+
+ /**
+ * STEP_DETECTOR
+ * reporting-mode: special
+ *
+ * A sensor of this type triggers an event each time a step is taken
+ * by the user. The only allowed value to return is 1.0 and an event
+ * is generated for each step.
+ *
+ * Both wake-up and non wake-up versions are useful.
+ */
+ STEP_DETECTOR = 18,
+
+ /**
+ * STEP_COUNTER
+ * reporting-mode: on-change
+ *
+ * A sensor of this type returns the number of steps taken by the user since
+ * the last reboot while activated. The value is returned as a uint64_t and
+ * is reset to zero only on a system / android reboot.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ STEP_COUNTER = 19,
+
+ /**
+ * GEOMAGNETIC_ROTATION_VECTOR
+ * reporting-mode: continuous
+ *
+ * Similar to ROTATION_VECTOR, but using a magnetometer instead
+ * of using a gyroscope.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ GEOMAGNETIC_ROTATION_VECTOR = 20,
+
+ /**
+ * HEART_RATE
+ * reporting-mode: on-change
+ *
+ * A sensor of this type returns the current heart rate.
+ * The events contain the current heart rate in beats per minute (BPM) and
+ * the status of the sensor during the measurement. See "HeartRate" below
+ * for more details.
+ *
+ * Because this sensor is on-change, events must be generated when and only
+ * when heart_rate.bpm or heart_rate.status have changed since the last
+ * event. In particular, upon the first activation, unless the device is
+ * known to not be on the body, the status field of the first event must be
+ * set to SensorStatus::UNRELIABLE. The event should be generated no faster
+ * than every period_ns passed to setDelay() or to batch().
+ * See the definition of the on-change reporting mode for more information.
+ *
+ * SensorInfo.requiredPermission must be set to
+ * SENSOR_PERMISSION_BODY_SENSORS.
+ *
+ * Both wake-up and non wake-up versions are useful.
+ */
+ HEART_RATE = 21,
+
+ /**
+ * WAKE_UP_TILT_DETECTOR
+ * reporting-mode: special (setDelay has no impact)
+ *
+ * A sensor of this type generates an event each time a tilt event is
+ * detected. A tilt event must be generated if the direction of the
+ * 2-seconds window average gravity changed by at least 35 degrees since the
+ * activation or the last trigger of the sensor.
+ *
+ * reference_estimated_gravity = average of accelerometer measurements over
+ * the first 1 second after activation or the estimated gravity at the last
+ * trigger.
+ *
+ * current_estimated_gravity = average of accelerometer measurements over
+ * the last 2 seconds.
+ *
+ * trigger when
+ * angle(reference_estimated_gravity, current_estimated_gravity)
+ * > 35 degrees
+ *
+ * Large accelerations without a change in phone orientation must not
+ * trigger a tilt event.
+ * For example, a sharp turn or strong acceleration while driving a car
+ * must not trigger a tilt event, even though the angle of the average
+ * acceleration might vary by more than 35 degrees.
+ *
+ * Typically, this sensor is implemented with the help of only an
+ * accelerometer. Other sensors can be used as well if they do not increase
+ * the power consumption significantly. This is a low power sensor that
+ * must allow the AP to go into suspend mode. Do not emulate this sensor
+ * in the HAL.
+ * Like other wake up sensors, the driver is expected to a hold a wake_lock
+ * with a timeout of 200 ms while reporting this event. The only allowed
+ * return value is 1.0.
+ *
+ * Implement only the wake-up version of this sensor.
+ */
+ TILT_DETECTOR = 22,
+
+ /**
+ * WAKE_GESTURE
+ * reporting-mode: one-shot
+ *
+ * A sensor enabling waking up the device based on a device specific motion.
+ *
+ * When this sensor triggers, the device behaves as if the power button was
+ * pressed, turning the screen on. This behavior (turning on the screen when
+ * this sensor triggers) might be deactivated by the user in the device
+ * settings. Changes in settings do not impact the behavior of the sensor:
+ * only whether the framework turns the screen on when it triggers.
+ *
+ * The actual gesture to be detected is not specified, and can be chosen by
+ * the manufacturer of the device.
+ * This sensor must be low power, as it is likely to be activated 24/7.
+ * The only allowed value to return is 1.0.
+ *
+ * Implement only the wake-up version of this sensor.
+ */
+ WAKE_GESTURE = 23,
+
+ /**
+ * GLANCE_GESTURE
+ * reporting-mode: one-shot
+ *
+ * A sensor enabling briefly turning the screen on to enable the user to
+ * glance content on screen based on a specific motion. The device must
+ * turn the screen off after a few moments.
+ *
+ * When this sensor triggers, the device turns the screen on momentarily
+ * to allow the user to glance notifications or other content while the
+ * device remains locked in a non-interactive state (dozing). This behavior
+ * (briefly turning on the screen when this sensor triggers) might be
+ * deactivated by the user in the device settings.
+ * Changes in settings do not impact the behavior of the sensor: only
+ * whether the framework briefly turns the screen on when it triggers.
+ *
+ * The actual gesture to be detected is not specified, and can be chosen by
+ * the manufacturer of the device.
+ * This sensor must be low power, as it is likely to be activated 24/7.
+ * The only allowed value to return is 1.0.
+ *
+ * Implement only the wake-up version of this sensor.
+ */
+ GLANCE_GESTURE = 24,
+
+ /**
+ * PICK_UP_GESTURE
+ * reporting-mode: one-shot
+ *
+ * A sensor of this type triggers when the device is picked up regardless of
+ * wherever is was before (desk, pocket, bag). The only allowed return value
+ * is 1.0. This sensor de-activates itself immediately after it triggers.
+ *
+ * Implement only the wake-up version of this sensor.
+ */
+ PICK_UP_GESTURE = 25,
+
+ /**
+ * WRIST_TILT_GESTURE
+ * trigger-mode: special
+ * wake-up sensor: yes
+ *
+ * A sensor of this type triggers an event each time a tilt of the
+ * wrist-worn device is detected.
+ *
+ * This sensor must be low power, as it is likely to be activated 24/7.
+ * The only allowed value to return is 1.0.
+ *
+ * Implement only the wake-up version of this sensor.
+ */
+ WRIST_TILT_GESTURE = 26,
+
+ /**
+ * DEVICE_ORIENTATION
+ * reporting-mode: on-change
+ *
+ * The current orientation of the device. The value is reported in
+ * the "scalar" element of the EventPayload in Event. The
+ * only values that can be reported are (please refer to Android Sensor
+ * Coordinate System to understand the X and Y axis direction with respect
+ * to default orientation):
+ * - 0: device is in default orientation (Y axis is vertical and points up)
+ * - 1: device is rotated 90 degrees counter-clockwise from default
+ * orientation (X axis is vertical and points up)
+ * - 2: device is rotated 180 degrees from default orientation (Y axis is
+ * vertical and points down)
+ * - 3: device is rotated 90 degrees clockwise from default orientation
+ * (X axis is vertical and points down)
+ *
+ * Moving the device to an orientation where the Z axis is vertical (either
+ * up or down) must not cause a new event to be reported.
+ *
+ * To improve the user experience of this sensor, it is recommended to
+ * implement some physical (i.e., rotation angle) and temporal (i.e., delay)
+ * hysteresis. In other words, minor or transient rotations must not cause
+ * a new event to be reported.
+ *
+ * This is a low power sensor that intended to reduce interrupts of
+ * application processor and thus allow it to go sleep. Use hardware
+ * implementation based on low power consumption sensors, such as
+ * accelerometer. Device must not emulate this sensor in the HAL.
+ *
+ * Both wake-up and non wake-up versions are useful.
+ */
+ DEVICE_ORIENTATION = 27,
+
+ /**
+ * POSE_6DOF
+ * trigger-mode: continuous
+ *
+ * A sensor of this type returns the pose of the device.
+ * Pose of the device is defined as the orientation of the device from a
+ * Earth Centered Earth Fixed frame and the translation from an arbitrary
+ * point at subscription.
+ *
+ * This sensor can be high power. It can use any and all of the following
+ * . Accelerometer
+ * . Gyroscope
+ * . Camera
+ * . Depth Camera
+ *
+ */
+ POSE_6DOF = 28,
+
+ /**
+ * STATIONARY_DETECT
+ * trigger mode: one shot
+ *
+ * A sensor of this type returns an event if the device is still/stationary
+ * for a while. The period of time to monitor for stationarity must be
+ * greater than 5 seconds. The latency must be less than 10 seconds.
+ *
+ * Stationarity here refers to absolute stationarity. eg: device on desk.
+ *
+ * The only allowed value to return is 1.0.
+ */
+ STATIONARY_DETECT = 29,
+
+ /**
+ * MOTION_DETECT
+ * trigger mode: one shot
+ *
+ * A sensor of this type returns an event if the device is not still for
+ * for a while. The period of time to monitor for stationarity must be
+ * greater than 5 seconds. The latency must be less than 10 seconds.
+ *
+ * Motion here refers to any mechanism in which the device is causes to be
+ * moved in its inertial frame. eg: Pickin up the device and walking with it
+ * to a nearby room may trigger motion wherewas keeping the device on a
+ * table on a smooth train moving at constant velocity may not trigger
+ * motion.
+ *
+ * The only allowed value to return is 1.0.
+ */
+ MOTION_DETECT = 30,
+
+ /**
+ * HEART_BEAT
+ * trigger mode: continuous
+ *
+ * A sensor of this type returns an event everytime a hear beat peak is
+ * detected.
+ *
+ * Peak here ideally corresponds to the positive peak in the QRS complex of
+ * and ECG signal.
+ *
+ * The sensor is not expected to be optimized for latency. As a guide, a
+ * latency of up to 10 seconds is acceptable. However, the timestamp attached
+ * to the event must be accuratly correspond to the time the peak occurred.
+ *
+ * The sensor event contains a parameter for the confidence in the detection
+ * of the peak where 0.0 represent no information at all, and 1.0 represents
+ * certainty.
+ */
+ HEART_BEAT = 31,
+
+ /**
+ * DYNAMIC_SENSOR_META
+ * trigger-mode: special
+ * wake-up sensor: yes
+ *
+ * A sensor event of this type is received when a dynamic sensor is added to
+ * or removed from the system. At most one sensor of this type can be
+ * present in one sensor HAL implementation and presence of a sensor of this
+ * type in sensor HAL implementation indicates that this sensor HAL supports
+ * dynamic sensor feature. Operations, such as batch, activate and setDelay,
+ * to this special purpose sensor must be treated as no-op and return
+ * successful; flush() also has to generate flush complete event as if this
+ * is a sensor that does not support batching.
+ *
+ * A dynamic sensor connection indicates connection of a physical device or
+ * instantiation of a virtual sensor backed by algorithm; and a dynamic
+ * sensor disconnection indicates the opposite. A sensor event of
+ * DYNAMIC_SENSOR_META type should be delivered regardless of
+ * the activation status of the sensor in the event of dynamic sensor
+ * connection and disconnection. In the sensor event, besides the common
+ * data entries, "dynamic_sensor_meta", which includes fields for connection
+ * status, handle of the sensor involved, pointer to sensor_t structure and
+ * a uuid field, must be populated.
+ *
+ * At a dynamic sensor connection event, fields of sensor_t structure
+ * referenced by a pointer in dynamic_sensor_meta must be filled as if it
+ * was regular sensors. Sensor HAL is responsible for recovery of memory if
+ * the corresponding data is dynamicially allocated. However, the
+ * pointer must be valid until the first activate call to the sensor
+ * reported in this connection event. At a dynamic sensor disconnection,
+ * the sensor_t pointer must be NULL.
+ *
+ * The sensor handle assigned to dynamic sensors must never be the same as
+ * that of any regular static sensors, and must be unique until next boot.
+ * In another word, if a handle h is used for a dynamic sensor A, that same
+ * number cannot be used for the same dynamic sensor A or another dynamic
+ * sensor B even after disconnection of A until reboot.
+ *
+ * The UUID field will be used for identifying the sensor in addition to
+ * name, vendor and version and type. For physical sensors of the same
+ * model, all sensors will have the same values in sensor_t, but the UUID
+ * must be unique and persistent for each individual unit. An all zero
+ * UUID indicates it is not possible to differentiate individual sensor
+ * unit.
+ *
+ */
+ DYNAMIC_SENSOR_META = 32,
+
+ /**
+ * ADDITIONAL_INFO
+ * reporting-mode: N/A
+ *
+ * This sensor type is for delivering additional sensor information aside
+ * from sensor event data.
+ * Additional information may include sensor front-end group delay, internal
+ * calibration parameters, noise level metrics, device internal temperature,
+ * etc.
+ *
+ * This type will never bind to a sensor. In other words, no sensor in the
+ * sensor list can have the type SENSOR_TYPE_ADDITIONAL_INFO. If a
+ * sensor HAL supports sensor additional information feature, it reports
+ * sensor_event_t with "sensor" field set to handle of the reporting sensor
+ * and "type" field set to ADDITIONAL_INFO. Delivery of
+ * additional information events is triggered under two conditions: an
+ * enable activate() call or a flush() call to the corresponding sensor.
+ * Besides, time varying parameters can update infrequently without being
+ * triggered. Device is responsible to control update rate. The recommend
+ * update rate is less than 1/1000 of sensor event rate or less than once
+ * per minute in average.
+ *
+ * A single additional information report consists of multiple frames.
+ * Sequences of these frames are ordered using timestamps, which means the
+ * timestamps of sequential frames have to be at least 1 nanosecond apart
+ * from each other. Each frame is a sensor_event_t delivered through the HAL
+ * interface, with related data stored in the "additional_info" field, which
+ * is of type additional_info_event_t.
+ * The "type" field of additional_info_event_t denotes the nature of the
+ * payload data (see additional_info_type_t).
+ * The "serial" field is used to keep the sequence of payload data that
+ * spans multiple frames. The first frame of the entire report is always of
+ * type AINFO_BEGIN, and the last frame is always AINFO_END.
+ *
+ * If flush() was triggering the report, all additional information frames
+ * must be delivered after flush complete event.
+ */
+ ADDITIONAL_INFO = 33,
+
+ /**
+ * LOW_LATENCY_OFFBODY_DETECT
+ * trigger-mode: on-change
+ * wake-up sensor: yes
+ *
+ * A sensor of this type is defined for devices that are supposed to be worn
+ * by the user in the normal use case (such as a watch, wristband, etc) and
+ * is not yet defined for other device.
+ *
+ * A sensor of this type triggers an event each time the wearable device
+ * is removed from the body and each time it's put back onto the body.
+ * It must be low-latency and be able to detect the on-body to off-body
+ * transition within one second (event delivery time included),
+ * and 3-second latency to determine the off-body to on-body transition
+ * (event delivery time included).
+ *
+ * There are only two valid event values for the sensor to return :
+ * 0.0 for off-body
+ * 1.0 for on-body
+ *
+ */
+ LOW_LATENCY_OFFBODY_DETECT = 34,
+
+ /**
+ * ACCELEROMETER_UNCALIBRATED
+ * reporting-mode: continuous
+ *
+ * All values are in SI units (m/s^2) and measure the acceleration of the
+ * device minus the acceleration due to gravity.
+ *
+ * Implement the non-wake-up version of this sensor and implement the
+ * wake-up version if the system possesses a wake up fifo.
+ */
+ ACCELEROMETER_UNCALIBRATED = 35,
+
+ /**
+ * HINGE_ANGLE
+ * reporting-mode: on-change
+ * wake-up sensor: yes
+ *
+ * A sensor of this type measures the angle, in degrees, between two
+ * integral parts of the device. Movement of a hinge measured by this sensor
+ * type is expected to alter the ways in which the user may interact with
+ * the device, for example by unfolding or revealing a display.
+ *
+ * Sensor data is output using EventPayload.scalar.
+ *
+ * Implement wake-up proximity sensor before implementing a non wake-up
+ * proximity sensor.
+ */
+ HINGE_ANGLE = 36,
+
+ /**
+ * Base for device manufacturers private sensor types.
+ * These sensor types can't be exposed in the SDK.
+ */
+ DEVICE_PRIVATE_BASE = 0x10000,
+}
diff --git a/sensors/aidl/default/Android.bp b/sensors/aidl/default/Android.bp
new file mode 100644
index 0000000..49841a4
--- /dev/null
+++ b/sensors/aidl/default/Android.bp
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library_static {
+ name: "libsensorsexampleimpl",
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libfmq",
+ "libpower",
+ "libbinder_ndk",
+ "android.hardware.sensors-V1-ndk",
+ ],
+ export_include_dirs: ["include"],
+ srcs: [
+ "Sensors.cpp",
+ "Sensor.cpp",
+ ],
+ visibility: [
+ ":__subpackages__",
+ "//hardware/interfaces/tests/extension/sensors:__subpackages__",
+ ],
+}
+
+cc_binary {
+ name: "android.hardware.sensors-service.example",
+ relative_install_path: "hw",
+ init_rc: ["sensors-default.rc"],
+ vintf_fragments: ["sensors-default.xml"],
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libbinder_ndk",
+ "libfmq",
+ "libpower",
+ "libcutils",
+ "liblog",
+ "libutils",
+ "android.hardware.sensors-V1-ndk",
+ ],
+ static_libs: [
+ "libsensorsexampleimpl",
+ ],
+ srcs: ["main.cpp"],
+}
diff --git a/sensors/aidl/default/Sensor.cpp b/sensors/aidl/default/Sensor.cpp
new file mode 100644
index 0000000..50d8841
--- /dev/null
+++ b/sensors/aidl/default/Sensor.cpp
@@ -0,0 +1,434 @@
+/*
+ * 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 "sensors-impl/Sensor.h"
+
+#include "utils/SystemClock.h"
+
+#include <cmath>
+
+using ::ndk::ScopedAStatus;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace sensors {
+
+static constexpr int32_t kDefaultMaxDelayUs = 10 * 1000 * 1000;
+
+Sensor::Sensor(ISensorsEventCallback* callback)
+ : mIsEnabled(false),
+ mSamplingPeriodNs(0),
+ mLastSampleTimeNs(0),
+ mCallback(callback),
+ mMode(OperationMode::NORMAL) {
+ mRunThread = std::thread(startThread, this);
+}
+
+Sensor::~Sensor() {
+ std::unique_lock<std::mutex> lock(mRunMutex);
+ mStopThread = true;
+ mIsEnabled = false;
+ mWaitCV.notify_all();
+ lock.release();
+ mRunThread.join();
+}
+
+const SensorInfo& Sensor::getSensorInfo() const {
+ return mSensorInfo;
+}
+
+void Sensor::batch(int64_t samplingPeriodNs) {
+ if (samplingPeriodNs < mSensorInfo.minDelayUs * 1000ll) {
+ samplingPeriodNs = mSensorInfo.minDelayUs * 1000ll;
+ } else if (samplingPeriodNs > mSensorInfo.maxDelayUs * 1000ll) {
+ samplingPeriodNs = mSensorInfo.maxDelayUs * 1000ll;
+ }
+
+ 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();
+ }
+}
+
+ScopedAStatus 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>(SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE))) {
+ return ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(BnSensors::ERROR_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;
+ EventPayload::MetaData meta = {
+ .what = MetaDataEventType::META_DATA_FLUSH_COMPLETE,
+ };
+ ev.payload.set<EventPayload::Tag::meta>(meta);
+ std::vector<Event> evs{ev};
+ mCallback->postEvents(evs, isWakeUpSensor());
+
+ return ScopedAStatus::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_BOOTTIME, &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>(SensorInfo::SENSOR_FLAG_BITS_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();
+ memset(&event.payload, 0, sizeof(event.payload));
+ readEventPayload(event.payload);
+ 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>(SensorInfo::SENSOR_FLAG_BITS_DATA_INJECTION);
+}
+
+ScopedAStatus Sensor::injectEvent(const Event& event) {
+ if (event.sensorType == SensorType::ADDITIONAL_INFO) {
+ return ScopedAStatus::ok();
+ // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation
+ // environment data into the device.
+ }
+
+ if (!supportsDataInjection()) {
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
+ if (mMode == OperationMode::DATA_INJECTION) {
+ mCallback->postEvents(std::vector<Event>{event}, isWakeUpSensor());
+ return ScopedAStatus::ok();
+ }
+
+ return ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(BnSensors::ERROR_BAD_VALUE));
+}
+
+OnChangeSensor::OnChangeSensor(ISensorsEventCallback* callback)
+ : Sensor(callback), mPreviousEventSet(false) {}
+
+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 (!mPreviousEventSet ||
+ memcmp(&mPreviousEvent.payload, &ev.payload, sizeof(ev.payload)) != 0) {
+ outputEvents.push_back(ev);
+ mPreviousEvent = ev;
+ mPreviousEventSet = true;
+ }
+ }
+ return outputEvents;
+}
+
+AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Accel Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::ACCELEROMETER;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 78.4f; // +/- 8g
+ mSensorInfo.resolution = 1.52e-5;
+ mSensorInfo.power = 0.001f; // mA
+ mSensorInfo.minDelayUs = 10 * 1000; // microseconds
+ mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_DATA_INJECTION);
+};
+
+void AccelSensor::readEventPayload(EventPayload& payload) {
+ EventPayload::Vec3 vec3 = {
+ .x = 0,
+ .y = 0,
+ .z = -9.8,
+ .status = SensorStatus::ACCURACY_HIGH,
+ };
+ payload.set<EventPayload::Tag::vec3>(vec3);
+}
+
+PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : Sensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Pressure Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::PRESSURE;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 1100.0f; // hPa
+ mSensorInfo.resolution = 0.005f; // hPa
+ mSensorInfo.power = 0.001f; // mA
+ mSensorInfo.minDelayUs = 100 * 1000; // microseconds
+ mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = 0;
+};
+
+void PressureSensor::readEventPayload(EventPayload& payload) {
+ payload.set<EventPayload::Tag::scalar>(1013.25f);
+}
+
+MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : Sensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Magnetic Field Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::MAGNETIC_FIELD;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 1300.0f;
+ mSensorInfo.resolution = 0.01f;
+ mSensorInfo.power = 0.001f; // mA
+ mSensorInfo.minDelayUs = 20 * 1000; // microseconds
+ mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = 0;
+};
+
+void MagnetometerSensor::readEventPayload(EventPayload& payload) {
+ EventPayload::Vec3 vec3 = {
+ .x = 100.0,
+ .y = 0,
+ .z = 50.0,
+ .status = SensorStatus::ACCURACY_HIGH,
+ };
+ payload.set<EventPayload::Tag::vec3>(vec3);
+}
+
+LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : OnChangeSensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Light Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::LIGHT;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 43000.0f;
+ mSensorInfo.resolution = 10.0f;
+ mSensorInfo.power = 0.001f; // mA
+ mSensorInfo.minDelayUs = 200 * 1000; // microseconds
+ mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE);
+};
+
+void LightSensor::readEventPayload(EventPayload& payload) {
+ payload.set<EventPayload::Tag::scalar>(80.0f);
+}
+
+ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : OnChangeSensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Proximity Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::PROXIMITY;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 5.0f;
+ mSensorInfo.resolution = 1.0f;
+ mSensorInfo.power = 0.012f; // mA
+ mSensorInfo.minDelayUs = 200 * 1000; // microseconds
+ mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE |
+ SensorInfo::SENSOR_FLAG_BITS_WAKE_UP);
+};
+
+void ProximitySensor::readEventPayload(EventPayload& payload) {
+ payload.set<EventPayload::Tag::scalar>(2.5f);
+}
+
+GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Gyro Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::GYROSCOPE;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f;
+ mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f);
+ mSensorInfo.power = 0.001f;
+ mSensorInfo.minDelayUs = 10 * 1000; // microseconds
+ mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = 0;
+};
+
+void GyroSensor::readEventPayload(EventPayload& payload) {
+ EventPayload::Vec3 vec3 = {
+ .x = 0,
+ .y = 0,
+ .z = 0,
+ .status = SensorStatus::ACCURACY_HIGH,
+ };
+ payload.set<EventPayload::Tag::vec3>(vec3);
+}
+
+AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : OnChangeSensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Ambient Temp Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 80.0f;
+ mSensorInfo.resolution = 0.01f;
+ mSensorInfo.power = 0.001f;
+ mSensorInfo.minDelayUs = 40 * 1000; // microseconds
+ mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE);
+};
+
+void AmbientTempSensor::readEventPayload(EventPayload& payload) {
+ payload.set<EventPayload::Tag::scalar>(40.0f);
+}
+
+RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
+ ISensorsEventCallback* callback)
+ : OnChangeSensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Relative Humidity Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::RELATIVE_HUMIDITY;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 100.0f;
+ mSensorInfo.resolution = 0.1f;
+ mSensorInfo.power = 0.001f;
+ mSensorInfo.minDelayUs = 40 * 1000; // microseconds
+ mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE);
+}
+
+void RelativeHumiditySensor::readEventPayload(EventPayload& payload) {
+ payload.set<EventPayload::Tag::scalar>(50.0f);
+}
+
+HingeAngleSensor::HingeAngleSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : OnChangeSensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Hinge Angle Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::HINGE_ANGLE;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 360.0f;
+ mSensorInfo.resolution = 1.0f;
+ mSensorInfo.power = 0.001f;
+ mSensorInfo.minDelayUs = 40 * 1000; // microseconds
+ mSensorInfo.maxDelayUs = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = static_cast<uint32_t>(SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE |
+ SensorInfo::SENSOR_FLAG_BITS_WAKE_UP |
+ SensorInfo::SENSOR_FLAG_BITS_DATA_INJECTION);
+}
+
+void HingeAngleSensor::readEventPayload(EventPayload& payload) {
+ payload.set<EventPayload::Tag::scalar>(180.0f);
+}
+
+} // namespace sensors
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/sensors/aidl/default/Sensors.cpp b/sensors/aidl/default/Sensors.cpp
new file mode 100644
index 0000000..65dd304
--- /dev/null
+++ b/sensors/aidl/default/Sensors.cpp
@@ -0,0 +1,157 @@
+/*
+ * 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 "sensors-impl/Sensors.h"
+
+#include <aidl/android/hardware/common/fmq/SynchronizedReadWrite.h>
+
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::aidl::android::hardware::sensors::Event;
+using ::aidl::android::hardware::sensors::ISensors;
+using ::aidl::android::hardware::sensors::ISensorsCallback;
+using ::aidl::android::hardware::sensors::SensorInfo;
+using ::ndk::ScopedAStatus;
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace sensors {
+
+ScopedAStatus Sensors::activate(int32_t in_sensorHandle, bool in_enabled) {
+ auto sensor = mSensors.find(in_sensorHandle);
+ if (sensor != mSensors.end()) {
+ sensor->second->activate(in_enabled);
+ return ScopedAStatus::ok();
+ }
+
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ScopedAStatus Sensors::batch(int32_t in_sensorHandle, int64_t in_samplingPeriodNs,
+ int64_t /* in_maxReportLatencyNs */) {
+ auto sensor = mSensors.find(in_sensorHandle);
+ if (sensor != mSensors.end()) {
+ sensor->second->batch(in_samplingPeriodNs);
+ return ScopedAStatus::ok();
+ }
+
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ScopedAStatus Sensors::configDirectReport(int32_t /* in_sensorHandle */,
+ int32_t /* in_channelHandle */,
+ ISensors::RateLevel /* in_rate */,
+ int32_t* _aidl_return) {
+ *_aidl_return = EX_UNSUPPORTED_OPERATION;
+
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ScopedAStatus Sensors::flush(int32_t in_sensorHandle) {
+ auto sensor = mSensors.find(in_sensorHandle);
+ if (sensor != mSensors.end()) {
+ return sensor->second->flush();
+ }
+
+ return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+}
+
+ScopedAStatus Sensors::getSensorsList(std::vector<SensorInfo>* _aidl_return) {
+ for (const auto& sensor : mSensors) {
+ _aidl_return->push_back(sensor.second->getSensorInfo());
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Sensors::initialize(
+ const MQDescriptor<Event, SynchronizedReadWrite>& in_eventQueueDescriptor,
+ const MQDescriptor<int32_t, SynchronizedReadWrite>& in_wakeLockDescriptor,
+ const std::shared_ptr<::aidl::android::hardware::sensors::ISensorsCallback>&
+ in_sensorsCallback) {
+ ScopedAStatus result = ScopedAStatus::ok();
+
+ mEventQueue = std::make_unique<AidlMessageQueue<Event, SynchronizedReadWrite>>(
+ in_eventQueueDescriptor, true /* resetPointers */);
+
+ // Ensure that all sensors are disabled.
+ for (auto sensor : mSensors) {
+ sensor.second->activate(false);
+ }
+
+ // Stop the Wake Lock thread if it is currently running
+ if (mReadWakeLockQueueRun.load()) {
+ mReadWakeLockQueueRun = false;
+ mWakeLockThread.join();
+ }
+
+ // Save a reference to the callback
+ mCallback = in_sensorsCallback;
+
+ // Ensure that any existing EventFlag is properly deleted
+ deleteEventFlag();
+
+ // Create the EventFlag that is used to signal to the framework that sensor events have been
+ // written to the Event FMQ
+ if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
+ result = ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ // 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<AidlMessageQueue<int32_t, SynchronizedReadWrite>>(
+ in_wakeLockDescriptor, true /* resetPointers */);
+
+ if (!mCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
+ result = ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ // Start the thread to read events from the Wake Lock FMQ
+ mReadWakeLockQueueRun = true;
+ mWakeLockThread = std::thread(startReadWakeLockThread, this);
+ return result;
+}
+
+ScopedAStatus Sensors::injectSensorData(const Event& in_event) {
+ auto sensor = mSensors.find(in_event.sensorHandle);
+ if (sensor != mSensors.end()) {
+ return sensor->second->injectEvent(in_event);
+ }
+ return ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(ERROR_BAD_VALUE));
+}
+
+ScopedAStatus Sensors::registerDirectChannel(const ISensors::SharedMemInfo& /* in_mem */,
+ int32_t* _aidl_return) {
+ *_aidl_return = EX_UNSUPPORTED_OPERATION;
+
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ScopedAStatus Sensors::setOperationMode(OperationMode in_mode) {
+ for (auto sensor : mSensors) {
+ sensor.second->setOperationMode(in_mode);
+ }
+ return ScopedAStatus::ok();
+}
+
+ScopedAStatus Sensors::unregisterDirectChannel(int32_t /* in_channelHandle */) {
+ return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+} // namespace sensors
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/sensors/aidl/default/include/sensors-impl/Sensor.h b/sensors/aidl/default/include/sensors-impl/Sensor.h
new file mode 100644
index 0000000..e6cd3e6
--- /dev/null
+++ b/sensors/aidl/default/include/sensors-impl/Sensor.h
@@ -0,0 +1,168 @@
+/*
+ * 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 <thread>
+
+#include <aidl/android/hardware/sensors/BnSensors.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace sensors {
+
+class ISensorsEventCallback {
+ public:
+ using Event = ::aidl::android::hardware::sensors::Event;
+
+ virtual ~ISensorsEventCallback(){};
+ virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0;
+};
+
+class Sensor {
+ public:
+ using OperationMode = ::aidl::android::hardware::sensors::ISensors::OperationMode;
+ using Event = ::aidl::android::hardware::sensors::Event;
+ using EventPayload = ::aidl::android::hardware::sensors::Event::EventPayload;
+ using SensorInfo = ::aidl::android::hardware::sensors::SensorInfo;
+ using SensorType = ::aidl::android::hardware::sensors::SensorType;
+ using MetaDataEventType =
+ ::aidl::android::hardware::sensors::Event::EventPayload::MetaData::MetaDataEventType;
+
+ Sensor(ISensorsEventCallback* callback);
+ virtual ~Sensor();
+
+ const SensorInfo& getSensorInfo() const;
+ void batch(int64_t samplingPeriodNs);
+ virtual void activate(bool enable);
+ ndk::ScopedAStatus flush();
+
+ void setOperationMode(OperationMode mode);
+ bool supportsDataInjection() const;
+ ndk::ScopedAStatus injectEvent(const Event& event);
+
+ protected:
+ void run();
+ virtual std::vector<Event> readEvents();
+ virtual void readEventPayload(EventPayload&) = 0;
+ 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(ISensorsEventCallback* callback);
+
+ virtual void activate(bool enable) override;
+
+ protected:
+ virtual std::vector<Event> readEvents() override;
+
+ protected:
+ Event mPreviousEvent;
+ bool mPreviousEventSet;
+};
+
+class AccelSensor : public Sensor {
+ public:
+ AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ protected:
+ virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class GyroSensor : public Sensor {
+ public:
+ GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ protected:
+ virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class AmbientTempSensor : public OnChangeSensor {
+ public:
+ AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ protected:
+ virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class PressureSensor : public Sensor {
+ public:
+ PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ protected:
+ virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class MagnetometerSensor : public Sensor {
+ public:
+ MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ protected:
+ virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class LightSensor : public OnChangeSensor {
+ public:
+ LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ protected:
+ virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class ProximitySensor : public OnChangeSensor {
+ public:
+ ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ protected:
+ virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class RelativeHumiditySensor : public OnChangeSensor {
+ public:
+ RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ protected:
+ virtual void readEventPayload(EventPayload& payload) override;
+};
+
+class HingeAngleSensor : public OnChangeSensor {
+ public:
+ HingeAngleSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+ protected:
+ virtual void readEventPayload(EventPayload& payload) override;
+};
+
+} // namespace sensors
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/sensors/aidl/default/include/sensors-impl/Sensors.h b/sensors/aidl/default/include/sensors-impl/Sensors.h
new file mode 100644
index 0000000..e270d96
--- /dev/null
+++ b/sensors/aidl/default/include/sensors-impl/Sensors.h
@@ -0,0 +1,216 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/common/fmq/SynchronizedReadWrite.h>
+#include <aidl/android/hardware/sensors/BnSensors.h>
+#include <fmq/AidlMessageQueue.h>
+#include <hardware_legacy/power.h>
+#include <map>
+#include "Sensor.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace sensors {
+
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+using ::android::OK;
+using ::android::status_t;
+using ::android::hardware::EventFlag;
+
+class Sensors : public BnSensors, public ISensorsEventCallback {
+ static constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP";
+
+ public:
+ Sensors()
+ : mEventQueueFlag(nullptr),
+ mNextHandle(1),
+ mOutstandingWakeUpEvents(0),
+ mReadWakeLockQueueRun(false),
+ mAutoReleaseWakeLockTime(0),
+ mHasWakeLock(false) {
+ AddSensor<AccelSensor>();
+ AddSensor<GyroSensor>();
+ AddSensor<AmbientTempSensor>();
+ AddSensor<PressureSensor>();
+ AddSensor<MagnetometerSensor>();
+ AddSensor<LightSensor>();
+ AddSensor<ProximitySensor>();
+ AddSensor<RelativeHumiditySensor>();
+ AddSensor<HingeAngleSensor>();
+ }
+
+ virtual ~Sensors() {
+ deleteEventFlag();
+ mReadWakeLockQueueRun = false;
+ mWakeLockThread.join();
+ }
+
+ ::ndk::ScopedAStatus activate(int32_t in_sensorHandle, bool in_enabled) override;
+ ::ndk::ScopedAStatus batch(int32_t in_sensorHandle, int64_t in_samplingPeriodNs,
+ int64_t in_maxReportLatencyNs) override;
+ ::ndk::ScopedAStatus configDirectReport(
+ int32_t in_sensorHandle, int32_t in_channelHandle,
+ ::aidl::android::hardware::sensors::ISensors::RateLevel in_rate,
+ int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus flush(int32_t in_sensorHandle) override;
+ ::ndk::ScopedAStatus getSensorsList(
+ std::vector<::aidl::android::hardware::sensors::SensorInfo>* _aidl_return) override;
+ ::ndk::ScopedAStatus initialize(
+ const ::aidl::android::hardware::common::fmq::MQDescriptor<
+ ::aidl::android::hardware::sensors::Event,
+ ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>&
+ in_eventQueueDescriptor,
+ const ::aidl::android::hardware::common::fmq::MQDescriptor<
+ int32_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>&
+ in_wakeLockDescriptor,
+ const std::shared_ptr<::aidl::android::hardware::sensors::ISensorsCallback>&
+ in_sensorsCallback) override;
+ ::ndk::ScopedAStatus injectSensorData(
+ const ::aidl::android::hardware::sensors::Event& in_event) override;
+ ::ndk::ScopedAStatus registerDirectChannel(
+ const ::aidl::android::hardware::sensors::ISensors::SharedMemInfo& in_mem,
+ int32_t* _aidl_return) override;
+ ::ndk::ScopedAStatus setOperationMode(
+ ::aidl::android::hardware::sensors::ISensors::OperationMode in_mode) override;
+ ::ndk::ScopedAStatus unregisterDirectChannel(int32_t in_channelHandle) override;
+
+ void postEvents(const std::vector<Event>& events, bool wakeup) override {
+ std::lock_guard<std::mutex> lock(mWriteLock);
+ if (mEventQueue == nullptr) {
+ return;
+ }
+ if (mEventQueue->write(&events.front(), events.size())) {
+ mEventQueueFlag->wake(
+ static_cast<uint32_t>(BnSensors::EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS));
+
+ if (wakeup) {
+ // Keep track of the number of outstanding WAKE_UP events in order to properly hold
+ // a wake lock until the framework has secured a wake lock
+ updateWakeLock(events.size(), 0 /* eventsHandled */);
+ }
+ }
+ }
+
+ protected:
+ // Add a new sensor
+ template <class SensorType>
+ void AddSensor() {
+ std::shared_ptr<SensorType> sensor =
+ std::make_shared<SensorType>(mNextHandle++ /* sensorHandle */, this /* callback */);
+ mSensors[sensor->getSensorInfo().sensorHandle] = sensor;
+ }
+
+ // Utility function to delete the Event Flag
+ void deleteEventFlag() {
+ if (mEventQueueFlag != nullptr) {
+ status_t status = EventFlag::deleteEventFlag(&mEventQueueFlag);
+ if (status != OK) {
+ ALOGI("Failed to delete event flag: %d", status);
+ }
+ }
+ }
+
+ static void startReadWakeLockThread(Sensors* sensors) { sensors->readWakeLockFMQ(); }
+
+ // Function to read the Wake Lock FMQ and release the wake lock when appropriate
+ void readWakeLockFMQ() {
+ while (mReadWakeLockQueueRun.load()) {
+ constexpr int64_t kReadTimeoutNs = 500 * 1000 * 1000; // 500 ms
+ int32_t eventsHandled = 0;
+
+ // Read events from the Wake Lock FMQ. Timeout after a reasonable amount of time to
+ // ensure that any held wake lock is able to be released if it is held for too long.
+ mWakeLockQueue->readBlocking(
+ &eventsHandled, 1 /* count */, 0 /* readNotification */,
+ static_cast<uint32_t>(WAKE_LOCK_QUEUE_FLAG_BITS_DATA_WRITTEN), kReadTimeoutNs);
+ updateWakeLock(0 /* eventsWritten */, eventsHandled);
+ }
+ }
+
+ /**
+ * Responsible for acquiring and releasing a wake lock when there are unhandled WAKE_UP events
+ */
+ void updateWakeLock(int32_t eventsWritten, int32_t eventsHandled) {
+ std::lock_guard<std::mutex> lock(mWakeLockLock);
+ int32_t newVal = mOutstandingWakeUpEvents + eventsWritten - eventsHandled;
+ if (newVal < 0) {
+ mOutstandingWakeUpEvents = 0;
+ } else {
+ mOutstandingWakeUpEvents = newVal;
+ }
+
+ if (eventsWritten > 0) {
+ // Update the time at which the last WAKE_UP event was sent
+ mAutoReleaseWakeLockTime = ::android::uptimeMillis() +
+ static_cast<uint32_t>(WAKE_LOCK_TIMEOUT_SECONDS) * 1000;
+ }
+
+ if (!mHasWakeLock && mOutstandingWakeUpEvents > 0 &&
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLockName) == 0) {
+ mHasWakeLock = true;
+ } else if (mHasWakeLock) {
+ // Check if the wake lock should be released automatically if
+ // SensorTimeout::WAKE_LOCK_SECONDS has elapsed since the last WAKE_UP event was written
+ // to the Wake Lock FMQ.
+ if (::android::uptimeMillis() > mAutoReleaseWakeLockTime) {
+ ALOGD("No events read from wake lock FMQ for %d seconds, auto releasing wake lock",
+ WAKE_LOCK_TIMEOUT_SECONDS);
+ mOutstandingWakeUpEvents = 0;
+ }
+
+ if (mOutstandingWakeUpEvents == 0 && release_wake_lock(kWakeLockName) == 0) {
+ mHasWakeLock = false;
+ }
+ }
+ }
+
+ private:
+ // The Event FMQ where sensor events are written
+ std::unique_ptr<AidlMessageQueue<Event, SynchronizedReadWrite>> mEventQueue;
+ // The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events
+ std::unique_ptr<AidlMessageQueue<int32_t, SynchronizedReadWrite>> mWakeLockQueue;
+ // Event Flag to signal to the framework when sensor events are available to be read
+ EventFlag* mEventQueueFlag;
+ // Callback for asynchronous events, such as dynamic sensor connections.
+ std::shared_ptr<::aidl::android::hardware::sensors::ISensorsCallback> mCallback;
+ // A map of the available sensors.
+ std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
+ // The next available sensor handle.
+ int32_t mNextHandle;
+ // Lock to protect writes to the FMQs.
+ std::mutex mWriteLock;
+ // Lock to protect acquiring and releasing the wake lock
+ std::mutex mWakeLockLock;
+ // Track the number of WAKE_UP events that have not been handled by the framework
+ uint32_t mOutstandingWakeUpEvents;
+ // A thread to read the Wake Lock FMQ
+ std::thread mWakeLockThread;
+ // Flag to indicate that the Wake Lock Thread should continue to run
+ std::atomic_bool mReadWakeLockQueueRun;
+ // Track the time when the wake lock should automatically be released
+ int64_t mAutoReleaseWakeLockTime;
+ // Flag to indicate if a wake lock has been acquired
+ bool mHasWakeLock;
+};
+
+} // namespace sensors
+} // namespace hardware
+} // namespace android
+} // namespace aidl
diff --git a/sensors/aidl/default/main.cpp b/sensors/aidl/default/main.cpp
new file mode 100644
index 0000000..8a5a7de
--- /dev/null
+++ b/sensors/aidl/default/main.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "sensors-impl/Sensors.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::sensors::Sensors;
+
+int main() {
+ ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+ // Make a default sensors service
+ auto sensor = ndk::SharedRefBase::make<Sensors>();
+ const std::string sensorName = std::string() + Sensors::descriptor + "/default";
+ binder_status_t status =
+ AServiceManager_addService(sensor->asBinder().get(), sensorName.c_str());
+ CHECK_EQ(status, STATUS_OK);
+
+ ABinderProcess_joinThreadPool();
+ return EXIT_FAILURE; // should not reach
+}
diff --git a/sensors/aidl/default/sensors-default.rc b/sensors/aidl/default/sensors-default.rc
new file mode 100644
index 0000000..96da85d
--- /dev/null
+++ b/sensors/aidl/default/sensors-default.rc
@@ -0,0 +1,5 @@
+service vendor.sensors-default /vendor/bin/hw/android.hardware.sensors-service.example
+ class hal
+ user system
+ group system
+ rlimit rtprio 10 10
diff --git a/sensors/aidl/default/sensors-default.xml b/sensors/aidl/default/sensors-default.xml
new file mode 100644
index 0000000..7898a6b
--- /dev/null
+++ b/sensors/aidl/default/sensors-default.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+ <hal format="aidl">
+ <name>android.hardware.sensors</name>
+ <version>1</version>
+ <fqname>ISensors/default</fqname>
+ </hal>
+</manifest>
diff --git a/sensors/aidl/vts/Android.bp b/sensors/aidl/vts/Android.bp
new file mode 100644
index 0000000..5a519a5
--- /dev/null
+++ b/sensors/aidl/vts/Android.bp
@@ -0,0 +1,49 @@
+// Copyright 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.
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+ name: "VtsAidlHalSensorsTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "VtsAidlHalSensorsTargetTest.cpp",
+ "SensorsAidlEnvironment.cpp",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libbinder_ndk",
+ "libfmq",
+ "android.hardware.common-V2-ndk",
+ "android.hardware.common.fmq-V1-ndk",
+ ],
+ static_libs: [
+ "android.hardware.sensors-V1-ndk",
+ "VtsHalSensorsTargetTestUtils",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/sensors/aidl/vts/OWNERS b/sensors/aidl/vts/OWNERS
new file mode 100644
index 0000000..90c2330
--- /dev/null
+++ b/sensors/aidl/vts/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
diff --git a/sensors/aidl/vts/SensorsAidlEnvironment.cpp b/sensors/aidl/vts/SensorsAidlEnvironment.cpp
new file mode 100644
index 0000000..e71251f
--- /dev/null
+++ b/sensors/aidl/vts/SensorsAidlEnvironment.cpp
@@ -0,0 +1,164 @@
+/*
+ * 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 "SensorsAidlEnvironment.h"
+
+#include <android/binder_manager.h>
+#include <log/log.h>
+
+#include <aidl/android/hardware/sensors/BnSensorsCallback.h>
+
+using aidl::android::hardware::sensors::BnSensorsCallback;
+using aidl::android::hardware::sensors::SensorInfo;
+using android::hardware::EventFlag;
+using ndk::ScopedAStatus;
+using ndk::SpAIBinder;
+
+namespace {
+
+void serviceDied(void* /* cookie */) {
+ ALOGE("Sensors HAL died (likely crashed) during test");
+ FAIL() << "Sensors HAL died during test";
+}
+
+class NoOpSensorsCallback : public BnSensorsCallback {
+ public:
+ ScopedAStatus onDynamicSensorsConnected(
+ const std::vector<SensorInfo>& /* sensorInfos */) override {
+ return ScopedAStatus::ok();
+ }
+
+ ScopedAStatus onDynamicSensorsDisconnected(
+ const std::vector<int32_t>& /* sensorHandles */) override {
+ return ScopedAStatus::ok();
+ }
+};
+
+} // anonymous namespace
+
+SensorsAidlEnvironment::SensorsAidlEnvironment(const std::string& service_name)
+ : SensorsVtsEnvironmentBase(service_name),
+ mCallback(ndk::SharedRefBase::make<NoOpSensorsCallback>()),
+ mDeathRecipient(AIBinder_DeathRecipient_new(serviceDied)) {}
+
+bool SensorsAidlEnvironment::resetHal() {
+ bool succeed = false;
+ do {
+ mSensors = ISensors::fromBinder(
+ SpAIBinder(AServiceManager_waitForService(mServiceName.c_str())));
+ if (mSensors == nullptr) {
+ break;
+ }
+
+ AIBinder_linkToDeath(mSensors->asBinder().get(), mDeathRecipient.get(), this);
+
+ // Initialize FMQs
+ mWakeLockQueue = std::make_unique<WakeLockQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
+ true /* configureEventFlagWord */);
+ mEventQueue = std::make_unique<EventQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
+ true /* configureEventFlagWord */);
+
+ if (mWakeLockQueue == nullptr || mEventQueue == nullptr) {
+ break;
+ }
+
+ EventFlag::deleteEventFlag(&mEventQueueFlag);
+ EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag);
+ if (mEventQueueFlag == nullptr) {
+ break;
+ }
+
+ mSensors->initialize(mEventQueue->dupeDesc(), mWakeLockQueue->dupeDesc(), mCallback);
+
+ std::vector<SensorInfo> sensorList;
+ if (!mSensors->getSensorsList(&sensorList).isOk()) {
+ break;
+ }
+
+ // stop each sensor individually
+ bool ok = true;
+ for (const auto& i : sensorList) {
+ if (!mSensors->activate(i.sensorHandle, false).isOk()) {
+ ok = false;
+ break;
+ }
+ }
+
+ if (!ok) {
+ break;
+ }
+
+ // mark it done
+ succeed = true;
+ } while (0);
+
+ if (!succeed) {
+ mSensors = nullptr;
+ }
+
+ return succeed;
+}
+
+void SensorsAidlEnvironment::TearDown() {
+ mStopThread = true;
+
+ if (mEventQueueFlag != nullptr) {
+ // Wake up the event queue so the poll thread can exit
+ mEventQueueFlag->wake(ISensors::EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS);
+ if (mPollThread.joinable()) {
+ mPollThread.join();
+ }
+
+ EventFlag::deleteEventFlag(&mEventQueueFlag);
+ }
+}
+
+void SensorsAidlEnvironment::startPollingThread() {
+ mStopThread = false;
+ mEvents.reserve(MAX_RECEIVE_BUFFER_EVENT_COUNT);
+ mPollThread = std::thread(pollingThread, this);
+}
+
+void SensorsAidlEnvironment::readEvents() {
+ size_t availableEvents = mEventQueue->availableToRead();
+
+ if (availableEvents == 0) {
+ uint32_t eventFlagState = 0;
+
+ mEventQueueFlag->wait(ISensors::EVENT_QUEUE_FLAG_BITS_READ_AND_PROCESS, &eventFlagState);
+ availableEvents = mEventQueue->availableToRead();
+ }
+
+ size_t eventsToRead = std::min(availableEvents, mEventBuffer.size());
+ if (eventsToRead > 0) {
+ if (mEventQueue->read(mEventBuffer.data(), eventsToRead)) {
+ mEventQueueFlag->wake(ISensors::EVENT_QUEUE_FLAG_BITS_EVENTS_READ);
+ for (size_t i = 0; i < eventsToRead; i++) {
+ addEvent(mEventBuffer[i]);
+ }
+ }
+ }
+}
+
+void SensorsAidlEnvironment::pollingThread(SensorsAidlEnvironment* env) {
+ ALOGD("polling thread start");
+
+ while (!env->mStopThread.load()) {
+ env->readEvents();
+ }
+
+ ALOGD("polling thread end");
+}
diff --git a/sensors/aidl/vts/SensorsAidlEnvironment.h b/sensors/aidl/vts/SensorsAidlEnvironment.h
new file mode 100644
index 0000000..2f5f287
--- /dev/null
+++ b/sensors/aidl/vts/SensorsAidlEnvironment.h
@@ -0,0 +1,110 @@
+/*
+ * 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 ANDROID_SENSORS_AIDL_ENVIRONMENT_H
+#define ANDROID_SENSORS_AIDL_ENVIRONMENT_H
+
+#include "sensors-vts-utils/SensorsVtsEnvironmentBase.h"
+
+#include <atomic>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <fmq/AidlMessageQueue.h>
+
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using aidl::android::hardware::sensors::Event;
+using aidl::android::hardware::sensors::ISensors;
+using aidl::android::hardware::sensors::ISensorsCallback;
+
+static constexpr size_t MAX_RECEIVE_BUFFER_EVENT_COUNT = 256;
+
+class SensorsAidlTest;
+
+class SensorsAidlEnvironment : public SensorsVtsEnvironmentBase<Event> {
+ public:
+ virtual void TearDown() override;
+
+ protected:
+ friend SensorsAidlTest;
+ SensorsAidlEnvironment(const std::string& service_name);
+
+ /**
+ * Resets the HAL with new FMQs and a new Event Flag
+ *
+ * @return bool true if successful, false otherwise
+ */
+ bool resetHal() override;
+
+ /**
+ * Starts the polling thread that reads sensor events from the Event FMQ
+ */
+ void startPollingThread() override;
+
+ /**
+ * Thread responsible for calling functions to read Event FMQ
+ *
+ * @param env SensorEnvironment to being polling for events on
+ */
+ static void pollingThread(SensorsAidlEnvironment* env);
+
+ /**
+ * Reads and saves sensor events from the Event FMQ
+ */
+ void readEvents();
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsAidlEnvironment);
+
+ /**
+ * Pointer to the Sensors HAL Interface that allows the test to call HAL functions.
+ */
+ std::shared_ptr<ISensors> mSensors;
+ std::shared_ptr<ISensorsCallback> mCallback;
+
+ ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+ /**
+ * Type used to simplify the creation of the Wake Lock FMQ
+ */
+ typedef android::AidlMessageQueue<int32_t, SynchronizedReadWrite> WakeLockQueue;
+ typedef android::AidlMessageQueue<Event, SynchronizedReadWrite> EventQueue;
+
+ /**
+ * The Wake Lock FMQ is used by the test to notify the Sensors HAL whenever it has processed
+ * WAKE_UP sensor events.
+ */
+ std::unique_ptr<WakeLockQueue> mWakeLockQueue;
+ std::unique_ptr<EventQueue> mEventQueue;
+
+ /**
+ * The Event Queue Flag notifies the test framework when sensor events have been written to the
+ * Event FMQ by the Sensors HAL.
+ */
+ ::android::hardware::EventFlag* mEventQueueFlag;
+
+ std::atomic_bool mStopThread;
+ std::thread mPollThread;
+
+ /**
+ * An array that is used to store sensor events read from the Event FMQ
+ */
+ std::array<Event, MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer;
+};
+
+#endif // ANDROID_SENSORS_AIDL_ENVIRONMENT_H
diff --git a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
new file mode 100644
index 0000000..33645b2
--- /dev/null
+++ b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
@@ -0,0 +1,871 @@
+/*
+ * 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 <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <aidl/android/hardware/sensors/BnSensors.h>
+#include <aidl/android/hardware/sensors/ISensors.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <hardware/sensors.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+
+#include "SensorsAidlEnvironment.h"
+#include "sensors-vts-utils/SensorsVtsEnvironmentBase.h"
+
+#include <cinttypes>
+#include <condition_variable>
+#include <map>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+using aidl::android::hardware::sensors::Event;
+using aidl::android::hardware::sensors::ISensors;
+using aidl::android::hardware::sensors::SensorInfo;
+using aidl::android::hardware::sensors::SensorStatus;
+using aidl::android::hardware::sensors::SensorType;
+using android::ProcessState;
+using std::chrono::duration_cast;
+
+namespace {
+
+static void assertTypeMatchStringType(SensorType type, const std::string& stringType) {
+ if (type >= SensorType::DEVICE_PRIVATE_BASE) {
+ return;
+ }
+
+ switch (type) {
+#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type) \
+ case SensorType::type: \
+ ASSERT_STREQ(SENSOR_STRING_TYPE_##type, stringType.c_str()); \
+ break;
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE);
+ CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE);
+ default:
+ FAIL() << "Type " << static_cast<int>(type)
+ << " in android defined range is not checked, "
+ << "stringType = " << stringType;
+#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE
+ }
+}
+
+int expectedReportModeForType(SensorType type) {
+ switch (type) {
+ case SensorType::ACCELEROMETER:
+ case SensorType::ACCELEROMETER_UNCALIBRATED:
+ case SensorType::GYROSCOPE:
+ case SensorType::MAGNETIC_FIELD:
+ case SensorType::ORIENTATION:
+ case SensorType::PRESSURE:
+ case SensorType::GRAVITY:
+ case SensorType::LINEAR_ACCELERATION:
+ case SensorType::ROTATION_VECTOR:
+ case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+ case SensorType::GAME_ROTATION_VECTOR:
+ case SensorType::GYROSCOPE_UNCALIBRATED:
+ case SensorType::GEOMAGNETIC_ROTATION_VECTOR:
+ case SensorType::POSE_6DOF:
+ case SensorType::HEART_BEAT:
+ return SensorInfo::SENSOR_FLAG_BITS_CONTINUOUS_MODE;
+
+ case SensorType::LIGHT:
+ case SensorType::PROXIMITY:
+ case SensorType::RELATIVE_HUMIDITY:
+ case SensorType::AMBIENT_TEMPERATURE:
+ case SensorType::HEART_RATE:
+ case SensorType::DEVICE_ORIENTATION:
+ case SensorType::STEP_COUNTER:
+ case SensorType::LOW_LATENCY_OFFBODY_DETECT:
+ return SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE;
+
+ case SensorType::SIGNIFICANT_MOTION:
+ case SensorType::WAKE_GESTURE:
+ case SensorType::GLANCE_GESTURE:
+ case SensorType::PICK_UP_GESTURE:
+ case SensorType::MOTION_DETECT:
+ case SensorType::STATIONARY_DETECT:
+ return SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE;
+
+ case SensorType::STEP_DETECTOR:
+ case SensorType::TILT_DETECTOR:
+ case SensorType::WRIST_TILT_GESTURE:
+ case SensorType::DYNAMIC_SENSOR_META:
+ return SensorInfo::SENSOR_FLAG_BITS_SPECIAL_REPORTING_MODE;
+
+ default:
+ ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type);
+ return INT32_MAX;
+ }
+}
+
+void assertTypeMatchReportMode(SensorType type, int reportMode) {
+ if (type >= SensorType::DEVICE_PRIVATE_BASE) {
+ return;
+ }
+
+ int expected = expectedReportModeForType(type);
+
+ ASSERT_TRUE(expected == INT32_MAX || expected == reportMode)
+ << "reportMode=" << static_cast<int>(reportMode)
+ << "expected=" << static_cast<int>(expected);
+}
+
+void assertDelayMatchReportMode(int32_t minDelayUs, int32_t maxDelayUs, int reportMode) {
+ switch (reportMode) {
+ case SensorInfo::SENSOR_FLAG_BITS_CONTINUOUS_MODE:
+ ASSERT_LT(0, minDelayUs);
+ ASSERT_LE(0, maxDelayUs);
+ break;
+ case SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE:
+ ASSERT_LE(0, minDelayUs);
+ ASSERT_LE(0, maxDelayUs);
+ break;
+ case SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE:
+ ASSERT_EQ(-1, minDelayUs);
+ ASSERT_EQ(0, maxDelayUs);
+ break;
+ case SensorInfo::SENSOR_FLAG_BITS_SPECIAL_REPORTING_MODE:
+ // do not enforce anything for special reporting mode
+ break;
+ default:
+ FAIL() << "Report mode " << static_cast<int>(reportMode) << " not checked";
+ }
+}
+
+void checkIsOk(ndk::ScopedAStatus status) {
+ ASSERT_TRUE(status.isOk());
+}
+
+} // namespace
+
+class EventCallback : public IEventCallback<Event> {
+ public:
+ void reset() {
+ mFlushMap.clear();
+ mEventMap.clear();
+ }
+
+ void onEvent(const Event& event) override {
+ if (event.sensorType == SensorType::META_DATA &&
+ event.payload.get<Event::EventPayload::Tag::meta>().what ==
+ Event::EventPayload::MetaData::MetaDataEventType::META_DATA_FLUSH_COMPLETE) {
+ std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+ mFlushMap[event.sensorHandle]++;
+ mFlushCV.notify_all();
+ } else if (event.sensorType != SensorType::ADDITIONAL_INFO) {
+ std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+ mEventMap[event.sensorHandle].push_back(event);
+ mEventCV.notify_all();
+ }
+ }
+
+ int32_t getFlushCount(int32_t sensorHandle) {
+ std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+ return mFlushMap[sensorHandle];
+ }
+
+ void waitForFlushEvents(const std::vector<SensorInfo>& sensorsToWaitFor,
+ int32_t numCallsToFlush, std::chrono::milliseconds timeout) {
+ std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+ mFlushCV.wait_for(lock, timeout,
+ [&] { return flushesReceived(sensorsToWaitFor, numCallsToFlush); });
+ }
+
+ const std::vector<Event> getEvents(int32_t sensorHandle) {
+ std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+ return mEventMap[sensorHandle];
+ }
+
+ void waitForEvents(const std::vector<SensorInfo>& sensorsToWaitFor,
+ std::chrono::milliseconds timeout) {
+ std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+ mEventCV.wait_for(lock, timeout, [&] { return eventsReceived(sensorsToWaitFor); });
+ }
+
+ protected:
+ bool flushesReceived(const std::vector<SensorInfo>& sensorsToWaitFor, int32_t numCallsToFlush) {
+ for (const SensorInfo& sensor : sensorsToWaitFor) {
+ if (getFlushCount(sensor.sensorHandle) < numCallsToFlush) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool eventsReceived(const std::vector<SensorInfo>& sensorsToWaitFor) {
+ for (const SensorInfo& sensor : sensorsToWaitFor) {
+ if (getEvents(sensor.sensorHandle).size() == 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ std::map<int32_t, int32_t> mFlushMap;
+ std::recursive_mutex mFlushMutex;
+ std::condition_variable_any mFlushCV;
+
+ std::map<int32_t, std::vector<Event>> mEventMap;
+ std::recursive_mutex mEventMutex;
+ std::condition_variable_any mEventCV;
+};
+
+class SensorsAidlTest : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ mEnvironment = new SensorsAidlEnvironment(GetParam());
+ mEnvironment->SetUp();
+
+ // Ensure that we have a valid environment before performing tests
+ ASSERT_NE(getSensors(), nullptr);
+ }
+
+ virtual void TearDown() override {
+ for (int32_t handle : mSensorHandles) {
+ activate(handle, false);
+ }
+ mSensorHandles.clear();
+
+ mEnvironment->TearDown();
+ delete mEnvironment;
+ mEnvironment = nullptr;
+ }
+
+ protected:
+ std::vector<SensorInfo> getNonOneShotSensors();
+ std::vector<SensorInfo> getNonOneShotAndNonSpecialSensors();
+ std::vector<SensorInfo> getNonOneShotAndNonOnChangeAndNonSpecialSensors();
+ std::vector<SensorInfo> getOneShotSensors();
+ std::vector<SensorInfo> getInjectEventSensors();
+
+ inline std::shared_ptr<ISensors>& getSensors() { return mEnvironment->mSensors; }
+
+ inline SensorsAidlEnvironment* getEnvironment() { return mEnvironment; }
+
+ inline bool isValidType(SensorType sensorType) { return (int)sensorType > 0; }
+
+ std::vector<SensorInfo> getSensorsList();
+
+ int32_t getInvalidSensorHandle() {
+ // Find a sensor handle that does not exist in the sensor list
+ int32_t maxHandle = 0;
+ for (const SensorInfo& sensor : getSensorsList()) {
+ maxHandle = std::max(maxHandle, sensor.sensorHandle);
+ }
+ return maxHandle + 1;
+ }
+
+ ndk::ScopedAStatus activate(int32_t sensorHandle, bool enable);
+ void activateAllSensors(bool enable);
+
+ ndk::ScopedAStatus batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) {
+ return getSensors()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
+ }
+
+ ndk::ScopedAStatus flush(int32_t sensorHandle) { return getSensors()->flush(sensorHandle); }
+
+ void runSingleFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
+ int32_t expectedFlushCount, bool expectedResult);
+
+ void runFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
+ int32_t flushCalls, int32_t expectedFlushCount, bool expectedResult);
+
+ inline static int32_t extractReportMode(int32_t flag) {
+ return (flag & (SensorInfo::SENSOR_FLAG_BITS_CONTINUOUS_MODE |
+ SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE |
+ SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE |
+ SensorInfo::SENSOR_FLAG_BITS_SPECIAL_REPORTING_MODE));
+ }
+
+ // All sensors and direct channnels used
+ std::unordered_set<int32_t> mSensorHandles;
+ std::unordered_set<int32_t> mDirectChannelHandles;
+
+ private:
+ SensorsAidlEnvironment* mEnvironment;
+};
+
+std::vector<SensorInfo> SensorsAidlTest::getSensorsList() {
+ std::vector<SensorInfo> sensorInfoList;
+ checkIsOk(getSensors()->getSensorsList(&sensorInfoList));
+ return sensorInfoList;
+}
+
+ndk::ScopedAStatus SensorsAidlTest::activate(int32_t sensorHandle, bool enable) {
+ // If activating a sensor, add the handle in a set so that when test fails it can be turned off.
+ // The handle is not removed when it is deactivating on purpose so that it is not necessary to
+ // check the return value of deactivation. Deactivating a sensor more than once does not have
+ // negative effect.
+ if (enable) {
+ mSensorHandles.insert(sensorHandle);
+ }
+ return getSensors()->activate(sensorHandle, enable);
+}
+
+void SensorsAidlTest::activateAllSensors(bool enable) {
+ for (const SensorInfo& sensorInfo : getSensorsList()) {
+ if (isValidType(sensorInfo.type)) {
+ checkIsOk(batch(sensorInfo.sensorHandle, sensorInfo.minDelayUs,
+ 0 /* maxReportLatencyNs */));
+ checkIsOk(activate(sensorInfo.sensorHandle, enable));
+ }
+ }
+}
+
+std::vector<SensorInfo> SensorsAidlTest::getNonOneShotSensors() {
+ std::vector<SensorInfo> sensors;
+ for (const SensorInfo& info : getSensorsList()) {
+ if (extractReportMode(info.flags) != SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE) {
+ sensors.push_back(info);
+ }
+ }
+ return sensors;
+}
+
+std::vector<SensorInfo> SensorsAidlTest::getNonOneShotAndNonSpecialSensors() {
+ std::vector<SensorInfo> sensors;
+ for (const SensorInfo& info : getSensorsList()) {
+ int reportMode = extractReportMode(info.flags);
+ if (reportMode != SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE &&
+ reportMode != SensorInfo::SENSOR_FLAG_BITS_SPECIAL_REPORTING_MODE) {
+ sensors.push_back(info);
+ }
+ }
+ return sensors;
+}
+
+std::vector<SensorInfo> SensorsAidlTest::getNonOneShotAndNonOnChangeAndNonSpecialSensors() {
+ std::vector<SensorInfo> sensors;
+ for (const SensorInfo& info : getSensorsList()) {
+ int reportMode = extractReportMode(info.flags);
+ if (reportMode != SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE &&
+ reportMode != SensorInfo::SENSOR_FLAG_BITS_ON_CHANGE_MODE &&
+ reportMode != SensorInfo::SENSOR_FLAG_BITS_SPECIAL_REPORTING_MODE) {
+ sensors.push_back(info);
+ }
+ }
+ return sensors;
+}
+
+std::vector<SensorInfo> SensorsAidlTest::getOneShotSensors() {
+ std::vector<SensorInfo> sensors;
+ for (const SensorInfo& info : getSensorsList()) {
+ if (extractReportMode(info.flags) == SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE) {
+ sensors.push_back(info);
+ }
+ }
+ return sensors;
+}
+
+std::vector<SensorInfo> SensorsAidlTest::getInjectEventSensors() {
+ std::vector<SensorInfo> out;
+ std::vector<SensorInfo> sensorInfoList = getSensorsList();
+ for (const SensorInfo& info : sensorInfoList) {
+ if (info.flags & SensorInfo::SENSOR_FLAG_BITS_DATA_INJECTION) {
+ out.push_back(info);
+ }
+ }
+ return out;
+}
+
+void SensorsAidlTest::runSingleFlushTest(const std::vector<SensorInfo>& sensors,
+ bool activateSensor, int32_t expectedFlushCount,
+ bool expectedResult) {
+ runFlushTest(sensors, activateSensor, 1 /* flushCalls */, expectedFlushCount, expectedResult);
+}
+
+void SensorsAidlTest::runFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
+ int32_t flushCalls, int32_t expectedFlushCount,
+ bool expectedResult) {
+ EventCallback callback;
+ getEnvironment()->registerCallback(&callback);
+
+ for (const SensorInfo& sensor : sensors) {
+ // Configure and activate the sensor
+ batch(sensor.sensorHandle, sensor.maxDelayUs, 0 /* maxReportLatencyNs */);
+ activate(sensor.sensorHandle, activateSensor);
+
+ // Flush the sensor
+ for (int32_t i = 0; i < flushCalls; i++) {
+ SCOPED_TRACE(::testing::Message()
+ << "Flush " << i << "/" << flushCalls << ": "
+ << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+ << sensor.sensorHandle << std::dec
+ << " type=" << static_cast<int>(sensor.type) << " name=" << sensor.name);
+
+ EXPECT_EQ(flush(sensor.sensorHandle).isOk(), expectedResult);
+ }
+ }
+
+ // Wait up to one second for the flush events
+ callback.waitForFlushEvents(sensors, flushCalls, std::chrono::milliseconds(1000) /* timeout */);
+
+ // Deactivate all sensors after waiting for flush events so pending flush events are not
+ // abandoned by the HAL.
+ for (const SensorInfo& sensor : sensors) {
+ activate(sensor.sensorHandle, false);
+ }
+ getEnvironment()->unregisterCallback();
+
+ // Check that the correct number of flushes are present for each sensor
+ for (const SensorInfo& sensor : sensors) {
+ SCOPED_TRACE(::testing::Message()
+ << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+ << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+ << " name=" << sensor.name);
+ ASSERT_EQ(callback.getFlushCount(sensor.sensorHandle), expectedFlushCount);
+ }
+}
+
+TEST_P(SensorsAidlTest, SensorListValid) {
+ std::vector<SensorInfo> sensorInfoList = getSensorsList();
+ std::unordered_map<int32_t, std::vector<std::string>> sensorTypeNameMap;
+ for (size_t i = 0; i < sensorInfoList.size(); ++i) {
+ const SensorInfo& info = sensorInfoList[i];
+ SCOPED_TRACE(::testing::Message()
+ << i << "/" << sensorInfoList.size() << ": "
+ << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+ << info.sensorHandle << std::dec << " type=" << static_cast<int>(info.type)
+ << " name=" << info.name);
+
+ // Test type string non-empty only for private sensor typeinfo.
+ if (info.type >= SensorType::DEVICE_PRIVATE_BASE) {
+ EXPECT_FALSE(info.typeAsString.empty());
+ } else if (!info.typeAsString.empty()) {
+ // Test type string matches framework string if specified for non-private typeinfo.
+ EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(info.type, info.typeAsString));
+ }
+
+ // Test if all sensor has name and vendor
+ EXPECT_FALSE(info.name.empty());
+ EXPECT_FALSE(info.vendor.empty());
+
+ // Make sure that sensors of the same type have a unique name.
+ std::vector<std::string>& v = sensorTypeNameMap[static_cast<int32_t>(info.type)];
+ bool isUniqueName = std::find(v.begin(), v.end(), info.name) == v.end();
+ EXPECT_TRUE(isUniqueName) << "Duplicate sensor Name: " << info.name;
+ if (isUniqueName) {
+ v.push_back(info.name);
+ }
+
+ EXPECT_LE(0, info.power);
+ EXPECT_LT(0, info.maxRange);
+
+ // Info type, should have no sensor
+ EXPECT_FALSE(info.type == SensorType::ADDITIONAL_INFO ||
+ info.type == SensorType::META_DATA);
+
+ EXPECT_GE(info.fifoMaxEventCount, info.fifoReservedEventCount);
+
+ // Test Reporting mode valid
+ EXPECT_NO_FATAL_FAILURE(
+ assertTypeMatchReportMode(info.type, extractReportMode(info.flags)));
+
+ // Test min max are in the right order
+ EXPECT_LE(info.minDelayUs, info.maxDelayUs);
+ // Test min/max delay matches reporting mode
+ EXPECT_NO_FATAL_FAILURE(assertDelayMatchReportMode(info.minDelayUs, info.maxDelayUs,
+ extractReportMode(info.flags)));
+ }
+}
+
+TEST_P(SensorsAidlTest, SetOperationMode) {
+ if (getInjectEventSensors().size() > 0) {
+ ASSERT_TRUE(getSensors()->setOperationMode(ISensors::OperationMode::NORMAL).isOk());
+ ASSERT_TRUE(getSensors()->setOperationMode(ISensors::OperationMode::DATA_INJECTION).isOk());
+ ASSERT_TRUE(getSensors()->setOperationMode(ISensors::OperationMode::NORMAL).isOk());
+ } else {
+ ASSERT_EQ(getSensors()
+ ->setOperationMode(ISensors::OperationMode::DATA_INJECTION)
+ .getExceptionCode(),
+ EX_UNSUPPORTED_OPERATION);
+ }
+}
+
+TEST_P(SensorsAidlTest, InjectSensorEventData) {
+ std::vector<SensorInfo> sensors = getInjectEventSensors();
+ if (sensors.size() == 0) {
+ return;
+ }
+
+ ASSERT_TRUE(getSensors()->setOperationMode(ISensors::OperationMode::DATA_INJECTION).isOk());
+
+ EventCallback callback;
+ getEnvironment()->registerCallback(&callback);
+
+ // AdditionalInfo event should not be sent to Event FMQ
+ Event additionalInfoEvent;
+ additionalInfoEvent.sensorType = SensorType::ADDITIONAL_INFO;
+ additionalInfoEvent.timestamp = android::elapsedRealtimeNano();
+
+ Event injectedEvent;
+ injectedEvent.timestamp = android::elapsedRealtimeNano();
+ Event::EventPayload::Vec3 data = {1, 2, 3, SensorStatus::ACCURACY_HIGH};
+ injectedEvent.payload.set<Event::EventPayload::Tag::vec3>(data);
+
+ for (const auto& s : sensors) {
+ additionalInfoEvent.sensorHandle = s.sensorHandle;
+ ASSERT_TRUE(getSensors()->injectSensorData(additionalInfoEvent).isOk());
+
+ injectedEvent.sensorType = s.type;
+ injectedEvent.sensorHandle = s.sensorHandle;
+ ASSERT_TRUE(getSensors()->injectSensorData(injectedEvent).isOk());
+ }
+
+ // Wait for events to be written back to the Event FMQ
+ callback.waitForEvents(sensors, std::chrono::milliseconds(1000) /* timeout */);
+ getEnvironment()->unregisterCallback();
+
+ for (const auto& s : sensors) {
+ auto events = callback.getEvents(s.sensorHandle);
+ if (events.empty()) {
+ FAIL() << "Received no events";
+ } else {
+ auto lastEvent = events.back();
+ SCOPED_TRACE(::testing::Message()
+ << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+ << s.sensorHandle << std::dec << " type=" << static_cast<int>(s.type)
+ << " name=" << s.name);
+
+ // Verify that only a single event has been received
+ ASSERT_EQ(events.size(), 1);
+
+ // Verify that the event received matches the event injected and is not the additional
+ // info event
+ ASSERT_EQ(lastEvent.sensorType, s.type);
+ ASSERT_EQ(lastEvent.timestamp, injectedEvent.timestamp);
+ ASSERT_EQ(lastEvent.payload.get<Event::EventPayload::Tag::vec3>().x,
+ injectedEvent.payload.get<Event::EventPayload::Tag::vec3>().x);
+ ASSERT_EQ(lastEvent.payload.get<Event::EventPayload::Tag::vec3>().y,
+ injectedEvent.payload.get<Event::EventPayload::Tag::vec3>().y);
+ ASSERT_EQ(lastEvent.payload.get<Event::EventPayload::Tag::vec3>().z,
+ injectedEvent.payload.get<Event::EventPayload::Tag::vec3>().z);
+ ASSERT_EQ(lastEvent.payload.get<Event::EventPayload::Tag::vec3>().status,
+ injectedEvent.payload.get<Event::EventPayload::Tag::vec3>().status);
+ }
+ }
+
+ ASSERT_TRUE(getSensors()->setOperationMode(ISensors::OperationMode::NORMAL).isOk());
+}
+
+TEST_P(SensorsAidlTest, CallInitializeTwice) {
+ // Create a helper class so that a second environment is able to be instantiated
+ class SensorsAidlEnvironmentTest : public SensorsAidlEnvironment {
+ public:
+ SensorsAidlEnvironmentTest(const std::string& service_name)
+ : SensorsAidlEnvironment(service_name) {}
+ };
+
+ if (getSensorsList().size() == 0) {
+ // No sensors
+ return;
+ }
+
+ constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000; // 1s
+ constexpr int32_t kNumEvents = 1;
+
+ // Create a new environment that calls initialize()
+ std::unique_ptr<SensorsAidlEnvironmentTest> newEnv =
+ std::make_unique<SensorsAidlEnvironmentTest>(GetParam());
+ newEnv->SetUp();
+ if (HasFatalFailure()) {
+ return; // Exit early if setting up the new environment failed
+ }
+
+ activateAllSensors(true);
+ // Verify that the old environment does not receive any events
+ EXPECT_EQ(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), 0);
+ // Verify that the new event queue receives sensor events
+ EXPECT_GE(newEnv.get()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+ activateAllSensors(false);
+
+ // Cleanup the test environment
+ newEnv->TearDown();
+
+ // Restore the test environment for future tests
+ getEnvironment()->TearDown();
+ getEnvironment()->SetUp();
+ if (HasFatalFailure()) {
+ return; // Exit early if resetting the environment failed
+ }
+
+ // Ensure that the original environment is receiving events
+ activateAllSensors(true);
+ EXPECT_GE(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+ activateAllSensors(false);
+}
+
+TEST_P(SensorsAidlTest, CleanupConnectionsOnInitialize) {
+ activateAllSensors(true);
+
+ // Verify that events are received
+ constexpr useconds_t kCollectionTimeoutUs = 1000 * 1000; // 1s
+ constexpr int32_t kNumEvents = 1;
+ ASSERT_GE(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+
+ // Clear the active sensor handles so they are not disabled during TearDown
+ auto handles = mSensorHandles;
+ mSensorHandles.clear();
+ getEnvironment()->TearDown();
+ getEnvironment()->SetUp();
+ if (HasFatalFailure()) {
+ return; // Exit early if resetting the environment failed
+ }
+
+ // Verify no events are received until sensors are re-activated
+ ASSERT_EQ(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), 0);
+ activateAllSensors(true);
+ ASSERT_GE(getEnvironment()->collectEvents(kCollectionTimeoutUs, kNumEvents).size(), kNumEvents);
+
+ // Disable sensors
+ activateAllSensors(false);
+
+ // Restore active sensors prior to clearing the environment
+ mSensorHandles = handles;
+}
+
+TEST_P(SensorsAidlTest, FlushSensor) {
+ std::vector<SensorInfo> sensors = getNonOneShotSensors();
+ if (sensors.size() == 0) {
+ return;
+ }
+
+ constexpr int32_t kFlushes = 5;
+ runSingleFlushTest(sensors, true /* activateSensor */, 1 /* expectedFlushCount */,
+ true /* expectedResult */);
+ runFlushTest(sensors, true /* activateSensor */, kFlushes, kFlushes, true /* expectedResult */);
+}
+
+TEST_P(SensorsAidlTest, FlushOneShotSensor) {
+ // Find a sensor that is a one-shot sensor
+ std::vector<SensorInfo> sensors = getOneShotSensors();
+ if (sensors.size() == 0) {
+ return;
+ }
+
+ runSingleFlushTest(sensors, true /* activateSensor */, 0 /* expectedFlushCount */,
+ false /* expectedResult */);
+}
+
+TEST_P(SensorsAidlTest, FlushInactiveSensor) {
+ // Attempt to find a non-one shot sensor, then a one-shot sensor if necessary
+ std::vector<SensorInfo> sensors = getNonOneShotSensors();
+ if (sensors.size() == 0) {
+ sensors = getOneShotSensors();
+ if (sensors.size() == 0) {
+ return;
+ }
+ }
+
+ runSingleFlushTest(sensors, false /* activateSensor */, 0 /* expectedFlushCount */,
+ false /* expectedResult */);
+}
+
+TEST_P(SensorsAidlTest, Batch) {
+ if (getSensorsList().size() == 0) {
+ return;
+ }
+
+ activateAllSensors(false /* enable */);
+ for (const SensorInfo& sensor : getSensorsList()) {
+ SCOPED_TRACE(::testing::Message()
+ << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+ << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+ << " name=" << sensor.name);
+
+ // Call batch on inactive sensor
+ // One shot sensors have minDelay set to -1 which is an invalid
+ // parameter. Use 0 instead to avoid errors.
+ int64_t samplingPeriodNs =
+ extractReportMode(sensor.flags) == SensorInfo::SENSOR_FLAG_BITS_ONE_SHOT_MODE
+ ? 0
+ : sensor.minDelayUs;
+ checkIsOk(batch(sensor.sensorHandle, samplingPeriodNs, 0 /* maxReportLatencyNs */));
+
+ // Activate the sensor
+ activate(sensor.sensorHandle, true /* enabled */);
+
+ // Call batch on an active sensor
+ checkIsOk(batch(sensor.sensorHandle, sensor.maxDelayUs, 0 /* maxReportLatencyNs */));
+ }
+ activateAllSensors(false /* enable */);
+
+ // Call batch on an invalid sensor
+ SensorInfo sensor = getSensorsList().front();
+ sensor.sensorHandle = getInvalidSensorHandle();
+ ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelayUs, 0 /* maxReportLatencyNs */)
+ .getExceptionCode(),
+ EX_ILLEGAL_ARGUMENT);
+}
+
+TEST_P(SensorsAidlTest, Activate) {
+ if (getSensorsList().size() == 0) {
+ return;
+ }
+
+ // Verify that sensor events are generated when activate is called
+ for (const SensorInfo& sensor : getSensorsList()) {
+ SCOPED_TRACE(::testing::Message()
+ << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+ << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+ << " name=" << sensor.name);
+
+ checkIsOk(batch(sensor.sensorHandle, sensor.minDelayUs, 0 /* maxReportLatencyNs */));
+ checkIsOk(activate(sensor.sensorHandle, true));
+
+ // Call activate on a sensor that is already activated
+ checkIsOk(activate(sensor.sensorHandle, true));
+
+ // Deactivate the sensor
+ checkIsOk(activate(sensor.sensorHandle, false));
+
+ // Call deactivate on a sensor that is already deactivated
+ checkIsOk(activate(sensor.sensorHandle, false));
+ }
+
+ // Attempt to activate an invalid sensor
+ int32_t invalidHandle = getInvalidSensorHandle();
+ ASSERT_EQ(activate(invalidHandle, true).getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+ ASSERT_EQ(activate(invalidHandle, false).getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+}
+
+TEST_P(SensorsAidlTest, NoStaleEvents) {
+ constexpr std::chrono::milliseconds kFiveHundredMs(500);
+ constexpr std::chrono::milliseconds kOneSecond(1000);
+
+ // Register the callback to receive sensor events
+ EventCallback callback;
+ getEnvironment()->registerCallback(&callback);
+
+ // This test is not valid for one-shot, on-change or special-report-mode sensors
+ const std::vector<SensorInfo> sensors = getNonOneShotAndNonOnChangeAndNonSpecialSensors();
+ std::chrono::milliseconds maxMinDelay(0);
+ for (const SensorInfo& sensor : sensors) {
+ std::chrono::milliseconds minDelay = duration_cast<std::chrono::milliseconds>(
+ std::chrono::microseconds(sensor.minDelayUs));
+ maxMinDelay = std::chrono::milliseconds(std::max(maxMinDelay.count(), minDelay.count()));
+ }
+
+ // Activate the sensors so that they start generating events
+ activateAllSensors(true);
+
+ // According to the CDD, the first sample must be generated within 400ms + 2 * sample_time
+ // and the maximum reporting latency is 100ms + 2 * sample_time. Wait a sufficient amount
+ // of time to guarantee that a sample has arrived.
+ callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
+ activateAllSensors(false);
+
+ // Save the last received event for each sensor
+ std::map<int32_t, int64_t> lastEventTimestampMap;
+ for (const SensorInfo& sensor : sensors) {
+ SCOPED_TRACE(::testing::Message()
+ << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+ << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+ << " name=" << sensor.name);
+
+ if (callback.getEvents(sensor.sensorHandle).size() >= 1) {
+ lastEventTimestampMap[sensor.sensorHandle] =
+ callback.getEvents(sensor.sensorHandle).back().timestamp;
+ }
+ }
+
+ // Allow some time to pass, reset the callback, then reactivate the sensors
+ usleep(duration_cast<std::chrono::microseconds>(kOneSecond + (5 * maxMinDelay)).count());
+ callback.reset();
+ activateAllSensors(true);
+ callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
+ activateAllSensors(false);
+
+ getEnvironment()->unregisterCallback();
+
+ for (const SensorInfo& sensor : sensors) {
+ SCOPED_TRACE(::testing::Message()
+ << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+ << sensor.sensorHandle << std::dec << " type=" << static_cast<int>(sensor.type)
+ << " name=" << sensor.name);
+
+ // Skip sensors that did not previously report an event
+ if (lastEventTimestampMap.find(sensor.sensorHandle) == lastEventTimestampMap.end()) {
+ continue;
+ }
+
+ // Ensure that the first event received is not stale by ensuring that its timestamp is
+ // sufficiently different from the previous event
+ const Event newEvent = callback.getEvents(sensor.sensorHandle).front();
+ std::chrono::milliseconds delta =
+ duration_cast<std::chrono::milliseconds>(std::chrono::nanoseconds(
+ newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle]));
+ std::chrono::milliseconds sensorMinDelay = duration_cast<std::chrono::milliseconds>(
+ std::chrono::microseconds(sensor.minDelayUs));
+ ASSERT_GE(delta, kFiveHundredMs + (3 * sensorMinDelay));
+ }
+}
+
+TEST_P(SensorsAidlTest, DirectChannelAshmem) {
+ // TODO(b/195593357): Implement this
+}
+
+TEST_P(SensorsAidlTest, DirectChannelGralloc) {
+ // TODO(b/195593357): Implement this
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SensorsAidlTest);
+INSTANTIATE_TEST_SUITE_P(Sensors, SensorsAidlTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(ISensors::descriptor)),
+ android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ ProcessState::self()->startThreadPool();
+ return RUN_ALL_TESTS();
+}