Merge "Separates VTS tests by HAL version."
diff --git a/camera/metadata/3.4/types.hal b/camera/metadata/3.4/types.hal
index b228de8..4eb6929 100644
--- a/camera/metadata/3.4/types.hal
+++ b/camera/metadata/3.4/types.hal
@@ -44,6 +44,21 @@
ANDROID_REQUEST_END_3_4,
+ /** android.scaler.availableRecommendedStreamConfigurations [static, enum[], ndk_public]
+ *
+ * <p>Recommended stream configurations for common client use cases.</p>
+ */
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_SCALER_END,
+
+ /** android.scaler.availableRecommendedInputOutputFormatsMap [static, int32, ndk_public]
+ *
+ * <p>Recommended mappings of image formats that are supported by this
+ * camera device for input streams, to their corresponding output formats.</p>
+ */
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP,
+
+ ANDROID_SCALER_END_3_4,
+
/** android.info.supportedBufferManagementVersion [static, enum, system]
*
* <p>The version of buffer management API this camera device supports and opts into.</p>
@@ -52,12 +67,52 @@
ANDROID_INFO_END_3_4,
+ /** android.depth.availableRecommendedDepthStreamConfigurations [static, int32[], ndk_public]
+ *
+ * <p>Recommended depth stream configurations for common client use cases.</p>
+ */
+ ANDROID_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_DEPTH_END,
+
+ ANDROID_DEPTH_END_3_4,
+
};
/*
* Enumeration definitions for the various entries that need them
*/
+/** android.scaler.availableFormats enumeration values added since v3.2
+ * @see ANDROID_SCALER_AVAILABLE_FORMATS
+ */
+enum CameraMetadataEnumAndroidScalerAvailableFormats :
+ @3.2::CameraMetadataEnumAndroidScalerAvailableFormats {
+ ANDROID_SCALER_AVAILABLE_FORMATS_RAW10 = 0x25,
+ ANDROID_SCALER_AVAILABLE_FORMATS_RAW12 = 0x26,
+ ANDROID_SCALER_AVAILABLE_FORMATS_Y8 = 0x20203859,
+};
+
+/** android.scaler.availableRecommendedStreamConfigurations enumeration values
+ * @see ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS
+ */
+enum CameraMetadataEnumAndroidScalerAvailableRecommendedStreamConfigurations : uint32_t {
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PREVIEW
+ = 0x0,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_RECORD
+ = 0x1,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VIDEO_SNAPSHOT
+ = 0x2,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_SNAPSHOT
+ = 0x3,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_ZSL
+ = 0x4,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_RAW
+ = 0x5,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END
+ = 0x6,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VENDOR_START
+ = 0x18,
+};
+
/** android.info.supportedBufferManagementVersion enumeration values
* @see ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION
*/
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 94d06e8..837905c 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -681,6 +681,7 @@
const CameraMetadata& chars, int deviceVersion,
const hidl_vec<hidl_string>& deviceNames);
void verifyCameraCharacteristics(Status status, const CameraMetadata& chars);
+ void verifyRecommendedConfigs(const CameraMetadata& metadata);
static Status getAvailableOutputStreams(camera_metadata_t *staticMeta,
std::vector<AvailableStream> &outputStreams,
@@ -698,7 +699,7 @@
/*out*/);
static Status pickConstrainedModeSize(camera_metadata_t *staticMeta,
AvailableStream &hfrStream);
- static Status isZSLModeAvailable(camera_metadata_t *staticMeta);
+ static Status isZSLModeAvailable(const camera_metadata_t *staticMeta);
static Status getZSLInputOutputMap(camera_metadata_t *staticMeta,
std::vector<AvailableZSLInputOutput> &inputOutputMap);
static Status findLargestSize(
@@ -2079,7 +2080,7 @@
ret = device3_x->getCameraCharacteristics([&](auto status, const auto& chars) {
verifyCameraCharacteristics(status, chars);
-
+ verifyRecommendedConfigs(chars);
verifyLogicalCameraMetadata(name, device3_x, chars, deviceVersion,
cameraDeviceNames);
});
@@ -4323,7 +4324,7 @@
// Check whether ZSL is available using the static camera
// characteristics.
-Status CameraHidlTest::isZSLModeAvailable(camera_metadata_t *staticMeta) {
+Status CameraHidlTest::isZSLModeAvailable(const camera_metadata_t *staticMeta) {
Status ret = Status::METHOD_NOT_SUPPORTED;
if (nullptr == staticMeta) {
return Status::ILLEGAL_ARGUMENT;
@@ -4978,6 +4979,94 @@
ASSERT_TRUE(ret.isOk());
}
+void CameraHidlTest::verifyRecommendedConfigs(const CameraMetadata& chars) {
+ size_t CONFIG_ENTRY_SIZE = 5;
+ size_t CONFIG_ENTRY_TYPE_OFFSET = 3;
+ size_t CONFIG_ENTRY_BITFIELD_OFFSET = 4;
+ uint32_t maxPublicUsecase =
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_PUBLIC_END;
+ uint32_t vendorUsecaseStart =
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS_VENDOR_START;
+ uint32_t usecaseMask = (1 << vendorUsecaseStart) - 1;
+ usecaseMask &= ~((1 << maxPublicUsecase) - 1);
+
+ const camera_metadata_t* metadata = reinterpret_cast<const camera_metadata_t*> (chars.data());
+
+ camera_metadata_ro_entry recommendedConfigsEntry, recommendedDepthConfigsEntry, ioMapEntry;
+ recommendedConfigsEntry.count = recommendedDepthConfigsEntry.count = ioMapEntry.count = 0;
+ int retCode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS, &recommendedConfigsEntry);
+ int depthRetCode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS,
+ &recommendedDepthConfigsEntry);
+ int ioRetCode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP, &ioMapEntry);
+ if ((0 != retCode) && (0 != depthRetCode)) {
+ //In case both regular and depth recommended configurations are absent,
+ //I/O should be absent as well.
+ ASSERT_NE(ioRetCode, 0);
+ return;
+ }
+
+ camera_metadata_ro_entry availableKeysEntry;
+ retCode = find_camera_metadata_ro_entry(metadata,
+ ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &availableKeysEntry);
+ ASSERT_TRUE((0 == retCode) && (availableKeysEntry.count > 0));
+ std::vector<int32_t> availableKeys;
+ availableKeys.reserve(availableKeysEntry.count);
+ availableKeys.insert(availableKeys.end(), availableKeysEntry.data.i32,
+ availableKeysEntry.data.i32 + availableKeysEntry.count);
+
+ if (recommendedConfigsEntry.count > 0) {
+ ASSERT_NE(std::find(availableKeys.begin(), availableKeys.end(),
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_STREAM_CONFIGURATIONS),
+ availableKeys.end());
+ ASSERT_EQ((recommendedConfigsEntry.count % CONFIG_ENTRY_SIZE), 0);
+ for (size_t i = 0; i < recommendedConfigsEntry.count; i += CONFIG_ENTRY_SIZE) {
+ int32_t entryType =
+ recommendedConfigsEntry.data.i32[i + CONFIG_ENTRY_TYPE_OFFSET];
+ uint32_t bitfield =
+ recommendedConfigsEntry.data.i32[i + CONFIG_ENTRY_BITFIELD_OFFSET];
+ ASSERT_TRUE((entryType ==
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) ||
+ (entryType ==
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT));
+ ASSERT_TRUE((bitfield & usecaseMask) == 0);
+ }
+ }
+
+ if (recommendedDepthConfigsEntry.count > 0) {
+ ASSERT_NE(std::find(availableKeys.begin(), availableKeys.end(),
+ ANDROID_DEPTH_AVAILABLE_RECOMMENDED_DEPTH_STREAM_CONFIGURATIONS),
+ availableKeys.end());
+ ASSERT_EQ((recommendedDepthConfigsEntry.count % CONFIG_ENTRY_SIZE), 0);
+ for (size_t i = 0; i < recommendedDepthConfigsEntry.count; i += CONFIG_ENTRY_SIZE) {
+ int32_t entryType =
+ recommendedDepthConfigsEntry.data.i32[i + CONFIG_ENTRY_TYPE_OFFSET];
+ uint32_t bitfield =
+ recommendedDepthConfigsEntry.data.i32[i + CONFIG_ENTRY_BITFIELD_OFFSET];
+ ASSERT_TRUE((entryType ==
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT) ||
+ (entryType ==
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT));
+ ASSERT_TRUE((bitfield & usecaseMask) == 0);
+ }
+
+ if (recommendedConfigsEntry.count == 0) {
+ //In case regular recommended configurations are absent but suggested depth
+ //configurations are present, I/O should be absent.
+ ASSERT_NE(ioRetCode, 0);
+ }
+ }
+
+ if ((ioRetCode == 0) && (ioMapEntry.count > 0)) {
+ ASSERT_NE(std::find(availableKeys.begin(), availableKeys.end(),
+ ANDROID_SCALER_AVAILABLE_RECOMMENDED_INPUT_OUTPUT_FORMATS_MAP),
+ availableKeys.end());
+ ASSERT_EQ(isZSLModeAvailable(metadata), Status::OK);
+ }
+}
+
int main(int argc, char **argv) {
::testing::AddGlobalTestEnvironment(CameraHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
diff --git a/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp b/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp
index a1676be..70b5830 100644
--- a/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp
+++ b/configstore/1.0/vts/functional/VtsHalConfigstoreV1_0TargetTest.cpp
@@ -131,6 +131,27 @@
}
}
+/**
+ * Make sure the constrains of hasWideColorDisplay, hasHDRDisplay
+ * are enforced.
+ */
+TEST_F(ConfigstoreHidlTest, TestColorConstrainsBasic) {
+ bool hasWideColorDisplay;
+ bool hasHDRDisplay;
+
+ Return<void> status = sfConfigs->hasWideColorDisplay(
+ [&](OptionalBool arg) { hasWideColorDisplay = arg.specified; });
+ EXPECT_OK(status);
+
+ status = sfConfigs->hasHDRDisplay([&](OptionalBool arg) { hasHDRDisplay = arg.specified; });
+ EXPECT_OK(status);
+
+ // When hasHDRDisplay returns true, hasWideColorDisplay must also return true.
+ if (hasHDRDisplay) {
+ ASSERT_TRUE(hasWideColorDisplay);
+ }
+}
+
int main(int argc, char** argv) {
::testing::AddGlobalTestEnvironment(ConfigstoreHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
diff --git a/configstore/1.2/vts/functional/Android.bp b/configstore/1.2/vts/functional/Android.bp
new file mode 100644
index 0000000..5f1eca6
--- /dev/null
+++ b/configstore/1.2/vts/functional/Android.bp
@@ -0,0 +1,27 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+ name: "VtsHalConfigstoreV1_2TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalConfigstoreV1_2TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.configstore@1.0",
+ "android.hardware.configstore@1.1",
+ "android.hardware.configstore@1.2",
+ ],
+}
+
diff --git a/configstore/1.2/vts/functional/OWNERS b/configstore/1.2/vts/functional/OWNERS
new file mode 100644
index 0000000..2b4fb8c
--- /dev/null
+++ b/configstore/1.2/vts/functional/OWNERS
@@ -0,0 +1,7 @@
+# Graphics team
+lpy@google.com
+olv@google.com
+stoza@google.com
+
+# VTS team
+yim@google.com
diff --git a/configstore/1.2/vts/functional/VtsHalConfigstoreV1_2TargetTest.cpp b/configstore/1.2/vts/functional/VtsHalConfigstoreV1_2TargetTest.cpp
new file mode 100644
index 0000000..dc5fec5
--- /dev/null
+++ b/configstore/1.2/vts/functional/VtsHalConfigstoreV1_2TargetTest.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "ConfigstoreHidlHalTest"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/configstore/1.0/types.h>
+#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
+#include <unistd.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::configstore::V1_0::OptionalBool;
+using ::android::hardware::configstore::V1_0::OptionalInt64;
+using ::android::hardware::configstore::V1_0::OptionalUInt64;
+using ::android::hardware::configstore::V1_2::ISurfaceFlingerConfigs;
+using ::android::hardware::graphics::common::V1_1::PixelFormat;
+using ::android::hardware::graphics::common::V1_2::Dataspace;
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
+#define EXPECT_OK(ret) EXPECT_TRUE(ret.isOk())
+
+// Test environment for Configstore HIDL HAL.
+class ConfigstoreHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static ConfigstoreHidlEnvironment* Instance() {
+ static ConfigstoreHidlEnvironment* instance = new ConfigstoreHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<ISurfaceFlingerConfigs>(); }
+};
+
+class ConfigstoreHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ sp<ISurfaceFlingerConfigs> sfConfigs;
+
+ virtual void SetUp() override {
+ sfConfigs = ::testing::VtsHalHidlTargetTestBase::getService<ISurfaceFlingerConfigs>(
+ ConfigstoreHidlEnvironment::Instance()->getServiceName<ISurfaceFlingerConfigs>());
+ ASSERT_NE(sfConfigs, nullptr);
+ }
+
+ virtual void TearDown() override {}
+
+ bool isSupportedWideColorGamut(Dataspace dataspace) {
+ Dataspace standard = static_cast<Dataspace>(dataspace & Dataspace::STANDARD_MASK);
+ return standard == Dataspace::STANDARD_DCI_P3 || standard == Dataspace::STANDARD_BT2020;
+ }
+};
+
+/**
+ * Make sure the constrains of hasWideColorDisplay, hasHDRDisplay
+ * and useColorManagement are enforced.
+ */
+TEST_F(ConfigstoreHidlTest, TestColorConstrainsWithColorManagement) {
+ bool hasWideColorDisplay;
+ bool hasHDRDisplay;
+ bool useColorManagement;
+
+ Return<void> status = sfConfigs->hasWideColorDisplay(
+ [&](OptionalBool arg) { hasWideColorDisplay = arg.specified; });
+ EXPECT_OK(status);
+
+ status = sfConfigs->hasHDRDisplay([&](OptionalBool arg) { hasHDRDisplay = arg.specified; });
+ EXPECT_OK(status);
+
+ status = sfConfigs->useColorManagement(
+ [&](OptionalBool arg) { useColorManagement = arg.specified; });
+ EXPECT_OK(status);
+
+ // When hasHDRDisplay returns true, hasWideColorDisplay must also return true.
+ if (hasHDRDisplay) {
+ ASSERT_TRUE(hasWideColorDisplay);
+ }
+
+ // When hasWideColorDisplay returns true, useColorManagement
+ // must also return true.
+ if (hasWideColorDisplay) {
+ ASSERT_TRUE(useColorManagement);
+ }
+}
+
+TEST_F(ConfigstoreHidlTest, TestGetCompositionPreference) {
+ bool hasWideColorDisplay;
+
+ Return<void> status = sfConfigs->hasWideColorDisplay(
+ [&](OptionalBool arg) { hasWideColorDisplay = arg.specified; });
+ EXPECT_OK(status);
+
+ Dataspace defaultDataspace, wcgDataspace;
+
+ status = sfConfigs->getCompositionPreference(
+ [&](auto tmpDefaultDataspace, PixelFormat, auto tmpWcgDataspace, PixelFormat) {
+ defaultDataspace = tmpDefaultDataspace;
+ wcgDataspace = tmpWcgDataspace;
+ });
+ EXPECT_OK(status);
+
+ // Default data space and wide color gamut data space must not be UNKNOWN.
+ ASSERT_TRUE(defaultDataspace != Dataspace::UNKNOWN && wcgDataspace != Dataspace::UNKNOWN);
+
+ // If hasWideColorDisplay returns true, the wide color gamut data space must be a valid wide
+ // color gamut.
+ if (hasWideColorDisplay) {
+ ASSERT_TRUE(isSupportedWideColorGamut(wcgDataspace));
+ }
+}
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(ConfigstoreHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ ConfigstoreHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/graphics/composer/2.3/IComposerClient.hal b/graphics/composer/2.3/IComposerClient.hal
index dec3b25..7856658 100644
--- a/graphics/composer/2.3/IComposerClient.hal
+++ b/graphics/composer/2.3/IComposerClient.hal
@@ -161,6 +161,116 @@
Dataspace dataspace)
generates (Error error);
+ enum FormatColorComponent : uint8_t {
+ /* The first component (eg, for RGBA_8888, this is R) */
+ FORMAT_COMPONENT_0 = 1 << 0,
+ /* The second component (eg, for RGBA_8888, this is G) */
+ FORMAT_COMPONENT_1 = 1 << 1,
+ /* The third component (eg, for RGBA_8888, this is B) */
+ FORMAT_COMPONENT_2 = 1 << 2,
+ /* The fourth component (eg, for RGBA_8888, this is A) */
+ FORMAT_COMPONENT_3 = 1 << 3,
+ };
+
+ /**
+ * Query for what types of color sampling the hardware supports.
+ *
+ * @param display is the display where the samples are collected.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display was passed in, or
+ * UNSUPPORTED when there is no efficient way to sample.
+ * @return format The format of the sampled pixels.
+ * @return dataspace The dataspace of the sampled pixels.
+ * @return componentMask The mask of which components can be sampled.
+ */
+ getDisplayedContentSamplingAttributes(Display display)
+ generates (Error error,
+ PixelFormat format,
+ Dataspace dataspace,
+ bitfield<FormatColorComponent> componentMask);
+
+ /** DisplayedContentSampling values passed to setDisplayedContentSamplingEnabled. */
+ enum DisplayedContentSampling : int32_t {
+ INVALID = 0,
+
+ /** Enable content sampling. */
+ ENABLE = 1,
+
+ /** Disable content sampling. */
+ DISABLE = 2,
+ };
+
+ /**
+ * Enables or disables the collection of color content statistics
+ * on this display.
+ *
+ * Sampling occurs on the contents of the final composition on this display
+ * (i.e., the contents presented on screen). Samples should be collected after all
+ * color transforms have been applied.
+ *
+ * Sampling support is optional, and is set to DISABLE by default.
+ * On each call to ENABLE, all collected statistics must be reset.
+ *
+ * Sample data can be queried via getDisplayedContentSample().
+ *
+ * @param display is the display to which the sampling mode is set.
+ * @param enabled indicates whether to enable or disable sampling.
+ * @param componentMask The mask of which components should be sampled. If zero, all supported
+ * components are to be enabled.
+ * @param maxFrames is the maximum number of frames that should be stored before discard.
+ * The sample represents the most-recently posted frames.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in,
+ * BAD_PARAMETER when enabled was an invalid value, or
+ * NO_RESOURCES when the requested ringbuffer size via maxFrames was
+ * not available.
+ * UNSUPPORTED when there is no efficient way to sample.
+ */
+ setDisplayedContentSamplingEnabled(
+ Display display, DisplayedContentSampling enable,
+ bitfield<FormatColorComponent> componentMask, uint64_t maxFrames)
+ generates (Error error);
+
+ /**
+ * Collects the results of display content color sampling for display.
+ *
+ * Collection of data can occur whether the sampling is in ENABLE or
+ * DISABLE state.
+ *
+ * @param display is the display to which the sampling is collected.
+ * @param maxFrames is the maximum number of frames that should be represented in the sample.
+ * The sample represents the most-recently posted frames.
+ * If maxFrames is 0, all frames are to be represented by the sample.
+ * @param timestamp is the timestamp after which any frames were posted that should be
+ * included in the sample. Timestamp is CLOCK_MONOTONIC.
+ * If timestamp is 0, do not filter from the sample by time.
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display was passed in, or
+ * UNSUPPORTED when there is no efficient way to sample, or
+ * BAD_PARAMETER when the component is not supported by the hardware.
+ * @return frameCount The number of frames represented by this sample.
+ * @return sampleComponent0 is a histogram counting how many times a pixel of a given value
+ * was displayed onscreen for FORMAT_COMPONENT_0.
+ * The buckets of the histogram are evenly weighted, the number of buckets
+ * is device specific.
+ * eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that
+ * 10 red pixels were displayed onscreen in range 0x00->0x3F, 6 red pixels
+ * were displayed onscreen in range 0x40->0x7F, etc.
+ * @return sampleComponent1 is the same sample definition as sampleComponent0,
+ * but for FORMAT_COMPONENT_1.
+ * @return sampleComponent2 is the same sample definition as sampleComponent0,
+ * but for FORMAT_COMPONENT_2.
+ * @return sampleComponent3 is the same sample definition as sampleComponent0,
+ * but for FORMAT_COMPONENT_3.
+ */
+ getDisplayedContentSample(Display display, uint64_t maxFrames, uint64_t timestamp)
+ generates (Error error,
+ uint64_t frameCount,
+ vec<uint64_t> sampleComponent0,
+ vec<uint64_t> sampleComponent1,
+ vec<uint64_t> sampleComponent2,
+ vec<uint64_t> sampleComponent3);
+
/**
* Executes commands from the input command message queue. Return values
* generated by the input commands are written to the output command
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
index f9d6774..be0ef4c 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
@@ -91,6 +91,42 @@
return Void();
}
+ Return<void> getDisplayedContentSamplingAttributes(
+ uint64_t display,
+ IComposerClient::getDisplayedContentSamplingAttributes_cb hidl_cb) override {
+ common::V1_1::PixelFormat format;
+ common::V1_2::Dataspace dataspace;
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask;
+ Error error =
+ mHal->getDisplayedContentSamplingAttributes(display, format, dataspace, componentMask);
+ hidl_cb(error, format, dataspace, componentMask);
+ return Void();
+ }
+
+ Return<Error> setDisplayedContentSamplingEnabled(
+ uint64_t display, IComposerClient::DisplayedContentSampling enable,
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
+ uint64_t maxFrames) override {
+ return mHal->setDisplayedContentSamplingEnabled(display, enable, componentMask, maxFrames);
+ }
+
+ Return<void> getDisplayedContentSample(
+ uint64_t display, uint64_t maxFrames, uint64_t timestamp,
+ IComposerClient::getDisplayedContentSample_cb hidl_cb) override {
+ uint64_t frameCount;
+ hidl_vec<uint64_t> sampleComponent0;
+ hidl_vec<uint64_t> sampleComponent1;
+ hidl_vec<uint64_t> sampleComponent2;
+ hidl_vec<uint64_t> sampleComponent3;
+
+ Error error = mHal->getDisplayedContentSample(display, maxFrames, timestamp, frameCount,
+ sampleComponent0, sampleComponent1,
+ sampleComponent2, sampleComponent3);
+ hidl_cb(error, frameCount, sampleComponent0, sampleComponent1, sampleComponent2,
+ sampleComponent3);
+ return Void();
+ }
+
Return<void> executeCommands_2_3(uint32_t inLength, const hidl_vec<hidl_handle>& inHandles,
IComposerClient::executeCommands_2_2_cb hidl_cb) override {
std::lock_guard<std::mutex> lock(mCommandEngineMutex);
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
index 27efc2b..8ca5d75 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
@@ -72,6 +72,18 @@
virtual Error getDisplayIdentificationData(Display display, uint8_t* outPort,
std::vector<uint8_t>* outData) = 0;
virtual Error setLayerColorTransform(Display display, Layer layer, const float* matrix) = 0;
+ virtual Error getDisplayedContentSamplingAttributes(
+ uint64_t display, PixelFormat& format, Dataspace& dataspace,
+ hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) = 0;
+ virtual Error setDisplayedContentSamplingEnabled(
+ uint64_t display, IComposerClient::DisplayedContentSampling enable,
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, uint64_t maxFrames) = 0;
+ virtual Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames,
+ uint64_t timestamp, uint64_t& frameCount,
+ hidl_vec<uint64_t>& sampleComponent0,
+ hidl_vec<uint64_t>& sampleComponent1,
+ hidl_vec<uint64_t>& sampleComponent2,
+ hidl_vec<uint64_t>& sampleComponent3) = 0;
};
} // namespace hal
diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
index df68f58..8d444c8 100644
--- a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
+++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
@@ -104,6 +104,65 @@
return static_cast<Error>(err);
}
+ Error getDisplayedContentSamplingAttributes(
+ uint64_t display, PixelFormat& format, Dataspace& dataspace,
+ hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) override {
+ if (!mDispatch.getDisplayedContentSamplingAttributes) {
+ return Error::UNSUPPORTED;
+ }
+ int32_t formatRaw = 0;
+ int32_t dataspaceRaw = 0;
+ uint8_t componentMaskRaw = 0;
+ int32_t errorRaw = mDispatch.getDisplayedContentSamplingAttributes(
+ mDevice, display, &formatRaw, &dataspaceRaw, &componentMaskRaw);
+ auto error = static_cast<Error>(errorRaw);
+ if (error == Error::NONE) {
+ format = static_cast<PixelFormat>(formatRaw);
+ dataspace = static_cast<Dataspace>(dataspaceRaw);
+ componentMask =
+ static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(componentMaskRaw);
+ }
+ return error;
+ };
+
+ Error setDisplayedContentSamplingEnabled(
+ uint64_t display, IComposerClient::DisplayedContentSampling enable,
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
+ uint64_t maxFrames) override {
+ if (!mDispatch.setDisplayedContentSamplingEnabled) {
+ return Error::UNSUPPORTED;
+ }
+ return static_cast<Error>(mDispatch.setDisplayedContentSamplingEnabled(
+ mDevice, display, static_cast<int32_t>(enable), componentMask, maxFrames));
+ }
+
+ Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, uint64_t timestamp,
+ uint64_t& frameCount, hidl_vec<uint64_t>& sampleComponent0,
+ hidl_vec<uint64_t>& sampleComponent1,
+ hidl_vec<uint64_t>& sampleComponent2,
+ hidl_vec<uint64_t>& sampleComponent3) override {
+ if (!mDispatch.getDisplayedContentSample) {
+ return Error::UNSUPPORTED;
+ }
+
+ int32_t size[4] = {0};
+ auto errorRaw = mDispatch.getDisplayedContentSample(mDevice, display, maxFrames, timestamp,
+ &frameCount, size, nullptr);
+ if (errorRaw != HWC2_ERROR_NONE) {
+ return static_cast<Error>(errorRaw);
+ }
+
+ sampleComponent0.resize(size[0]);
+ sampleComponent1.resize(size[1]);
+ sampleComponent2.resize(size[2]);
+ sampleComponent3.resize(size[3]);
+ uint64_t* samples[] = {sampleComponent0.data(), sampleComponent1.data(),
+ sampleComponent2.data(), sampleComponent3.data()};
+ errorRaw = mDispatch.getDisplayedContentSample(mDevice, display, maxFrames, timestamp,
+ &frameCount, size, samples);
+ return static_cast<Error>(errorRaw);
+ }
+
protected:
bool initDispatch() override {
if (!BaseType2_2::initDispatch()) {
@@ -114,6 +173,12 @@
&mDispatch.getDisplayIdentificationData);
this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM,
&mDispatch.setLayerColorTransform);
+ this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES,
+ &mDispatch.getDisplayedContentSamplingAttributes);
+ this->initOptionalDispatch(HWC2_FUNCTION_SET_DISPLAYED_CONTENT_SAMPLING_ENABLED,
+ &mDispatch.setDisplayedContentSamplingEnabled);
+ this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAYED_CONTENT_SAMPLE,
+ &mDispatch.getDisplayedContentSample);
return true;
}
@@ -121,6 +186,9 @@
struct {
HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA getDisplayIdentificationData;
HWC2_PFN_SET_LAYER_COLOR_TRANSFORM setLayerColorTransform;
+ HWC2_PFN_GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES getDisplayedContentSamplingAttributes;
+ HWC2_PFN_SET_DISPLAYED_CONTENT_SAMPLING_ENABLED setDisplayedContentSamplingEnabled;
+ HWC2_PFN_GET_DISPLAYED_CONTENT_SAMPLE getDisplayedContentSample;
} mDispatch = {};
using BaseType2_2 = V2_2::passthrough::detail::HwcHalImpl<Hal>;
diff --git a/graphics/composer/2.3/utils/vts/ComposerVts.cpp b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
index 656c8c4..9304992 100644
--- a/graphics/composer/2.3/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
@@ -108,6 +108,48 @@
return error == Error::NONE;
}
+Error ComposerClient::getDisplayedContentSamplingAttributes(
+ uint64_t display, PixelFormat& format, Dataspace& dataspace,
+ hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) {
+ auto error = Error::BAD_PARAMETER;
+ mClient->getDisplayedContentSamplingAttributes(
+ display, [&](const auto& tmpError, const auto& tmpFormat, const auto& tmpDataspace,
+ const auto& tmpComponentMask) {
+ error = tmpError;
+ format = tmpFormat;
+ dataspace = tmpDataspace;
+ componentMask = tmpComponentMask;
+ });
+ return error;
+}
+
+Error ComposerClient::setDisplayedContentSamplingEnabled(
+ uint64_t display, IComposerClient::DisplayedContentSampling enable,
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, uint64_t maxFrames) {
+ return mClient->setDisplayedContentSamplingEnabled(display, enable, componentMask, maxFrames);
+}
+
+Error ComposerClient::getDisplayedContentSample(uint64_t display, uint64_t maxFrames,
+ uint64_t timestamp, uint64_t& frameCount,
+ hidl_vec<uint64_t>& sampleComponent0,
+ hidl_vec<uint64_t>& sampleComponent1,
+ hidl_vec<uint64_t>& sampleComponent2,
+ hidl_vec<uint64_t>& sampleComponent3) {
+ auto error = Error::BAD_PARAMETER;
+ mClient->getDisplayedContentSample(
+ display, maxFrames, timestamp,
+ [&](const auto& tmpError, const auto& tmpFrameCount, const auto& tmpSamples0,
+ const auto& tmpSamples1, const auto& tmpSamples2, const auto& tmpSamples3) {
+ error = tmpError;
+ frameCount = tmpFrameCount;
+ sampleComponent0 = tmpSamples0;
+ sampleComponent1 = tmpSamples1;
+ sampleComponent2 = tmpSamples2;
+ sampleComponent3 = tmpSamples3;
+ });
+ return error;
+}
+
} // namespace vts
} // namespace V2_3
} // namespace composer
diff --git a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
index ec1a2a1..4b9c955 100644
--- a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
+++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
@@ -37,6 +37,7 @@
using common::V1_2::ColorMode;
using common::V1_2::Dataspace;
using V2_1::Display;
+using V2_1::Error;
using V2_3::IComposer;
using V2_3::IComposerClient;
@@ -67,6 +68,17 @@
bool getDisplayIdentificationData(Display display, uint8_t* outPort,
std::vector<uint8_t>* outData);
+ Error getDisplayedContentSamplingAttributes(
+ uint64_t display, PixelFormat& format, Dataspace& dataspace,
+ hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask);
+ Error setDisplayedContentSamplingEnabled(
+ uint64_t display, IComposerClient::DisplayedContentSampling enable,
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask, uint64_t maxFrames);
+ Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, uint64_t timestamp,
+ uint64_t& frameCount, hidl_vec<uint64_t>& sampleComponent0,
+ hidl_vec<uint64_t>& sampleComponent1,
+ hidl_vec<uint64_t>& sampleComponent2,
+ hidl_vec<uint64_t>& sampleComponent3);
std::vector<ColorMode> getColorModes_2_3(Display display);
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
index 3ca21aa..a294825 100644
--- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -355,6 +355,78 @@
execute();
}
+TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSamplingAttributes) {
+ using common::V1_1::PixelFormat;
+ using common::V1_2::Dataspace;
+
+ int constexpr invalid = -1;
+ auto format = static_cast<PixelFormat>(invalid);
+ auto dataspace = static_cast<Dataspace>(invalid);
+ auto componentMask = static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid);
+ auto error = mComposerClient->getDisplayedContentSamplingAttributes(mPrimaryDisplay, format,
+ dataspace, componentMask);
+
+ if (error == Error::UNSUPPORTED) {
+ SUCCEED() << "Device does not support optional extension. Test skipped";
+ return;
+ }
+
+ EXPECT_EQ(error, Error::NONE);
+ EXPECT_NE(format, static_cast<PixelFormat>(invalid));
+ EXPECT_NE(dataspace, static_cast<Dataspace>(invalid));
+ EXPECT_NE(componentMask,
+ static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid));
+};
+
+TEST_F(GraphicsComposerHidlTest, SetDisplayedContentSamplingEnabled) {
+ auto const maxFrames = 10;
+ auto const enableAllComponents = 0;
+ auto error = mComposerClient->setDisplayedContentSamplingEnabled(
+ mPrimaryDisplay, IComposerClient::DisplayedContentSampling::ENABLE, enableAllComponents,
+ maxFrames);
+ if (error == Error::UNSUPPORTED) {
+ SUCCEED() << "Device does not support optional extension. Test skipped";
+ return;
+ }
+ EXPECT_EQ(error, Error::NONE);
+
+ error = mComposerClient->setDisplayedContentSamplingEnabled(
+ mPrimaryDisplay, IComposerClient::DisplayedContentSampling::DISABLE, enableAllComponents,
+ maxFrames);
+ EXPECT_EQ(error, Error::NONE);
+}
+
+TEST_F(GraphicsComposerHidlTest, GetDisplayedContentSample) {
+ int constexpr invalid = -1;
+ auto format = static_cast<PixelFormat>(invalid);
+ auto dataspace = static_cast<Dataspace>(invalid);
+ auto componentMask = static_cast<hidl_bitfield<IComposerClient::FormatColorComponent>>(invalid);
+ auto error = mComposerClient->getDisplayedContentSamplingAttributes(mPrimaryDisplay, format,
+ dataspace, componentMask);
+
+ uint64_t maxFrames = 10;
+ uint64_t timestamp = 0;
+ uint64_t frameCount = 0;
+ hidl_array<hidl_vec<uint64_t>, 4> histogram;
+ error = mComposerClient->getDisplayedContentSample(mPrimaryDisplay, maxFrames, timestamp,
+ frameCount, histogram[0], histogram[1],
+ histogram[2], histogram[3]);
+ if (error == Error::UNSUPPORTED) {
+ SUCCEED() << "Device does not support optional extension. Test skipped";
+ return;
+ }
+
+ EXPECT_EQ(error, Error::NONE);
+ EXPECT_LE(frameCount, maxFrames);
+ for (auto i = 0; i < histogram.size(); i++) {
+ if (componentMask & (1 << i)) {
+ EXPECT_NE(histogram[i].size(), 0);
+ } else {
+ EXPECT_EQ(histogram[i].size(), 0);
+ }
+ }
+}
+
} // namespace
} // namespace vts
} // namespace V2_3
diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
index f8b021e..00207b1 100644
--- a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
+++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
@@ -94,9 +94,9 @@
}
void SensorsHidlEnvironmentV1_0::startPollingThread() {
- stopThread = false;
- pollThread = std::thread(pollingThread, this, std::ref(stopThread));
- events.reserve(128);
+ mStopThread = false;
+ mPollThread = std::thread(pollingThread, this, std::ref(mStopThread));
+ mEvents.reserve(128);
}
void SensorsHidlEnvironmentV1_0::pollingThread(SensorsHidlEnvironmentV1_0* env,
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
index 2fb67a6..37b7349 100644
--- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
+++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
@@ -95,19 +95,19 @@
}
void SensorsHidlEnvironmentV2_0::HidlTearDown() {
- stopThread = true;
+ mStopThread = true;
// Wake up the event queue so the poll thread can exit
mEventQueueFlag->wake(asBaseType(EventQueueFlagBits::READ_AND_PROCESS));
- pollThread.join();
+ mPollThread.join();
EventFlag::deleteEventFlag(&mEventQueueFlag);
}
void SensorsHidlEnvironmentV2_0::startPollingThread() {
- stopThread = false;
- pollThread = std::thread(pollingThread, this);
- events.reserve(MAX_RECEIVE_BUFFER_EVENT_COUNT);
+ mStopThread = false;
+ mPollThread = std::thread(pollingThread, this);
+ mEvents.reserve(MAX_RECEIVE_BUFFER_EVENT_COUNT);
}
void SensorsHidlEnvironmentV2_0::readEvents() {
@@ -133,7 +133,7 @@
void SensorsHidlEnvironmentV2_0::pollingThread(SensorsHidlEnvironmentV2_0* env) {
ALOGD("polling thread start");
- while (!env->stopThread.load()) {
+ while (!env->mStopThread.load()) {
env->readEvents();
}
diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
index 94cd6e5..3e5837b 100644
--- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -25,15 +25,89 @@
#include <utils/SystemClock.h>
#include <cinttypes>
+#include <condition_variable>
+#include <map>
#include <vector>
using ::android::sp;
using ::android::hardware::Return;
using ::android::hardware::Void;
+using ::android::hardware::sensors::V1_0::MetaDataEventType;
using ::android::hardware::sensors::V1_0::OperationMode;
using ::android::hardware::sensors::V1_0::SensorStatus;
using ::android::hardware::sensors::V1_0::Vec3;
+class EventCallback : public IEventCallback {
+ public:
+ void reset() {
+ mFlushMap.clear();
+ mEventMap.clear();
+ }
+
+ void onEvent(const ::android::hardware::sensors::V1_0::Event& event) override {
+ if (event.sensorType == SensorType::ADDITIONAL_INFO &&
+ event.u.meta.what == 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, int64_t timeoutMs) {
+ std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
+ mFlushCV.wait_for(lock, std::chrono::milliseconds(timeoutMs),
+ [&] { 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, int32_t timeoutMs) {
+ std::unique_lock<std::recursive_mutex> lock(mEventMutex);
+ mEventCV.wait_for(lock, std::chrono::milliseconds(timeoutMs),
+ [&] { 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;
+};
+
// The main test class for SENSORS HIDL HAL.
class SensorsHidlTest : public SensorsHidlTestBase {
@@ -80,8 +154,17 @@
return SensorsHidlEnvironmentV2_0::Instance();
}
+ // Test helpers
+ void runSingleFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
+ int32_t expectedFlushCount, Result expectedResponse);
+ void runFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
+ int32_t flushCalls, int32_t expectedFlushCount, Result expectedResponse);
+
// Helper functions
void activateAllSensors(bool enable);
+ std::vector<SensorInfo> getNonOneShotSensors();
+ std::vector<SensorInfo> getOneShotSensors();
+ int32_t getInvalidSensorHandle();
};
Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
@@ -140,6 +223,35 @@
return ret;
}
+std::vector<SensorInfo> SensorsHidlTest::getNonOneShotSensors() {
+ std::vector<SensorInfo> sensors;
+ for (const SensorInfo& info : getSensorsList()) {
+ if (extractReportMode(info.flags) != SensorFlagBits::ONE_SHOT_MODE) {
+ sensors.push_back(info);
+ }
+ }
+ return sensors;
+}
+
+std::vector<SensorInfo> SensorsHidlTest::getOneShotSensors() {
+ std::vector<SensorInfo> sensors;
+ for (const SensorInfo& info : getSensorsList()) {
+ if (extractReportMode(info.flags) == SensorFlagBits::ONE_SHOT_MODE) {
+ sensors.push_back(info);
+ }
+ }
+ return sensors;
+}
+
+int32_t SensorsHidlTest::getInvalidSensorHandle() {
+ // Find a sensor handle that does not exist in the sensor list
+ int32_t maxHandle = 0;
+ for (const SensorInfo& sensor : getSensorsList()) {
+ maxHandle = max(maxHandle, sensor.sensorHandle);
+ }
+ return maxHandle + 1;
+}
+
// Test if sensor list returned is valid
TEST_F(SensorsHidlTest, SensorListValid) {
getSensors()->getSensorsList([&](const auto& list) {
@@ -488,6 +600,195 @@
activateAllSensors(false);
}
+void SensorsHidlTest::runSingleFlushTest(const std::vector<SensorInfo>& sensors,
+ bool activateSensor, int32_t expectedFlushCount,
+ Result expectedResponse) {
+ runFlushTest(sensors, activateSensor, 1 /* flushCalls */, expectedFlushCount, expectedResponse);
+}
+
+void SensorsHidlTest::runFlushTest(const std::vector<SensorInfo>& sensors, bool activateSensor,
+ int32_t flushCalls, int32_t expectedFlushCount,
+ Result expectedResponse) {
+ EventCallback callback;
+ getEnvironment()->registerCallback(&callback);
+
+ for (const SensorInfo& sensor : sensors) {
+ // Configure and activate the sensor
+ batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */);
+ activate(sensor.sensorHandle, activateSensor);
+
+ // Flush the sensor
+ for (int32_t i = 0; i < flushCalls; i++) {
+ Result flushResult = flush(sensor.sensorHandle);
+ ASSERT_EQ(flushResult, expectedResponse);
+ }
+ activate(sensor.sensorHandle, false);
+ }
+
+ // Wait up to one second for the flush events
+ callback.waitForFlushEvents(sensors, flushCalls, 1000 /* timeoutMs */);
+ getEnvironment()->unregisterCallback();
+
+ // Check that the correct number of flushes are present for each sensor
+ for (const SensorInfo& sensor : sensors) {
+ ASSERT_EQ(callback.getFlushCount(sensor.sensorHandle), expectedFlushCount);
+ }
+}
+
+TEST_F(SensorsHidlTest, FlushSensor) {
+ // Find a sensor that is not a one-shot sensor
+ std::vector<SensorInfo> sensors = getNonOneShotSensors();
+ if (sensors.size() == 0) {
+ return;
+ }
+
+ constexpr int32_t kFlushes = 5;
+ runSingleFlushTest(sensors, true /* activateSensor */, 1 /* expectedFlushCount */, Result::OK);
+ runFlushTest(sensors, true /* activateSensor */, kFlushes, kFlushes, Result::OK);
+}
+
+TEST_F(SensorsHidlTest, 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 */,
+ Result::BAD_VALUE);
+}
+
+TEST_F(SensorsHidlTest, 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 */,
+ Result::BAD_VALUE);
+}
+
+TEST_F(SensorsHidlTest, FlushNonexistentSensor) {
+ SensorInfo sensor;
+ std::vector<SensorInfo> sensors = getNonOneShotSensors();
+ if (sensors.size() == 0) {
+ sensors = getOneShotSensors();
+ if (sensors.size() == 0) {
+ return;
+ }
+ }
+ sensor = sensors.front();
+ sensor.sensorHandle = getInvalidSensorHandle();
+ runSingleFlushTest(std::vector<SensorInfo>{sensor}, false /* activateSensor */,
+ 0 /* expectedFlushCount */, Result::BAD_VALUE);
+}
+
+TEST_F(SensorsHidlTest, Batch) {
+ if (getSensorsList().size() == 0) {
+ return;
+ }
+
+ activateAllSensors(false /* enable */);
+ for (const SensorInfo& sensor : getSensorsList()) {
+ // Call batch on inactive sensor
+ ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */),
+ Result::OK);
+
+ // Activate the sensor
+ activate(sensor.sensorHandle, true /* enabled */);
+
+ // Call batch on an active sensor
+ ASSERT_EQ(batch(sensor.sensorHandle, sensor.maxDelay, 0 /* maxReportLatencyNs */),
+ Result::OK);
+ }
+ activateAllSensors(false /* enable */);
+
+ // Call batch on an invalid sensor
+ SensorInfo sensor = getSensorsList().front();
+ sensor.sensorHandle = getInvalidSensorHandle();
+ ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */),
+ Result::BAD_VALUE);
+}
+
+TEST_F(SensorsHidlTest, Activate) {
+ if (getSensorsList().size() == 0) {
+ return;
+ }
+
+ // Verify that sensor events are generated when activate is called
+ for (const SensorInfo& sensor : getSensorsList()) {
+ batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */);
+ ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK);
+
+ // Call activate on a sensor that is already activated
+ ASSERT_EQ(activate(sensor.sensorHandle, true), Result::OK);
+
+ // Deactivate the sensor
+ ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK);
+
+ // Call deactivate on a sensor that is already deactivated
+ ASSERT_EQ(activate(sensor.sensorHandle, false), Result::OK);
+ }
+
+ // Attempt to activate an invalid sensor
+ int32_t invalidHandle = getInvalidSensorHandle();
+ ASSERT_EQ(activate(invalidHandle, true), Result::BAD_VALUE);
+ ASSERT_EQ(activate(invalidHandle, false), Result::BAD_VALUE);
+}
+
+TEST_F(SensorsHidlTest, NoStaleEvents) {
+ constexpr int64_t kFiveHundredMilliseconds = 500 * 1000;
+ constexpr int64_t kOneSecond = 1000 * 1000;
+
+ // Register the callback to receive sensor events
+ EventCallback callback;
+ getEnvironment()->registerCallback(&callback);
+
+ const std::vector<SensorInfo> sensors = getSensorsList();
+ int32_t maxMinDelay = 0;
+ for (const SensorInfo& sensor : getSensorsList()) {
+ maxMinDelay = std::max(maxMinDelay, sensor.minDelay);
+ }
+
+ // 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, kFiveHundredMilliseconds + (5 * maxMinDelay));
+ activateAllSensors(false);
+
+ // Save the last received event for each sensor
+ std::map<int32_t, int64_t> lastEventTimestampMap;
+ for (const SensorInfo& sensor : sensors) {
+ ASSERT_GE(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(kOneSecond + (5 * maxMinDelay));
+ callback.reset();
+ activateAllSensors(true);
+ callback.waitForEvents(sensors, kFiveHundredMilliseconds + (5 * maxMinDelay));
+ activateAllSensors(false);
+
+ for (const SensorInfo& sensor : sensors) {
+ // 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();
+ int64_t delta = newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle];
+ ASSERT_GE(delta, kFiveHundredMilliseconds + (3 * sensor.minDelay));
+ }
+
+ getEnvironment()->unregisterCallback();
+}
+
int main(int argc, char** argv) {
::testing::AddGlobalTestEnvironment(SensorsHidlEnvironmentV2_0::Instance());
::testing::InitGoogleTest(&argc, argv);
diff --git a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
index 21c08d2..affdf8b 100644
--- a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
+++ b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
@@ -19,7 +19,7 @@
void SensorsHidlEnvironmentBase::HidlSetUp() {
ASSERT_TRUE(resetHal()) << "could not get hidl service";
- collectionEnabled = false;
+ mCollectionEnabled = false;
startPollingThread();
// In case framework just stopped for test and there is sensor events in the pipe,
@@ -28,26 +28,40 @@
}
void SensorsHidlEnvironmentBase::HidlTearDown() {
- stopThread = true;
- pollThread.detach();
+ mStopThread = true;
+ mPollThread.detach();
}
void SensorsHidlEnvironmentBase::catEvents(std::vector<Event>* output) {
- std::lock_guard<std::mutex> lock(events_mutex);
+ std::lock_guard<std::mutex> lock(mEventsMutex);
if (output) {
- output->insert(output->end(), events.begin(), events.end());
+ output->insert(output->end(), mEvents.begin(), mEvents.end());
}
- events.clear();
+ mEvents.clear();
}
void SensorsHidlEnvironmentBase::setCollection(bool enable) {
- std::lock_guard<std::mutex> lock(events_mutex);
- collectionEnabled = enable;
+ std::lock_guard<std::mutex> lock(mEventsMutex);
+ mCollectionEnabled = enable;
}
void SensorsHidlEnvironmentBase::addEvent(const Event& ev) {
- std::lock_guard<std::mutex> lock(events_mutex);
- if (collectionEnabled) {
- events.push_back(ev);
+ std::lock_guard<std::mutex> lock(mEventsMutex);
+ if (mCollectionEnabled) {
+ mEvents.push_back(ev);
+ }
+
+ if (mCallback != nullptr) {
+ mCallback->onEvent(ev);
}
}
+
+void SensorsHidlEnvironmentBase::registerCallback(IEventCallback* callback) {
+ std::lock_guard<std::mutex> lock(mEventsMutex);
+ mCallback = callback;
+}
+
+void SensorsHidlEnvironmentBase::unregisterCallback() {
+ std::lock_guard<std::mutex> lock(mEventsMutex);
+ mCallback = nullptr;
+}
\ No newline at end of file
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
index 96e6085..6499fba 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
@@ -27,6 +27,12 @@
#include <thread>
#include <vector>
+class IEventCallback {
+ public:
+ virtual ~IEventCallback() = default;
+ virtual void onEvent(const ::android::hardware::sensors::V1_0::Event& event) = 0;
+};
+
class SensorsHidlEnvironmentBase : public ::testing::VtsHalHidlTargetTestEnvBase {
public:
using Event = ::android::hardware::sensors::V1_0::Event;
@@ -40,19 +46,24 @@
// set sensor event collection status
void setCollection(bool enable);
+ void registerCallback(IEventCallback* callback);
+ void unregisterCallback();
+
protected:
- SensorsHidlEnvironmentBase() {}
+ SensorsHidlEnvironmentBase() : mCollectionEnabled(false), mCallback(nullptr) {}
void addEvent(const Event& ev);
virtual void startPollingThread() = 0;
virtual bool resetHal() = 0;
- bool collectionEnabled;
- std::atomic_bool stopThread;
- std::thread pollThread;
- std::vector<Event> events;
- std::mutex events_mutex;
+ bool mCollectionEnabled;
+ std::atomic_bool mStopThread;
+ std::thread mPollThread;
+ std::vector<Event> mEvents;
+ std::mutex mEventsMutex;
+
+ IEventCallback* mCallback;
GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentBase);
};
diff --git a/tests/expression/1.0/IExpression.hal b/tests/expression/1.0/IExpression.hal
index 2db9f61..36aed60 100644
--- a/tests/expression/1.0/IExpression.hal
+++ b/tests/expression/1.0/IExpression.hal
@@ -147,6 +147,28 @@
logand4 = (0 && 1) == 0,
};
+ // Tests for enum tags
+ enum NoElements : uint32_t {};
+ enum OneElement : uint32_t {A};
+ enum TwoElement : uint32_t {A,B};
+ enum TwoCollidingElements : uint32_t {A=1,B=1};
+ enum ThreeFromInheritance : TwoElement {C};
+ enum ThreeFromDoubleInheritance : ThreeFromInheritance {};
+ enum ThreeCollidingFromInheritance : TwoCollidingElements {C};
+
+ enum EnumTagTest : uint32_t {
+ a = NoElements#len == 0,
+ b = OneElement#len == 1,
+ c = TwoElement#len == 2,
+ d = TwoCollidingElements#len == 2,
+ e = ThreeFromInheritance#len == 3,
+ f = ThreeFromDoubleInheritance#len == 3,
+ g = ThreeCollidingFromInheritance#len == 3,
+
+ // fine to reference current enum as well
+ h = EnumTagTest#len == 8,
+ };
+
enum Grayscale : int8_t {
WHITE = 126,
GRAY, // 127