Merge changes from topic "playback"
* changes:
Tuner HAL Demux Playback interface VTS
Tuner HAL Demux Playback interface implementation
Add record and playback to Tuner HAL
diff --git a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
index d3d7387..a4e95ed 100644
--- a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
+++ b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
@@ -64,7 +64,7 @@
// The error passed to the last onError() callback.
FaceError error;
- // The userId passed to the last onRemoved() callback.
+ // The userId passed to the last callback.
int32_t userId;
};
@@ -74,24 +74,32 @@
class FaceCallback : public ::testing::VtsHalHidlTargetCallbackBase<FaceCallbackArgs>,
public IBiometricsFaceClientCallback {
public:
- Return<void> onEnrollResult(uint64_t, uint32_t, int32_t, uint32_t) override {
- NotifyFromCallback(kCallbackNameOnEnrollResult);
+ Return<void> onEnrollResult(uint64_t, uint32_t, int32_t userId, uint32_t) override {
+ FaceCallbackArgs args = {};
+ args.userId = userId;
+ NotifyFromCallback(kCallbackNameOnEnrollResult, args);
return Void();
}
- Return<void> onAuthenticated(uint64_t, uint32_t, int32_t, const hidl_vec<uint8_t>&) override {
- NotifyFromCallback(kCallbackNameOnAuthenticated);
+ Return<void> onAuthenticated(uint64_t, uint32_t, int32_t userId,
+ const hidl_vec<uint8_t>&) override {
+ FaceCallbackArgs args = {};
+ args.userId = userId;
+ NotifyFromCallback(kCallbackNameOnAuthenticated, args);
return Void();
}
- Return<void> onAcquired(uint64_t, int32_t, FaceAcquiredInfo, int32_t) override {
- NotifyFromCallback(kCallbackNameOnAcquired);
+ Return<void> onAcquired(uint64_t, int32_t userId, FaceAcquiredInfo, int32_t) override {
+ FaceCallbackArgs args = {};
+ args.userId = userId;
+ NotifyFromCallback(kCallbackNameOnAcquired, args);
return Void();
}
- Return<void> onError(uint64_t, int32_t, FaceError error, int32_t) override {
+ Return<void> onError(uint64_t, int32_t userId, FaceError error, int32_t) override {
FaceCallbackArgs args = {};
args.error = error;
+ args.userId = userId;
NotifyFromCallback(kCallbackNameOnError, args);
return Void();
}
@@ -103,8 +111,10 @@
return Void();
}
- Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t) override {
- NotifyFromCallback(kCallbackNameOnEnumerate);
+ Return<void> onEnumerate(uint64_t, const hidl_vec<uint32_t>&, int32_t userId) override {
+ FaceCallbackArgs args = {};
+ args.userId = userId;
+ NotifyFromCallback(kCallbackNameOnEnumerate, args);
return Void();
}
@@ -185,6 +195,7 @@
// onError should be called with a meaningful (nonzero) error.
auto res = mCallback->WaitForCallback(kCallbackNameOnError);
EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
}
@@ -205,6 +216,7 @@
// onError should be called with a meaningful (nonzero) error.
auto res = mCallback->WaitForCallback(kCallbackNameOnError);
EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
EXPECT_EQ(FaceError::UNABLE_TO_PROCESS, res.args->error);
}
@@ -271,6 +283,7 @@
Return<Status> ret = mService->enumerate();
ASSERT_EQ(Status::OK, static_cast<Status>(ret));
auto res = mCallback->WaitForCallback(kCallbackNameOnEnumerate);
+ EXPECT_EQ(kUserId, res.args->userId);
EXPECT_TRUE(res.no_timeout);
}
@@ -330,6 +343,7 @@
auto res = mCallback->WaitForCallback(kCallbackNameOnError);
// make sure callback was invoked within kRevokeChallengeTimeout
EXPECT_TRUE(res.no_timeout);
+ EXPECT_EQ(kUserId, res.args->userId);
EXPECT_EQ(FaceError::CANCELED, res.args->error);
}
diff --git a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
index 14b8bbd..f0bba57 100644
--- a/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
+++ b/cas/1.0/vts/functional/VtsHalCasV1_0TargetTest.cpp
@@ -325,7 +325,7 @@
return ::testing::AssertionFailure();
}
- uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->pointer()));
+ uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->unsecurePointer()));
memcpy(ipBuffer, kInBinaryBuffer, sizeof(kInBinaryBuffer));
// hidlMemory is not to be passed out of scope!
@@ -568,7 +568,7 @@
EXPECT_EQ(Status::OK, descrambleStatus);
ASSERT_NE(nullptr, dataMemory.get());
- uint8_t* opBuffer = static_cast<uint8_t*>(static_cast<void*>(dataMemory->pointer()));
+ uint8_t* opBuffer = static_cast<uint8_t*>(static_cast<void*>(dataMemory->unsecurePointer()));
int compareResult =
memcmp(static_cast<const void*>(opBuffer), static_cast<const void*>(kOutRefBinaryBuffer),
diff --git a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
index 88f1fb0..0264bdd 100644
--- a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
+++ b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
@@ -366,7 +366,7 @@
return ::testing::AssertionFailure();
}
- uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->pointer()));
+ uint8_t* ipBuffer = static_cast<uint8_t*>(static_cast<void*>(mem->unsecurePointer()));
memcpy(ipBuffer, kInBinaryBuffer, sizeof(kInBinaryBuffer));
// hidlMemory is not to be passed out of scope!
@@ -543,7 +543,7 @@
EXPECT_EQ(Status::OK, descrambleStatus);
ASSERT_NE(nullptr, dataMemory.get());
- uint8_t* opBuffer = static_cast<uint8_t*>(static_cast<void*>(dataMemory->pointer()));
+ uint8_t* opBuffer = static_cast<uint8_t*>(static_cast<void*>(dataMemory->unsecurePointer()));
int compareResult =
memcmp(static_cast<const void*>(opBuffer),
diff --git a/current.txt b/current.txt
index 2aa9ef2..83657b2 100644
--- a/current.txt
+++ b/current.txt
@@ -574,8 +574,8 @@
# ABI preserving changes to HALs during Android R
2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types
b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
-ad431c8de51c07934a068e3043d8dd0537ac4d3158627706628b123f42df48dc android.hardware.neuralnetworks@1.0::IPreparedModel
+eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel
fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice
-aafcc10cf04ab247e86d4582586c71c6b4c2b8c479241ffa7fe37deb659fc942 android.hardware.neuralnetworks@1.2::IPreparedModel
+40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel
1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface
diff --git a/drm/1.0/default/CryptoPlugin.cpp b/drm/1.0/default/CryptoPlugin.cpp
index 666653b..8ddc380 100644
--- a/drm/1.0/default/CryptoPlugin.cpp
+++ b/drm/1.0/default/CryptoPlugin.cpp
@@ -101,11 +101,20 @@
std::unique_ptr<android::CryptoPlugin::SubSample[]> legacySubSamples =
std::make_unique<android::CryptoPlugin::SubSample[]>(subSamples.size());
+ size_t destSize = 0;
for (size_t i = 0; i < subSamples.size(); i++) {
- legacySubSamples[i].mNumBytesOfClearData
- = subSamples[i].numBytesOfClearData;
- legacySubSamples[i].mNumBytesOfEncryptedData
- = subSamples[i].numBytesOfEncryptedData;
+ uint32_t numBytesOfClearData = subSamples[i].numBytesOfClearData;
+ legacySubSamples[i].mNumBytesOfClearData = numBytesOfClearData;
+ uint32_t numBytesOfEncryptedData = subSamples[i].numBytesOfEncryptedData;
+ legacySubSamples[i].mNumBytesOfEncryptedData = numBytesOfEncryptedData;
+ if (__builtin_add_overflow(destSize, numBytesOfClearData, &destSize)) {
+ _hidl_cb(Status::BAD_VALUE, 0, "subsample clear size overflow");
+ return Void();
+ }
+ if (__builtin_add_overflow(destSize, numBytesOfEncryptedData, &destSize)) {
+ _hidl_cb(Status::BAD_VALUE, 0, "subsample encrypted size overflow");
+ return Void();
+ }
}
AString detailMessage;
@@ -137,11 +146,24 @@
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
return Void();
}
+
+ if (destSize > destBuffer.size) {
+ _hidl_cb(Status::BAD_VALUE, 0, "subsample sum too large");
+ return Void();
+ }
+
destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
} else if (destination.type == BufferType::NATIVE_HANDLE) {
+ if (!secure) {
+ _hidl_cb(Status::BAD_VALUE, 0, "native handle destination must be secure");
+ return Void();
+ }
native_handle_t *handle = const_cast<native_handle_t *>(
destination.secureMemory.getNativeHandle());
destPtr = static_cast<void *>(handle);
+ } else {
+ _hidl_cb(Status::BAD_VALUE, 0, "invalid destination type");
+ return Void();
}
ssize_t result = mLegacyPlugin->decrypt(secure, keyId.data(), iv.data(),
legacyMode, legacyPattern, srcPtr, legacySubSamples.get(),
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h
index 62a163c..4b8c6bb 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/Composer.h
@@ -67,6 +67,14 @@
}
}
+ // we do not have HWC2_CAPABILITY_SKIP_VALIDATE defined in
+ // IComposer::Capability. However, this is defined in hwcomposer2.h,
+ // so if the device returns it, add it manually to be returned to the
+ // client
+ if (mHal->hasCapability(HWC2_CAPABILITY_SKIP_VALIDATE)) {
+ caps.push_back(static_cast<IComposer::Capability>(HWC2_CAPABILITY_SKIP_VALIDATE));
+ }
+
hidl_vec<IComposer::Capability> caps_reply;
caps_reply.setToExternal(caps.data(), caps.size());
hidl_cb(caps_reply);
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index 5d2f65d..9477ee6 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -20,6 +20,7 @@
#include <composer-vts/2.1/ComposerVts.h>
#include <composer-vts/2.1/GraphicsComposerCallback.h>
#include <composer-vts/2.1/TestCommandReader.h>
+#include <hardware/hwcomposer2.h>
#include <mapper-vts/2.0/MapperVts.h>
#include <mapper-vts/3.0/MapperVts.h>
#include <mapper-vts/4.0/MapperVts.h>
@@ -789,6 +790,12 @@
* surface damage have been set
*/
TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) {
+ if (!mComposer->hasCapability(
+ static_cast<IComposer::Capability>(HWC2_CAPABILITY_SKIP_VALIDATE))) {
+ std::cout << "Device does not have skip validate capability, skipping" << std::endl;
+ GTEST_SUCCEED();
+ return;
+ }
mWriter->selectDisplay(mPrimaryDisplay);
mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::ON);
mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::NATIVE);
diff --git a/neuralnetworks/1.0/IPreparedModel.hal b/neuralnetworks/1.0/IPreparedModel.hal
index 5320050..3dc3202 100644
--- a/neuralnetworks/1.0/IPreparedModel.hal
+++ b/neuralnetworks/1.0/IPreparedModel.hal
@@ -49,11 +49,14 @@
* must not change the content of any of the data objects corresponding to
* 'request' inputs.
*
- * If the prepared model was prepared from a model wherein all
- * tensor operands have fully specified dimensions, and the inputs
- * to the function are valid, then the execution should launch
- * and complete successfully (ErrorStatus::NONE). There must be
- * no failure unless the device itself is in a bad state.
+ * If the prepared model was prepared from a model wherein all tensor
+ * operands have fully specified dimensions, and the inputs to the function
+ * are valid, then:
+ * - the execution should launch successfully (ErrorStatus::NONE): There
+ * must be no failure unless the device itself is in a bad state.
+ * - if at execution time every operation's input operands have legal
+ * values, the execution should complete successfully (ErrorStatus::NONE):
+ * There must be no failure unless the device itself is in a bad state.
*
* Multiple threads can call the execute function on the same IPreparedModel
* object concurrently with different requests.
diff --git a/neuralnetworks/1.2/IPreparedModel.hal b/neuralnetworks/1.2/IPreparedModel.hal
index ba16334..1445f18 100644
--- a/neuralnetworks/1.2/IPreparedModel.hal
+++ b/neuralnetworks/1.2/IPreparedModel.hal
@@ -54,11 +54,14 @@
* must not change the content of any of the data objects corresponding to
* 'request' inputs.
*
- * If the prepared model was prepared from a model wherein all
- * tensor operands have fully specified dimensions, and the inputs
- * to the function are valid, then the execution should launch
- * and complete successfully (ErrorStatus::NONE). There must be
- * no failure unless the device itself is in a bad state.
+ * If the prepared model was prepared from a model wherein all tensor
+ * operands have fully specified dimensions, and the inputs to the function
+ * are valid, then:
+ * - the execution should launch successfully (ErrorStatus::NONE): There
+ * must be no failure unless the device itself is in a bad state.
+ * - if at execution time every operation's input operands have legal
+ * values, the execution should complete successfully (ErrorStatus::NONE):
+ * There must be no failure unless the device itself is in a bad state.
*
* Any number of calls to the execute, execute_1_2, and executeSynchronously
* functions, in any combination, may be made concurrently, even on the same
@@ -105,8 +108,9 @@
*
* If the prepared model was prepared from a model wherein all tensor
* operands have fully specified dimensions, and the inputs to the function
- * are valid, then the execution should complete successfully
- * (ErrorStatus::NONE). There must be no failure unless the device itself is
+ * are valid, and at execution time every operation's input operands have
+ * legal values, then the execution should complete successfully
+ * (ErrorStatus::NONE): There must be no failure unless the device itself is
* in a bad state.
*
* Any number of calls to the execute, execute_1_2, and executeSynchronously
@@ -145,23 +149,52 @@
* Configure a Burst object used to execute multiple inferences on a
* prepared model in rapid succession.
*
+ * If the prepared model was prepared from a model wherein all tensor
+ * operands have fully specified dimensions, and a valid serialized Request
+ * is sent to the Burst for execution, and at execution time every
+ * operation's input operands have legal values, then the execution should
+ * complete successfully (ErrorStatus::NONE): There must be no failure
+ * unless the device itself is in a bad state.
+ *
* @param callback A callback object used to retrieve memory resources
- * corresponding to a unique identifiers ("slots").
- * @param requestChannel Used by the client to send a serialized Request to
- * the Burst for execution. The client must not change
- * the content of any data object referenced by the
- * Request (described by the {@link @1.0::DataLocation}
- * of an {@link OperandInformation}) until a result
- * has been received from resultChannel. Execution
- * must not change the content of any of the data
- * objects corresponding to Request inputs. requestChannel
+ * corresponding to unique identifiers ("slots").
+ * @param requestChannel FMQ used by the client to send a serialized Request
+ * to the Burst for execution. The client must not
+ * change the content of any data object referenced by
+ * the Request (described by the
+ * {@link @1.0::DataLocation} of an
+ * {@link OperandInformation}) until a result has been
+ * received from resultChannel. Execution must not
+ * change the content of any of the data objects
+ * corresponding to Request inputs. requestChannel
* must not be used to pass a second Request object
- * until a result has been received from resultChannel.
- * @param resultChannel Used by the service to return the results of an
- * execution to the client: the status of the execution
- * and OutputShape of all output tensors. resultChannel
- * must be used to return the results if a Request was
- * sent through the requestChannel.
+ * until a result has been received from
+ * resultChannel. The client must send the request
+ * messages to the consumer atomically by using
+ * MessageQueue::writeBlocking if the queue is
+ * blocking, or by using MessageQueue::write if the
+ * queue is non-blocking. When the service receives a
+ * packet, it must dequeue the entire packet from the
+ * requestChannel. The client must not send a request
+ * packet that exceeds the length of the FMQ.
+ * @param resultChannel FMQ used by the service to return the results of an
+ * execution to the client: the status of the
+ * execution, OutputShape of all output tensors, and
+ * timing information. resultChannel must be used to
+ * return the results if a Request was sent through the
+ * requestChannel. The service must send the result
+ * messages to the consumer atomically by using
+ * MessageQueue::writeBlocking if the queue is
+ * blocking, or by using MessageQueue::write if the
+ * queue is non-blocking. When the client receives a
+ * packet, it must dequeue the entire packet from the
+ * resultChannel. If the packet's length exceeds the
+ * size of the FMQ, the service must not send this
+ * result packet; instead, the service must send a
+ * packet consisting of the error code
+ * ErrorStatus::GENERAL_FAILURE, no information for the
+ * outputShapes, and an indication that timing
+ * information is unavailable.
* @return status Error status of configuring the execution burst, must be:
* - NONE if the burst is successfully configured
* - DEVICE_UNAVAILABLE if driver is offline or busy
diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp
index 44dddfd..697bf9e 100644
--- a/sensors/2.0/multihal/Android.bp
+++ b/sensors/2.0/multihal/Android.bp
@@ -45,6 +45,7 @@
],
init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"],
vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"],
+ cflags: ["-DLOG_TAG=\"SensorsMultiHal\""],
}
cc_library_headers {
diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp
index 80d7296..b4d2466 100644
--- a/sensors/2.0/multihal/HalProxy.cpp
+++ b/sensors/2.0/multihal/HalProxy.cpp
@@ -69,43 +69,13 @@
};
HalProxy::HalProxy() {
- const char* kMultiHalConfigFilePath = "/vendor/etc/sensors/hals.conf";
- std::ifstream subHalConfigStream(kMultiHalConfigFilePath);
- if (!subHalConfigStream) {
- LOG_FATAL("Failed to load subHal config file: %s", kMultiHalConfigFilePath);
- } else {
- std::string subHalLibraryFile;
- while (subHalConfigStream >> subHalLibraryFile) {
- void* handle = dlopen(subHalLibraryFile.c_str(), RTLD_NOW);
- if (handle == nullptr) {
- LOG_FATAL("dlopen failed for library: %s", subHalLibraryFile.c_str());
- } else {
- SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr =
- (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal");
- if (sensorsHalGetSubHalPtr == nullptr) {
- LOG_FATAL("Failed to locate sensorsHalGetSubHal function for library: %s",
- subHalLibraryFile.c_str());
- } else {
- std::function<SensorsHalGetSubHalFunc> sensorsHalGetSubHal =
- *sensorsHalGetSubHalPtr;
- uint32_t version;
- ISensorsSubHal* subHal = sensorsHalGetSubHal(&version);
- if (version != SUB_HAL_2_0_VERSION) {
- LOG_FATAL("SubHal version was not 2.0 for library: %s",
- subHalLibraryFile.c_str());
- } else {
- ALOGI("Loaded SubHal from library: %s", subHalLibraryFile.c_str());
- mSubHalList.push_back(subHal);
- }
- }
- }
- }
- }
- // TODO: Discover sensors
+ const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf";
+ initializeSubHalListFromConfigFile(kMultiHalConfigFile);
+ initializeSensorList();
}
HalProxy::HalProxy(std::vector<ISensorsSubHal*>& subHalList) : mSubHalList(subHalList) {
- // TODO: Perform the same steps as the empty constructor.
+ initializeSensorList();
}
HalProxy::~HalProxy() {
@@ -113,19 +83,37 @@
// state.
}
-Return<void> HalProxy::getSensorsList(getSensorsList_cb /* _hidl_cb */) {
- // TODO: Output sensors list created as part of HalProxy().
+Return<void> HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) {
+ _hidl_cb(mSensorList);
return Void();
}
-Return<Result> HalProxy::setOperationMode(OperationMode /* mode */) {
- // TODO: Proxy API call to all sub-HALs and return appropriate result.
- return Result::INVALID_OPERATION;
+Return<Result> HalProxy::setOperationMode(OperationMode mode) {
+ Result result = Result::OK;
+ size_t subHalIndex;
+ for (subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
+ ISensorsSubHal* subHal = mSubHalList[subHalIndex];
+ result = subHal->setOperationMode(mode);
+ if (result != Result::OK) {
+ ALOGE("setOperationMode failed for SubHal: %s", subHal->getName().c_str());
+ break;
+ }
+ }
+ if (result != Result::OK) {
+ // Reset the subhal operation modes that have been flipped
+ for (size_t i = 0; i < subHalIndex; i++) {
+ ISensorsSubHal* subHal = mSubHalList[i];
+ subHal->setOperationMode(mCurrentOperationMode);
+ }
+ } else {
+ mCurrentOperationMode = mode;
+ }
+ return result;
}
-Return<Result> HalProxy::activate(int32_t /* sensorHandle */, bool /* enabled */) {
- // TODO: Proxy API call to appropriate sub-HAL.
- return Result::INVALID_OPERATION;
+Return<Result> HalProxy::activate(int32_t sensorHandle, bool enabled) {
+ return getSubHalForSensorHandle(sensorHandle)
+ ->activate(clearSubHalIndex(sensorHandle), enabled);
}
Return<Result> HalProxy::initialize(
@@ -163,15 +151,14 @@
return result;
}
-Return<Result> HalProxy::batch(int32_t /* sensorHandle */, int64_t /* samplingPeriodNs */,
- int64_t /* maxReportLatencyNs */) {
- // TODO: Proxy API call to appropriate sub-HAL.
- return Result::INVALID_OPERATION;
+Return<Result> HalProxy::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) {
+ return getSubHalForSensorHandle(sensorHandle)
+ ->batch(clearSubHalIndex(sensorHandle), samplingPeriodNs, maxReportLatencyNs);
}
-Return<Result> HalProxy::flush(int32_t /* sensorHandle */) {
- // TODO: Proxy API call to appropriate sub-HAL.
- return Result::INVALID_OPERATION;
+Return<Result> HalProxy::flush(int32_t sensorHandle) {
+ return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle));
}
Return<Result> HalProxy::injectSensorData(const Event& /* event */) {
@@ -218,6 +205,83 @@
return Return<void>();
}
+void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) {
+ std::ifstream subHalConfigStream(configFileName);
+ if (!subHalConfigStream) {
+ ALOGE("Failed to load subHal config file: %s", configFileName);
+ } else {
+ std::string subHalLibraryFile;
+ while (subHalConfigStream >> subHalLibraryFile) {
+ void* handle = dlopen(subHalLibraryFile.c_str(), RTLD_NOW);
+ if (handle == nullptr) {
+ ALOGE("dlopen failed for library: %s", subHalLibraryFile.c_str());
+ } else {
+ SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr =
+ (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal");
+ if (sensorsHalGetSubHalPtr == nullptr) {
+ ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s",
+ subHalLibraryFile.c_str());
+ } else {
+ std::function<SensorsHalGetSubHalFunc> sensorsHalGetSubHal =
+ *sensorsHalGetSubHalPtr;
+ uint32_t version;
+ ISensorsSubHal* subHal = sensorsHalGetSubHal(&version);
+ if (version != SUB_HAL_2_0_VERSION) {
+ ALOGE("SubHal version was not 2.0 for library: %s",
+ subHalLibraryFile.c_str());
+ } else {
+ ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str());
+ mSubHalList.push_back(subHal);
+ }
+ }
+ }
+ }
+ }
+}
+
+void HalProxy::initializeSensorList() {
+ for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
+ ISensorsSubHal* subHal = mSubHalList[subHalIndex];
+ auto result = subHal->getSensorsList([&](const auto& list) {
+ for (SensorInfo sensor : list) {
+ if ((sensor.sensorHandle & kSensorHandleSubHalIndexMask) != 0) {
+ ALOGE("SubHal sensorHandle's first byte was not 0");
+ } else {
+ ALOGV("Loaded sensor: %s", sensor.name.c_str());
+ sensor.sensorHandle |= (subHalIndex << 24);
+ setDirectChannelFlags(&sensor, subHal);
+ mSensorList.push_back(sensor);
+ }
+ }
+ });
+ if (!result.isOk()) {
+ ALOGE("getSensorsList call failed for SubHal: %s", subHal->getName().c_str());
+ }
+ }
+}
+
+void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal) {
+ bool sensorSupportsDirectChannel =
+ (sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
+ V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL)) != 0;
+ if (mDirectChannelSubHal == nullptr && sensorSupportsDirectChannel) {
+ mDirectChannelSubHal = subHal;
+ } else if (mDirectChannelSubHal != nullptr && subHal != mDirectChannelSubHal) {
+ // disable direct channel capability for sensors in subHals that are not
+ // the only one we will enable
+ sensorInfo->flags &= ~(V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
+ V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
+ }
+}
+
+ISensorsSubHal* HalProxy::getSubHalForSensorHandle(uint32_t sensorHandle) {
+ return mSubHalList[static_cast<size_t>(sensorHandle >> 24)];
+}
+
+uint32_t HalProxy::clearSubHalIndex(uint32_t sensorHandle) {
+ return sensorHandle & (~kSensorHandleSubHalIndexMask);
+}
+
} // namespace implementation
} // namespace V2_0
} // namespace sensors
diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h
index 9d5787c..4ecb58b 100644
--- a/sensors/2.0/multihal/include/HalProxy.h
+++ b/sensors/2.0/multihal/include/HalProxy.h
@@ -39,7 +39,8 @@
using ::android::hardware::Return;
using ::android::hardware::Void;
-struct HalProxy : public ISensors {
+class HalProxy : public ISensors {
+ public:
using Event = ::android::hardware::sensors::V1_0::Event;
using OperationMode = ::android::hardware::sensors::V1_0::OperationMode;
using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
@@ -118,6 +119,64 @@
* SubHal object pointers that have been saved from vendor dynamic libraries.
*/
std::vector<ISensorsSubHal*> mSubHalList;
+
+ /**
+ * List of SensorInfo objects that contains the sensor info from subhals as
+ * well as the modified sensor handle for the framework.
+ *
+ * The subhal index is encoded in the first byte of the sensor handle and
+ * the remaining bytes are generated by the subhal to identify the sensor.
+ */
+ std::vector<SensorInfo> mSensorList;
+
+ //! The current operation mode for all subhals.
+ OperationMode mCurrentOperationMode = OperationMode::NORMAL;
+
+ //! The single subHal that supports directChannel reporting.
+ ISensorsSubHal* mDirectChannelSubHal = nullptr;
+
+ //! The bit mask used to get the subhal index from a sensor handle.
+ static constexpr uint32_t kSensorHandleSubHalIndexMask = 0xFF000000;
+
+ /**
+ * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries
+ * listed in a config file.
+ */
+ void initializeSubHalListFromConfigFile(const char* configFileName);
+
+ /**
+ * Initialize the list of SensorInfo objects in mSensorList by getting sensors from each
+ * subhal.
+ */
+ void initializeSensorList();
+
+ /**
+ * Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel
+ * subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first
+ * direct channel enabled sensor seen.
+ *
+ * @param sensorInfo The SensorInfo object that may be altered to have direct channel support
+ * disabled.
+ * @param subHal The subhal pointer that the current sensorInfo object came from.
+ */
+ void setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal);
+
+ /*
+ * Get the subhal pointer which can be found by indexing into the mSubHalList vector
+ * using the index from the first byte of sensorHandle.
+ *
+ * @param sensorHandle The handle used to identify a sensor in one of the subhals.
+ */
+ ISensorsSubHal* getSubHalForSensorHandle(uint32_t sensorHandle);
+
+ /*
+ * Clear out the subhal index bytes from a sensorHandle.
+ *
+ * @param sensorHandle The sensor handle to modify.
+ *
+ * @return The modified version of the sensor handle.
+ */
+ static uint32_t clearSubHalIndex(uint32_t sensorHandle);
};
} // namespace implementation
diff --git a/sensors/2.0/multihal/include/SubHal.h b/sensors/2.0/multihal/include/SubHal.h
index 75e93a1..e84cba5 100644
--- a/sensors/2.0/multihal/include/SubHal.h
+++ b/sensors/2.0/multihal/include/SubHal.h
@@ -137,6 +137,7 @@
* sub-HALs can continue to use the lower 3 bytes of the handle.
*/
class ISensorsSubHal : public ISensors {
+ public:
// The ISensors version of initialize isn't used for multihal. Instead, sub-HALs must implement
// the version below to allow communciation logic to centralized in the HalProxy
Return<Result> initialize(
diff --git a/sensors/2.0/multihal/service.cpp b/sensors/2.0/multihal/service.cpp
index 995cf3c..ef77048 100644
--- a/sensors/2.0/multihal/service.cpp
+++ b/sensors/2.0/multihal/service.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "android.hardware.sensors@2.0-service"
-
#include <android/hardware/sensors/2.0/ISensors.h>
#include <hidl/HidlTransportSupport.h>
#include <log/log.h>
diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp
index 13d80f7..21ceb0c 100644
--- a/sensors/2.0/multihal/tests/Android.bp
+++ b/sensors/2.0/multihal/tests/Android.bp
@@ -86,4 +86,4 @@
"libutils",
],
test_suites: ["device-tests"],
-}
\ No newline at end of file
+}
diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp
index 9edc88a..1e1f9e9 100644
--- a/sensors/2.0/multihal/tests/HalProxy_test.cpp
+++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp
@@ -15,25 +15,176 @@
#include <gtest/gtest.h>
+#include <android/hardware/sensors/2.0/types.h>
+
#include "HalProxy.h"
#include "SensorsSubHal.h"
+#include <vector>
+
+namespace {
+
+using ::android::hardware::sensors::V1_0::SensorFlagBits;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+using ::android::hardware::sensors::V1_0::SensorType;
using ::android::hardware::sensors::V2_0::implementation::HalProxy;
+using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::
+ AllSupportDirectChannelSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::
+ DoesNotSupportDirectChannelSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal;
using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal;
-// TODO: Add more interesting tests such as
-// - verify setOperationMode invokes all subhals
-// - verify if a subhal fails to change operation mode, that state is reset properly
-// - Available sensors are obtained during initialization
-//
-// You can run this suite using "atest android.hardware.sensors@2.0-halproxy-unit-tests".
-//
-// See https://source.android.com/compatibility/tests/development/native-func-e2e.md for more info
-// on how tests are set up and for information on the gtest framework itself.
-TEST(HalProxyTest, ExampleTest) {
- SensorsSubHal subHal;
- std::vector<ISensorsSubHal*> fakeSubHals;
- fakeSubHals.push_back(&subHal);
+using ::android::hardware::sensors::V2_0::subhal::implementation::
+ SetOperationModeFailingSensorsSubHal;
+// Helper declarations follow
+
+/**
+ * Tests that for each SensorInfo object from a proxy getSensorsList call each corresponding
+ * object from a subhal getSensorsList call has the same type and its last 3 bytes are the
+ * same for sensorHandle field.
+ *
+ * @param proxySensorsList The list of SensorInfo objects from the proxy.getSensorsList callback.
+ * @param subHalSenosrsList The list of SensorInfo objects from the subHal.getSensorsList callback.
+ */
+void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
+ const std::vector<SensorInfo>& subHalSensorsList);
+
+/**
+ * Tests that there is exactly one subhal that allows its sensors to have direct channel enabled.
+ * Therefore, all SensorInfo objects that are not from the enabled subhal should be disabled for
+ * direct channel.
+ *
+ * @param sensorsList The SensorInfo object list from proxy.getSensorsList call.
+ * @param enabledSubHalIndex The index of the subhal in the halproxy that is expected to be
+ * enabled.
+ */
+void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
+ size_t enabledSubHalIndex);
+
+// Tests follow
+TEST(HalProxyTest, GetSensorsListOneSubHalTest) {
+ AllSensorsSubHal subHal;
+ std::vector<ISensorsSubHal*> fakeSubHals{&subHal};
HalProxy proxy(fakeSubHals);
-}
\ No newline at end of file
+
+ proxy.getSensorsList([&](const auto& proxySensorsList) {
+ subHal.getSensorsList([&](const auto& subHalSensorsList) {
+ testSensorsListFromProxyAndSubHal(proxySensorsList, subHalSensorsList);
+ });
+ });
+}
+
+TEST(HalProxyTest, GetSensorsListTwoSubHalTest) {
+ ContinuousSensorsSubHal continuousSubHal;
+ OnChangeSensorsSubHal onChangeSubHal;
+ std::vector<ISensorsSubHal*> fakeSubHals;
+ fakeSubHals.push_back(&continuousSubHal);
+ fakeSubHals.push_back(&onChangeSubHal);
+ HalProxy proxy(fakeSubHals);
+
+ std::vector<SensorInfo> proxySensorsList, combinedSubHalSensorsList;
+
+ proxy.getSensorsList([&](const auto& list) { proxySensorsList = list; });
+ continuousSubHal.getSensorsList([&](const auto& list) {
+ combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
+ });
+ onChangeSubHal.getSensorsList([&](const auto& list) {
+ combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
+ });
+
+ testSensorsListFromProxyAndSubHal(proxySensorsList, combinedSubHalSensorsList);
+}
+
+TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) {
+ ContinuousSensorsSubHal subHal1;
+ OnChangeSensorsSubHal subHal2;
+
+ std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
+ HalProxy proxy(fakeSubHals);
+
+ EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
+ EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
+
+ Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);
+
+ EXPECT_EQ(result, Result::OK);
+ EXPECT_EQ(subHal1.getOperationMode(), OperationMode::DATA_INJECTION);
+ EXPECT_EQ(subHal2.getOperationMode(), OperationMode::DATA_INJECTION);
+}
+
+TEST(HalProxyTest, SetOperationModeTwoSubHalFailTest) {
+ AllSensorsSubHal subHal1;
+ SetOperationModeFailingSensorsSubHal subHal2;
+
+ std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
+ HalProxy proxy(fakeSubHals);
+
+ EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
+ EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
+
+ Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);
+
+ EXPECT_NE(result, Result::OK);
+ EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
+ EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
+}
+
+TEST(HalProxyTest, InitDirectChannelTwoSubHalsUnitTest) {
+ AllSupportDirectChannelSensorsSubHal subHal1;
+ AllSupportDirectChannelSensorsSubHal subHal2;
+
+ std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
+ HalProxy proxy(fakeSubHals);
+
+ proxy.getSensorsList([&](const auto& sensorsList) {
+ testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 0);
+ });
+}
+
+TEST(HalProxyTest, InitDirectChannelThreeSubHalsUnitTest) {
+ DoesNotSupportDirectChannelSensorsSubHal subHal1;
+ AllSupportDirectChannelSensorsSubHal subHal2, subHal3;
+ std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2, &subHal3};
+ HalProxy proxy(fakeSubHals);
+
+ proxy.getSensorsList([&](const auto& sensorsList) {
+ testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 1);
+ });
+}
+
+// Helper implementations follow
+void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
+ const std::vector<SensorInfo>& subHalSensorsList) {
+ EXPECT_EQ(proxySensorsList.size(), subHalSensorsList.size());
+
+ for (size_t i = 0; i < proxySensorsList.size(); i++) {
+ const SensorInfo& proxySensor = proxySensorsList[i];
+ const SensorInfo& subHalSensor = subHalSensorsList[i];
+
+ EXPECT_EQ(proxySensor.type, subHalSensor.type);
+ EXPECT_EQ(proxySensor.sensorHandle & 0x00FFFFFF, subHalSensor.sensorHandle);
+ }
+}
+
+void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
+ size_t enabledSubHalIndex) {
+ for (const SensorInfo& sensor : sensorsList) {
+ size_t subHalIndex = static_cast<size_t>(sensor.sensorHandle >> 24);
+ if (subHalIndex == enabledSubHalIndex) {
+ // First subhal should have been picked as the direct channel subhal
+ // and so have direct channel enabled on all of its sensors
+ EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
+ EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
+ } else {
+ // All other subhals should have direct channel disabled for all sensors
+ EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
+ EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
+ }
+ }
+}
+
+} // namespace
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
index 8d45982..d581c49 100644
--- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
+++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
@@ -20,7 +20,16 @@
#include <log/log.h>
ISensorsSubHal* sensorsHalGetSubHal(uint32_t* version) {
+#if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
+ static ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal subHal;
+#elif defined SUPPORT_CONTINUOUS_SENSORS
+ static ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal
+ subHal;
+#elif defined SUPPORT_ON_CHANGE_SENSORS
+ static ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal subHal;
+#else
static ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal subHal;
+#endif // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
*version = SUB_HAL_2_0_VERSION;
return &subHal;
}
@@ -42,22 +51,7 @@
using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock;
-SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {
-#ifdef SUPPORT_CONTINUOUS_SENSORS
- AddSensor<AccelSensor>();
- AddSensor<GyroSensor>();
- AddSensor<MagnetometerSensor>();
- AddSensor<PressureSensor>();
-#endif // SUPPORT_CONTINUOUS_SENSORS
-
-#ifdef SUPPORT_ON_CHANGE_SENSORS
- AddSensor<AmbientTempSensor>();
- AddSensor<DeviceTempSensor>();
- AddSensor<LightSensor>();
- AddSensor<ProximitySensor>();
- AddSensor<RelativeHumiditySensor>();
-#endif // SUPPORT_ON_CHANGE_SENSORS
-}
+SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {}
// Methods from ::android::hardware::sensors::V2_0::ISensors follow.
Return<void> SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
@@ -74,6 +68,7 @@
for (auto sensor : mSensors) {
sensor.second->setOperationMode(mode);
}
+ mCurrentOperationMode = mode;
return Result::OK;
}
@@ -171,6 +166,61 @@
mCallback->postEvents(events, std::move(wakelock));
}
+ContinuousSensorsSubHal::ContinuousSensorsSubHal() {
+ AddSensor<AccelSensor>();
+ AddSensor<GyroSensor>();
+ AddSensor<MagnetometerSensor>();
+ AddSensor<PressureSensor>();
+}
+
+OnChangeSensorsSubHal::OnChangeSensorsSubHal() {
+ AddSensor<AmbientTempSensor>();
+ AddSensor<DeviceTempSensor>();
+ AddSensor<LightSensor>();
+ AddSensor<ProximitySensor>();
+ AddSensor<RelativeHumiditySensor>();
+}
+
+AllSensorsSubHal::AllSensorsSubHal() {
+ AddSensor<AccelSensor>();
+ AddSensor<GyroSensor>();
+ AddSensor<MagnetometerSensor>();
+ AddSensor<PressureSensor>();
+ AddSensor<AmbientTempSensor>();
+ AddSensor<DeviceTempSensor>();
+ AddSensor<LightSensor>();
+ AddSensor<ProximitySensor>();
+ AddSensor<RelativeHumiditySensor>();
+}
+
+Return<Result> SetOperationModeFailingSensorsSubHal::setOperationMode(OperationMode /*mode*/) {
+ return Result::BAD_VALUE;
+}
+
+Return<void> AllSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
+ std::vector<SensorInfo> sensors;
+ for (const auto& sensor : mSensors) {
+ SensorInfo sensorInfo = sensor.second->getSensorInfo();
+ sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL;
+ sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_REPORT;
+ sensors.push_back(sensorInfo);
+ }
+ _hidl_cb(sensors);
+ return Void();
+}
+
+Return<void> DoesNotSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
+ std::vector<SensorInfo> sensors;
+ for (const auto& sensor : mSensors) {
+ SensorInfo sensorInfo = sensor.second->getSensorInfo();
+ sensorInfo.flags &= ~static_cast<uint32_t>(V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
+ sensorInfo.flags &= ~static_cast<uint32_t>(V1_0::SensorFlagBits::MASK_DIRECT_REPORT);
+ sensors.push_back(sensorInfo);
+ }
+ _hidl_cb(sensors);
+ return Void();
+}
+
} // namespace implementation
} // namespace subhal
} // namespace V2_0
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
index 93009d5..61caa2c 100644
--- a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
+++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
@@ -20,6 +20,8 @@
#include "Sensor.h"
+#include <vector>
+
namespace android {
namespace hardware {
namespace sensors {
@@ -27,6 +29,8 @@
namespace subhal {
namespace implementation {
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::Result;
using ::android::hardware::sensors::V2_0::implementation::IHalProxyCallback;
/**
@@ -35,18 +39,18 @@
*/
class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback {
using Event = ::android::hardware::sensors::V1_0::Event;
- using OperationMode = ::android::hardware::sensors::V1_0::OperationMode;
using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
- using Result = ::android::hardware::sensors::V1_0::Result;
using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
public:
SensorsSubHal();
// Methods from ::android::hardware::sensors::V2_0::ISensors follow.
- Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+ virtual Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
- Return<Result> setOperationMode(OperationMode mode) override;
+ virtual Return<Result> setOperationMode(OperationMode mode) override;
+
+ OperationMode getOperationMode() const { return mCurrentOperationMode; }
Return<Result> activate(int32_t sensorHandle, bool enabled) override;
@@ -81,7 +85,7 @@
// Method from ISensorsEventCallback.
void postEvents(const std::vector<Event>& events, bool wakeup) override;
- private:
+ protected:
template <class SensorType>
void AddSensor() {
std::shared_ptr<SensorType> sensor =
@@ -90,6 +94,18 @@
}
/**
+ * A map of the available sensors
+ */
+ std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
+
+ private:
+ /**
+ * The current operation mode of the multihal framework. Ensures that all subhals are set to
+ * the same operation mode.
+ */
+ OperationMode mCurrentOperationMode = OperationMode::NORMAL;
+
+ /**
* Callback used to communicate to the HalProxy when dynamic sensors are connected /
* disconnected, sensor events need to be sent to the framework, and when a wakelock should be
* acquired.
@@ -97,16 +113,44 @@
sp<IHalProxyCallback> mCallback;
/**
- * A map of the available sensors
- */
- std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
-
- /**
* The next available sensor handle
*/
int32_t mNextHandle;
};
+// SubHal that has continuous sensors for testing purposes.
+class ContinuousSensorsSubHal : public SensorsSubHal {
+ public:
+ ContinuousSensorsSubHal();
+};
+
+// SubHal that has on-change sensors for testing purposes.
+class OnChangeSensorsSubHal : public SensorsSubHal {
+ public:
+ OnChangeSensorsSubHal();
+};
+
+// SubHal that has both continuous and on-change sensors for testing purposes.
+class AllSensorsSubHal : public SensorsSubHal {
+ public:
+ AllSensorsSubHal();
+};
+
+class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal {
+ public:
+ Return<Result> setOperationMode(OperationMode mode) override;
+};
+
+class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal {
+ public:
+ Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+};
+
+class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal {
+ public:
+ Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+};
+
} // namespace implementation
} // namespace subhal
} // namespace V2_0
diff --git a/tests/baz/1.0/IBaz.hal b/tests/baz/1.0/IBaz.hal
index 91ed1f2..7855446 100644
--- a/tests/baz/1.0/IBaz.hal
+++ b/tests/baz/1.0/IBaz.hal
@@ -29,6 +29,11 @@
VALL = V0 | V1 | V2 | V3,
};
+ struct BitFieldTester {
+ bitfield<BitField> scalar;
+ vec<bitfield<BitField>> vector;
+ };
+
enum SomeOtherEnum : uint8_t {
bar = 66
};
@@ -108,6 +113,7 @@
haveSomeStrings(string[3] array) generates (string[2] result);
haveAStringVec(vec<string> vector) generates (vec<string> result);
+ repeatBitfieldVec(vec<bitfield<BitField>> vector) generates (vec<bitfield<BitField>> result);
returnABunchOfStrings() generates (string a, string b, string c);
diff --git a/tests/baz/1.0/default/Baz.cpp b/tests/baz/1.0/default/Baz.cpp
index e118122..2ce096c 100644
--- a/tests/baz/1.0/default/Baz.cpp
+++ b/tests/baz/1.0/default/Baz.cpp
@@ -364,6 +364,12 @@
return Void();
}
+Return<void> Baz::repeatBitfieldVec(const hidl_vec<uint8_t>& vector,
+ repeatBitfieldVec_cb _hidl_cb) {
+ _hidl_cb(vector);
+ return Void();
+}
+
Return<void> Baz::returnABunchOfStrings(returnABunchOfStrings_cb _hidl_cb) {
hidl_string eins; eins = "Eins";
hidl_string zwei; zwei = "Zwei";
diff --git a/tests/baz/1.0/default/Baz.h b/tests/baz/1.0/default/Baz.h
index c264f47..1e24d52 100644
--- a/tests/baz/1.0/default/Baz.h
+++ b/tests/baz/1.0/default/Baz.h
@@ -86,6 +86,8 @@
haveSomeStrings_cb _hidl_cb) override;
Return<void> haveAStringVec(const hidl_vec<hidl_string>& vector,
haveAStringVec_cb _hidl_cb) override;
+ Return<void> repeatBitfieldVec(const hidl_vec<uint8_t>& vector,
+ repeatBitfieldVec_cb _hidl_cb) override;
Return<void> returnABunchOfStrings(returnABunchOfStrings_cb _hidl_cb) override;
Return<uint8_t> returnABitField() override;
Return<uint32_t> size(uint32_t size) override;