Merge changes from topic "canbus"
* changes:
Test CAN bus HAL
Implement CAN bus HAL tools
Default implementation for CAN bus HAL
Define CAN bus HAL.
diff --git a/OWNERS b/OWNERS
index 1d7a8e1..433bbb7 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,3 +1,6 @@
+per-file *.hal,*.aidl,OWNERS = set noparent
+per-file *.hal,*.aidl,OWNERS = elsk@google.com,malchev@google.com,smoreland@google.com
+
elsk@google.com
maco@google.com
malchev@google.com
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 213c93a..0140275 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -3,3 +3,8 @@
[Builtin Hooks]
clang_format = true
+
+[Hook Scripts]
+aosp_hook_confirmationui = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} confirmationui
+aosp_hook_gatekeeper = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} gatekeeper
+aosp_hook_keymaster = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} keymaster
diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp
index 97b4553..3283223 100644
--- a/audio/core/all-versions/default/Android.bp
+++ b/audio/core/all-versions/default/Android.bp
@@ -19,6 +19,7 @@
export_include_dirs: ["include"],
shared_libs: [
+ "libaudiofoundation",
"libbase",
"libcutils",
"libfmq",
diff --git a/audio/core/all-versions/default/Stream.cpp b/audio/core/all-versions/default/Stream.cpp
index e62f6d3..2a4ef6d 100644
--- a/audio/core/all-versions/default/Stream.cpp
+++ b/audio/core/all-versions/default/Stream.cpp
@@ -26,9 +26,8 @@
#include <android/log.h>
#include <hardware/audio.h>
#include <hardware/audio_effect.h>
+#include <media/AudioContainers.h>
#include <media/TypeConverter.h>
-#include <utils/SortedVector.h>
-#include <utils/Vector.h>
namespace android {
namespace hardware {
@@ -100,11 +99,11 @@
Result result =
getParam(AudioParameter::keyStreamSupportedSamplingRates, &halListValue, context);
hidl_vec<uint32_t> sampleRates;
- SortedVector<uint32_t> halSampleRates;
+ SampleRateSet halSampleRates;
if (result == Result::OK) {
halSampleRates =
samplingRatesFromString(halListValue.string(), AudioParameter::valueListSeparator);
- sampleRates.setToExternal(halSampleRates.editArray(), halSampleRates.size());
+ sampleRates = hidl_vec<uint32_t>(halSampleRates.begin(), halSampleRates.end());
// Legacy get_parameter does not return a status_t, thus can not advertise of failure.
// Note that this method must succeed (non empty list) if the format is supported.
if (sampleRates.size() == 0) {
@@ -126,13 +125,14 @@
String8 halListValue;
Result result = getParam(AudioParameter::keyStreamSupportedChannels, &halListValue, context);
hidl_vec<AudioChannelBitfield> channelMasks;
- SortedVector<audio_channel_mask_t> halChannelMasks;
+ ChannelMaskSet halChannelMasks;
if (result == Result::OK) {
halChannelMasks =
channelMasksFromString(halListValue.string(), AudioParameter::valueListSeparator);
channelMasks.resize(halChannelMasks.size());
- for (size_t i = 0; i < halChannelMasks.size(); ++i) {
- channelMasks[i] = AudioChannelBitfield(halChannelMasks[i]);
+ size_t i = 0;
+ for (auto channelMask : halChannelMasks) {
+ channelMasks[i++] = AudioChannelBitfield(channelMask);
}
// Legacy get_parameter does not return a status_t, thus can not advertise of failure.
// Note that this method must succeed (non empty list) if the format is supported.
@@ -168,7 +168,7 @@
String8 halListValue;
Result result = getParam(AudioParameter::keyStreamSupportedFormats, &halListValue);
hidl_vec<AudioFormat> formats;
- Vector<audio_format_t> halFormats;
+ FormatVector halFormats;
if (result == Result::OK) {
halFormats = formatsFromString(halListValue.string(), AudioParameter::valueListSeparator);
formats.resize(halFormats.size());
diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp
index 88fdb5a..5e17ade 100644
--- a/audio/core/all-versions/vts/functional/Android.bp
+++ b/audio/core/all-versions/vts/functional/Android.bp
@@ -24,6 +24,7 @@
"libxml2",
],
shared_libs: [
+ "libaudiofoundation",
"libfmq",
],
header_libs: [
diff --git a/automotive/audiocontrol/1.0/IAudioControl.hal b/automotive/audiocontrol/1.0/IAudioControl.hal
index 3c8b086..2e7ef75 100644
--- a/automotive/audiocontrol/1.0/IAudioControl.hal
+++ b/automotive/audiocontrol/1.0/IAudioControl.hal
@@ -29,6 +29,11 @@
*
* For every context, a valid bus number (0 - num busses-1) must be returned. If an
* unrecognized contextNumber is encountered, then -1 shall be returned.
+ *
+ * Deprecated: usage of this API and car_volume_groups.xml has been replaced with
+ * car_audio_configuration.xml. If using car_audio_configuration.xml, then the framework
+ * will not call this method. If it doesn't, then it will load car_volume_groups.xml and
+ * call this method.
*/
getBusForContext(ContextNumber contextNumber)
generates (int32_t busNumber);
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
index d689e62..8ee3c54 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
@@ -153,7 +153,7 @@
std::unique_ptr<VehiclePropValue> createAvailabilityRequest();
// Creates a VehiclePropValue containing a message of type
-// VmsMessageType.AVAILABILITY_REQUEST.
+// VmsMessageType.SUBSCRIPTIONS_REQUEST.
std::unique_ptr<VehiclePropValue> createSubscriptionsRequest();
// Creates a VehiclePropValue containing a message of type VmsMessageType.DATA.
@@ -202,21 +202,21 @@
// Returns true if the new sequence number is greater than the last seen
// sequence number.
-bool isSequenceNumberNewer(const VehiclePropValue& subscription_change,
+bool isSequenceNumberNewer(const VehiclePropValue& subscriptions_state,
const int last_seen_sequence_number);
// Returns sequence number of the message.
-int32_t getSequenceNumberForSubscriptionsState(const VehiclePropValue& subscription_change);
+int32_t getSequenceNumberForSubscriptionsState(const VehiclePropValue& subscriptions_state);
-// Takes a subscription change message and returns the layers that have active
+// Takes a subscriptions state message and returns the layers that have active
// subscriptions of the layers that are offered by your HAL client/publisher.
//
-// A publisher can use this function when receiving a subscription change message
-// to determine which layers to publish data on.
+// A publisher can use this function when receiving a subscriptions response or subscriptions
+// change message to determine which layers to publish data on.
// The caller of this function can optionally decide to not consume these layers
// if the subscription change has the sequence number less than the last seen
// sequence number.
-std::vector<VmsLayer> getSubscribedLayers(const VehiclePropValue& subscription_change,
+std::vector<VmsLayer> getSubscribedLayers(const VehiclePropValue& subscriptions_state,
const VmsOffers& offers);
// Takes an availability change message and returns true if the parsed message implies that
diff --git a/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
index d346206..9eba905 100644
--- a/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
@@ -194,32 +194,35 @@
return -1;
}
-bool isSequenceNumberNewer(const VehiclePropValue& subscription_change,
+bool isSequenceNumberNewer(const VehiclePropValue& subscriptions_state,
const int last_seen_sequence_number) {
- return (isValidVmsMessage(subscription_change) &&
- parseMessageType(subscription_change) == VmsMessageType::SUBSCRIPTIONS_CHANGE &&
- subscription_change.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex &&
- subscription_change.value.int32Values[kSubscriptionStateSequenceNumberIndex] >
+ return (isValidVmsMessage(subscriptions_state) &&
+ (parseMessageType(subscriptions_state) == VmsMessageType::SUBSCRIPTIONS_CHANGE ||
+ parseMessageType(subscriptions_state) == VmsMessageType::SUBSCRIPTIONS_RESPONSE) &&
+ subscriptions_state.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex &&
+ subscriptions_state.value.int32Values[kSubscriptionStateSequenceNumberIndex] >
last_seen_sequence_number);
}
-int32_t getSequenceNumberForSubscriptionsState(const VehiclePropValue& subscription_change) {
- if (isValidVmsMessage(subscription_change) &&
- parseMessageType(subscription_change) == VmsMessageType::SUBSCRIPTIONS_CHANGE &&
- subscription_change.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex) {
- return subscription_change.value.int32Values[kSubscriptionStateSequenceNumberIndex];
+int32_t getSequenceNumberForSubscriptionsState(const VehiclePropValue& subscriptions_state) {
+ if (isValidVmsMessage(subscriptions_state) &&
+ (parseMessageType(subscriptions_state) == VmsMessageType::SUBSCRIPTIONS_CHANGE ||
+ parseMessageType(subscriptions_state) == VmsMessageType::SUBSCRIPTIONS_RESPONSE) &&
+ subscriptions_state.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex) {
+ return subscriptions_state.value.int32Values[kSubscriptionStateSequenceNumberIndex];
}
return -1;
}
-std::vector<VmsLayer> getSubscribedLayers(const VehiclePropValue& subscription_change,
+std::vector<VmsLayer> getSubscribedLayers(const VehiclePropValue& subscriptions_state,
const VmsOffers& offers) {
- if (isValidVmsMessage(subscription_change) &&
- parseMessageType(subscription_change) == VmsMessageType::SUBSCRIPTIONS_CHANGE &&
- subscription_change.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex) {
- const int32_t num_of_layers = subscription_change.value.int32Values[toInt(
+ if (isValidVmsMessage(subscriptions_state) &&
+ (parseMessageType(subscriptions_state) == VmsMessageType::SUBSCRIPTIONS_CHANGE ||
+ parseMessageType(subscriptions_state) == VmsMessageType::SUBSCRIPTIONS_RESPONSE) &&
+ subscriptions_state.value.int32Values.size() > kSubscriptionStateSequenceNumberIndex) {
+ const int32_t num_of_layers = subscriptions_state.value.int32Values[toInt(
VmsSubscriptionsStateIntegerValuesIndex::NUMBER_OF_LAYERS)];
- const int32_t num_of_associated_layers = subscription_change.value.int32Values[toInt(
+ const int32_t num_of_associated_layers = subscriptions_state.value.int32Values[toInt(
VmsSubscriptionsStateIntegerValuesIndex ::NUMBER_OF_ASSOCIATED_LAYERS)];
std::unordered_set<VmsLayer, VmsLayer::VmsLayerHashFunction> offered_layers;
@@ -231,9 +234,9 @@
int current_index = toInt(VmsSubscriptionsStateIntegerValuesIndex::SUBSCRIPTIONS_START);
// Add all subscribed layers which are offered by the current publisher.
for (int i = 0; i < num_of_layers; i++) {
- VmsLayer layer = VmsLayer(subscription_change.value.int32Values[current_index],
- subscription_change.value.int32Values[current_index + 1],
- subscription_change.value.int32Values[current_index + 2]);
+ VmsLayer layer = VmsLayer(subscriptions_state.value.int32Values[current_index],
+ subscriptions_state.value.int32Values[current_index + 1],
+ subscriptions_state.value.int32Values[current_index + 2]);
if (offered_layers.find(layer) != offered_layers.end()) {
subscribed_layers.push_back(layer);
}
@@ -243,15 +246,15 @@
// For this, we need to check if the associated layer has a publisher ID which is
// same as that of the current publisher.
for (int i = 0; i < num_of_associated_layers; i++) {
- VmsLayer layer = VmsLayer(subscription_change.value.int32Values[current_index],
- subscription_change.value.int32Values[current_index + 1],
- subscription_change.value.int32Values[current_index + 2]);
+ VmsLayer layer = VmsLayer(subscriptions_state.value.int32Values[current_index],
+ subscriptions_state.value.int32Values[current_index + 1],
+ subscriptions_state.value.int32Values[current_index + 2]);
current_index += kLayerSize;
if (offered_layers.find(layer) != offered_layers.end()) {
- int32_t num_of_publisher_ids = subscription_change.value.int32Values[current_index];
+ int32_t num_of_publisher_ids = subscriptions_state.value.int32Values[current_index];
current_index++;
for (int j = 0; j < num_of_publisher_ids; j++) {
- if (subscription_change.value.int32Values[current_index] ==
+ if (subscriptions_state.value.int32Values[current_index] ==
offers.publisher_id) {
subscribed_layers.push_back(layer);
}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 7bafd2c..5452cfa 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -85,6 +85,12 @@
0x0666 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
/**
+ * This property is used for test purpose. End to end tests use this property to test set and get
+ * method for MIXED type properties.
+ */
+const int32_t kMixedTypePropertyForTest =
+ 0x1111 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+/**
* FakeDataCommand enum defines the supported command type for kGenerateFakeDataControllingProperty.
* All those commands can be send independently with each other. And each will override the one sent
* previously.
@@ -422,6 +428,17 @@
.areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}},
.initialValue = {.int32Values = {0}} // Will be used for all areas.
},
+ {
+ .config = {.prop = toInt(VehicleProperty::HVAC_ELECTRIC_DEFROSTER_ON),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .areaConfigs =
+ {VehicleAreaConfig{
+ .areaId = toInt(VehicleAreaWindow::FRONT_WINDSHIELD)},
+ VehicleAreaConfig{
+ .areaId = toInt(VehicleAreaWindow::REAR_WINDSHIELD)}}},
+ .initialValue = {.int32Values = {0}} // Will be used for all areas.
+ },
{.config = {.prop = toInt(VehicleProperty::HVAC_MAX_DEFROST_ON),
.access = VehiclePropertyAccess::READ_WRITE,
@@ -556,6 +573,13 @@
.configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS}},
.initialValue = {.int32Values = {(int)VehicleUnit::FAHRENHEIT}}},
+ {.config = {.prop = toInt(VehicleProperty::DISTANCE_DISPLAY_UNITS),
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {(int)VehicleUnit::KILOMETER, (int)VehicleUnit::MILE},
+ .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}},
+ .initialValue = {.int32Values = {(int)VehicleUnit::MILE}}},
+
{.config =
{
.prop = toInt(VehicleProperty::NIGHT_MODE),
@@ -607,6 +631,14 @@
},
},
+ {.config = {.prop = kMixedTypePropertyForTest,
+ .access = VehiclePropertyAccess::READ_WRITE,
+ .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .configArray = {1, 1, 0, 2, 0, 0, 1, 0, 0}},
+ .initialValue = {.stringValue = "MIXED property",
+ .int32Values = {1 /* indicate TRUE boolean value */, 2, 3},
+ .floatValues = {4.5f}}},
+
{.config = {.prop = toInt(VehicleProperty::DOOR_LOCK),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
diff --git a/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
index 7189212..8b547f1 100644
--- a/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
@@ -214,57 +214,82 @@
EXPECT_EQ(parsePublisherIdResponse(*message), -1);
}
-TEST(VmsUtilsTest, validSequenceNumberForSubscriptionsState) {
+TEST(VmsUtilsTest, validSequenceNumberForSubscriptionsChange) {
auto message = createBaseVmsMessage(2);
message->value.int32Values =
hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234};
EXPECT_EQ(getSequenceNumberForSubscriptionsState(*message), 1234);
}
+TEST(VmsUtilsTest, validSequenceNumberForSubscriptionsResponse) {
+ auto message = createBaseVmsMessage(2);
+ message->value.int32Values =
+ hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_RESPONSE), 1234};
+ EXPECT_EQ(getSequenceNumberForSubscriptionsState(*message), 1234);
+}
+
TEST(VmsUtilsTest, invalidSubscriptionsState) {
auto message = createBaseVmsMessage(1);
EXPECT_EQ(getSequenceNumberForSubscriptionsState(*message), -1);
}
-TEST(VmsUtilsTest, newSequenceNumberForExistingSmallerNumber) {
+TEST(VmsUtilsTest, newSequenceNumberForExistingSmallerNumberForChange) {
auto message = createBaseVmsMessage(2);
message->value.int32Values =
hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234};
EXPECT_TRUE(isSequenceNumberNewer(*message, 1233));
}
-TEST(VmsUtilsTest, newSequenceNumberForExistingGreaterNumber) {
+TEST(VmsUtilsTest, newSequenceNumberForExistingSmallerNumberForResponse) {
+ auto message = createBaseVmsMessage(2);
+ message->value.int32Values =
+ hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_RESPONSE), 1234};
+ EXPECT_TRUE(isSequenceNumberNewer(*message, 1233));
+}
+
+TEST(VmsUtilsTest, newSequenceNumberForExistingGreaterNumberForChange) {
auto message = createBaseVmsMessage(2);
message->value.int32Values =
hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234};
EXPECT_FALSE(isSequenceNumberNewer(*message, 1235));
}
-TEST(VmsUtilsTest, newSequenceNumberForSameNumber) {
+TEST(VmsUtilsTest, newSequenceNumberForExistingGreaterNumberForResponse) {
+ auto message = createBaseVmsMessage(2);
+ message->value.int32Values =
+ hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_RESPONSE), 1234};
+ EXPECT_FALSE(isSequenceNumberNewer(*message, 1235));
+}
+
+TEST(VmsUtilsTest, newSequenceNumberForSameNumberForChange) {
auto message = createBaseVmsMessage(2);
message->value.int32Values =
hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE), 1234};
EXPECT_FALSE(isSequenceNumberNewer(*message, 1234));
}
-TEST(VmsUtilsTest, subscribedLayers) {
+TEST(VmsUtilsTest, newSequenceNumberForSameNumberForResponse) {
+ auto message = createBaseVmsMessage(2);
+ message->value.int32Values =
+ hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_RESPONSE), 1234};
+ EXPECT_FALSE(isSequenceNumberNewer(*message, 1234));
+}
+
+void testSubscribedLayers(VmsMessageType type) {
VmsOffers offers = {123,
{VmsLayerOffering(VmsLayer(1, 0, 1), {VmsLayer(4, 1, 1)}),
VmsLayerOffering(VmsLayer(2, 0, 1))}};
auto message = createBaseVmsMessage(2);
- message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE),
+ message->value.int32Values = hidl_vec<int32_t>{toInt(type),
1234, // sequence number
2, // number of layers
1, // number of associated layers
1, // layer 1
- 0,
- 1,
+ 0, 1,
4, // layer 2
- 1,
- 1,
+ 1, 1,
2, // associated layer
- 0,
- 1,
+ 0, 1,
2, // number of publisher IDs
111, // publisher IDs
123};
@@ -275,10 +300,18 @@
EXPECT_EQ(result.at(1), VmsLayer(2, 0, 1));
}
-TEST(VmsUtilsTest, subscribedLayersWithDifferentSubtype) {
+TEST(VmsUtilsTest, subscribedLayersForChange) {
+ testSubscribedLayers(VmsMessageType::SUBSCRIPTIONS_CHANGE);
+}
+
+TEST(VmsUtilsTest, subscribedLayersForResponse) {
+ testSubscribedLayers(VmsMessageType::SUBSCRIPTIONS_RESPONSE);
+}
+
+void testSubscribedLayersWithDifferentSubtype(VmsMessageType type) {
VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 1))}};
auto message = createBaseVmsMessage(2);
- message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE),
+ message->value.int32Values = hidl_vec<int32_t>{toInt(type),
1234, // sequence number
1, // number of layers
0, // number of associated layers
@@ -289,36 +322,58 @@
EXPECT_TRUE(getSubscribedLayers(*message, offers).empty());
}
-TEST(VmsUtilsTest, subscribedLayersWithDifferentVersion) {
+TEST(VmsUtilsTest, subscribedLayersWithDifferentSubtypeForChange) {
+ testSubscribedLayersWithDifferentSubtype(VmsMessageType::SUBSCRIPTIONS_CHANGE);
+}
+
+TEST(VmsUtilsTest, subscribedLayersWithDifferentSubtypeForResponse) {
+ testSubscribedLayersWithDifferentSubtype(VmsMessageType::SUBSCRIPTIONS_RESPONSE);
+}
+
+void subscribedLayersWithDifferentVersion(VmsMessageType type) {
VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 1))}};
auto message = createBaseVmsMessage(2);
- message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE),
- 1234, // sequence number
- 1, // number of layers
- 0, // number of associated layers
- 1, // layer 1
- 0,
- 2}; // different version
+ message->value.int32Values = hidl_vec<int32_t>{toInt(type),
+ 1234, // sequence number
+ 1, // number of layers
+ 0, // number of associated layers
+ 1, // layer 1
+ 0, 2}; // different version
EXPECT_TRUE(isValidVmsMessage(*message));
EXPECT_TRUE(getSubscribedLayers(*message, offers).empty());
}
-TEST(VmsUtilsTest, subscribedLayersWithDifferentPublisherId) {
+TEST(VmsUtilsTest, subscribedLayersWithDifferentVersionForChange) {
+ subscribedLayersWithDifferentVersion(VmsMessageType::SUBSCRIPTIONS_CHANGE);
+}
+
+TEST(VmsUtilsTest, subscribedLayersWithDifferentVersionForResponse) {
+ subscribedLayersWithDifferentVersion(VmsMessageType::SUBSCRIPTIONS_RESPONSE);
+}
+
+void subscribedLayersWithDifferentPublisherId(VmsMessageType type) {
VmsOffers offers = {123, {VmsLayerOffering(VmsLayer(1, 0, 1))}};
auto message = createBaseVmsMessage(2);
- message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIPTIONS_CHANGE),
+ message->value.int32Values = hidl_vec<int32_t>{toInt(type),
1234, // sequence number
0, // number of layers
1, // number of associated layers
1, // associated layer 1
- 0,
- 1,
+ 0, 1,
1, // number of publisher IDs
234}; // publisher ID 1
EXPECT_TRUE(isValidVmsMessage(*message));
EXPECT_TRUE(getSubscribedLayers(*message, offers).empty());
}
+TEST(VmsUtilsTest, subscribedLayersWithDifferentPublisherIdForChange) {
+ subscribedLayersWithDifferentPublisherId(VmsMessageType::SUBSCRIPTIONS_CHANGE);
+}
+
+TEST(VmsUtilsTest, subscribedLayersWithDifferentPublisherIdForResponse) {
+ subscribedLayersWithDifferentPublisherId(VmsMessageType::SUBSCRIPTIONS_RESPONSE);
+}
+
TEST(VmsUtilsTest, serviceNewlyStarted) {
auto message = createBaseVmsMessage(2);
message->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::AVAILABILITY_CHANGE), 0};
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index f6ebcdd..8c84c0a 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -35,6 +35,21 @@
/**
* Any combination of scalar or vector types. The exact format must be
* provided in the description of the property.
+ *
+ * For vendor MIXED type properties, configArray needs to be formatted in this
+ * structure.
+ * configArray[0], 1 indicates the property has a String value
+ * configArray[1], 1 indicates the property has a Boolean value .
+ * configArray[2], 1 indicates the property has an Integer value.
+ * configArray[3], the number indicates the size of Integer[] in the property.
+ * configArray[4], 1 indicates the property has a Long value.
+ * configArray[5], the number indicates the size of Long[] in the property.
+ * configArray[6], 1 indicates the property has a Float value.
+ * configArray[7], the number indicates the size of Float[] in the property.
+ * configArray[8], the number indicates the size of byte[] in the property.
+ * For example:
+ * {@code configArray = {1, 1, 1, 3, 0, 0, 0, 0, 0}} indicates the property has
+ * a String value, a Boolean value, an Integer value and an array with 3 integers.
*/
MIXED = 0x00e00000,
@@ -799,7 +814,7 @@
| VehicleArea:SEAT),
/**
- * On/off defrost for designated window
+ * Fan-based defrost for designated window.
*
* @change_mode VehiclePropertyChangeMode:ON_CHANGE
* @access VehiclePropertyAccess:READ_WRITE
@@ -1076,6 +1091,7 @@
*
* @change_mode VehiclePropertyChangeMode:STATIC
* @access VehiclePropertyAccess:READ
+ * @data_enum VehicleHvacFanDirection
*/
HVAC_FAN_DIRECTION_AVAILABLE = (
0x0511
@@ -1118,6 +1134,18 @@
| VehiclePropertyType:INT32
| VehicleArea:SEAT),
+ /**
+ * Electric defrosters' status
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ HVAC_ELECTRIC_DEFROSTER_ON = (
+ 0x0514
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:BOOLEAN
+ | VehicleArea:WINDOW),
+
/**
* Distance units for display
*
@@ -2458,9 +2486,19 @@
* Bit flags for fan direction
*/
enum VehicleHvacFanDirection : int32_t {
+ UNKNOWN = 0x0,
+
FACE = 0x1,
FLOOR = 0x2,
+ /**
+ * FACE_AND_FLOOR = FACE | FLOOR
+ */
+ FACE_AND_FLOOR = 0x3,
DEFROST = 0x4,
+ /**
+ * DEFROST_AND_FLOOR = DEFROST | FLOOR
+ */
+ DEFROST_AND_FLOOR = 0x06,
};
enum VehicleOilLevel : int32_t {
@@ -2723,6 +2761,8 @@
* Various gears which can be selected by user and chosen in system.
*/
enum VehicleGear : int32_t {
+ GEAR_UNKNOWN = 0x0000,
+
GEAR_NEUTRAL = 0x0001,
GEAR_REVERSE = 0x0002,
GEAR_PARK = 0x0004,
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 6e1bc8f..3e83cdc 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -195,8 +195,8 @@
</hal>
<hal format="hidl" optional="false">
<name>android.hardware.graphics.allocator</name>
- <version>2.0</version>
<version>3.0</version>
+ <version>4.0</version>
<interface>
<name>IAllocator</name>
<instance>default</instance>
@@ -212,8 +212,8 @@
</hal>
<hal format="hidl" optional="false">
<name>android.hardware.graphics.mapper</name>
- <version>2.1</version>
<version>3.0</version>
+ <version>4.0</version>
<interface>
<name>IMapper</name>
<instance>default</instance>
diff --git a/current.txt b/current.txt
index eb1b1ca..fbb9752 100644
--- a/current.txt
+++ b/current.txt
@@ -576,3 +576,4 @@
ad431c8de51c07934a068e3043d8dd0537ac4d3158627706628b123f42df48dc android.hardware.neuralnetworks@1.0::IPreparedModel
aafcc10cf04ab247e86d4582586c71c6b4c2b8c479241ffa7fe37deb659fc942 android.hardware.neuralnetworks@1.2::IPreparedModel
1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
+fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface
diff --git a/graphics/allocator/4.0/Android.bp b/graphics/allocator/4.0/Android.bp
new file mode 100644
index 0000000..f5f9458
--- /dev/null
+++ b/graphics/allocator/4.0/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.graphics.allocator@4.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "IAllocator.hal",
+ ],
+ interfaces: [
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
diff --git a/graphics/allocator/4.0/IAllocator.hal b/graphics/allocator/4.0/IAllocator.hal
new file mode 100644
index 0000000..9931685
--- /dev/null
+++ b/graphics/allocator/4.0/IAllocator.hal
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.allocator@4.0;
+
+import android.hardware.graphics.mapper@4.0;
+
+interface IAllocator {
+ /**
+ * Retrieves implementation-defined debug information, which will be
+ * displayed during, for example, `dumpsys SurfaceFlinger`.
+ *
+ * @return debugInfo is a string of debug information.
+ */
+ dumpDebugInfo() generates (string debugInfo);
+
+ /**
+ * Allocates buffers with the properties specified by the descriptor.
+ *
+ * Allocations should be optimized for usage bits provided in the
+ * descriptor.
+ *
+ * @param descriptor Properties of the buffers to allocate. This must be
+ * obtained from IMapper::createDescriptor().
+ * @param count The number of buffers to allocate.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_DESCRIPTOR` if the descriptor is invalid.
+ * - `NO_RESOURCES` if the allocation cannot be fulfilled at this time.
+ * - `UNSUPPORTED` if any of the properties encoded in the descriptor
+ * are not supported.
+ * @return stride The number of pixels between two consecutive rows of
+ * an allocated buffer, when the concept of consecutive rows is defined.
+ * Otherwise, it has no meaning.
+ * @return buffers Array of raw handles to the allocated buffers.
+ */
+ allocate(BufferDescriptor descriptor, uint32_t count)
+ generates (Error error,
+ uint32_t stride,
+ vec<handle> buffers);
+};
+
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index cc24774..1319035 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -29,6 +29,7 @@
"libhidlbase",
"libhidltransport",
"libhwbinder",
+ "libprocessgroup",
"libsync",
"libui",
"libgui",
diff --git a/graphics/mapper/4.0/Android.bp b/graphics/mapper/4.0/Android.bp
new file mode 100644
index 0000000..42c4942
--- /dev/null
+++ b/graphics/mapper/4.0/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.graphics.mapper@4.0",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ srcs: [
+ "types.hal",
+ "IMapper.hal",
+ ],
+ interfaces: [
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
diff --git a/graphics/mapper/4.0/IMapper.hal b/graphics/mapper/4.0/IMapper.hal
new file mode 100644
index 0000000..f5df04b
--- /dev/null
+++ b/graphics/mapper/4.0/IMapper.hal
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.mapper@4.0;
+
+import android.hardware.graphics.common@1.2::BufferUsage;
+import android.hardware.graphics.common@1.2::PixelFormat;
+import android.hardware.graphics.common@1.2::Rect;
+
+interface IMapper {
+ struct BufferDescriptorInfo {
+ /**
+ * The width specifies how many columns of pixels must be in the
+ * allocated buffer, but does not necessarily represent the offset in
+ * columns between the same column in adjacent rows. The rows may be
+ * padded.
+ */
+ uint32_t width;
+
+ /**
+ * The height specifies how many rows of pixels must be in the
+ * allocated buffer.
+ */
+ uint32_t height;
+
+ /**
+ * The number of image layers that must be in the allocated buffer.
+ */
+ uint32_t layerCount;
+
+ /** Buffer pixel format. */
+ PixelFormat format;
+
+ /**
+ * Buffer usage mask; valid flags can be found in the definition of
+ * BufferUsage.
+ */
+ bitfield<BufferUsage> usage;
+ };
+
+ struct Rect {
+ int32_t left;
+ int32_t top;
+ int32_t width;
+ int32_t height;
+ };
+
+ /**
+ * Creates a buffer descriptor. The descriptor can be used with IAllocator
+ * to allocate buffers.
+ *
+ * Since the buffer descriptor fully describes a buffer, any device
+ * dependent or device independent checks must be performed here whenever
+ * possible. Specifically, when layered buffers are not supported, this
+ * function must return `UNSUPPORTED` if `description.layers` is great than
+ * 1.
+ *
+ * @param description Attributes of the descriptor.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_VALUE` if any of the specified attributes are invalid or
+ * inconsistent.
+ * - `NO_RESOURCES` if the creation cannot be fullfilled due to
+ * unavailability of resources.
+ * - `UNSUPPORTED` when any of the specified attributes are not
+ * supported.
+ * @return descriptor Newly created buffer descriptor.
+ */
+ createDescriptor(BufferDescriptorInfo description)
+ generates (Error error,
+ BufferDescriptor descriptor);
+
+ /**
+ * Imports a raw buffer handle to create an imported buffer handle for use
+ * with the rest of the mapper or with other in-process libraries.
+ *
+ * A buffer handle is considered raw when it is cloned (e.g., with
+ * `native_handle_clone()`) from another buffer handle locally, or when it
+ * is received from another HAL server/client or another process. A raw
+ * buffer handle must not be used to access the underlying graphic
+ * buffer. It must be imported to create an imported handle first.
+ *
+ * This function must at least validate the raw handle before creating the
+ * imported handle. It must also support importing the same raw handle
+ * multiple times to create multiple imported handles. The imported handle
+ * must be considered valid everywhere in the process, including in
+ * another instance of the mapper.
+ *
+ * Because of passthrough HALs, a raw buffer handle received from a HAL
+ * may actually have been imported in the process. importBuffer() must treat
+ * such a handle as if it is raw and must not return `BAD_BUFFER`. The
+ * returned handle is independent from the input handle as usual, and
+ * freeBuffer() must be called on it when it is no longer needed.
+ *
+ * @param rawHandle Raw buffer handle to import.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the raw handle is invalid.
+ * - `NO_RESOURCES` if the raw handle cannot be imported due to
+ * unavailability of resources.
+ * @return buffer Imported buffer handle that has the type
+ * `buffer_handle_t` which is a handle type.
+ */
+ importBuffer(handle rawHandle) generates (Error error, pointer buffer);
+
+ /**
+ * Frees a buffer handle. Buffer handles returned by importBuffer() must be
+ * freed with this function when no longer needed.
+ *
+ * This function must free up all resources allocated by importBuffer() for
+ * the imported handle. For example, if the imported handle was created
+ * with `native_handle_create()`, this function must call
+ * `native_handle_close()` and `native_handle_delete()`.
+ *
+ * @param buffer Imported buffer handle.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid.
+ */
+ freeBuffer(pointer buffer) generates (Error error);
+
+ /**
+ * Validates that the buffer can be safely accessed by a caller who assumes
+ * the specified @p description and @p stride. This must at least validate
+ * that the buffer size is large enough. Validating the buffer against
+ * individual buffer attributes is optional.
+ *
+ * @param buffer Buffer to validate against.
+ * @param description Attributes of the buffer.
+ * @param stride Stride returned by IAllocator::allocate().
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid.
+ * - `BAD_VALUE` if the buffer cannot be safely accessed.
+ */
+ validateBufferSize(pointer buffer,
+ BufferDescriptorInfo description,
+ uint32_t stride)
+ generates (Error error);
+
+ /**
+ * Calculates the transport size of a buffer. An imported buffer handle is a
+ * raw buffer handle with the process-local runtime data appended. This
+ * function, for example, allows a caller to omit the process-local runtime
+ * data at the tail when serializing the imported buffer handle.
+ *
+ * Note that a client might or might not omit the process-local runtime data
+ * when sending an imported buffer handle. The mapper must support both
+ * cases on the receiving end.
+ *
+ * @param buffer Buffer to get the transport size from.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid.
+ * @return numFds The number of file descriptors needed for transport.
+ * @return numInts The number of integers needed for transport.
+ */
+ getTransportSize(pointer buffer)
+ generates (Error error,
+ uint32_t numFds,
+ uint32_t numInts);
+
+ /**
+ * Locks the given buffer for the specified CPU usage.
+ *
+ * Locking the same buffer simultaneously from multiple threads is
+ * permitted, but if any of the threads attempt to lock the buffer for
+ * writing, the behavior is undefined, except that it must not cause
+ * process termination or block the client indefinitely. Leaving the
+ * buffer content in an indeterminate state or returning an error are both
+ * acceptable.
+ *
+ * 1D buffers (width = size in bytes, height = 1, pixel_format = BLOB) must
+ * "lock in place". The buffers must be directly accessible via mapping.
+ *
+ * The client must not modify the content of the buffer outside of
+ * @p accessRegion, and the device need not guarantee that content outside
+ * of @p accessRegion is valid for reading. The result of reading or writing
+ * outside of @p accessRegion is undefined, except that it must not cause
+ * process termination.
+ *
+ * On success, @p data must be filled with a pointer to the locked buffer
+ * memory. This address will represent the top-left corner of the entire
+ * buffer, even if @p accessRegion does not begin at the top-left corner.
+ *
+ * On success, bytesPerPixel must contain the number of bytes per pixel in
+ * the buffer. If the bytesPerPixel is unknown or variable, a value of -1
+ * should be returned. bytesPerStride must contain the bytes per stride of
+ * the buffer. If the bytesPerStride is unknown or variable, a value of -1
+ * should be returned.
+ *
+ * @param buffer Buffer to lock.
+ * @param cpuUsage CPU usage flags to request. See +ndk
+ * libnativewindow#AHardwareBuffer_UsageFlags for possible values.
+ * @param accessRegion Portion of the buffer that the client intends to
+ * access.
+ * @param acquireFence Handle containing a file descriptor referring to a
+ * sync fence object, which will be signaled when it is safe for the
+ * mapper to lock the buffer. @p acquireFence may be an empty fence if
+ * it is already safe to lock.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or is incompatible with this
+ * function.
+ * - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or
+ * is incompatible with the buffer.
+ * - `NO_RESOURCES` if the buffer cannot be locked at this time. Note
+ * that locking may succeed at a later time.
+ * @return data CPU-accessible pointer to the buffer data.
+ * @return bytesPerPixel the number of bytes per pixel in the buffer
+ * @return bytesPerStride the number of bytes per stride of the buffer
+ */
+ lock(pointer buffer,
+ uint64_t cpuUsage,
+ Rect accessRegion,
+ handle acquireFence)
+ generates (Error error,
+ pointer data,
+ int32_t bytesPerPixel,
+ int32_t bytesPerStride);
+
+ /**
+ * Locks a YCbCr buffer for the specified CPU usage.
+ *
+ * This is largely the same as lock(), except that instead of returning a
+ * pointer directly to the buffer data, it returns a `YCbCrLayout` struct
+ * describing how to access the data planes.
+ *
+ * This function must work on buffers with
+ * `AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_*` if supported by the device, as well
+ * as with any other formats requested by multimedia codecs when they are
+ * configured with a flexible-YUV-compatible color format.
+ *
+ * @param buffer Buffer to lock.
+ * @param cpuUsage CPU usage flags to request. See +ndk
+ * libnativewindow#AHardwareBuffer_UsageFlags for possible values.
+ * @param accessRegion Portion of the buffer that the client intends to
+ * access.
+ * @param acquireFence Handle containing a file descriptor referring to a
+ * sync fence object, which will be signaled when it is safe for the
+ * mapper to lock the buffer. @p acquireFence may be empty if it is
+ * already safe to lock.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or is incompatible with this
+ * function.
+ * - `BAD_VALUE` if @p cpuUsage is 0, contains non-CPU usage flags, or
+ * is incompatible with the buffer.
+ * - `NO_RESOURCES` if the buffer cannot be locked at this time. Note
+ * that locking may succeed at a later time.
+ * @return layout Data layout of the locked buffer.
+ */
+ lockYCbCr(pointer buffer,
+ uint64_t cpuUsage,
+ Rect accessRegion,
+ handle acquireFence)
+ generates (Error error,
+ YCbCrLayout layout);
+
+ /**
+ * Unlocks a buffer to indicate all CPU accesses to the buffer have
+ * completed.
+ *
+ * @param buffer Buffer to unlock.
+ * @return error Error status of the call, which may be
+ * - `NONE` upon success.
+ * - `BAD_BUFFER` if the buffer is invalid or not locked.
+ * @return releaseFence Handle containing a file descriptor referring to a
+ * sync fence object. The sync fence object will be signaled when the
+ * mapper has completed any pending work. @p releaseFence may be an
+ * empty fence.
+ */
+ unlock(pointer buffer) generates (Error error, handle releaseFence);
+
+ /**
+ * Test whether the given BufferDescriptorInfo is allocatable.
+ *
+ * If this function returns true, it means that a buffer with the given
+ * description can be allocated on this implementation, unless resource
+ * exhaustion occurs. If this function returns false, it means that the
+ * allocation of the given description will never succeed.
+ *
+ * @param description the description of the buffer
+ * @return supported whether the description is supported
+ */
+ isSupported(BufferDescriptorInfo description)
+ generates (Error error,
+ bool supported);
+
+};
+
diff --git a/graphics/mapper/4.0/types.hal b/graphics/mapper/4.0/types.hal
new file mode 100644
index 0000000..603b243
--- /dev/null
+++ b/graphics/mapper/4.0/types.hal
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.mapper@4.0;
+
+/**
+ * Error values that may be returned by a method of IAllocator or IMapper.
+ */
+enum Error : int32_t {
+ /**
+ * No error.
+ */
+ NONE = 0,
+ /**
+ * Invalid BufferDescriptor.
+ */
+ BAD_DESCRIPTOR = 1,
+ /**
+ * Invalid buffer handle.
+ */
+ BAD_BUFFER = 2,
+ /**
+ * Invalid HardwareBufferDescription.
+ */
+ BAD_VALUE = 3,
+ /**
+ * Resource unavailable.
+ */
+ NO_RESOURCES = 5,
+ /**
+ * Permanent failure.
+ */
+ UNSUPPORTED = 7,
+};
+
+/**
+ * A buffer descriptor is an implementation-defined opaque data returned by
+ * createDescriptor(). It describes the properties of a buffer and is consumed
+ * by the allocator.
+ */
+typedef vec<uint32_t> BufferDescriptor;
+
+/**
+ * Structure for describing YCbCr formats for consumption by applications.
+ * This is used with PixelFormat::YCBCR_*_888.
+ *
+ * Buffer chroma subsampling is defined in the format.
+ * e.g. PixelFormat::YCBCR_420_888 has subsampling 4:2:0.
+ *
+ * Buffers must have a 8 bit depth.
+ *
+ * y, cb, and cr point to the first byte of their respective planes.
+ *
+ * Stride describes the distance in bytes from the first value of one row of
+ * the image to the first value of the next row. It includes the width of the
+ * image plus padding.
+ * yStride is the stride of the luma plane.
+ * cStride is the stride of the chroma planes.
+ *
+ * chromaStep is the distance in bytes from one chroma pixel value to the
+ * next. This is 2 bytes for semiplanar (because chroma values are interleaved
+ * and each chroma value is one byte) and 1 for planar.
+ */
+struct YCbCrLayout {
+ pointer y;
+ pointer cb;
+ pointer cr;
+ uint32_t yStride;
+ uint32_t cStride;
+ uint32_t chromaStep;
+};
diff --git a/graphics/mapper/4.0/utils/OWNERS b/graphics/mapper/4.0/utils/OWNERS
new file mode 100644
index 0000000..96f6d51
--- /dev/null
+++ b/graphics/mapper/4.0/utils/OWNERS
@@ -0,0 +1,3 @@
+# Graphics team
+marissaw@google.com
+stoza@google.com
diff --git a/graphics/mapper/4.0/utils/vts/Android.bp b/graphics/mapper/4.0/utils/vts/Android.bp
new file mode 100644
index 0000000..e451584
--- /dev/null
+++ b/graphics/mapper/4.0/utils/vts/Android.bp
@@ -0,0 +1,34 @@
+//
+// Copyright (C) 2019 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_library_static {
+ name: "android.hardware.graphics.mapper@4.0-vts",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["MapperVts.cpp"],
+ cflags: [
+ "-O0",
+ "-g",
+ ],
+ static_libs: [
+ "android.hardware.graphics.allocator@4.0",
+ "android.hardware.graphics.mapper@4.0",
+ ],
+ export_static_lib_headers: [
+ "android.hardware.graphics.allocator@4.0",
+ "android.hardware.graphics.mapper@4.0",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/mapper/4.0/utils/vts/MapperVts.cpp b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
new file mode 100644
index 0000000..056b7c9
--- /dev/null
+++ b/graphics/mapper/4.0/utils/vts/MapperVts.cpp
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <mapper-vts/4.0/MapperVts.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V4_0 {
+namespace vts {
+
+Gralloc::Gralloc(const std::string& allocatorServiceName, const std::string& mapperServiceName,
+ bool errOnFailure) {
+ if (errOnFailure) {
+ init(allocatorServiceName, mapperServiceName);
+ } else {
+ initNoErr(allocatorServiceName, mapperServiceName);
+ }
+}
+
+void Gralloc::init(const std::string& allocatorServiceName, const std::string& mapperServiceName) {
+ mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(allocatorServiceName);
+ ASSERT_NE(nullptr, mAllocator.get()) << "failed to get allocator service";
+
+ mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(mapperServiceName);
+ ASSERT_NE(nullptr, mMapper.get()) << "failed to get mapper service";
+ ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
+}
+
+void Gralloc::initNoErr(const std::string& allocatorServiceName,
+ const std::string& mapperServiceName) {
+ mAllocator = ::testing::VtsHalHidlTargetTestBase::getService<IAllocator>(allocatorServiceName);
+
+ mMapper = ::testing::VtsHalHidlTargetTestBase::getService<IMapper>(mapperServiceName);
+ if (mMapper.get()) {
+ ASSERT_FALSE(mMapper->isRemote()) << "mapper is not in passthrough mode";
+ }
+}
+
+Gralloc::~Gralloc() {
+ for (auto bufferHandle : mClonedBuffers) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ native_handle_close(buffer);
+ native_handle_delete(buffer);
+ }
+ mClonedBuffers.clear();
+
+ for (auto bufferHandle : mImportedBuffers) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ EXPECT_EQ(Error::NONE, mMapper->freeBuffer(buffer)) << "failed to free buffer " << buffer;
+ }
+ mImportedBuffers.clear();
+}
+
+sp<IAllocator> Gralloc::getAllocator() const {
+ return mAllocator;
+}
+
+std::string Gralloc::dumpDebugInfo() {
+ std::string debugInfo;
+ mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+
+ return debugInfo;
+}
+
+const native_handle_t* Gralloc::cloneBuffer(const hidl_handle& rawHandle) {
+ const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
+ EXPECT_NE(nullptr, bufferHandle);
+
+ if (bufferHandle) {
+ mClonedBuffers.insert(bufferHandle);
+ }
+
+ return bufferHandle;
+}
+
+std::vector<const native_handle_t*> Gralloc::allocate(const BufferDescriptor& descriptor,
+ uint32_t count, bool import,
+ uint32_t* outStride) {
+ std::vector<const native_handle_t*> bufferHandles;
+ bufferHandles.reserve(count);
+ mAllocator->allocate(descriptor, count,
+ [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to allocate buffers";
+ ASSERT_EQ(count, tmpBuffers.size()) << "invalid buffer array";
+
+ for (uint32_t i = 0; i < count; i++) {
+ if (import) {
+ ASSERT_NO_FATAL_FAILURE(
+ bufferHandles.push_back(importBuffer(tmpBuffers[i])));
+ } else {
+ ASSERT_NO_FATAL_FAILURE(
+ bufferHandles.push_back(cloneBuffer(tmpBuffers[i])));
+ }
+ }
+
+ if (outStride) {
+ *outStride = tmpStride;
+ }
+ });
+
+ if (::testing::Test::HasFatalFailure()) {
+ bufferHandles.clear();
+ }
+
+ return bufferHandles;
+}
+
+const native_handle_t* Gralloc::allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+ bool import, uint32_t* outStride) {
+ BufferDescriptor descriptor = createDescriptor(descriptorInfo);
+ if (::testing::Test::HasFatalFailure()) {
+ return nullptr;
+ }
+
+ auto buffers = allocate(descriptor, 1, import, outStride);
+ if (::testing::Test::HasFatalFailure()) {
+ return nullptr;
+ }
+
+ return buffers[0];
+}
+
+sp<IMapper> Gralloc::getMapper() const {
+ return mMapper;
+}
+
+BufferDescriptor Gralloc::createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+ BufferDescriptor descriptor;
+ mMapper->createDescriptor(descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to create descriptor";
+ descriptor = tmpDescriptor;
+ });
+
+ return descriptor;
+}
+
+const native_handle_t* Gralloc::importBuffer(const hidl_handle& rawHandle) {
+ const native_handle_t* bufferHandle = nullptr;
+ mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
+ ASSERT_EQ(Error::NONE, tmpError)
+ << "failed to import buffer %p" << rawHandle.getNativeHandle();
+ bufferHandle = static_cast<const native_handle_t*>(tmpBuffer);
+ });
+
+ if (bufferHandle) {
+ mImportedBuffers.insert(bufferHandle);
+ }
+
+ return bufferHandle;
+}
+
+void Gralloc::freeBuffer(const native_handle_t* bufferHandle) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ if (mImportedBuffers.erase(bufferHandle)) {
+ Error error = mMapper->freeBuffer(buffer);
+ ASSERT_EQ(Error::NONE, error) << "failed to free buffer " << buffer;
+ } else {
+ mClonedBuffers.erase(bufferHandle);
+ native_handle_close(buffer);
+ native_handle_delete(buffer);
+ }
+}
+
+void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ hidl_handle acquireFenceHandle;
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
+
+ *outBytesPerPixel = -1;
+ *outBytesPerStride = -1;
+
+ void* data = nullptr;
+ mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpData, int32_t tmpBytesPerPixel,
+ int32_t tmpBytesPerStride) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to lock buffer " << buffer;
+ data = tmpData;
+ *outBytesPerPixel = tmpBytesPerPixel;
+ *outBytesPerStride = tmpBytesPerStride;
+ });
+
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ return data;
+}
+
+YCbCrLayout Gralloc::lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int acquireFence) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ hidl_handle acquireFenceHandle;
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
+
+ YCbCrLayout layout = {};
+ mMapper->lockYCbCr(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpLayout) {
+ ASSERT_EQ(Error::NONE, tmpError)
+ << "failed to lockYCbCr buffer " << buffer;
+ layout = tmpLayout;
+ });
+
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ return layout;
+}
+
+int Gralloc::unlock(const native_handle_t* bufferHandle) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ int releaseFence = -1;
+ mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to unlock buffer " << buffer;
+
+ auto fenceHandle = tmpReleaseFence.getNativeHandle();
+ if (fenceHandle) {
+ ASSERT_EQ(0, fenceHandle->numInts) << "invalid fence handle " << fenceHandle;
+ if (fenceHandle->numFds == 1) {
+ releaseFence = dup(fenceHandle->data[0]);
+ ASSERT_LT(0, releaseFence) << "failed to dup fence fd";
+ } else {
+ ASSERT_EQ(0, fenceHandle->numFds) << " invalid fence handle " << fenceHandle;
+ }
+ }
+ });
+
+ return releaseFence;
+}
+
+bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle,
+ const IMapper::BufferDescriptorInfo& descriptorInfo,
+ uint32_t stride) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ Error error = mMapper->validateBufferSize(buffer, descriptorInfo, stride);
+ return error == Error::NONE;
+}
+
+void Gralloc::getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ *outNumFds = 0;
+ *outNumInts = 0;
+ mMapper->getTransportSize(buffer, [&](const auto& tmpError, const auto& tmpNumFds,
+ const auto& tmpNumInts) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to get transport size";
+ ASSERT_GE(bufferHandle->numFds, int(tmpNumFds)) << "invalid numFds " << tmpNumFds;
+ ASSERT_GE(bufferHandle->numInts, int(tmpNumInts)) << "invalid numInts " << tmpNumInts;
+
+ *outNumFds = tmpNumFds;
+ *outNumInts = tmpNumInts;
+ });
+}
+
+bool Gralloc::isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo) {
+ bool supported = false;
+ mMapper->isSupported(descriptorInfo, [&](const auto& tmpError, const auto& tmpSupported) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to check is supported";
+ supported = tmpSupported;
+ });
+ return supported;
+}
+
+} // namespace vts
+} // namespace V4_0
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
new file mode 100644
index 0000000..03ce764
--- /dev/null
+++ b/graphics/mapper/4.0/utils/vts/include/mapper-vts/4.0/MapperVts.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+#include <unordered_set>
+#include <vector>
+
+#include <android/hardware/graphics/allocator/4.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V4_0 {
+namespace vts {
+
+using android::hardware::graphics::allocator::V4_0::IAllocator;
+
+// A wrapper to IAllocator and IMapper.
+class Gralloc {
+ public:
+ Gralloc(const std::string& allocatorServiceName = "default",
+ const std::string& mapperServiceName = "default", bool errOnFailure = true);
+ ~Gralloc();
+
+ // IAllocator methods
+
+ sp<IAllocator> getAllocator() const;
+
+ std::string dumpDebugInfo();
+
+ // When import is false, this simply calls IAllocator::allocate. When import
+ // is true, the returned buffers are also imported into the mapper.
+ //
+ // Either case, the returned buffers must be freed with freeBuffer.
+ std::vector<const native_handle_t*> allocate(const BufferDescriptor& descriptor, uint32_t count,
+ bool import = true, uint32_t* outStride = nullptr);
+ const native_handle_t* allocate(const IMapper::BufferDescriptorInfo& descriptorInfo,
+ bool import = true, uint32_t* outStride = nullptr);
+
+ // IMapper methods
+
+ sp<IMapper> getMapper() const;
+
+ BufferDescriptor createDescriptor(const IMapper::BufferDescriptorInfo& descriptorInfo);
+
+ const native_handle_t* importBuffer(const hidl_handle& rawHandle);
+ void freeBuffer(const native_handle_t* bufferHandle);
+
+ // We use fd instead of hidl_handle in these functions to pass fences
+ // in and out of the mapper. The ownership of the fd is always transferred
+ // with each of these functions.
+ void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int acquireFence, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride);
+ YCbCrLayout lockYCbCr(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+ const IMapper::Rect& accessRegion, int acquireFence);
+ int unlock(const native_handle_t* bufferHandle);
+
+ bool validateBufferSize(const native_handle_t* bufferHandle,
+ const IMapper::BufferDescriptorInfo& descriptorInfo, uint32_t stride);
+ void getTransportSize(const native_handle_t* bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts);
+
+ bool isSupported(const IMapper::BufferDescriptorInfo& descriptorInfo);
+
+ private:
+ void init(const std::string& allocatorServiceName, const std::string& mapperServiceName);
+
+ // initialize without checking for failure to get service
+ void initNoErr(const std::string& allocatorServiceName, const std::string& mapperServiceName);
+ const native_handle_t* cloneBuffer(const hidl_handle& rawHandle);
+
+ sp<IAllocator> mAllocator;
+ sp<IMapper> mMapper;
+
+ // Keep track of all cloned and imported handles. When a test fails with
+ // ASSERT_*, the destructor will free the handles for the test.
+ std::unordered_set<const native_handle_t*> mClonedBuffers;
+ std::unordered_set<const native_handle_t*> mImportedBuffers;
+};
+
+} // namespace vts
+} // namespace V4_0
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/mapper/4.0/vts/OWNERS b/graphics/mapper/4.0/vts/OWNERS
new file mode 100644
index 0000000..96f6d51
--- /dev/null
+++ b/graphics/mapper/4.0/vts/OWNERS
@@ -0,0 +1,3 @@
+# Graphics team
+marissaw@google.com
+stoza@google.com
diff --git a/graphics/mapper/4.0/vts/functional/Android.bp b/graphics/mapper/4.0/vts/functional/Android.bp
new file mode 100644
index 0000000..a90ee0c
--- /dev/null
+++ b/graphics/mapper/4.0/vts/functional/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright 2019 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: "VtsHalGraphicsMapperV4_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalGraphicsMapperV4_0TargetTest.cpp"],
+ static_libs: [
+ "android.hardware.graphics.allocator@4.0",
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hardware.graphics.mapper@4.0-vts",
+ ],
+ test_suites: ["general-tests"],
+}
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
new file mode 100644
index 0000000..706c658
--- /dev/null
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -0,0 +1,494 @@
+/*
+ * Copyright 2019 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 "VtsHalGraphicsMapperV4_0TargetTest"
+
+#include <chrono>
+#include <thread>
+#include <vector>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <mapper-vts/4.0/MapperVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace mapper {
+namespace V4_0 {
+namespace vts {
+namespace {
+
+using android::hardware::graphics::common::V1_2::BufferUsage;
+using android::hardware::graphics::common::V1_2::PixelFormat;
+
+// Test environment for graphics.mapper.
+class GraphicsMapperHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static GraphicsMapperHidlEnvironment* Instance() {
+ static GraphicsMapperHidlEnvironment* instance = new GraphicsMapperHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override {
+ registerTestService<IAllocator>();
+ registerTestService<IMapper>();
+ }
+};
+
+class GraphicsMapperHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(
+ mGralloc = std::make_unique<Gralloc>(
+ GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
+ GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+
+ mDummyDescriptorInfo.width = 64;
+ mDummyDescriptorInfo.height = 64;
+ mDummyDescriptorInfo.layerCount = 1;
+ mDummyDescriptorInfo.format = PixelFormat::RGBA_8888;
+ mDummyDescriptorInfo.usage =
+ static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+ }
+
+ void TearDown() override {}
+
+ std::unique_ptr<Gralloc> mGralloc;
+ IMapper::BufferDescriptorInfo mDummyDescriptorInfo{};
+};
+
+/**
+ * Test IAllocator::dumpDebugInfo by calling it.
+ */
+TEST_F(GraphicsMapperHidlTest, AllocatorDumpDebugInfo) {
+ mGralloc->dumpDebugInfo();
+}
+
+/**
+ * Test IAllocator::allocate with valid buffer descriptors.
+ */
+TEST_F(GraphicsMapperHidlTest, AllocatorAllocate) {
+ BufferDescriptor descriptor;
+ ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
+
+ for (uint32_t count = 0; count < 5; count++) {
+ std::vector<const native_handle_t*> bufferHandles;
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(bufferHandles =
+ mGralloc->allocate(descriptor, count, false, &stride));
+
+ if (count >= 1) {
+ EXPECT_LE(mDummyDescriptorInfo.width, stride) << "invalid buffer stride";
+ }
+
+ for (auto bufferHandle : bufferHandles) {
+ mGralloc->freeBuffer(bufferHandle);
+ }
+ }
+}
+
+/**
+ * Test IAllocator::allocate with invalid buffer descriptors.
+ */
+TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNegative) {
+ // this assumes any valid descriptor is non-empty
+ BufferDescriptor descriptor;
+ mGralloc->getAllocator()->allocate(descriptor, 1,
+ [&](const auto& tmpError, const auto&, const auto&) {
+ EXPECT_EQ(Error::BAD_DESCRIPTOR, tmpError);
+ });
+}
+
+/**
+ * Test IAllocator::allocate does not leak.
+ */
+TEST_F(GraphicsMapperHidlTest, AllocatorAllocateNoLeak) {
+ auto info = mDummyDescriptorInfo;
+ info.width = 1024;
+ info.height = 1024;
+
+ for (int i = 0; i < 2048; i++) {
+ auto bufferHandle = mGralloc->allocate(info, false);
+ mGralloc->freeBuffer(bufferHandle);
+ }
+}
+
+/**
+ * Test that IAllocator::allocate is thread-safe.
+ */
+TEST_F(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
+ BufferDescriptor descriptor;
+ ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
+
+ std::atomic<bool> timeUp(false);
+ std::atomic<uint64_t> allocationCount(0);
+ auto threadLoop = [&]() {
+ while (!timeUp) {
+ mGralloc->getAllocator()->allocate(
+ descriptor, 1,
+ [&](const auto&, const auto&, const auto&) { allocationCount++; });
+ }
+ };
+
+ std::vector<std::thread> threads;
+ for (int i = 0; i < 8; i++) {
+ threads.push_back(std::thread(threadLoop));
+ }
+
+ std::this_thread::sleep_for(std::chrono::seconds(3));
+ timeUp = true;
+ LOG(VERBOSE) << "Made " << allocationCount << " threaded allocations";
+
+ for (auto& thread : threads) {
+ thread.join();
+ }
+}
+
+/**
+ * Test IMapper::createDescriptor with valid descriptor info.
+ */
+TEST_F(GraphicsMapperHidlTest, CreateDescriptorBasic) {
+ ASSERT_NO_FATAL_FAILURE(mGralloc->createDescriptor(mDummyDescriptorInfo));
+}
+
+/**
+ * Test IMapper::createDescriptor with invalid descriptor info.
+ */
+TEST_F(GraphicsMapperHidlTest, CreateDescriptorNegative) {
+ auto info = mDummyDescriptorInfo;
+ info.width = 0;
+ mGralloc->getMapper()->createDescriptor(info, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_VALUE, tmpError) << "createDescriptor did not fail with BAD_VALUE";
+ });
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer with allocated buffers.
+ */
+TEST_F(GraphicsMapperHidlTest, ImportFreeBufferBasic) {
+ const native_handle_t* bufferHandle;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(bufferHandle));
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer with cloned buffers.
+ */
+TEST_F(GraphicsMapperHidlTest, ImportFreeBufferClone) {
+ const native_handle_t* clonedBufferHandle;
+ ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
+
+ // A cloned handle is a raw handle. Check that we can import it multiple
+ // times.
+ const native_handle_t* importedBufferHandles[2];
+ ASSERT_NO_FATAL_FAILURE(importedBufferHandles[0] = mGralloc->importBuffer(clonedBufferHandle));
+ ASSERT_NO_FATAL_FAILURE(importedBufferHandles[1] = mGralloc->importBuffer(clonedBufferHandle));
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[0]));
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(importedBufferHandles[1]));
+
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(clonedBufferHandle));
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer cross mapper instances.
+ */
+TEST_F(GraphicsMapperHidlTest, ImportFreeBufferSingleton) {
+ const native_handle_t* rawHandle;
+ ASSERT_NO_FATAL_FAILURE(rawHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
+
+ native_handle_t* importedHandle = nullptr;
+ mGralloc->getMapper()->importBuffer(rawHandle, [&](const auto& tmpError, const auto& buffer) {
+ ASSERT_EQ(Error::NONE, tmpError);
+ importedHandle = static_cast<native_handle_t*>(buffer);
+ });
+
+ // free the imported handle with another mapper
+ std::unique_ptr<Gralloc> anotherGralloc;
+ ASSERT_NO_FATAL_FAILURE(
+ anotherGralloc = std::make_unique<Gralloc>(
+ GraphicsMapperHidlEnvironment::Instance()->getServiceName<IAllocator>(),
+ GraphicsMapperHidlEnvironment::Instance()->getServiceName<IMapper>()));
+ Error error = mGralloc->getMapper()->freeBuffer(importedHandle);
+ ASSERT_EQ(Error::NONE, error);
+
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawHandle));
+}
+
+/**
+ * Test IMapper::importBuffer and IMapper::freeBuffer do not leak.
+ */
+TEST_F(GraphicsMapperHidlTest, ImportFreeBufferNoLeak) {
+ auto info = mDummyDescriptorInfo;
+ info.width = 1024;
+ info.height = 1024;
+
+ for (int i = 0; i < 2048; i++) {
+ auto bufferHandle = mGralloc->allocate(info, true);
+ mGralloc->freeBuffer(bufferHandle);
+ }
+}
+
+/**
+ * Test IMapper::importBuffer with invalid buffers.
+ */
+TEST_F(GraphicsMapperHidlTest, ImportBufferNegative) {
+ native_handle_t* invalidHandle = nullptr;
+ mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "importBuffer with nullptr did not fail with BAD_BUFFER";
+ });
+
+ invalidHandle = native_handle_create(0, 0);
+ mGralloc->getMapper()->importBuffer(invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "importBuffer with invalid handle did not fail with BAD_BUFFER";
+ });
+ native_handle_delete(invalidHandle);
+}
+
+/**
+ * Test IMapper::freeBuffer with invalid buffers.
+ */
+TEST_F(GraphicsMapperHidlTest, FreeBufferNegative) {
+ native_handle_t* invalidHandle = nullptr;
+ Error error = mGralloc->getMapper()->freeBuffer(invalidHandle);
+ EXPECT_EQ(Error::BAD_BUFFER, error) << "freeBuffer with nullptr did not fail with BAD_BUFFER";
+
+ invalidHandle = native_handle_create(0, 0);
+ error = mGralloc->getMapper()->freeBuffer(invalidHandle);
+ EXPECT_EQ(Error::BAD_BUFFER, error)
+ << "freeBuffer with invalid handle did not fail with BAD_BUFFER";
+ native_handle_delete(invalidHandle);
+
+ const native_handle_t* clonedBufferHandle;
+ ASSERT_NO_FATAL_FAILURE(clonedBufferHandle = mGralloc->allocate(mDummyDescriptorInfo, false));
+ error = mGralloc->getMapper()->freeBuffer(invalidHandle);
+ EXPECT_EQ(Error::BAD_BUFFER, error)
+ << "freeBuffer with un-imported handle did not fail with BAD_BUFFER";
+
+ mGralloc->freeBuffer(clonedBufferHandle);
+}
+
+/**
+ * Test IMapper::lock and IMapper::unlock.
+ */
+TEST_F(GraphicsMapperHidlTest, LockUnlockBasic) {
+ const auto& info = mDummyDescriptorInfo;
+
+ const native_handle_t* bufferHandle;
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, &stride));
+
+ // lock buffer for writing
+ const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+ static_cast<int32_t>(info.height)};
+ int fence = -1;
+ uint8_t* data;
+ int32_t bytesPerPixel = -1;
+ int32_t bytesPerStride = -1;
+ ASSERT_NO_FATAL_FAILURE(
+ data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence,
+ &bytesPerPixel, &bytesPerStride)));
+
+ // Valid return values are -1 for unsupported or the number bytes for supported which is >=0
+ EXPECT_GT(bytesPerPixel, -1);
+ EXPECT_GT(bytesPerStride, -1);
+
+ // RGBA_8888
+ size_t strideInBytes = stride * 4;
+ size_t writeInBytes = info.width * 4;
+
+ for (uint32_t y = 0; y < info.height; y++) {
+ memset(data, y, writeInBytes);
+ data += strideInBytes;
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+
+ bytesPerPixel = -1;
+ bytesPerStride = -1;
+
+ // lock again for reading
+ ASSERT_NO_FATAL_FAILURE(
+ data = static_cast<uint8_t*>(mGralloc->lock(bufferHandle, info.usage, region, fence,
+ &bytesPerPixel, &bytesPerStride)));
+ for (uint32_t y = 0; y < info.height; y++) {
+ for (size_t i = 0; i < writeInBytes; i++) {
+ EXPECT_EQ(static_cast<uint8_t>(y), data[i]);
+ }
+ data += strideInBytes;
+ }
+
+ EXPECT_GT(bytesPerPixel, -1);
+ EXPECT_GT(bytesPerStride, -1);
+
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+ if (fence >= 0) {
+ close(fence);
+ }
+}
+
+/**
+ * Test IMapper::lockYCbCr. This locks a YV12 buffer, and makes sure we can
+ * write to and read from it.
+ */
+TEST_F(GraphicsMapperHidlTest, LockYCbCrBasic) {
+ auto info = mDummyDescriptorInfo;
+ info.format = PixelFormat::YV12;
+
+ const native_handle_t* bufferHandle;
+ uint32_t stride;
+ ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(info, true, &stride));
+
+ // lock buffer for writing
+ const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+ static_cast<int32_t>(info.height)};
+ int fence = -1;
+ YCbCrLayout layout;
+ ASSERT_NO_FATAL_FAILURE(layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence));
+
+ auto yData = static_cast<uint8_t*>(layout.y);
+ auto cbData = static_cast<uint8_t*>(layout.cb);
+ auto crData = static_cast<uint8_t*>(layout.cr);
+ for (uint32_t y = 0; y < info.height; y++) {
+ for (uint32_t x = 0; x < info.width; x++) {
+ auto val = static_cast<uint8_t>(info.height * y + x);
+
+ yData[layout.yStride * y + x] = val;
+ if (y % 2 == 0 && x % 2 == 0) {
+ cbData[layout.cStride * y / 2 + x / 2] = val;
+ crData[layout.cStride * y / 2 + x / 2] = val;
+ }
+ }
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+
+ // lock again for reading
+ ASSERT_NO_FATAL_FAILURE(layout = mGralloc->lockYCbCr(bufferHandle, info.usage, region, fence));
+
+ yData = static_cast<uint8_t*>(layout.y);
+ cbData = static_cast<uint8_t*>(layout.cb);
+ crData = static_cast<uint8_t*>(layout.cr);
+ for (uint32_t y = 0; y < info.height; y++) {
+ for (uint32_t x = 0; x < info.width; x++) {
+ auto val = static_cast<uint8_t>(info.height * y + x);
+
+ EXPECT_EQ(val, yData[layout.yStride * y + x]);
+ if (y % 2 == 0 && x % 2 == 0) {
+ EXPECT_EQ(val, cbData[layout.cStride * y / 2 + x / 2]);
+ EXPECT_EQ(val, crData[layout.cStride * y / 2 + x / 2]);
+ }
+ }
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fence = mGralloc->unlock(bufferHandle));
+ if (fence >= 0) {
+ close(fence);
+ }
+}
+
+/**
+ * Test IMapper::unlock with invalid buffers.
+ */
+TEST_F(GraphicsMapperHidlTest, UnlockNegative) {
+ native_handle_t* invalidHandle = nullptr;
+ mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "unlock with nullptr did not fail with BAD_BUFFER";
+ });
+
+ invalidHandle = native_handle_create(0, 0);
+ mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "unlock with invalid handle did not fail with BAD_BUFFER";
+ });
+ native_handle_delete(invalidHandle);
+
+ ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast<native_handle_t*>(
+ mGralloc->allocate(mDummyDescriptorInfo, false)));
+ mGralloc->getMapper()->unlock(invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "unlock with un-imported handle did not fail with BAD_BUFFER";
+ });
+ mGralloc->freeBuffer(invalidHandle);
+
+// disabled as it fails on many existing drivers
+#if 0
+ ASSERT_NO_FATAL_FAILURE(invalidHandle = const_cast<native_handle_t*>(
+ mGralloc->allocate(mDummyDescriptorInfo, true)));
+ mGralloc->getMapper()->unlock(
+ invalidHandle, [&](const auto& tmpError, const auto&) {
+ EXPECT_EQ(Error::BAD_BUFFER, tmpError)
+ << "unlock with unlocked handle did not fail with BAD_BUFFER";
+ });
+ mGralloc->freeBuffer(invalidHandle);
+#endif
+}
+
+/**
+ * Test IMapper::isSupported with required format RGBA_8888
+ */
+TEST_F(GraphicsMapperHidlTest, IsSupportedRGBA8888) {
+ const auto& info = mDummyDescriptorInfo;
+ bool supported = false;
+
+ ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
+ ASSERT_TRUE(supported);
+}
+
+/**
+ * Test IMapper::isSupported with required format YV12
+ */
+TEST_F(GraphicsMapperHidlTest, IsSupportedYV12) {
+ auto info = mDummyDescriptorInfo;
+ info.format = PixelFormat::YV12;
+ bool supported = false;
+
+ ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
+ ASSERT_TRUE(supported);
+}
+
+/**
+ * Test IMapper::isSupported with optional format Y16
+ */
+TEST_F(GraphicsMapperHidlTest, IsSupportedY16) {
+ auto info = mDummyDescriptorInfo;
+ info.format = PixelFormat::Y16;
+ bool supported = false;
+
+ ASSERT_NO_FATAL_FAILURE(supported = mGralloc->isSupported(info));
+}
+
+} // namespace
+} // namespace vts
+} // namespace V4_0
+} // namespace mapper
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+int main(int argc, char** argv) {
+ using android::hardware::graphics::mapper::V4_0::vts::GraphicsMapperHidlEnvironment;
+ ::testing::AddGlobalTestEnvironment(GraphicsMapperHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ GraphicsMapperHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp
index 444797d..7bb992b 100644
--- a/sensors/1.0/vts/functional/Android.bp
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -24,7 +24,10 @@
],
static_libs: [
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@2.1",
+ "android.hardware.graphics.mapper@3.0",
"android.hardware.sensors@1.0",
"VtsHalSensorsTargetTestUtils",
],
diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp
new file mode 100644
index 0000000..f0b33e4
--- /dev/null
+++ b/sensors/2.0/multihal/Android.bp
@@ -0,0 +1,47 @@
+//
+// Copyright (C) 2019 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_binary {
+ name: "android.hardware.sensors@2.0-service.multihal",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: [
+ "service.cpp",
+ "HalProxy.cpp",
+ ],
+ init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"],
+ header_libs: [
+ "android.hardware.sensors@2.0-subhal.header",
+ ],
+ shared_libs: [
+ "android.hardware.sensors@1.0",
+ "android.hardware.sensors@2.0",
+ "libcutils",
+ "libfmq",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libpower",
+ "libutils",
+ ],
+ vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"],
+}
+
+cc_library_headers {
+ name: "android.hardware.sensors@2.0-subhal.header",
+ vendor: true,
+ export_include_dirs: ["include"],
+}
\ No newline at end of file
diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp
new file mode 100644
index 0000000..31f8a18
--- /dev/null
+++ b/sensors/2.0/multihal/HalProxy.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "HalProxy.h"
+
+#include <android/hardware/sensors/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+// TODO: Use this wake lock name as the prefix to all sensors HAL wake locks acquired.
+// constexpr const char* kWakeLockName = "SensorsHAL_WAKEUP";
+
+// TODO: Use the following class as a starting point for implementing the full HalProxyCallback
+// along with being inspiration for how to implement the ScopedWakelock class.
+/**
+ * Callback class used to provide the HalProxy with the index of which subHal is invoking
+ */
+class SensorsCallbackProxy : public ISensorsCallback {
+ public:
+ SensorsCallbackProxy(wp<HalProxy>& halProxy, int32_t subHalIndex)
+ : mHalProxy(halProxy), mSubHalIndex(subHalIndex) {}
+
+ Return<void> onDynamicSensorsConnected(
+ const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
+ sp<HalProxy> halProxy(mHalProxy.promote());
+ if (halProxy != nullptr) {
+ return halProxy->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex);
+ }
+ return Return<void>();
+ }
+
+ Return<void> onDynamicSensorsDisconnected(
+ const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
+ sp<HalProxy> halProxy(mHalProxy.promote());
+ if (halProxy != nullptr) {
+ return halProxy->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved,
+ mSubHalIndex);
+ }
+ return Return<void>();
+ }
+
+ private:
+ wp<HalProxy>& mHalProxy;
+ int32_t mSubHalIndex;
+};
+
+HalProxy::HalProxy() {
+ // TODO: Initialize all sub-HALs and discover sensors.
+}
+
+HalProxy::~HalProxy() {
+ // TODO: Join any running threads and clean up FMQs and any other allocated
+ // state.
+}
+
+Return<void> HalProxy::getSensorsList(getSensorsList_cb /* _hidl_cb */) {
+ // TODO: Output sensors list created as part of HalProxy().
+ 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::activate(int32_t /* sensorHandle */, bool /* enabled */) {
+ // TODO: Proxy API call to appropriate sub-HAL.
+ return Result::INVALID_OPERATION;
+}
+
+Return<Result> HalProxy::initialize(
+ const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
+ const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+ const sp<ISensorsCallback>& sensorsCallback) {
+ Result result = Result::OK;
+
+ // TODO: clean up sensor requests, if not already done elsewhere through a death recipient, and
+ // clean up any other resources that exist (FMQs, flags, threads, etc.)
+
+ mDynamicSensorsCallback = sensorsCallback;
+
+ // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions.
+ mEventQueue =
+ std::make_unique<EventMessageQueue>(eventQueueDescriptor, true /* resetPointers */);
+
+ // Create the EventFlag that is used to signal to the framework that sensor events have been
+ // written to the Event FMQ
+ if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
+ result = Result::BAD_VALUE;
+ }
+
+ // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP
+ // events have been successfully read and handled by the framework.
+ mWakeLockQueue =
+ std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */);
+
+ if (!mDynamicSensorsCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
+ result = Result::BAD_VALUE;
+ }
+
+ // TODO: start threads to read wake locks and process events from sub HALs.
+
+ 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::flush(int32_t /* sensorHandle */) {
+ // TODO: Proxy API call to appropriate sub-HAL.
+ return Result::INVALID_OPERATION;
+}
+
+Return<Result> HalProxy::injectSensorData(const Event& /* event */) {
+ // TODO: Proxy API call to appropriate sub-HAL.
+ return Result::INVALID_OPERATION;
+}
+
+Return<void> HalProxy::registerDirectChannel(const SharedMemInfo& /* mem */,
+ registerDirectChannel_cb _hidl_cb) {
+ // TODO: During init, discover the first sub-HAL in the config that has sensors with direct
+ // channel support, if any, and proxy the API call there.
+ _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
+ return Return<void>();
+}
+
+Return<Result> HalProxy::unregisterDirectChannel(int32_t /* channelHandle */) {
+ // TODO: During init, discover the first sub-HAL in the config that has sensors with direct
+ // channel support, if any, and proxy the API call there.
+ return Result::INVALID_OPERATION;
+}
+
+Return<void> HalProxy::configDirectReport(int32_t /* sensorHandle */, int32_t /* channelHandle */,
+ RateLevel /* rate */, configDirectReport_cb _hidl_cb) {
+ // TODO: During init, discover the first sub-HAL in the config that has sensors with direct
+ // channel support, if any, and proxy the API call there.
+ _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */);
+ return Return<void>();
+}
+
+Return<void> HalProxy::debug(const hidl_handle& /* fd */, const hidl_vec<hidl_string>& /* args */) {
+ // TODO: output debug information
+ return Return<void>();
+}
+
+Return<void> HalProxy::onDynamicSensorsConnected(
+ const hidl_vec<SensorInfo>& /* dynamicSensorsAdded */, int32_t /* subHalIndex */) {
+ // TODO: Map the SensorInfo to the global list and then invoke the framework's callback.
+ return Return<void>();
+}
+
+Return<void> HalProxy::onDynamicSensorsDisconnected(
+ const hidl_vec<int32_t>& /* dynamicSensorHandlesRemoved */, int32_t /* subHalIndex */) {
+ // TODO: Unmap the SensorInfo from the global list and then invoke the framework's callback.
+ return Return<void>();
+}
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/2.0/multihal/HalProxy.h b/sensors/2.0/multihal/HalProxy.h
new file mode 100644
index 0000000..b9855a6
--- /dev/null
+++ b/sensors/2.0/multihal/HalProxy.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "SubHal.h"
+
+#include <android/hardware/sensors/2.0/ISensors.h>
+#include <fmq/MessageQueue.h>
+#include <hardware_legacy/power.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::EventFlag;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptor;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct HalProxy : public ISensors {
+ 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;
+
+ HalProxy();
+ ~HalProxy();
+
+ // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+ Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+
+ Return<Result> setOperationMode(OperationMode mode) override;
+
+ Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+
+ Return<Result> initialize(
+ const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
+ const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+ const sp<ISensorsCallback>& sensorsCallback) override;
+
+ Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) override;
+
+ Return<Result> flush(int32_t sensorHandle) override;
+
+ Return<Result> injectSensorData(const Event& event) override;
+
+ Return<void> registerDirectChannel(const SharedMemInfo& mem,
+ registerDirectChannel_cb _hidl_cb) override;
+
+ Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
+
+ Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+ configDirectReport_cb _hidl_cb) override;
+
+ Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+
+ // Below methods from ::android::hardware::sensors::V2_0::ISensorsCaback with a minor change
+ // to pass in the sub-HAL index. While the above methods are invoked from the sensors framework
+ // via the binder, these methods are invoked from a callback provided to sub-HALs inside the
+ // same process as the HalProxy, but potentially running on different threads.
+ Return<void> onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
+ int32_t subHalIndex);
+
+ Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& dynamicSensorHandlesRemoved,
+ int32_t subHalIndex);
+
+ private:
+ using EventMessageQueue = MessageQueue<Event, kSynchronizedReadWrite>;
+ using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>;
+
+ /**
+ * The Event FMQ where sensor events are written
+ */
+ std::unique_ptr<EventMessageQueue> mEventQueue;
+
+ /**
+ * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events
+ */
+ std::unique_ptr<WakeLockMessageQueue> mWakeLockQueue;
+
+ /**
+ * Event Flag to signal to the framework when sensor events are available to be read
+ */
+ EventFlag* mEventQueueFlag;
+
+ /**
+ * Callback to the sensors framework to inform it that new sensors have been added or removed.
+ */
+ sp<ISensorsCallback> mDynamicSensorsCallback;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/2.0/multihal/OWNERS b/sensors/2.0/multihal/OWNERS
new file mode 100644
index 0000000..e955670
--- /dev/null
+++ b/sensors/2.0/multihal/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
\ No newline at end of file
diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml b/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml
new file mode 100644
index 0000000..a771100
--- /dev/null
+++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.sensors</name>
+ <transport>hwbinder</transport>
+ <version>2.0</version>
+ <interface>
+ <name>ISensors</name>
+ <instance>multihal</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
new file mode 100644
index 0000000..1671689
--- /dev/null
+++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
@@ -0,0 +1,6 @@
+service vendor.sensors-hal-2-0-multihal /vendor/bin/hw/android.hardware.sensors@2.0-service.multihal
+ class hal
+ user system
+ group system
+ capabilities BLOCK_SUSPEND
+ rlimit rtprio 10 10
diff --git a/sensors/2.0/multihal/include/SubHal.h b/sensors/2.0/multihal/include/SubHal.h
new file mode 100644
index 0000000..75e93a1
--- /dev/null
+++ b/sensors/2.0/multihal/include/SubHal.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/sensors/1.0/types.h>
+#include <android/hardware/sensors/2.0/ISensors.h>
+
+#include <vector>
+
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+
+// Indicates the current version of the multiHAL interface formatted as (HAL major version) << 24 |
+// (HAL minor version) << 16 | (multiHAL version)
+#define SUB_HAL_2_0_VERSION 0x02000000
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+/**
+ * Wrapper around wake lock acquisition functions (acquire/release_wake_lock) that provides a
+ * RAII-style mechanism for keeping a wake lock held for the duration of a scoped block.
+ * When a ScopedWakelock is created, it increments the reference count stored in the HalProxy
+ * for the sub-HALs specific wake lock, acquiring the wake lock if necessary. When the object goes
+ * out of scope, the ref count is decremented, potentially releasing the wake lock if no other
+ * references to the wake lock exist.
+ *
+ * This class is allocated through the createScopedWakelock callback inside the IHalProxyCallback
+ * provided to sub-HALs during initialization and should be used for all wake lock acquisition
+ * inside of the sub-HAL to ensure wake locks are not held indefinitely.
+ *
+ * The most prevalent use case for this class will be for posting events to the framework through
+ * the postEvents HalProxy callback. The expectation is that sub-HALs will create this
+ * ScopedWakelock through the createScopedWakelock upon receiving a sensor events. The lock boolean
+ * provided to createScopedWakelock will be set the according to whether the sensor events are
+ * from wakeup sensors. Then, the sub-HAL will perform any processing necessary before invoking the
+ * postEvents callback passing in the previously created ScopedWakelock. At this point, ownership
+ * of the object will be passed to the HalProxy that will then be responsible for ensuring any
+ * wake locks continue to be held, if necessary.
+ */
+class ScopedWakelock {
+ public:
+ ScopedWakelock(ScopedWakelock&&) = default;
+ ScopedWakelock& operator=(ScopedWakelock&&) = default;
+ virtual ~ScopedWakelock() { mLocked = false; };
+
+ bool isLocked() const { return mLocked; }
+
+ protected:
+ bool mLocked;
+
+ private:
+ // TODO: Mark HalProxy's subclass of ScopedWakelock as a friend so that it can be initialized.
+ ScopedWakelock();
+ ScopedWakelock(const ScopedWakelock&) = delete;
+ ScopedWakelock& operator=(const ScopedWakelock&) = delete;
+};
+
+/**
+ * Interface that contains several callbacks into the HalProxy class to communicate dynamic sensor
+ * changes and sensor events to the framework and acquire wake locks. The HalProxy will ensure
+ * callbacks occurring at the same time from multiple sub-HALs are synchronized in a safe, efficient
+ * manner.
+ */
+class IHalProxyCallback : public ISensorsCallback {
+ public:
+ /**
+ * Thread-safe callback used to post events to the HalProxy. Sub-HALs should invoke this
+ * whenever new sensor events need to be delivered to the sensors framework. Once invoked, the
+ * HalProxy will attempt to send events to the sensors framework using a blocking write with a
+ * 5 second timeout. This write may be done asynchronously if the queue used to communicate
+ * with the framework is full to avoid blocking sub-HALs for the length of the timeout. If the
+ * write fails, the events will be dropped and any wake locks held will be released.
+ *
+ * The provided ScopedWakelock must be locked if the events are from wakeup sensors. If it's
+ * not locked accordingly, the HalProxy will crash as this indicates the sub-HAL isn't compliant
+ * with the sensors HAL 2.0 specification. Additionally, since ScopedWakelock isn't copyable,
+ * the HalProxy will take ownership of the wake lock given when this method is invoked. Once the
+ * method returns, the HalProxy will handle holding the wake lock, if necessary, until the
+ * framework has successfully processed any wakeup events.
+ *
+ * No return type is used for this callback to avoid sub-HALs trying to resend events when
+ * writes fail. Writes should only fail when the framework is under inordinate stress which will
+ * likely result in a framework restart so retrying will likely only result in overloading the
+ * HalProxy. Sub-HALs should always assume that the write was a success and perform any
+ * necessary cleanup. Additionally, the HalProxy will ensure it logs any errors (through ADB and
+ * bug reports) it encounters during delivery to ensure it's obvious that a failure occurred.
+ *
+ * @param events the events that should be sent to the sensors framework
+ * @param wakelock ScopedWakelock that should be locked to send events from wake sensors and
+ * unlocked otherwise.
+ */
+ virtual void postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) = 0;
+
+ /**
+ * Initializes a ScopedWakelock on the stack that, when locked, will increment the reference
+ * count for the sub-HAL's wake lock managed inside the HalProxy. See the ScopedWakelock class
+ * definition for how it should be used.
+ *
+ * @param lock whether the ScopedWakelock should be locked before it's returned.
+ * @return the created ScopedWakelock
+ */
+ virtual ScopedWakelock createScopedWakelock(bool lock) = 0;
+};
+
+/**
+ * ISensorsSubHal is an interface that sub-HALs must implement in order to be compliant with
+ * multihal 2.0 and in order for the HalProxy to successfully load and communicate with the sub-HAL.
+ *
+ * Any vendor wishing to implement this interface and support multihal 2.0 will need to create a
+ * dynamic library that exposes sensorsHalGetSubHal (defined below). This library will be loaded by
+ * the HalProxy when the sensors HAL is initialized and then the HalProxy will retrieve the vendor's
+ * implementation of sensorsHalGetSubHal.
+ *
+ * With the exception of the initialize method, ISensorsSubHal will implement the ISensors.hal spec.
+ * Any sensor handles given to the HalProxy, either through getSensorsList() or the
+ * onDynamicSensors(Dis)Connected callbacks, will be translated to avoid clashing with other sub-HAL
+ * handles. To achieve this, the HalProxy will use the upper byte to store the sub-HAL index and
+ * sub-HALs can continue to use the lower 3 bytes of the handle.
+ */
+class ISensorsSubHal : public ISensors {
+ // 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(
+ const ::android::hardware::MQDescriptorSync<Event>& /* eventQueueDescriptor */,
+ const ::android::hardware::MQDescriptorSync<uint32_t>& /* wakeLockDescriptor */,
+ const sp<ISensorsCallback>& /* sensorsCallback */) final {
+ return Result::INVALID_OPERATION;
+ }
+
+ /**
+ * Method defined in ::android::hidl::base::V1_0::IBase.
+ *
+ * This method should write debug information to hidl_handle that is useful for debugging
+ * issues. Suggestions include:
+ * - Sensor info including handle values and any other state available in the SensorInfo class
+ * - List of active sensors and their current sampling period and reporting latency
+ * - Information about pending flush requests
+ * - Current operating mode
+ * - Currently registered direct channel info
+ * - A history of any of the above
+ */
+ virtual Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) = 0;
+
+ /**
+ * @return A human-readable name for use in wake locks and logging.
+ */
+ virtual const std::string getName() = 0;
+
+ /**
+ * First method invoked on the sub-HAL after it's allocated through sensorsHalGetSubHal() by the
+ * HalProxy. Sub-HALs should use this to initialize any state and retain the callback given in
+ * order to communicate with the HalProxy.
+ *
+ * @param halProxyCallback callback used to inform the HalProxy when a dynamic sensor's state
+ * changes, new sensor events should be sent to the framework, and when a new ScopedWakelock
+ * should be created.
+ * @return result OK on success
+ */
+ virtual Return<Result> initialize(const sp<IHalProxyCallback>& halProxyCallback) = 0;
+};
+
+} // namespace implementation
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
+
+using ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal;
+
+/**
+ * Function that must be exported so the HalProxy class can invoke it on the sub-HAL dynamic
+ * library. This function will only be invoked once at initialization time.
+ *
+ * NOTE: The supported sensors HAL version must match SUB_HAL_2_0_VERSION exactly or the HalProxy
+ * will fail to initialize.
+ *
+ * @param uint32_t when this function returns, this parameter must contain the HAL version that
+ * this sub-HAL supports. To support this version of multi-HAL, this must be set to
+ * SUB_HAL_2_0_VERSION.
+ * @return A statically allocated, valid ISensorsSubHal implementation.
+ */
+__attribute__((visibility("default"))) extern "C" ISensorsSubHal* sensorsHalGetSubHal(
+ uint32_t* version);
diff --git a/sensors/2.0/multihal/service.cpp b/sensors/2.0/multihal/service.cpp
new file mode 100644
index 0000000..995cf3c
--- /dev/null
+++ b/sensors/2.0/multihal/service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 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 "android.hardware.sensors@2.0-service"
+
+#include <android/hardware/sensors/2.0/ISensors.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/StrongPointer.h>
+#include "HalProxy.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::sensors::V2_0::ISensors;
+using android::hardware::sensors::V2_0::implementation::HalProxy;
+
+int main(int /* argc */, char** /* argv */) {
+ configureRpcThreadpool(1, true);
+
+ android::sp<ISensors> halProxy = new HalProxy();
+ if (halProxy->registerAsService() != ::android::OK) {
+ ALOGE("Failed to register Sensors HAL instance");
+ return -1;
+ }
+
+ joinRpcThreadpool();
+ return 1; // joinRpcThreadpool shouldn't exit
+}
diff --git a/sensors/2.0/multihal/testing/Android.bp b/sensors/2.0/multihal/testing/Android.bp
new file mode 100644
index 0000000..3dedbd6
--- /dev/null
+++ b/sensors/2.0/multihal/testing/Android.bp
@@ -0,0 +1,55 @@
+//
+// Copyright (C) 2019 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_defaults {
+ name: "android.hardware.sensors@2.0-fakesubhal-defaults",
+ vendor: true,
+ srcs: [
+ "Sensor.cpp",
+ "SensorsSubHal.cpp",
+ ],
+ header_libs: [
+ "android.hardware.sensors@2.0-subhal.header",
+ ],
+ shared_libs: [
+ "android.hardware.sensors@1.0",
+ "android.hardware.sensors@2.0",
+ "libcutils",
+ "libfmq",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libpower",
+ "libutils",
+ ],
+}
+
+cc_library {
+ name: "android.hardware.sensors@2.0-fakesubhal-config1",
+ defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
+ cflags: [
+ "-DSUPPORT_CONTINUOUS_SENSORS",
+ "-DSUB_HAL_NAME=\"FakeSubHal-Continuous\"",
+ ],
+}
+
+cc_library {
+ name: "android.hardware.sensors@2.0-fakesubhal-config2",
+ defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
+ cflags: [
+ "-DSUPPORT_ON_CHANGE_SENSORS",
+ "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"",
+ ],
+}
\ No newline at end of file
diff --git a/sensors/2.0/multihal/testing/README b/sensors/2.0/multihal/testing/README
new file mode 100644
index 0000000..ddcc584
--- /dev/null
+++ b/sensors/2.0/multihal/testing/README
@@ -0,0 +1,19 @@
+This directory contains a modified version of the default implementation
+provided for sensors HAL 2.0 to support multi-HAL 2.0. It should be used as a
+means to verify the multi-HAL 2.0 implementation can successfully load and
+interact with sub-HALs.
+
+This sub-HAL implementation has two macros that can be used to configure support
+for different sets of sensors. One "SUPPORT_CONTINUOUS_SENSORS", enables
+support for continuous sensors like accel, and gyro whereas the other
+"SUPPORT_ON_CHANGE_SENSORS" enables support for on change sensors like the
+light and proximity sensor. A build target is defined for each of these macros,
+but more targets could be added to support both in one sub-HAL or none at all,
+if necessary.
+
+When built, the library will be written to
+out/target/product/<device>/vendor/lib64/android.hardware.sensors@2.0-fakesubhal.so
+
+Take this .so and place it where the multi-HAL config will cause the HalProxy to
+look and then restart the system server with adb shell stop / adb shell start
+to cause the multi-HAL to restart and attempt to load in the sub-HAL.
diff --git a/sensors/2.0/multihal/testing/Sensor.cpp b/sensors/2.0/multihal/testing/Sensor.cpp
new file mode 100644
index 0000000..e095efe
--- /dev/null
+++ b/sensors/2.0/multihal/testing/Sensor.cpp
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Sensor.h"
+
+#include <utils/SystemClock.h>
+
+#include <cmath>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+using ::android::hardware::sensors::V1_0::MetaDataEventType;
+using ::android::hardware::sensors::V1_0::SensorFlagBits;
+using ::android::hardware::sensors::V1_0::SensorStatus;
+
+static constexpr float kDefaultMaxDelayUs = 10 * 1000 * 1000;
+
+Sensor::Sensor(ISensorsEventCallback* callback)
+ : mIsEnabled(false),
+ mSamplingPeriodNs(0),
+ mLastSampleTimeNs(0),
+ mCallback(callback),
+ mMode(OperationMode::NORMAL) {
+ mRunThread = std::thread(startThread, this);
+}
+
+Sensor::~Sensor() {
+ std::unique_lock<std::mutex> lock(mRunMutex);
+ mStopThread = true;
+ mIsEnabled = false;
+ mWaitCV.notify_all();
+ lock.release();
+ mRunThread.join();
+}
+
+const SensorInfo& Sensor::getSensorInfo() const {
+ return mSensorInfo;
+}
+
+void Sensor::batch(int32_t samplingPeriodNs) {
+ samplingPeriodNs =
+ std::clamp(samplingPeriodNs, mSensorInfo.minDelay * 1000, mSensorInfo.maxDelay * 1000);
+
+ if (mSamplingPeriodNs != samplingPeriodNs) {
+ mSamplingPeriodNs = samplingPeriodNs;
+ // Wake up the 'run' thread to check if a new event should be generated now
+ mWaitCV.notify_all();
+ }
+}
+
+void Sensor::activate(bool enable) {
+ if (mIsEnabled != enable) {
+ std::unique_lock<std::mutex> lock(mRunMutex);
+ mIsEnabled = enable;
+ mWaitCV.notify_all();
+ }
+}
+
+Result Sensor::flush() {
+ // Only generate a flush complete event if the sensor is enabled and if the sensor is not a
+ // one-shot sensor.
+ if (!mIsEnabled || (mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::ONE_SHOT_MODE))) {
+ return Result::BAD_VALUE;
+ }
+
+ // Note: If a sensor supports batching, write all of the currently batched events for the sensor
+ // to the Event FMQ prior to writing the flush complete event.
+ Event ev;
+ ev.sensorHandle = mSensorInfo.sensorHandle;
+ ev.sensorType = SensorType::META_DATA;
+ ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE;
+ std::vector<Event> evs{ev};
+ mCallback->postEvents(evs, isWakeUpSensor());
+
+ return Result::OK;
+}
+
+void Sensor::startThread(Sensor* sensor) {
+ sensor->run();
+}
+
+void Sensor::run() {
+ std::unique_lock<std::mutex> runLock(mRunMutex);
+ constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000;
+
+ while (!mStopThread) {
+ if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) {
+ mWaitCV.wait(runLock, [&] {
+ return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread);
+ });
+ } else {
+ timespec curTime;
+ clock_gettime(CLOCK_REALTIME, &curTime);
+ int64_t now = (curTime.tv_sec * kNanosecondsInSeconds) + curTime.tv_nsec;
+ int64_t nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+
+ if (now >= nextSampleTime) {
+ mLastSampleTimeNs = now;
+ nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+ mCallback->postEvents(readEvents(), isWakeUpSensor());
+ }
+
+ mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now));
+ }
+ }
+}
+
+bool Sensor::isWakeUpSensor() {
+ return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
+}
+
+std::vector<Event> Sensor::readEvents() {
+ std::vector<Event> events;
+ Event event;
+ event.sensorHandle = mSensorInfo.sensorHandle;
+ event.sensorType = mSensorInfo.type;
+ event.timestamp = ::android::elapsedRealtimeNano();
+ event.u.vec3.x = 0;
+ event.u.vec3.y = 0;
+ event.u.vec3.z = 0;
+ event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+ events.push_back(event);
+ return events;
+}
+
+void Sensor::setOperationMode(OperationMode mode) {
+ if (mMode != mode) {
+ std::unique_lock<std::mutex> lock(mRunMutex);
+ mMode = mode;
+ mWaitCV.notify_all();
+ }
+}
+
+bool Sensor::supportsDataInjection() const {
+ return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION);
+}
+
+Result Sensor::injectEvent(const Event& event) {
+ Result result = Result::OK;
+ if (event.sensorType == SensorType::ADDITIONAL_INFO) {
+ // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation
+ // environment data into the device.
+ } else if (!supportsDataInjection()) {
+ result = Result::INVALID_OPERATION;
+ } else if (mMode == OperationMode::DATA_INJECTION) {
+ mCallback->postEvents(std::vector<Event>{event}, isWakeUpSensor());
+ } else {
+ result = Result::BAD_VALUE;
+ }
+ return result;
+}
+
+OnChangeSensor::OnChangeSensor(ISensorsEventCallback* callback)
+ : Sensor(callback), mPreviousEventSet(false) {}
+
+void OnChangeSensor::activate(bool enable) {
+ Sensor::activate(enable);
+ if (!enable) {
+ mPreviousEventSet = false;
+ }
+}
+
+std::vector<Event> OnChangeSensor::readEvents() {
+ std::vector<Event> events = Sensor::readEvents();
+ std::vector<Event> outputEvents;
+
+ for (auto iter = events.begin(); iter != events.end(); ++iter) {
+ Event ev = *iter;
+ if (ev.u.vec3 != mPreviousEvent.u.vec3 || !mPreviousEventSet) {
+ outputEvents.push_back(ev);
+ mPreviousEvent = ev;
+ mPreviousEventSet = true;
+ }
+ }
+ return outputEvents;
+}
+
+AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Accel Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::ACCELEROMETER;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 78.4f; // +/- 8g
+ mSensorInfo.resolution = 1.52e-5;
+ mSensorInfo.power = 0.001f; // mA
+ mSensorInfo.minDelay = 20 * 1000; // microseconds
+ mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION);
+};
+
+PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : Sensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Pressure Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::PRESSURE;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 1100.0f; // hPa
+ mSensorInfo.resolution = 0.005f; // hPa
+ mSensorInfo.power = 0.001f; // mA
+ mSensorInfo.minDelay = 100 * 1000; // microseconds
+ mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = 0;
+};
+
+MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : Sensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Magnetic Field Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::MAGNETIC_FIELD;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 1300.0f;
+ mSensorInfo.resolution = 0.01f;
+ mSensorInfo.power = 0.001f; // mA
+ mSensorInfo.minDelay = 20 * 1000; // microseconds
+ mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = 0;
+};
+
+LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : OnChangeSensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Light Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::LIGHT;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 43000.0f;
+ mSensorInfo.resolution = 10.0f;
+ mSensorInfo.power = 0.001f; // mA
+ mSensorInfo.minDelay = 200 * 1000; // microseconds
+ mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
+};
+
+ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : OnChangeSensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Proximity Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::PROXIMITY;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 5.0f;
+ mSensorInfo.resolution = 1.0f;
+ mSensorInfo.power = 0.012f; // mA
+ mSensorInfo.minDelay = 200 * 1000; // microseconds
+ mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags =
+ static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE | SensorFlagBits::WAKE_UP);
+};
+
+GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback) : Sensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Gyro Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::GYROSCOPE;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f;
+ mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f);
+ mSensorInfo.power = 0.001f;
+ mSensorInfo.minDelay = 2.5f * 1000; // microseconds
+ mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = 0;
+};
+
+AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : OnChangeSensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Ambient Temp Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 80.0f;
+ mSensorInfo.resolution = 0.01f;
+ mSensorInfo.power = 0.001f;
+ mSensorInfo.minDelay = 40 * 1000; // microseconds
+ mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
+};
+
+DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+ : OnChangeSensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Device Temp Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::TEMPERATURE;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 80.0f;
+ mSensorInfo.resolution = 0.01f;
+ mSensorInfo.power = 0.001f;
+ mSensorInfo.minDelay = 40 * 1000; // microseconds
+ mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
+}
+
+RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
+ ISensorsEventCallback* callback)
+ : OnChangeSensor(callback) {
+ mSensorInfo.sensorHandle = sensorHandle;
+ mSensorInfo.name = "Relative Humidity Sensor";
+ mSensorInfo.vendor = "Vendor String";
+ mSensorInfo.version = 1;
+ mSensorInfo.type = SensorType::RELATIVE_HUMIDITY;
+ mSensorInfo.typeAsString = "";
+ mSensorInfo.maxRange = 100.0f;
+ mSensorInfo.resolution = 0.1f;
+ mSensorInfo.power = 0.001f;
+ mSensorInfo.minDelay = 40 * 1000; // microseconds
+ mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+ mSensorInfo.fifoReservedEventCount = 0;
+ mSensorInfo.fifoMaxEventCount = 0;
+ mSensorInfo.requiredPermission = "";
+ mSensorInfo.flags = static_cast<uint32_t>(SensorFlagBits::ON_CHANGE_MODE);
+}
+
+} // namespace implementation
+} // namespace subhal
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/2.0/multihal/testing/Sensor.h b/sensors/2.0/multihal/testing/Sensor.h
new file mode 100644
index 0000000..980ea54
--- /dev/null
+++ b/sensors/2.0/multihal/testing/Sensor.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android/hardware/sensors/1.0/types.h>
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+using ::android::hardware::sensors::V1_0::SensorType;
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+class ISensorsEventCallback {
+ public:
+ virtual ~ISensorsEventCallback(){};
+ virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0;
+};
+
+class Sensor {
+ public:
+ Sensor(ISensorsEventCallback* callback);
+ virtual ~Sensor();
+
+ const SensorInfo& getSensorInfo() const;
+ void batch(int32_t samplingPeriodNs);
+ virtual void activate(bool enable);
+ Result flush();
+
+ void setOperationMode(OperationMode mode);
+ bool supportsDataInjection() const;
+ Result injectEvent(const Event& event);
+
+ protected:
+ void run();
+ virtual std::vector<Event> readEvents();
+ static void startThread(Sensor* sensor);
+
+ bool isWakeUpSensor();
+
+ bool mIsEnabled;
+ int64_t mSamplingPeriodNs;
+ int64_t mLastSampleTimeNs;
+ SensorInfo mSensorInfo;
+
+ std::atomic_bool mStopThread;
+ std::condition_variable mWaitCV;
+ std::mutex mRunMutex;
+ std::thread mRunThread;
+
+ ISensorsEventCallback* mCallback;
+
+ OperationMode mMode;
+};
+
+class OnChangeSensor : public Sensor {
+ public:
+ OnChangeSensor(ISensorsEventCallback* callback);
+
+ virtual void activate(bool enable) override;
+
+ protected:
+ virtual std::vector<Event> readEvents() override;
+
+ protected:
+ Event mPreviousEvent;
+ bool mPreviousEventSet;
+};
+
+class AccelSensor : public Sensor {
+ public:
+ AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class GyroSensor : public Sensor {
+ public:
+ GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class AmbientTempSensor : public OnChangeSensor {
+ public:
+ AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class DeviceTempSensor : public OnChangeSensor {
+ public:
+ DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class PressureSensor : public Sensor {
+ public:
+ PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class MagnetometerSensor : public Sensor {
+ public:
+ MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class LightSensor : public OnChangeSensor {
+ public:
+ LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class ProximitySensor : public OnChangeSensor {
+ public:
+ ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class RelativeHumiditySensor : public OnChangeSensor {
+ public:
+ RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+} // namespace implementation
+} // namespace subhal
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/2.0/multihal/testing/SensorsSubHal.cpp b/sensors/2.0/multihal/testing/SensorsSubHal.cpp
new file mode 100644
index 0000000..8d45982
--- /dev/null
+++ b/sensors/2.0/multihal/testing/SensorsSubHal.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SensorsSubHal.h"
+
+#include <android/hardware/sensors/2.0/types.h>
+#include <log/log.h>
+
+ISensorsSubHal* sensorsHalGetSubHal(uint32_t* version) {
+ static ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal subHal;
+ *version = SUB_HAL_2_0_VERSION;
+ return &subHal;
+}
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+using ::android::hardware::Void;
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::RateLevel;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SharedMemInfo;
+using ::android::hardware::sensors::V2_0::SensorTimeout;
+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
+}
+
+// Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+Return<void> SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
+ std::vector<SensorInfo> sensors;
+ for (const auto& sensor : mSensors) {
+ sensors.push_back(sensor.second->getSensorInfo());
+ }
+
+ _hidl_cb(sensors);
+ return Void();
+}
+
+Return<Result> SensorsSubHal::setOperationMode(OperationMode mode) {
+ for (auto sensor : mSensors) {
+ sensor.second->setOperationMode(mode);
+ }
+ return Result::OK;
+}
+
+Return<Result> SensorsSubHal::activate(int32_t sensorHandle, bool enabled) {
+ auto sensor = mSensors.find(sensorHandle);
+ if (sensor != mSensors.end()) {
+ sensor->second->activate(enabled);
+ return Result::OK;
+ }
+ return Result::BAD_VALUE;
+}
+
+Return<Result> SensorsSubHal::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t /* maxReportLatencyNs */) {
+ auto sensor = mSensors.find(sensorHandle);
+ if (sensor != mSensors.end()) {
+ sensor->second->batch(samplingPeriodNs);
+ return Result::OK;
+ }
+ return Result::BAD_VALUE;
+}
+
+Return<Result> SensorsSubHal::flush(int32_t sensorHandle) {
+ auto sensor = mSensors.find(sensorHandle);
+ if (sensor != mSensors.end()) {
+ return sensor->second->flush();
+ }
+ return Result::BAD_VALUE;
+}
+
+Return<Result> SensorsSubHal::injectSensorData(const Event& event) {
+ auto sensor = mSensors.find(event.sensorHandle);
+ if (sensor != mSensors.end()) {
+ return sensor->second->injectEvent(event);
+ }
+
+ return Result::BAD_VALUE;
+}
+
+Return<void> SensorsSubHal::registerDirectChannel(const SharedMemInfo& /* mem */,
+ registerDirectChannel_cb _hidl_cb) {
+ _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
+ return Return<void>();
+}
+
+Return<Result> SensorsSubHal::unregisterDirectChannel(int32_t /* channelHandle */) {
+ return Result::INVALID_OPERATION;
+}
+
+Return<void> SensorsSubHal::configDirectReport(int32_t /* sensorHandle */,
+ int32_t /* channelHandle */, RateLevel /* rate */,
+ configDirectReport_cb _hidl_cb) {
+ _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */);
+ return Return<void>();
+}
+
+Return<void> SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) {
+ if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
+ ALOGE("%s: missing fd for writing", __FUNCTION__);
+ return Void();
+ }
+
+ FILE* out = fdopen(dup(fd->data[0]), "w");
+
+ if (args.size() != 0) {
+ fprintf(out,
+ "Note: sub-HAL %s currently does not support args. Input arguments are "
+ "ignored.\n",
+ getName().c_str());
+ }
+
+ std::ostringstream stream;
+ stream << "Available sensors:" << std::endl;
+ for (auto sensor : mSensors) {
+ SensorInfo info = sensor.second->getSensorInfo();
+ stream << "Name: " << info.name << std::endl;
+ stream << "Min delay: " << info.minDelay << std::endl;
+ stream << "Flags: " << info.flags << std::endl;
+ }
+ stream << std::endl;
+
+ fprintf(out, "%s", stream.str().c_str());
+
+ fclose(out);
+ return Return<void>();
+}
+
+Return<Result> SensorsSubHal::initialize(const sp<IHalProxyCallback>& halProxyCallback) {
+ mCallback = halProxyCallback;
+ return Result::OK;
+}
+
+void SensorsSubHal::postEvents(const std::vector<Event>& events, bool wakeup) {
+ ScopedWakelock wakelock = mCallback->createScopedWakelock(wakeup);
+ mCallback->postEvents(events, std::move(wakelock));
+}
+
+} // namespace implementation
+} // namespace subhal
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/2.0/multihal/testing/SensorsSubHal.h b/sensors/2.0/multihal/testing/SensorsSubHal.h
new file mode 100644
index 0000000..93009d5
--- /dev/null
+++ b/sensors/2.0/multihal/testing/SensorsSubHal.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "SubHal.h"
+
+#include "Sensor.h"
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+using ::android::hardware::sensors::V2_0::implementation::IHalProxyCallback;
+
+/**
+ * Implementation of a ISensorsSubHal that can be used to test the implementation of multihal 2.0.
+ * See the README file for more details on how this class can be used for testing.
+ */
+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;
+
+ Return<Result> setOperationMode(OperationMode mode) override;
+
+ Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+
+ Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+ int64_t maxReportLatencyNs) override;
+
+ Return<Result> flush(int32_t sensorHandle) override;
+
+ Return<Result> injectSensorData(const Event& event) override;
+
+ Return<void> registerDirectChannel(const SharedMemInfo& mem,
+ registerDirectChannel_cb _hidl_cb) override;
+
+ Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
+
+ Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+ configDirectReport_cb _hidl_cb) override;
+
+ Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+
+ // Methods from ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal follow.
+ const std::string getName() override {
+#ifdef SUB_HAL_NAME
+ return SUB_HAL_NAME;
+#else // SUB_HAL_NAME
+ return "FakeSubHal";
+#endif // SUB_HAL_NAME
+ }
+
+ Return<Result> initialize(const sp<IHalProxyCallback>& halProxyCallback) override;
+
+ // Method from ISensorsEventCallback.
+ void postEvents(const std::vector<Event>& events, bool wakeup) override;
+
+ private:
+ template <class SensorType>
+ void AddSensor() {
+ std::shared_ptr<SensorType> sensor =
+ std::make_shared<SensorType>(mNextHandle++ /* sensorHandle */, this /* callback */);
+ mSensors[sensor->getSensorInfo().sensorHandle] = sensor;
+ }
+
+ /**
+ * 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.
+ */
+ 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;
+};
+
+} // namespace implementation
+} // namespace subhal
+} // namespace V2_0
+} // namespace sensors
+} // namespace hardware
+} // namespace android
diff --git a/sensors/2.0/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp
index 98f0eac..4765fa2 100644
--- a/sensors/2.0/vts/functional/Android.bp
+++ b/sensors/2.0/vts/functional/Android.bp
@@ -24,7 +24,10 @@
],
static_libs: [
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@2.1",
+ "android.hardware.graphics.mapper@3.0",
"android.hardware.sensors@1.0",
"android.hardware.sensors@2.0",
"libfmq",
diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
index 6ff393d..8364ba9 100644
--- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -176,19 +176,21 @@
// Helper functions
void activateAllSensors(bool enable);
std::vector<SensorInfo> getNonOneShotSensors();
+ std::vector<SensorInfo> getNonOneShotAndNonSpecialSensors();
std::vector<SensorInfo> getOneShotSensors();
std::vector<SensorInfo> getInjectEventSensors();
int32_t getInvalidSensorHandle();
bool getDirectChannelSensor(SensorInfo* sensor, SharedMemType* memType, RateLevel* rate);
void verifyDirectChannel(SharedMemType memType);
- void verifyRegisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
- std::shared_ptr<SensorsTestSharedMemory> mem,
- int32_t* directChannelHandle);
+ void verifyRegisterDirectChannel(std::shared_ptr<SensorsTestSharedMemory> mem,
+ int32_t* directChannelHandle, bool supportsSharedMemType,
+ bool supportsAnyDirectChannel);
void verifyConfigure(const SensorInfo& sensor, SharedMemType memType,
- int32_t directChannelHandle);
- void verifyUnregisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
- int32_t directChannelHandle);
+ int32_t directChannelHandle, bool directChannelSupported);
+ void verifyUnregisterDirectChannel(int32_t directChannelHandle, bool directChannelSupported);
void checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle, RateLevel rateLevel);
+ void queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
+ bool* supportsAnyDirectChannel);
};
Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
@@ -257,6 +259,18 @@
return sensors;
}
+std::vector<SensorInfo> SensorsHidlTest::getNonOneShotAndNonSpecialSensors() {
+ std::vector<SensorInfo> sensors;
+ for (const SensorInfo& info : getSensorsList()) {
+ SensorFlagBits reportMode = extractReportMode(info.flags);
+ if (reportMode != SensorFlagBits::ONE_SHOT_MODE &&
+ reportMode != SensorFlagBits::SPECIAL_REPORTING_MODE) {
+ sensors.push_back(info);
+ }
+ }
+ return sensors;
+}
+
std::vector<SensorInfo> SensorsHidlTest::getOneShotSensors() {
std::vector<SensorInfo> sensors;
for (const SensorInfo& info : getSensorsList()) {
@@ -777,7 +791,12 @@
activateAllSensors(false /* enable */);
for (const SensorInfo& sensor : getSensorsList()) {
// Call batch on inactive sensor
- ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */),
+ // One shot sensors have minDelay set to -1 which is an invalid
+ // parameter. Use 0 instead to avoid errors.
+ int64_t samplingPeriodNs = extractReportMode(sensor.flags) == SensorFlagBits::ONE_SHOT_MODE
+ ? 0
+ : sensor.minDelay;
+ ASSERT_EQ(batch(sensor.sensorHandle, samplingPeriodNs, 0 /* maxReportLatencyNs */),
Result::OK);
// Activate the sensor
@@ -830,9 +849,10 @@
EventCallback callback;
getEnvironment()->registerCallback(&callback);
- const std::vector<SensorInfo> sensors = getSensorsList();
+ // This test is not valid for one-shot or special-report-mode sensors
+ const std::vector<SensorInfo> sensors = getNonOneShotAndNonSpecialSensors();
milliseconds maxMinDelay(0);
- for (const SensorInfo& sensor : getSensorsList()) {
+ for (const SensorInfo& sensor : sensors) {
milliseconds minDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
maxMinDelay = milliseconds(std::max(maxMinDelay.count(), minDelay.count()));
}
@@ -849,9 +869,14 @@
// 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;
+ // Some on-change sensors may not report an event without stimulus
+ if (extractReportMode(sensor.flags) != SensorFlagBits::ON_CHANGE_MODE) {
+ ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1);
+ }
+ if (callback.getEvents(sensor.sensorHandle).size() >= 1) {
+ lastEventTimestampMap[sensor.sensorHandle] =
+ callback.getEvents(sensor.sensorHandle).back().timestamp;
+ }
}
// Allow some time to pass, reset the callback, then reactivate the sensors
@@ -862,6 +887,14 @@
activateAllSensors(false);
for (const SensorInfo& sensor : sensors) {
+ // Skip sensors that did not previously report an event
+ if (lastEventTimestampMap.find(sensor.sensorHandle) == lastEventTimestampMap.end()) {
+ continue;
+ }
+ // Skip on-change sensors that do not consistently report an initial event
+ if (callback.getEvents(sensor.sensorHandle).size() < 1) {
+ continue;
+ }
// Ensure that the first event received is not stale by ensuring that its timestamp is
// sufficiently different from the previous event
const Event newEvent = callback.getEvents(sensor.sensorHandle).front();
@@ -878,21 +911,43 @@
[&](Result result, int32_t reportToken) {
if (isDirectReportRateSupported(sensor, rateLevel)) {
ASSERT_EQ(result, Result::OK);
- ASSERT_GT(reportToken, 0);
+ if (rateLevel != RateLevel::STOP) {
+ ASSERT_GT(reportToken, 0);
+ }
} else {
ASSERT_EQ(result, Result::BAD_VALUE);
}
});
}
-void SensorsHidlTest::verifyRegisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
- std::shared_ptr<SensorsTestSharedMemory> mem,
- int32_t* directChannelHandle) {
+void SensorsHidlTest::queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
+ bool* supportsAnyDirectChannel) {
+ *supportsSharedMemType = false;
+ *supportsAnyDirectChannel = false;
+ for (const SensorInfo& curSensor : getSensorsList()) {
+ if (isDirectChannelTypeSupported(curSensor, memType)) {
+ *supportsSharedMemType = true;
+ }
+ if (isDirectChannelTypeSupported(curSensor, SharedMemType::ASHMEM) ||
+ isDirectChannelTypeSupported(curSensor, SharedMemType::GRALLOC)) {
+ *supportsAnyDirectChannel = true;
+ }
+
+ if (*supportsSharedMemType && *supportsAnyDirectChannel) {
+ break;
+ }
+ }
+}
+
+void SensorsHidlTest::verifyRegisterDirectChannel(std::shared_ptr<SensorsTestSharedMemory> mem,
+ int32_t* directChannelHandle,
+ bool supportsSharedMemType,
+ bool supportsAnyDirectChannel) {
char* buffer = mem->getBuffer();
memset(buffer, 0xff, mem->getSize());
registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) {
- if (isDirectChannelTypeSupported(sensor, memType)) {
+ if (supportsSharedMemType) {
ASSERT_EQ(result, Result::OK);
ASSERT_GT(channelHandle, 0);
@@ -901,7 +956,9 @@
ASSERT_EQ(buffer[i], 0x00);
}
} else {
- ASSERT_EQ(result, Result::INVALID_OPERATION);
+ Result expectedResult =
+ supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION;
+ ASSERT_EQ(result, expectedResult);
ASSERT_EQ(channelHandle, -1);
}
*directChannelHandle = channelHandle;
@@ -909,7 +966,7 @@
}
void SensorsHidlTest::verifyConfigure(const SensorInfo& sensor, SharedMemType memType,
- int32_t directChannelHandle) {
+ int32_t directChannelHandle, bool supportsAnyDirectChannel) {
if (isDirectChannelTypeSupported(sensor, memType)) {
// Verify that each rate level is properly supported
checkRateLevel(sensor, directChannelHandle, RateLevel::NORMAL);
@@ -925,22 +982,22 @@
-1 /* sensorHandle */, directChannelHandle, RateLevel::STOP,
[](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); });
} else {
- // Direct channel is not supported for this SharedMemType
+ // directChannelHandle will be -1 here, HAL should either reject it as a bad value if there
+ // is some level of direct channel report, otherwise return INVALID_OPERATION if direct
+ // channel is not supported at all
+ Result expectedResult =
+ supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION;
configDirectReport(sensor.sensorHandle, directChannelHandle, RateLevel::NORMAL,
- [](Result result, int32_t /* reportToken */) {
- ASSERT_EQ(result, Result::INVALID_OPERATION);
+ [expectedResult](Result result, int32_t /* reportToken */) {
+ ASSERT_EQ(result, expectedResult);
});
}
}
-void SensorsHidlTest::verifyUnregisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
- int32_t directChannelHandle) {
- Result result = unregisterDirectChannel(directChannelHandle);
- if (isDirectChannelTypeSupported(sensor, memType)) {
- ASSERT_EQ(result, Result::OK);
- } else {
- ASSERT_EQ(result, Result::INVALID_OPERATION);
- }
+void SensorsHidlTest::verifyUnregisterDirectChannel(int32_t directChannelHandle,
+ bool supportsAnyDirectChannel) {
+ Result expectedResult = supportsAnyDirectChannel ? Result::OK : Result::INVALID_OPERATION;
+ ASSERT_EQ(unregisterDirectChannel(directChannelHandle), expectedResult);
}
void SensorsHidlTest::verifyDirectChannel(SharedMemType memType) {
@@ -951,11 +1008,16 @@
SensorsTestSharedMemory::create(memType, kMemSize));
ASSERT_NE(mem, nullptr);
+ bool supportsSharedMemType;
+ bool supportsAnyDirectChannel;
+ queryDirectChannelSupport(memType, &supportsSharedMemType, &supportsAnyDirectChannel);
+
for (const SensorInfo& sensor : getSensorsList()) {
int32_t directChannelHandle = 0;
- verifyRegisterDirectChannel(sensor, memType, mem, &directChannelHandle);
- verifyConfigure(sensor, memType, directChannelHandle);
- verifyUnregisterDirectChannel(sensor, memType, directChannelHandle);
+ verifyRegisterDirectChannel(mem, &directChannelHandle, supportsSharedMemType,
+ supportsAnyDirectChannel);
+ verifyConfigure(sensor, memType, directChannelHandle, supportsAnyDirectChannel);
+ verifyUnregisterDirectChannel(directChannelHandle, supportsAnyDirectChannel);
}
}
diff --git a/sensors/common/vts/utils/Android.bp b/sensors/common/vts/utils/Android.bp
index 8da554a..02dc608 100644
--- a/sensors/common/vts/utils/Android.bp
+++ b/sensors/common/vts/utils/Android.bp
@@ -31,7 +31,10 @@
],
static_libs: [
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@2.1",
+ "android.hardware.graphics.mapper@3.0",
"android.hardware.sensors@1.0",
"VtsHalHidlTargetTestBase",
],
diff --git a/sensors/common/vts/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp
index 222ef96..1cad913 100644
--- a/sensors/common/vts/utils/GrallocWrapper.cpp
+++ b/sensors/common/vts/utils/GrallocWrapper.cpp
@@ -16,206 +16,262 @@
#include "GrallocWrapper.h"
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+
#include <utils/Log.h>
+#include <cinttypes>
+#include <type_traits>
+
+using IAllocator2 = ::android::hardware::graphics::allocator::V2_0::IAllocator;
+using IAllocator3 = ::android::hardware::graphics::allocator::V3_0::IAllocator;
+using IMapper2 = ::android::hardware::graphics::mapper::V2_0::IMapper;
+using IMapper2_1 = ::android::hardware::graphics::mapper::V2_1::IMapper;
+using IMapper3 = ::android::hardware::graphics::mapper::V3_0::IMapper;
+
+using Error2 = ::android::hardware::graphics::mapper::V2_0::Error;
+using Error3 = ::android::hardware::graphics::mapper::V3_0::Error;
+
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+
+// This is a typedef to the same underlying type across v2.0 and v3.0
+using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
namespace android {
-GrallocWrapper::GrallocWrapper() {
- init();
+// Since we use the same APIs across allocator/mapper HALs but they have major
+// version differences (meaning they are not related through inheritance), we
+// create a common interface abstraction for the IAllocator + IMapper combination
+// (major versions need to match in the current HALs, e.g. IAllocator 3.0 needs to
+// be paired with IMapper 3.0, so these are tied together)
+class IGrallocHalWrapper {
+ public:
+ virtual ~IGrallocHalWrapper() = default;
+
+ // IAllocator
+ virtual std::string dumpDebugInfo() = 0;
+ virtual native_handle_t* allocate(uint32_t size) = 0;
+ virtual void freeBuffer(native_handle_t* bufferHandle) = 0;
+
+ // IMapper
+ virtual void* lock(native_handle_t* bufferHandle) = 0;
+ virtual void unlock(native_handle_t* bufferHandle) = 0;
+};
+
+namespace {
+
+bool failed(Error2 error) {
+ return (error != Error2::NONE);
+}
+bool failed(Error3 error) {
+ return (error != Error3::NONE);
}
-void GrallocWrapper::init() {
- mAllocator = allocator2::IAllocator::getService();
- if (mAllocator == nullptr) {
- ALOGE("Failed to get allocator service");
- }
-
- mMapper = mapper2::IMapper::getService();
- if (mMapper == nullptr) {
- ALOGE("Failed to get mapper service");
- } else if (mMapper->isRemote()) {
- ALOGE("Mapper is not in passthrough mode");
- }
-}
-
-GrallocWrapper::~GrallocWrapper() {
- for (auto bufferHandle : mClonedBuffers) {
- auto buffer = const_cast<native_handle_t*>(bufferHandle);
- native_handle_close(buffer);
- native_handle_delete(buffer);
- }
- mClonedBuffers.clear();
-
- for (auto bufferHandle : mImportedBuffers) {
- auto buffer = const_cast<native_handle_t*>(bufferHandle);
- if (mMapper->freeBuffer(buffer) != mapper2::Error::NONE) {
- ALOGE("Failed to free buffer %p", buffer);
+// Since all the type and function names are the same for the things we use across the major HAL
+// versions, we use template magic to avoid repeating ourselves.
+template <typename AllocatorT, typename MapperT>
+class GrallocHalWrapper : public IGrallocHalWrapper {
+ public:
+ GrallocHalWrapper(const sp<AllocatorT>& allocator, const sp<MapperT>& mapper)
+ : mAllocator(allocator), mMapper(mapper) {
+ if (mapper->isRemote()) {
+ ALOGE("Mapper is in passthrough mode");
}
}
- mImportedBuffers.clear();
-}
-sp<allocator2::IAllocator> GrallocWrapper::getAllocator() const {
- return mAllocator;
-}
+ virtual std::string dumpDebugInfo() override;
+ virtual native_handle_t* allocate(uint32_t size) override;
+ virtual void freeBuffer(native_handle_t* bufferHandle) override;
-std::string GrallocWrapper::dumpDebugInfo() {
+ virtual void* lock(native_handle_t* bufferHandle) override;
+ virtual void unlock(native_handle_t* bufferHandle) override;
+
+ private:
+ static constexpr uint64_t kBufferUsage =
+ static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::CPU_READ_OFTEN);
+ sp<AllocatorT> mAllocator;
+ sp<MapperT> mMapper;
+
+ BufferDescriptor getDescriptor(uint32_t size);
+ native_handle_t* importBuffer(const hidl_handle& rawHandle);
+};
+
+template <typename AllocatorT, typename MapperT>
+std::string GrallocHalWrapper<AllocatorT, MapperT>::dumpDebugInfo() {
std::string debugInfo;
- mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
-
+ mAllocator->dumpDebugInfo([&](const hidl_string& tmpDebugInfo) { debugInfo = tmpDebugInfo; });
return debugInfo;
}
-const native_handle_t* GrallocWrapper::cloneBuffer(const hardware::hidl_handle& rawHandle) {
- const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
+template <typename AllocatorT, typename MapperT>
+native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::allocate(uint32_t size) {
+ constexpr uint32_t kBufferCount = 1;
+ BufferDescriptor descriptor = getDescriptor(size);
+ native_handle_t* bufferHandle = nullptr;
- if (bufferHandle) {
- mClonedBuffers.insert(bufferHandle);
- }
+ auto callback = [&](auto error, uint32_t /*stride*/, const hidl_vec<hidl_handle>& buffers) {
+ if (failed(error)) {
+ ALOGE("Failed to allocate buffer: %" PRId32, static_cast<int32_t>(error));
+ } else if (buffers.size() != kBufferCount) {
+ ALOGE("Invalid buffer array size (got %zu, expected %" PRIu32 ")", buffers.size(),
+ kBufferCount);
+ } else {
+ bufferHandle = importBuffer(buffers[0]);
+ }
+ };
+
+ mAllocator->allocate(descriptor, kBufferCount, callback);
return bufferHandle;
}
-std::vector<const native_handle_t*> GrallocWrapper::allocate(
- const mapper2::BufferDescriptor& descriptor, uint32_t count, bool import, uint32_t* outStride) {
- std::vector<const native_handle_t*> bufferHandles;
- bufferHandles.reserve(count);
- mAllocator->allocate(descriptor, count,
- [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
- if (mapper2::Error::NONE != tmpError) {
- ALOGE("Failed to allocate buffers");
- }
- if (count != tmpBuffers.size()) {
- ALOGE("Invalid buffer array");
- }
-
- for (uint32_t i = 0; i < count; i++) {
- if (import) {
- bufferHandles.push_back(importBuffer(tmpBuffers[i]));
- } else {
- bufferHandles.push_back(cloneBuffer(tmpBuffers[i]));
- }
- }
-
- if (outStride) {
- *outStride = tmpStride;
- }
- });
-
- return bufferHandles;
+template <typename AllocatorT, typename MapperT>
+void GrallocHalWrapper<AllocatorT, MapperT>::freeBuffer(native_handle_t* bufferHandle) {
+ auto error = mMapper->freeBuffer(bufferHandle);
+ if (!error.isOk() || failed(error)) {
+ ALOGE("Failed to free buffer %p", bufferHandle);
+ }
}
-const native_handle_t* GrallocWrapper::allocate(
- const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo, bool import,
- uint32_t* outStride) {
- mapper2::BufferDescriptor descriptor = createDescriptor(descriptorInfo);
- auto buffers = allocate(descriptor, 1, import, outStride);
- return buffers[0];
-}
+template <typename AllocatorT, typename MapperT>
+BufferDescriptor GrallocHalWrapper<AllocatorT, MapperT>::getDescriptor(uint32_t size) {
+ typename MapperT::BufferDescriptorInfo descriptorInfo = {
+ .width = size,
+ .height = 1,
+ .layerCount = 1,
+ .usage = kBufferUsage,
+ .format = static_cast<decltype(descriptorInfo.format)>(PixelFormat::BLOB),
+ };
-sp<mapper2::IMapper> GrallocWrapper::getMapper() const {
- return mMapper;
-}
-
-mapper2::BufferDescriptor GrallocWrapper::createDescriptor(
- const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo) {
- mapper2::BufferDescriptor descriptor;
- mMapper->createDescriptor(descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
- if (tmpError != mapper2::Error::NONE) {
- ALOGE("Failed to create descriptor");
+ BufferDescriptor descriptor;
+ auto callback = [&](auto error, const BufferDescriptor& tmpDescriptor) {
+ if (failed(error)) {
+ ALOGE("Failed to create descriptor: %" PRId32, static_cast<int32_t>(error));
+ } else {
+ descriptor = tmpDescriptor;
}
- descriptor = tmpDescriptor;
- });
+ };
+ mMapper->createDescriptor(descriptorInfo, callback);
return descriptor;
}
-const native_handle_t* GrallocWrapper::importBuffer(const hardware::hidl_handle& rawHandle) {
- const native_handle_t* bufferHandle = nullptr;
- mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
- if (tmpError != mapper2::Error::NONE) {
- ALOGE("Failed to import buffer %p", rawHandle.getNativeHandle());
- }
- bufferHandle = static_cast<const native_handle_t*>(tmpBuffer);
- });
+template <typename AllocatorT, typename MapperT>
+native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::importBuffer(
+ const hidl_handle& rawHandle) {
+ native_handle_t* bufferHandle = nullptr;
- if (bufferHandle) {
- mImportedBuffers.insert(bufferHandle);
- }
+ mMapper->importBuffer(rawHandle, [&](auto error, void* tmpBuffer) {
+ if (failed(error)) {
+ ALOGE("Failed to import buffer %p: %" PRId32, rawHandle.getNativeHandle(),
+ static_cast<int32_t>(error));
+ } else {
+ bufferHandle = static_cast<native_handle_t*>(tmpBuffer);
+ }
+ });
return bufferHandle;
}
-void GrallocWrapper::freeBuffer(const native_handle_t* bufferHandle) {
- auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
- if (mImportedBuffers.erase(bufferHandle)) {
- mapper2::Error error = mMapper->freeBuffer(buffer);
- if (error != mapper2::Error::NONE) {
- ALOGE("Failed to free %p", buffer);
- }
- } else {
- mClonedBuffers.erase(bufferHandle);
- native_handle_close(buffer);
- native_handle_delete(buffer);
- }
-}
-
-void* GrallocWrapper::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
- const mapper2::IMapper::Rect& accessRegion, int acquireFence) {
- auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
- NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
- hardware::hidl_handle acquireFenceHandle;
- if (acquireFence >= 0) {
- auto h = native_handle_init(acquireFenceStorage, 1, 0);
- h->data[0] = acquireFence;
- acquireFenceHandle = h;
- }
+template <typename AllocatorT, typename MapperT>
+void* GrallocHalWrapper<AllocatorT, MapperT>::lock(native_handle_t* bufferHandle) {
+ // Per the HAL, all-zeros Rect means the entire buffer
+ typename MapperT::Rect accessRegion = {};
+ hidl_handle acquireFenceHandle; // No fence needed, already safe to lock
void* data = nullptr;
- mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
- [&](const auto& tmpError, const auto& tmpData) {
- if (tmpError != mapper2::Error::NONE) {
- ALOGE("Failed to lock buffer %p", buffer);
+ mMapper->lock(bufferHandle, kBufferUsage, accessRegion, acquireFenceHandle,
+ [&](auto error, void* tmpData, ...) { // V3_0 passes extra args we don't use
+ if (failed(error)) {
+ ALOGE("Failed to lock buffer %p: %" PRId32, bufferHandle,
+ static_cast<int32_t>(error));
+ } else {
+ data = tmpData;
}
- data = tmpData;
});
- if (acquireFence >= 0) {
- close(acquireFence);
- }
-
return data;
}
-int GrallocWrapper::unlock(const native_handle_t* bufferHandle) {
- auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
- int releaseFence = -1;
- mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
- if (tmpError != mapper2::Error::NONE) {
- ALOGE("Failed to unlock buffer %p", buffer);
- }
-
- auto fenceHandle = tmpReleaseFence.getNativeHandle();
- if (fenceHandle) {
- if (fenceHandle->numInts != 0) {
- ALOGE("Invalid fence handle %p", fenceHandle);
- }
- if (fenceHandle->numFds == 1) {
- releaseFence = dup(fenceHandle->data[0]);
- if (releaseFence < 0) {
- ALOGE("Failed to dup fence fd");
- }
- } else {
- if (fenceHandle->numFds != 0) {
- ALOGE("Invalid fence handle %p", fenceHandle);
- }
- }
+template <typename AllocatorT, typename MapperT>
+void GrallocHalWrapper<AllocatorT, MapperT>::unlock(native_handle_t* bufferHandle) {
+ mMapper->unlock(bufferHandle, [&](auto error, const hidl_handle& /*releaseFence*/) {
+ if (failed(error)) {
+ ALOGE("Failed to unlock buffer %p: %" PRId32, bufferHandle,
+ static_cast<int32_t>(error));
}
});
+}
- return releaseFence;
+} // anonymous namespace
+
+GrallocWrapper::GrallocWrapper() {
+ sp<IAllocator3> allocator3 = IAllocator3::getService();
+ sp<IMapper3> mapper3 = IMapper3::getService();
+
+ if (allocator3 != nullptr && mapper3 != nullptr) {
+ mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
+ new GrallocHalWrapper<IAllocator3, IMapper3>(allocator3, mapper3));
+ } else {
+ ALOGD("Graphics HALs 3.0 not found (allocator %d mapper %d), falling back to 2.x",
+ (allocator3 != nullptr), (mapper3 != nullptr));
+
+ sp<IAllocator2> allocator2 = IAllocator2::getService();
+ sp<IMapper2> mapper2 = IMapper2_1::getService();
+ if (mapper2 == nullptr) {
+ mapper2 = IMapper2::getService();
+ }
+
+ if (allocator2 != nullptr && mapper2 != nullptr) {
+ mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
+ new GrallocHalWrapper<IAllocator2, IMapper2>(allocator2, mapper2));
+ } else {
+ ALOGE("Couldn't open 2.x/3.0 graphics HALs (2.x allocator %d mapper %d)",
+ (allocator2 != nullptr), (mapper2 != nullptr));
+ }
+ }
+}
+
+GrallocWrapper::~GrallocWrapper() {
+ for (auto bufferHandle : mAllocatedBuffers) {
+ mGrallocHal->unlock(bufferHandle);
+ mGrallocHal->freeBuffer(bufferHandle);
+ }
+ mAllocatedBuffers.clear();
+}
+
+std::string GrallocWrapper::dumpDebugInfo() {
+ return mGrallocHal->dumpDebugInfo();
+}
+
+std::pair<native_handle_t*, void*> GrallocWrapper::allocate(uint32_t size) {
+ native_handle_t* bufferHandle = mGrallocHal->allocate(size);
+ void* buffer = nullptr;
+ if (bufferHandle) {
+ buffer = mGrallocHal->lock(bufferHandle);
+ if (buffer) {
+ mAllocatedBuffers.insert(bufferHandle);
+ } else {
+ mGrallocHal->freeBuffer(bufferHandle);
+ bufferHandle = nullptr;
+ }
+ }
+ return std::make_pair<>(bufferHandle, buffer);
+}
+
+void GrallocWrapper::freeBuffer(native_handle_t* bufferHandle) {
+ if (mAllocatedBuffers.erase(bufferHandle)) {
+ mGrallocHal->unlock(bufferHandle);
+ mGrallocHal->freeBuffer(bufferHandle);
+ }
}
} // namespace android
diff --git a/sensors/common/vts/utils/SensorsTestSharedMemory.cpp b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
index 819e297..3b068bd 100644
--- a/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
+++ b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
@@ -119,32 +119,13 @@
}
case SharedMemType::GRALLOC: {
mGrallocWrapper = std::make_unique<::android::GrallocWrapper>();
- if (mGrallocWrapper->getAllocator() == nullptr ||
- mGrallocWrapper->getMapper() == nullptr) {
+ if (!mGrallocWrapper->isInitialized()) {
break;
}
- using android::hardware::graphics::common::V1_0::BufferUsage;
- using android::hardware::graphics::common::V1_0::PixelFormat;
- mapper2::IMapper::BufferDescriptorInfo buf_desc_info = {
- .width = static_cast<uint32_t>(size),
- .height = 1,
- .layerCount = 1,
- .usage = static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA |
- BufferUsage::CPU_READ_OFTEN),
- .format = PixelFormat::BLOB};
- handle = const_cast<native_handle_t*>(mGrallocWrapper->allocate(buf_desc_info));
- if (handle != nullptr) {
- mapper2::IMapper::Rect region{0, 0, static_cast<int32_t>(buf_desc_info.width),
- static_cast<int32_t>(buf_desc_info.height)};
- buffer = static_cast<char*>(
- mGrallocWrapper->lock(handle, buf_desc_info.usage, region, /*fence=*/-1));
- if (buffer != nullptr) {
- break;
- }
- mGrallocWrapper->freeBuffer(handle);
- handle = nullptr;
- }
+ std::pair<native_handle_t*, void*> buf = mGrallocWrapper->allocate(size);
+ handle = buf.first;
+ buffer = static_cast<char*>(buf.second);
break;
}
default:
@@ -175,9 +156,7 @@
}
case SharedMemType::GRALLOC: {
if (mSize != 0) {
- mGrallocWrapper->unlock(mNativeHandle);
mGrallocWrapper->freeBuffer(mNativeHandle);
-
mNativeHandle = nullptr;
mSize = 0;
}
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h b/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
index 3bd73c3..41e6334 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
@@ -14,66 +14,47 @@
* limitations under the License.
*/
-#ifndef GRALLO_WRAPPER_H_
-#define GRALLO_WRAPPER_H_
+#pragma once
+#include <utils/NativeHandle.h>
+
+#include <memory>
+#include <string>
#include <unordered_set>
-
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-
-namespace allocator2 = ::android::hardware::graphics::allocator::V2_0;
-namespace mapper2 = ::android::hardware::graphics::mapper::V2_0;
+#include <utility>
namespace android {
-// Modified from hardware/interfaces/graphics/mapper/2.0/vts/functional/
+class IGrallocHalWrapper;
+
+// Reference: hardware/interfaces/graphics/mapper/2.0/vts/functional/
class GrallocWrapper {
public:
GrallocWrapper();
~GrallocWrapper();
- sp<allocator2::IAllocator> getAllocator() const;
- sp<mapper2::IMapper> getMapper() const;
+ // After constructing this object, this function must be called to check the result. If it
+ // returns false, other methods are not safe to call.
+ bool isInitialized() const { return (mGrallocHal != nullptr); };
std::string dumpDebugInfo();
- // When import is false, this simply calls IAllocator::allocate. When import
- // is true, the returned buffers are also imported into the mapper.
- //
- // Either case, the returned buffers must be freed with freeBuffer.
- std::vector<const native_handle_t*> allocate(const mapper2::BufferDescriptor& descriptor,
- uint32_t count, bool import = true,
- uint32_t* outStride = nullptr);
- const native_handle_t* allocate(const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo,
- bool import = true, uint32_t* outStride = nullptr);
+ // Allocates a gralloc buffer suitable for direct channel sensors usage with the given size.
+ // The buffer should be freed using freeBuffer when it's not needed anymore; otherwise it'll
+ // be freed when this object is destroyed.
+ // Returns a handle to the buffer, and a CPU-accessible pointer for reading. On failure, both
+ // will be set to nullptr.
+ std::pair<native_handle_t*, void*> allocate(uint32_t size);
- mapper2::BufferDescriptor createDescriptor(
- const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo);
+ // Releases a gralloc buffer previously returned by allocate()
+ void freeBuffer(native_handle_t* bufferHandle);
- const native_handle_t* importBuffer(const hardware::hidl_handle& rawHandle);
- void freeBuffer(const native_handle_t* bufferHandle);
-
- // We use fd instead of hardware::hidl_handle in these functions to pass fences
- // in and out of the mapper. The ownership of the fd is always transferred
- // with each of these functions.
- void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
- const mapper2::IMapper::Rect& accessRegion, int acquireFence);
-
- int unlock(const native_handle_t* bufferHandle);
-
- private:
- void init();
- const native_handle_t* cloneBuffer(const hardware::hidl_handle& rawHandle);
-
- sp<allocator2::IAllocator> mAllocator;
- sp<mapper2::IMapper> mMapper;
+ private:
+ std::unique_ptr<IGrallocHalWrapper> mGrallocHal;
// Keep track of all cloned and imported handles. When a test fails with
// ASSERT_*, the destructor will free the handles for the test.
- std::unordered_set<const native_handle_t*> mClonedBuffers;
- std::unordered_set<const native_handle_t*> mImportedBuffers;
+ std::unordered_set<native_handle_t*> mAllocatedBuffers;
};
} // namespace android
-#endif // GRALLO_WRAPPER_H_
diff --git a/tests/expression/1.0/IExpression.hal b/tests/expression/1.0/IExpression.hal
index 36aed60..039897a 100644
--- a/tests/expression/1.0/IExpression.hal
+++ b/tests/expression/1.0/IExpression.hal
@@ -215,7 +215,6 @@
MY_INT32_MIN_PLUS_1, // 0x80000001
};
- @callflow(key=Constants:CONST_FOO + 1)
foo1(int32_t[Constants:CONST_FOO + 1] array);
foo2(int32_t[5 + 8] array);
foo3(int32_t[Constants:MAX_ARRAY_SIZE] array);
diff --git a/tests/expression/1.0/IExpressionExt.hal b/tests/expression/1.0/IExpressionExt.hal
index 8b56ec6..e721978 100644
--- a/tests/expression/1.0/IExpressionExt.hal
+++ b/tests/expression/1.0/IExpressionExt.hal
@@ -36,7 +36,6 @@
SixteenColors my16Colors;
};
- @callflow(key=@1.0::IExpression.Constants:MAX_ARRAY_SIZE)
foo3(int32_t[IExpression.Constants:MAX_ARRAY_SIZE] array);
foo2(SixteenColors array);
foo1(int32_t[Constants:CONST_FOO + 5] array);
diff --git a/wifi/1.0/IWifiP2pIface.hal b/wifi/1.0/IWifiP2pIface.hal
index b908591..025f7ab 100644
--- a/wifi/1.0/IWifiP2pIface.hal
+++ b/wifi/1.0/IWifiP2pIface.hal
@@ -19,6 +19,6 @@
import IWifiIface;
/**
- * Interface used to represent a single NAN iface.
+ * Interface used to represent a single P2P iface.
*/
interface IWifiP2pIface extends IWifiIface {};
diff --git a/wifi/supplicant/1.3/Android.bp b/wifi/supplicant/1.3/Android.bp
new file mode 100644
index 0000000..6633d9d
--- /dev/null
+++ b/wifi/supplicant/1.3/Android.bp
@@ -0,0 +1,21 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.wifi.supplicant@1.3",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ "ISupplicant.hal",
+ "ISupplicantStaNetwork.hal",
+ ],
+ interfaces: [
+ "android.hardware.wifi.supplicant@1.0",
+ "android.hardware.wifi.supplicant@1.1",
+ "android.hardware.wifi.supplicant@1.2",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: true,
+}
diff --git a/wifi/supplicant/1.3/ISupplicant.hal b/wifi/supplicant/1.3/ISupplicant.hal
new file mode 100644
index 0000000..75b7e96
--- /dev/null
+++ b/wifi/supplicant/1.3/ISupplicant.hal
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant@1.3;
+
+import @1.2::ISupplicant;
+
+/**
+ * Interface exposed by the supplicant HIDL service registered
+ * with the hardware service manager.
+ * This is the root level object for any the supplicant interactions.
+ * To use 1.3 features you must cast specific interfaces returned from the
+ * 1.2 HAL. For example V1_2::ISupplicant::addIface() adds V1_2::ISupplicantIface,
+ * which can be cast to V1_3::ISupplicantStaIface.
+ */
+interface ISupplicant extends @1.2::ISupplicant {
+};
diff --git a/wifi/supplicant/1.3/ISupplicantStaNetwork.hal b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
new file mode 100644
index 0000000..eb9de9a
--- /dev/null
+++ b/wifi/supplicant/1.3/ISupplicantStaNetwork.hal
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant@1.3;
+
+import @1.0::SupplicantStatus;
+import @1.2::ISupplicantStaNetwork;
+
+/**
+ * Interface exposed by the supplicant for each station mode network
+ * configuration it controls.
+ */
+interface ISupplicantStaNetwork extends @1.2::ISupplicantStaNetwork {
+ /**
+ * Set OCSP (Online Certificate Status Protocol) type for this network.
+ *
+ * @param ocspType value to set.
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ */
+ setOcsp(OcspType ocspType) generates (SupplicantStatus status);
+
+ /**
+ * Get OCSP (Online Certificate Status Protocol) type for this network.
+ *
+ * @return status Status of the operation.
+ * Possible status codes:
+ * |SupplicantStatusCode.SUCCESS|,
+ * |SupplicantStatusCode.FAILURE_ARGS_INVALID|,
+ * |SupplicantStatusCode.FAILURE_NETWORK_INVALID|
+ * @return ocspType ocsp type.
+ */
+ getOcsp() generates (SupplicantStatus status, OcspType ocspType);
+};
diff --git a/wifi/supplicant/1.3/types.hal b/wifi/supplicant/1.3/types.hal
new file mode 100644
index 0000000..a782b49
--- /dev/null
+++ b/wifi/supplicant/1.3/types.hal
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant@1.3;
+
+/**
+ * OcspType: The type of OCSP request.
+ */
+enum OcspType : uint32_t {
+ NONE,
+ REQUEST_CERT_STATUS,
+ REQUIRE_CERT_STATUS,
+ REQUIRE_ALL_CERTS_STATUS,
+};
diff --git a/wifi/supplicant/1.3/vts/OWNERS b/wifi/supplicant/1.3/vts/OWNERS
new file mode 100644
index 0000000..8bfb148
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/OWNERS
@@ -0,0 +1,2 @@
+rpius@google.com
+etancohen@google.com
diff --git a/wifi/supplicant/1.3/vts/functional/Android.bp b/wifi/supplicant/1.3/vts/functional/Android.bp
new file mode 100644
index 0000000..6f58168
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/Android.bp
@@ -0,0 +1,67 @@
+//
+// Copyright (C) 2019 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_library_static {
+ name: "VtsHalWifiSupplicantV1_3TargetTestUtil",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["supplicant_hidl_test_utils_1_3.cpp"],
+ export_include_dirs: [
+ "."
+ ],
+ static_libs: [
+ "VtsHalWifiV1_0TargetTestUtil",
+ "VtsHalWifiSupplicantV1_0TargetTestUtil",
+ "VtsHalWifiSupplicantV1_1TargetTestUtil",
+ "VtsHalWifiSupplicantV1_2TargetTestUtil",
+ "android.hardware.wifi.supplicant@1.0",
+ "android.hardware.wifi.supplicant@1.1",
+ "android.hardware.wifi.supplicant@1.2",
+ "android.hardware.wifi.supplicant@1.3",
+ "android.hardware.wifi@1.0",
+ "libcrypto",
+ "libgmock",
+ "libwifi-system",
+ "libwifi-system-iface",
+ ],
+}
+
+cc_test {
+ name: "VtsHalWifiSupplicantV1_3TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "VtsHalWifiSupplicantV1_3TargetTest.cpp",
+ "supplicant_sta_network_hidl_test.cpp",
+ ],
+ static_libs: [
+ "VtsHalWifiV1_0TargetTestUtil",
+ "VtsHalWifiSupplicantV1_0TargetTestUtil",
+ "VtsHalWifiSupplicantV1_1TargetTestUtil",
+ "VtsHalWifiSupplicantV1_2TargetTestUtil",
+ "VtsHalWifiSupplicantV1_3TargetTestUtil",
+ "android.hardware.wifi.supplicant@1.0",
+ "android.hardware.wifi.supplicant@1.1",
+ "android.hardware.wifi.supplicant@1.2",
+ "android.hardware.wifi.supplicant@1.3",
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "libcrypto",
+ "libgmock",
+ "libwifi-system",
+ "libwifi-system-iface",
+ ],
+ test_suites: ["general-tests"],
+}
+
diff --git a/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp b/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp
new file mode 100644
index 0000000..4dbb64e
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/VtsHalWifiSupplicantV1_3TargetTest.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/wifi/1.1/IWifi.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicant.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "wifi_hidl_test_utils.h"
+
+class WifiSupplicantHidlEnvironment_1_3 : public WifiSupplicantHidlEnvironment {
+ public:
+ // get the test environment singleton
+ static WifiSupplicantHidlEnvironment_1_3* Instance() {
+ static WifiSupplicantHidlEnvironment_1_3* instance =
+ new WifiSupplicantHidlEnvironment_1_3;
+ return instance;
+ }
+ virtual void registerTestServices() override {
+ registerTestService<::android::hardware::wifi::V1_0::IWifi>();
+ registerTestService<::android::hardware::wifi::V1_1::IWifi>();
+ registerTestService<
+ ::android::hardware::wifi::supplicant::V1_0::ISupplicant>();
+ registerTestService<
+ ::android::hardware::wifi::supplicant::V1_1::ISupplicant>();
+ registerTestService<
+ ::android::hardware::wifi::supplicant::V1_2::ISupplicant>();
+ registerTestService<
+ ::android::hardware::wifi::supplicant::V1_3::ISupplicant>();
+ }
+
+ private:
+ WifiSupplicantHidlEnvironment_1_3() {}
+};
+
+WifiSupplicantHidlEnvironment* gEnv =
+ WifiSupplicantHidlEnvironment_1_3::Instance();
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(gEnv);
+ ::testing::InitGoogleTest(&argc, argv);
+ gEnv->init(&argc, argv);
+ int status = gEnv->initFromOptions(argc, argv);
+ if (status == 0) {
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ }
+ return status;
+}
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp
new file mode 100644
index 0000000..86959eb
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_3.h"
+
+using ::android::sp;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
+
+sp<ISupplicantStaNetwork> createSupplicantStaNetwork_1_3() {
+ return ISupplicantStaNetwork::castFrom(createSupplicantStaNetwork());
+}
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h
new file mode 100644
index 0000000..8e64162
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_hidl_test_utils_1_3.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SUPPLICANT_HIDL_TEST_UTILS_1_3_H
+#define SUPPLICANT_HIDL_TEST_UTILS_1_3_H
+
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
+
+android::sp<android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork>
+createSupplicantStaNetwork_1_3();
+
+#endif /* SUPPLICANT_HIDL_TEST_UTILS_1_3_H */
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
new file mode 100644
index 0000000..e5be0cc
--- /dev/null
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/wifi/supplicant/1.3/ISupplicantStaNetwork.h>
+
+#include "supplicant_hidl_test_utils.h"
+#include "supplicant_hidl_test_utils_1_3.h"
+
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatus;
+using ::android::hardware::wifi::supplicant::V1_0::SupplicantStatusCode;
+using ::android::hardware::wifi::supplicant::V1_3::ISupplicantStaNetwork;
+using ::android::hardware::wifi::supplicant::V1_3::OcspType;
+namespace {
+constexpr OcspType kTestOcspType = OcspType::REQUEST_CERT_STATUS;
+constexpr OcspType kTestInvalidOcspType = (OcspType)-1;
+} // namespace
+
+class SupplicantStaNetworkHidlTest
+ : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ virtual void SetUp() override {
+ startSupplicantAndWaitForHidlService();
+ EXPECT_TRUE(turnOnExcessiveLogging());
+ sta_network_ = createSupplicantStaNetwork_1_3();
+ ASSERT_NE(sta_network_.get(), nullptr);
+ }
+
+ virtual void TearDown() override { stopSupplicant(); }
+
+ protected:
+ // ISupplicantStaNetwork object used for all tests in this fixture.
+ sp<ISupplicantStaNetwork> sta_network_;
+};
+
+/*
+ * SetGetOcsp
+ */
+TEST_F(SupplicantStaNetworkHidlTest, SetGetOcsp) {
+ OcspType testOcspType = kTestOcspType;
+
+ sta_network_->setOcsp(testOcspType, [](const SupplicantStatus &status) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ });
+
+ sta_network_->setOcsp(
+ kTestInvalidOcspType, [](const SupplicantStatus &status) {
+ EXPECT_EQ(SupplicantStatusCode::FAILURE_ARGS_INVALID, status.code);
+ });
+
+ sta_network_->getOcsp(
+ [testOcspType](const SupplicantStatus &status, OcspType ocspType) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(testOcspType, ocspType);
+ });
+}