Merge "NNAPI VTS fix from NNAPI CL: Cleanup HalInterfaces.h"
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index 8a7b2ea..2a6571b 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -36,6 +36,15 @@
using namespace android::hardware;
using android::OK;
+/** Try to register the provided factories in the provided order.
+ * If any registers successfully, do not register any other and return true.
+ * If all fail, return false.
+ */
+template <class... Factories>
+bool registerPassthroughServiceImplementations() {
+ return ((registerPassthroughServiceImplementation<Factories>() != OK) && ...);
+}
+
int main(int /* argc */, char* /* argv */ []) {
::android::ProcessState::initWithDriver("/dev/vndbinder");
// start a threadpool for vndbinder interactions
@@ -50,30 +59,30 @@
}
configureRpcThreadpool(16, true /*callerWillJoin*/);
- bool fail = registerPassthroughServiceImplementation<audio::V5_0::IDevicesFactory>() != OK &&
- registerPassthroughServiceImplementation<audio::V4_0::IDevicesFactory>() != OK &&
- registerPassthroughServiceImplementation<audio::V2_0::IDevicesFactory>() != OK;
- LOG_ALWAYS_FATAL_IF(fail, "Could not register audio core API 2, 4 nor 5");
+ LOG_ALWAYS_FATAL_IF((registerPassthroughServiceImplementations<audio::V5_0::IDevicesFactory,
+ audio::V4_0::IDevicesFactory,
+ audio::V2_0::IDevicesFactory>()),
+ "Could not register audio core API");
- fail = registerPassthroughServiceImplementation<audio::effect::V5_0::IEffectsFactory>() != OK &&
- registerPassthroughServiceImplementation<audio::effect::V4_0::IEffectsFactory>() != OK &&
- registerPassthroughServiceImplementation<audio::effect::V2_0::IEffectsFactory>() != OK,
- LOG_ALWAYS_FATAL_IF(fail, "Could not register audio effect API 2, 4 nor 5");
+ LOG_ALWAYS_FATAL_IF(
+ (registerPassthroughServiceImplementations<audio::effect::V5_0::IEffectsFactory,
+ audio::effect::V4_0::IEffectsFactory,
+ audio::effect::V2_0::IEffectsFactory>()),
+ "Could not register audio effect API");
- fail = registerPassthroughServiceImplementation<soundtrigger::V2_2::ISoundTriggerHw>() != OK &&
- registerPassthroughServiceImplementation<soundtrigger::V2_1::ISoundTriggerHw>() != OK &&
- registerPassthroughServiceImplementation<soundtrigger::V2_0::ISoundTriggerHw>() != OK,
- ALOGW_IF(fail, "Could not register soundtrigger API 2.0, 2.1 nor 2.2");
+ ALOGW_IF((registerPassthroughServiceImplementations<soundtrigger::V2_2::ISoundTriggerHw,
+ soundtrigger::V2_1::ISoundTriggerHw,
+ soundtrigger::V2_0::ISoundTriggerHw>()),
+ "Could not register soundtrigger API");
- fail = registerPassthroughServiceImplementation<
- bluetooth::audio::V2_0::IBluetoothAudioProvidersFactory>() != OK;
- ALOGW_IF(fail, "Could not register Bluetooth Audio API 2.0");
+ ALOGW_IF(registerPassthroughServiceImplementations<
+ bluetooth::audio::V2_0::IBluetoothAudioProvidersFactory>(),
+ "Could not register Bluetooth audio API");
// remove the old HIDL when Bluetooth Audio Hal V2 has offloading supported
- fail =
- registerPassthroughServiceImplementation<bluetooth::a2dp::V1_0::IBluetoothAudioOffload>() !=
- OK;
- ALOGW_IF(fail, "Could not register Bluetooth audio offload 1.0");
+ ALOGW_IF(registerPassthroughServiceImplementations<
+ bluetooth::a2dp::V1_0::IBluetoothAudioOffload>(),
+ "Could not register Bluetooth audio offload API");
joinRpcThreadpool();
}
diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp
index a1af3c4..97b4553 100644
--- a/audio/core/all-versions/default/Android.bp
+++ b/audio/core/all-versions/default/Android.bp
@@ -26,6 +26,7 @@
"libhidlbase",
"libhidltransport",
"liblog",
+ "libmedia_helper",
"libutils",
"android.hardware.audio.common-util",
],
@@ -37,10 +38,6 @@
"libhardware_headers",
"libmedia_headers",
],
-
- whole_static_libs: [
- "libmedia_helper",
- ],
}
cc_library_shared {
diff --git a/audio/effect/5.0/xml/Android.bp b/audio/effect/5.0/xml/Android.bp
index 967135c..eb2bcee 100644
--- a/audio/effect/5.0/xml/Android.bp
+++ b/audio/effect/5.0/xml/Android.bp
@@ -1,6 +1,6 @@
xsd_config {
- name: "audio_effects_conf",
+ name: "audio_effects_conf_V5_0",
srcs: ["audio_effects_conf.xsd"],
package_name: "audio.effects.V5_0",
}
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 a46de24..3e59584 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
@@ -167,7 +167,6 @@
.prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.floatValues = {15000.0f}}},
@@ -177,14 +176,13 @@
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
},
- .initialValue = {.int32Values = {1}}},
+ .initialValue = {.int32Values = {(int)FuelType::FUEL_TYPE_UNLEADED}}},
{.config =
{
.prop = toInt(VehicleProperty::INFO_EV_BATTERY_CAPACITY),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.floatValues = {150000.0f}}},
@@ -194,14 +192,13 @@
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
},
- .initialValue = {.int32Values = {1}}},
+ .initialValue = {.int32Values = {(int)EvConnectorType::IEC_TYPE_1_AC}}},
{.config =
{
.prop = toInt(VehicleProperty::INFO_DRIVER_SEAT),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {SEAT_1_LEFT}}},
@@ -210,7 +207,6 @@
.prop = toInt(VehicleProperty::INFO_FUEL_DOOR_LOCATION),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {FUEL_DOOR_REAR_LEFT}}},
@@ -219,7 +215,6 @@
.prop = toInt(VehicleProperty::INFO_EV_PORT_LOCATION),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT}}},
@@ -234,7 +229,7 @@
{
.prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
.access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
.minSampleRate = 1.0f,
.maxSampleRate = 10.0f,
},
@@ -265,7 +260,7 @@
{
.prop = toInt(VehicleProperty::PERF_ODOMETER),
.access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
},
.initialValue = {.floatValues = {0.0f}}},
@@ -285,8 +280,7 @@
{
.prop = toInt(VehicleProperty::FUEL_LEVEL),
.access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
},
.initialValue = {.floatValues = {15000.0f}}},
@@ -295,7 +289,6 @@
.prop = toInt(VehicleProperty::FUEL_DOOR_OPEN),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {0}}},
@@ -303,8 +296,7 @@
{
.prop = toInt(VehicleProperty::EV_BATTERY_LEVEL),
.access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
},
.initialValue = {.floatValues = {150000.0f}}},
@@ -313,7 +305,6 @@
.prop = toInt(VehicleProperty::EV_CHARGE_PORT_OPEN),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {0}}},
@@ -322,7 +313,6 @@
.prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {0}}},
@@ -330,17 +320,15 @@
{
.prop = toInt(VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE),
.access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+ .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
},
.initialValue = {.floatValues = {0.0f}}},
{.config =
{
.prop = toInt(VehicleProperty::RANGE_REMAINING),
- .access = VehiclePropertyAccess::READ,
+ .access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::CONTINUOUS,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
.minSampleRate = 1.0f,
.maxSampleRate = 2.0f,
},
@@ -365,7 +353,7 @@
VehicleAreaConfig{
.areaId = WHEEL_REAR_RIGHT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f,
}}},
- .initialValue = {.floatValues = {200}}}, // units in kPa
+ .initialValue = {.floatValues = {200.0f}}}, // units in kPa
{.config =
{
@@ -388,7 +376,6 @@
.prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {0}}},
@@ -541,8 +528,8 @@
{.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_DISPLAY_UNITS),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS},
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}}},
+ .configArray = {(int)VehicleUnit::FAHRENHEIT, (int)VehicleUnit::CELSIUS}
+ },
.initialValue = {.int32Values = {(int)VehicleUnit::FAHRENHEIT}}},
{.config =
@@ -713,7 +700,6 @@
.prop = toInt(VehicleProperty::HEADLIGHTS_STATE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_STATE_ON}}},
@@ -722,7 +708,6 @@
.prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_STATE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_STATE_ON}}},
@@ -731,7 +716,6 @@
.prop = toInt(VehicleProperty::FOG_LIGHTS_STATE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_STATE_ON}}},
@@ -740,7 +724,6 @@
.prop = toInt(VehicleProperty::HAZARD_LIGHTS_STATE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_STATE_ON}}},
@@ -749,7 +732,6 @@
.prop = toInt(VehicleProperty::HEADLIGHTS_SWITCH),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
@@ -758,7 +740,6 @@
.prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_SWITCH),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
@@ -767,7 +748,6 @@
.prop = toInt(VehicleProperty::FOG_LIGHTS_SWITCH),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
@@ -776,7 +756,6 @@
.prop = toInt(VehicleProperty::HAZARD_LIGHTS_SWITCH),
.access = VehiclePropertyAccess::READ_WRITE,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
- .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
},
.initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
diff --git a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
index 9227b6f..73c505d 100644
--- a/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
+++ b/cas/1.1/default/android.hardware.cas@1.1-service-lazy.rc
@@ -1,4 +1,5 @@
service vendor.cas-hal-1-1 /vendor/bin/hw/android.hardware.cas@1.1-service-lazy
+ interface android.hardware.cas@1.0::IMediaCasService default
interface android.hardware.cas@1.1::IMediaCasService default
oneshot
disabled
diff --git a/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
index 7dedd7f..6be30d3 100644
--- a/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
+++ b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
@@ -24,7 +24,7 @@
#include <android/hardware/drm/1.0/types.h>
#include <android/hardware/drm/1.1/types.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
#include <gtest/gtest.h>
#include <hidl/HidlSupport.h>
#include <hidl/ServiceManagement.h>
@@ -129,9 +129,9 @@
ALOGD("DrmHalClearkeyTest: Running test %s.%s", test_info->test_case_name(),
test_info->name());
- auto manager = android::hardware::defaultServiceManager();
+ auto manager = android::hardware::defaultServiceManager1_2();
ASSERT_NE(nullptr, manager.get());
- manager->listByInterface(IDrmFactory::descriptor,
+ manager->listManifestByInterface(IDrmFactory::descriptor,
[&](const hidl_vec<hidl_string> ®istered) {
for (const auto &instance : registered) {
sp<IDrmFactory> drmFactory =
@@ -144,7 +144,7 @@
}
);
- manager->listByInterface(ICryptoFactory::descriptor,
+ manager->listManifestByInterface(ICryptoFactory::descriptor,
[&](const hidl_vec<hidl_string> ®istered) {
for (const auto &instance : registered) {
sp<ICryptoFactory> cryptoFactory =
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index 4288d0d..ee236ba 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -24,6 +24,9 @@
using android::hardware::hidl_vec;
+using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
+using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
+
using android::hardware::gnss::V1_0::GnssConstellationType;
using android::hardware::gnss::V1_0::GnssLocation;
using android::hardware::gnss::V1_0::IGnssDebug;
@@ -43,11 +46,15 @@
* Gets the GnssMeasurementExtension and verify that it returns an actual extension.
*/
TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
- auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_1_1();
- ASSERT_TRUE(gnssMeasurement.isOk());
+ auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
+ ASSERT_TRUE(gnssMeasurement_1_1.isOk());
+ auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
+ ASSERT_TRUE(gnssMeasurement_1_0.isOk());
if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
- sp<IGnssMeasurement> iGnssMeas = gnssMeasurement;
- EXPECT_NE(iGnssMeas, nullptr);
+ sp<IGnssMeasurement_1_1> iGnssMeas_1_1 = gnssMeasurement_1_1;
+ sp<IGnssMeasurement_1_0> iGnssMeas_1_0 = gnssMeasurement_1_0;
+ // At least one interface must be non-null.
+ ASSERT_TRUE(iGnssMeas_1_1 != nullptr || iGnssMeas_1_0 != nullptr);
}
}
@@ -59,6 +66,11 @@
* each received location.
*/
TEST_F(GnssHalTest, GetLocationLowPower) {
+ if (!IsGnssHalVersion_1_1()) {
+ ALOGI("Test GetLocationLowPower skipped. GNSS HAL version is greater than 1.1.");
+ return;
+ }
+
const int kMinIntervalMsec = 5000;
const int kLocationTimeoutSubsequentSec = (kMinIntervalMsec / 1000) * 2;
const int kNoLocationPeriodSec = (kMinIntervalMsec / 1000) / 2;
diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
index 6e0887f..39736cc 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
@@ -416,6 +416,70 @@
}
/*
+ * GetLocationLowPower:
+ * Turns on location, waits for at least 5 locations allowing max of LOCATION_TIMEOUT_SUBSEQUENT_SEC
+ * between one location and the next. Also ensure that MIN_INTERVAL_MSEC is respected by waiting
+ * NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
+ * each received location.
+ */
+TEST_F(GnssHalTest, GetLocationLowPower) {
+ if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::LOW_POWER_MODE)) {
+ ALOGI("Test GetLocationLowPower skipped. LOW_POWER_MODE capability not supported.");
+ return;
+ }
+
+ const int kMinIntervalMsec = 5000;
+ const int kLocationTimeoutSubsequentSec = (kMinIntervalMsec / 1000) * 2;
+ const int kNoLocationPeriodSec = (kMinIntervalMsec / 1000) / 2;
+ const int kLocationsToCheck = 5;
+ const bool kLowPowerMode = true;
+
+ // Warmup period - VTS doesn't have AGPS access via GnssLocationProvider
+ gnss_cb_->location_cbq_.reset();
+ StartAndCheckLocations(kLocationsToCheck);
+ StopAndClearLocations();
+ gnss_cb_->location_cbq_.reset();
+
+ // Start of Low Power Mode test
+ SetPositionMode(kMinIntervalMsec, kLowPowerMode);
+
+ // Don't expect true - as without AGPS access
+ if (!StartAndCheckFirstLocation()) {
+ ALOGW("GetLocationLowPower test - no first low power location received.");
+ }
+
+ for (int i = 1; i < kLocationsToCheck; i++) {
+ // Verify that kMinIntervalMsec is respected by waiting kNoLocationPeriodSec and
+ // ensure that no location is received yet
+
+ gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, kNoLocationPeriodSec);
+ const int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+
+ // Tolerate (ignore) one extra location right after the first one
+ // to handle startup edge case scheduling limitations in some implementations
+ if ((i == 1) && (locationCalledCount == 2)) {
+ CheckLocation(gnss_cb_->last_location_, true);
+ continue; // restart the quiet wait period after this too-fast location
+ }
+ EXPECT_LE(locationCalledCount, i);
+ if (locationCalledCount != i) {
+ ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
+ locationCalledCount, i);
+ }
+
+ if (!gnss_cb_->location_cbq_.retrieve(
+ gnss_cb_->last_location_,
+ kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) {
+ ALOGW("GetLocationLowPower test - timeout awaiting location %d", i);
+ } else {
+ CheckLocation(gnss_cb_->last_location_, true);
+ }
+ }
+
+ StopAndClearLocations();
+}
+
+/*
* MapConstellationType:
* Given a GnssConstellationType_2_0 type constellation, maps to its equivalent
* GnssConstellationType_1_0 type constellation. For constellations that do not have
@@ -537,6 +601,8 @@
*/
TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
+ ALOGI("Test BlacklistIndividualSatellites skipped. SATELLITE_BLACKLIST capability"
+ " not supported.");
return;
}
@@ -680,6 +746,7 @@
*/
TEST_F(GnssHalTest, BlacklistConstellation) {
if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
+ ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported.");
return;
}
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index 30b9694..fa5ace6 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -790,7 +790,7 @@
TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) {
mWriter->selectDisplay(mPrimaryDisplay);
mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::ON);
- mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB);
+ mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::NATIVE);
auto handle = allocate();
ASSERT_NE(nullptr, handle);
diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
index 91efc6f..02ab49b 100644
--- a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
@@ -55,11 +55,23 @@
return std::string("V0_SRGB");
case Dataspace::DISPLAY_P3:
return std::string("DISPLAY_P3");
+ case Dataspace::UNKNOWN:
+ return std::string("UNKNOWN");
default:
return std::string("Unsupported dataspace for readback");
}
}
+Dataspace ReadbackHelper::getDataspaceForColorMode(ColorMode mode) {
+ switch (mode) {
+ case ColorMode::DISPLAY_P3:
+ return Dataspace::DISPLAY_P3;
+ case ColorMode::SRGB:
+ default:
+ return Dataspace::UNKNOWN;
+ }
+}
+
LayerSettings TestLayer::toRenderEngineLayerSettings() {
LayerSettings layerSettings;
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
index 5304cd4..9fa1c3c 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
@@ -146,6 +146,8 @@
static std::string getDataspaceString(Dataspace dataspace);
+ static Dataspace getDataspaceForColorMode(ColorMode mode);
+
static int32_t GetBytesPerPixel(PixelFormat pixelFormat);
static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index 72c9496..fd46e37 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -413,12 +413,28 @@
ASSERT_EQ(1, mReader->mCompositionChanges.size());
ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
- // create client target buffer
- uint32_t clientStride;
PixelFormat clientFormat = PixelFormat::RGBA_8888;
uint64_t clientUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN |
BufferUsage::CPU_WRITE_OFTEN |
BufferUsage::COMPOSER_CLIENT_TARGET);
+ Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
+ IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight};
+
+ bool clientTargetSupported = mComposerClient->getClientTargetSupport_2_2(
+ mPrimaryDisplay, layer->mWidth, layer->mHeight, clientFormat, clientDataspace);
+ // if the client target format is not supported, skip this
+ // configuration
+ if (!clientTargetSupported) {
+ std::cout << "Client target configuration width: " << layer->mWidth
+ << " height: " << layer->mHeight
+ << " pixel format: PixelFormat::RGBA_8888 dataspace: "
+ << ReadbackHelper::getDataspaceString(clientDataspace)
+ << " unsupported for display" << std::endl;
+ continue;
+ }
+
+ // create client target buffer
+ uint32_t clientStride;
const native_handle_t* clientBufferHandle =
mGralloc->allocate(layer->mWidth, layer->mHeight, layer->mLayerCount,
clientFormat, clientUsage, /*import*/ true, &clientStride);
@@ -436,8 +452,7 @@
close(clientFence);
}
- IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight};
- mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN,
+ mWriter->setClientTarget(0, clientBufferHandle, clientFence, clientDataspace,
std::vector<IComposerClient::Rect>(1, damage));
layer->setToClientComposition(mWriter);
@@ -507,22 +522,46 @@
ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors));
deviceLayer->write(mWriter);
- auto clientLayer = std::make_shared<TestBufferLayer>(
- mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, mDisplayHeight / 2,
- PixelFormat::RGBA_8888, IComposerClient::Composition::CLIENT);
- IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight};
- clientLayer->setDisplayFrame(clientFrame);
- clientLayer->setZOrder(0);
- clientLayer->write(mWriter);
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
-
- // create client target buffer
- uint32_t clientStride;
PixelFormat clientFormat = PixelFormat::RGBA_8888;
uint64_t clientUsage =
static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
BufferUsage::COMPOSER_CLIENT_TARGET);
+ Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
+ int32_t clientWidth = mDisplayWidth;
+ int32_t clientHeight = mDisplayHeight / 2;
+
+ bool clientTargetSupported = mComposerClient->getClientTargetSupport_2_2(
+ mPrimaryDisplay, clientWidth, clientHeight, clientFormat, clientDataspace);
+ // if the client target format is not supported, skip this
+ // configuration
+ if (!clientTargetSupported) {
+ std::cout << "Client target configuration width: " << clientWidth
+ << " height: " << clientHeight
+ << " pixel format: PixelFormat::RGBA_8888 dataspace: "
+ << ReadbackHelper::getDataspaceString(clientDataspace)
+ << " unsupported for display" << std::endl;
+ continue;
+ }
+
+ auto clientLayer = std::make_shared<TestBufferLayer>(
+ mComposerClient, mGralloc, mPrimaryDisplay, clientWidth, clientHeight,
+ PixelFormat::RGBA_FP16, IComposerClient::Composition::DEVICE);
+ IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight};
+ clientLayer->setDisplayFrame(clientFrame);
+ clientLayer->setZOrder(0);
+ clientLayer->write(mWriter);
+ mWriter->validateDisplay();
+ execute();
+
+ if (mReader->mCompositionChanges.size() != 1) {
+ std::cout << "HWC asked for none or more than 1 composition change, skipping"
+ << std::endl;
+ mReader->mCompositionChanges.clear();
+ continue;
+ }
+ // create client target buffer
+ ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
+ uint32_t clientStride;
const native_handle_t* clientBufferHandle =
mGralloc->allocate(mDisplayWidth, mDisplayHeight, clientLayer->mLayerCount,
clientFormat, clientUsage, /*import*/ true, &clientStride);
@@ -542,19 +581,14 @@
close(clientFence);
}
- mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN,
+ mWriter->setClientTarget(0, clientBufferHandle, clientFence, clientDataspace,
std::vector<IComposerClient::Rect>(1, clientFrame));
- execute();
- ASSERT_EQ(0, mReader->mErrors.size());
+ clientLayer->setToClientComposition(mWriter);
mWriter->validateDisplay();
execute();
- if (mReader->mCompositionChanges.size() != 0) {
- clearCommandReaderState();
- std::cout << "Composition change requested, skipping test" << std::endl;
- GTEST_SUCCEED() << "Composition change requested, skipping test";
- return;
- }
+ ASSERT_EQ(0, mReader->mCompositionChanges.size());
ASSERT_EQ(0, mReader->mErrors.size());
+
mWriter->presentDisplay();
execute();
ASSERT_EQ(0, mReader->mErrors.size());
diff --git a/graphics/composer/2.4/Android.bp b/graphics/composer/2.4/Android.bp
new file mode 100644
index 0000000..0e1bc09
--- /dev/null
+++ b/graphics/composer/2.4/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.graphics.composer@2.4",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "IComposer.hal",
+ "IComposerClient.hal",
+ ],
+ interfaces: [
+ "android.hardware.graphics.common@1.0",
+ "android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
+ "android.hidl.base@1.0",
+ ],
+ gen_java: false,
+}
diff --git a/graphics/composer/2.4/IComposer.hal b/graphics/composer/2.4/IComposer.hal
new file mode 100644
index 0000000..34801da
--- /dev/null
+++ b/graphics/composer/2.4/IComposer.hal
@@ -0,0 +1,34 @@
+/*
+ * 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.composer@2.4;
+
+import IComposerClient;
+
+import @2.1::Error;
+import @2.3::IComposer;
+
+interface IComposer extends @2.3::IComposer {
+
+ /**
+ * Creates a v2.4 client of the composer. Supersedes @2.3::createClient.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * NO_RESOURCES when the client could not be created.
+ * @return client is the newly created client.
+ */
+ createClient_2_4() generates (Error error, IComposerClient client);
+};
diff --git a/graphics/composer/2.4/IComposerClient.hal b/graphics/composer/2.4/IComposerClient.hal
new file mode 100644
index 0000000..8fe0976
--- /dev/null
+++ b/graphics/composer/2.4/IComposerClient.hal
@@ -0,0 +1,51 @@
+/*
+ * 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.composer@2.4;
+
+import @2.1::Display;
+import @2.1::Error;
+import @2.3::IComposerClient;
+
+interface IComposerClient extends @2.3::IComposerClient {
+
+ /**
+ * Required capabilities which are supported by the display. The
+ * particular set of supported capabilities for a given display may be
+ * retrieved using getDisplayCapabilities.
+ */
+ enum DisplayCapability : uint32_t {
+ /**
+ * Indicates that the display supports protected contents.
+ * When returned, hardware composer must be able to accept client target
+ * with protected buffers.
+ */
+ PROTECTED_CONTENTS = 4,
+ };
+
+ /**
+ * Provides a list of supported capabilities (as described in the
+ * definition of DisplayCapability above). This list must not change after
+ * initialization.
+ *
+ * @return error is NONE upon success. Otherwise,
+ * BAD_DISPLAY when an invalid display handle was passed in.
+ * @return capabilities is a list of supported capabilities.
+ */
+ getDisplayCapabilities_2_4(Display display)
+ generates (Error error,
+ vec<DisplayCapability> capabilities);
+};
diff --git a/graphics/composer/2.4/default/Android.bp b/graphics/composer/2.4/default/Android.bp
new file mode 100644
index 0000000..1bf51e0
--- /dev/null
+++ b/graphics/composer/2.4/default/Android.bp
@@ -0,0 +1,47 @@
+//
+// 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_binary {
+ name: "android.hardware.graphics.composer@2.4-service",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ relative_install_path: "hw",
+ srcs: ["service.cpp"],
+ init_rc: ["android.hardware.graphics.composer@2.4-service.rc"],
+ header_libs: [
+ "android.hardware.graphics.composer@2.4-passthrough",
+ ],
+ shared_libs: [
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
+ "android.hardware.graphics.composer@2.4",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "libbase",
+ "libbinder",
+ "libcutils",
+ "libfmq",
+ "libhardware",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwc2on1adapter",
+ "libhwc2onfbadapter",
+ "liblog",
+ "libsync",
+ "libutils",
+ ],
+}
diff --git a/graphics/composer/2.4/default/OWNERS b/graphics/composer/2.4/default/OWNERS
new file mode 100644
index 0000000..cc6d937
--- /dev/null
+++ b/graphics/composer/2.4/default/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+lpy@google.com
+stoza@google.com
+vhau@google.com
diff --git a/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc b/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc
new file mode 100644
index 0000000..a296b0a
--- /dev/null
+++ b/graphics/composer/2.4/default/android.hardware.graphics.composer@2.4-service.rc
@@ -0,0 +1,7 @@
+service vendor.hwcomposer-2-4 /vendor/bin/hw/android.hardware.graphics.composer@2.4-service
+ class hal animation
+ user system
+ group graphics drmrpc
+ capabilities SYS_NICE
+ onrestart restart surfaceflinger
+ writepid /dev/cpuset/system-background/tasks
diff --git a/graphics/composer/2.4/default/service.cpp b/graphics/composer/2.4/default/service.cpp
new file mode 100644
index 0000000..98dac3e
--- /dev/null
+++ b/graphics/composer/2.4/default/service.cpp
@@ -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.
+ */
+
+#include <sched.h>
+
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <binder/ProcessState.h>
+#include <composer-passthrough/2.4/HwcLoader.h>
+#include <hidl/HidlTransportSupport.h>
+
+using android::hardware::graphics::composer::V2_4::IComposer;
+using android::hardware::graphics::composer::V2_4::passthrough::HwcLoader;
+
+int main() {
+ // the conventional HAL might start binder services
+ android::ProcessState::initWithDriver("/dev/vndbinder");
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(4);
+ android::ProcessState::self()->startThreadPool();
+
+ // same as SF main thread
+ struct sched_param param = {0};
+ param.sched_priority = 2;
+ if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK, ¶m) != 0) {
+ ALOGE("Couldn't set SCHED_FIFO: %d", errno);
+ }
+
+ android::hardware::configureRpcThreadpool(4, true /* will join */);
+
+ android::sp<IComposer> composer = HwcLoader::load();
+ if (composer == nullptr) {
+ return 1;
+ }
+ if (composer->registerAsService() != android::NO_ERROR) {
+ ALOGE("failed to register service");
+ return 1;
+ }
+
+ android::hardware::joinRpcThreadpool();
+
+ ALOGE("service is terminating");
+ return 1;
+}
diff --git a/graphics/composer/2.4/utils/OWNERS b/graphics/composer/2.4/utils/OWNERS
new file mode 100644
index 0000000..cc6d937
--- /dev/null
+++ b/graphics/composer/2.4/utils/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+lpy@google.com
+stoza@google.com
+vhau@google.com
diff --git a/graphics/composer/2.4/utils/command-buffer/Android.bp b/graphics/composer/2.4/utils/command-buffer/Android.bp
new file mode 100644
index 0000000..8acf0e1
--- /dev/null
+++ b/graphics/composer/2.4/utils/command-buffer/Android.bp
@@ -0,0 +1,18 @@
+cc_library_headers {
+ name: "android.hardware.graphics.composer@2.4-command-buffer",
+ defaults: ["hidl_defaults"],
+ vendor_available: true,
+ shared_libs: [
+ "android.hardware.graphics.composer@2.4",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.composer@2.4",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
new file mode 100644
index 0000000..6b64c16
--- /dev/null
+++ b/graphics/composer/2.4/utils/command-buffer/include/composer-command-buffer/2.4/ComposerCommandBuffer.h
@@ -0,0 +1,58 @@
+/*
+ * 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
+
+#ifndef LOG_TAG
+#warn "ComposerCommandBuffer.h included without LOG_TAG"
+#endif
+
+#undef LOG_NDEBUG
+#define LOG_NDEBUG 0
+
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+
+using android::hardware::MessageQueue;
+using android::hardware::graphics::composer::V2_1::Error;
+using android::hardware::graphics::composer::V2_4::IComposerClient;
+
+// This class helps build a command queue. Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandWriterBase : public V2_3::CommandWriterBase {
+ public:
+ CommandWriterBase(uint32_t initialMaxSize) : V2_3::CommandWriterBase(initialMaxSize) {}
+};
+
+// This class helps parse a command queue. Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandReaderBase : public V2_3::CommandReaderBase {
+ public:
+ CommandReaderBase() : V2_3::CommandReaderBase(){};
+};
+
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/hal/Android.bp b/graphics/composer/2.4/utils/hal/Android.bp
new file mode 100644
index 0000000..3ee4e19
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/Android.bp
@@ -0,0 +1,36 @@
+//
+// 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_library_headers {
+ name: "android.hardware.graphics.composer@2.4-hal",
+ defaults: ["hidl_defaults"],
+ vendor_available: true,
+ shared_libs: [
+ "android.hardware.graphics.composer@2.4",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.composer@2.4",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.3-hal",
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.3-hal",
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h
new file mode 100644
index 0000000..129bae6
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/Composer.h
@@ -0,0 +1,89 @@
+/*
+ * 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
+
+#ifndef LOG_TAG
+#warning "Composer.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <composer-hal/2.3/Composer.h>
+#include <composer-hal/2.4/ComposerClient.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace hal {
+
+namespace detail {
+
+// ComposerImpl implements V2_*::IComposer on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerImpl : public V2_3::hal::detail::ComposerImpl<Interface, Hal> {
+ public:
+ static std::unique_ptr<ComposerImpl> create(std::unique_ptr<Hal> hal) {
+ return std::make_unique<ComposerImpl>(std::move(hal));
+ }
+
+ explicit ComposerImpl(std::unique_ptr<Hal> hal) : BaseType2_3(std::move(hal)) {}
+
+ // IComposer 2.4 interface
+
+ Return<void> createClient_2_4(IComposer::createClient_2_4_cb hidl_cb) override {
+ std::unique_lock<std::mutex> lock(mClientMutex);
+ if (!waitForClientDestroyedLocked(lock)) {
+ hidl_cb(Error::NO_RESOURCES, nullptr);
+ return Void();
+ }
+
+ sp<ComposerClient> client = ComposerClient::create(mHal.get()).release();
+ if (!client) {
+ hidl_cb(Error::NO_RESOURCES, nullptr);
+ return Void();
+ }
+
+ auto clientDestroyed = [this]() { onClientDestroyed(); };
+ client->setOnClientDestroyed(clientDestroyed);
+
+ mClient = client;
+ hidl_cb(Error::NONE, client);
+ return Void();
+ }
+
+ private:
+ using BaseType2_3 = V2_3::hal::detail::ComposerImpl<Interface, Hal>;
+ using BaseType2_1 = V2_1::hal::detail::ComposerImpl<Interface, Hal>;
+
+ using BaseType2_1::mClient;
+ using BaseType2_1::mClientMutex;
+ using BaseType2_1::mHal;
+ using BaseType2_1::onClientDestroyed;
+ using BaseType2_1::waitForClientDestroyedLocked;
+};
+
+} // namespace detail
+
+using Composer = detail::ComposerImpl<IComposer, ComposerHal>;
+
+} // namespace hal
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
new file mode 100644
index 0000000..7110c80
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerClient.h
@@ -0,0 +1,69 @@
+/*
+ * 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
+
+#ifndef LOG_TAG
+#warning "ComposerClient.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <composer-hal/2.4/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace hal {
+
+namespace detail {
+
+// ComposerClientImpl implements V2_*::IComposerClient on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerClientImpl : public V2_3::hal::detail::ComposerClientImpl<Interface, Hal> {
+ public:
+ ComposerClientImpl(Hal* hal) : BaseType2_3(hal) {}
+
+ Return<void> getDisplayCapabilities_2_4(
+ Display display, IComposerClient::getDisplayCapabilities_2_4_cb hidl_cb) override {
+ std::vector<IComposerClient::DisplayCapability> capabilities;
+ Error error = mHal->getDisplayCapabilities_2_4(display, &capabilities);
+ hidl_cb(error, capabilities);
+ return Void();
+ }
+
+ static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
+ auto client = std::make_unique<ComposerClientImpl>(hal);
+ return client->init() ? std::move(client) : nullptr;
+ }
+
+ private:
+ using BaseType2_3 = V2_3::hal::detail::ComposerClientImpl<Interface, Hal>;
+ using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
+ using BaseType2_1::mHal;
+};
+
+} // namespace detail
+
+using ComposerClient = detail::ComposerClientImpl<IComposerClient, ComposerHal>;
+
+} // namespace hal
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
new file mode 100644
index 0000000..0074808
--- /dev/null
+++ b/graphics/composer/2.4/utils/hal/include/composer-hal/2.4/ComposerHal.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <composer-hal/2.3/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace hal {
+
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::Hdr;
+using common::V1_2::PixelFormat;
+using V2_1::Display;
+using V2_1::Error;
+using V2_1::Layer;
+
+class ComposerHal : public V2_3::hal::ComposerHal {
+ public:
+ virtual Error getDisplayCapabilities_2_4(
+ Display display, std::vector<IComposerClient::DisplayCapability>* outCapabilities) = 0;
+};
+
+} // namespace hal
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/passthrough/Android.bp b/graphics/composer/2.4/utils/passthrough/Android.bp
new file mode 100644
index 0000000..43d9aaa
--- /dev/null
+++ b/graphics/composer/2.4/utils/passthrough/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_library_headers {
+ name: "android.hardware.graphics.composer@2.4-passthrough",
+ defaults: ["hidl_defaults"],
+ vendor: true,
+ header_libs: [
+ "android.hardware.graphics.composer@2.3-passthrough",
+ "android.hardware.graphics.composer@2.4-hal",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.3-passthrough",
+ "android.hardware.graphics.composer@2.4-hal",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
new file mode 100644
index 0000000..65d47d7
--- /dev/null
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcHal.h
@@ -0,0 +1,88 @@
+/*
+ * 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
+
+#ifndef LOG_TAG
+#warning "HwcHal.h included without LOG_TAG"
+#endif
+
+#include <type_traits>
+
+#include <composer-hal/2.4/ComposerHal.h>
+#include <composer-passthrough/2.3/HwcHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace passthrough {
+
+namespace detail {
+
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::Hdr;
+using common::V1_2::PixelFormat;
+using V2_1::Display;
+using V2_1::Error;
+
+// HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2
+template <typename Hal>
+class HwcHalImpl : public V2_3::passthrough::detail::HwcHalImpl<Hal> {
+ public:
+ Error getDisplayCapabilities_2_4(
+ Display display,
+ std::vector<IComposerClient::DisplayCapability>* outCapabilities) override {
+ std::vector<V2_3::IComposerClient::DisplayCapability> capabilities;
+ Error error = BaseType2_3::getDisplayCapabilities(display, &capabilities);
+ if (error != Error::NONE) {
+ return error;
+ }
+ outCapabilities->clear();
+ outCapabilities->reserve(capabilities.size());
+ for (auto capability : capabilities) {
+ outCapabilities->push_back(static_cast<IComposerClient::DisplayCapability>(capability));
+ }
+ return Error::NONE;
+ }
+
+ protected:
+ bool initDispatch() override {
+ if (!BaseType2_3::initDispatch()) {
+ return false;
+ }
+ return true;
+ }
+
+ private:
+ using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl<Hal>;
+ using BaseType2_3 = V2_3::passthrough::detail::HwcHalImpl<Hal>;
+ using BaseType2_1::mDevice;
+};
+
+} // namespace detail
+
+using HwcHal = detail::HwcHalImpl<hal::ComposerHal>;
+
+} // namespace passthrough
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h
new file mode 100644
index 0000000..a7cc588
--- /dev/null
+++ b/graphics/composer/2.4/utils/passthrough/include/composer-passthrough/2.4/HwcLoader.h
@@ -0,0 +1,79 @@
+/*
+ * 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
+
+#ifndef LOG_TAG
+#warning "HwcLoader.h included without LOG_TAG"
+#endif
+
+#include <composer-hal/2.4/Composer.h>
+#include <composer-hal/2.4/ComposerHal.h>
+#include <composer-passthrough/2.3/HwcLoader.h>
+#include <composer-passthrough/2.4/HwcHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace passthrough {
+
+class HwcLoader : public V2_3::passthrough::HwcLoader {
+ public:
+ static IComposer* load() {
+ const hw_module_t* module = loadModule();
+ if (!module) {
+ return nullptr;
+ }
+
+ auto hal = createHalWithAdapter(module);
+ if (!hal) {
+ return nullptr;
+ }
+
+ return createComposer(std::move(hal)).release();
+ }
+
+ // create a ComposerHal instance
+ static std::unique_ptr<hal::ComposerHal> createHal(const hw_module_t* module) {
+ auto hal = std::make_unique<HwcHal>();
+ return hal->initWithModule(module) ? std::move(hal) : nullptr;
+ }
+
+ // create a ComposerHal instance, insert an adapter if necessary
+ static std::unique_ptr<hal::ComposerHal> createHalWithAdapter(const hw_module_t* module) {
+ bool adapted;
+ hwc2_device_t* device = openDeviceWithAdapter(module, &adapted);
+ if (!device) {
+ return nullptr;
+ }
+ auto hal = std::make_unique<HwcHal>();
+ return hal->initWithDevice(std::move(device), !adapted) ? std::move(hal) : nullptr;
+ }
+
+ // create an IComposer instance
+ static std::unique_ptr<IComposer> createComposer(std::unique_ptr<hal::ComposerHal> hal) {
+ return hal::Composer::create(std::move(hal));
+ }
+};
+
+} // namespace passthrough
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp
new file mode 100644
index 0000000..b87a116
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/Android.bp
@@ -0,0 +1,42 @@
+//
+// 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_library_static {
+ name: "android.hardware.graphics.composer@2.4-vts",
+ defaults: ["hidl_defaults"],
+ srcs: [
+ "ComposerVts.cpp",
+ ],
+ static_libs: [
+ "VtsHalHidlTargetTestBase",
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3-vts",
+ "android.hardware.graphics.composer@2.3",
+ "android.hardware.graphics.composer@2.4",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ "android.hardware.graphics.composer@2.2-command-buffer",
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ ],
+ cflags: [
+ "-O0",
+ "-g",
+ "-DLOG_TAG=\"ComposerVts\"",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
new file mode 100644
index 0000000..ee4f3a3
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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 <composer-vts/2.4/ComposerVts.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace vts {
+
+using V2_1::Error;
+
+Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
+
+Composer::Composer(const std::string& name)
+ : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
+
+Composer::Composer(const sp<IComposer>& composer)
+ : V2_3::vts::Composer(composer), mComposer(composer) {}
+
+std::unique_ptr<ComposerClient> Composer::createClient() {
+ std::unique_ptr<ComposerClient> client;
+ mComposer->createClient_2_4([&client](const auto& tmpError, const auto& tmpClient) {
+ ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
+ client = std::make_unique<ComposerClient>(tmpClient);
+ });
+
+ return client;
+}
+
+sp<IComposerClient> ComposerClient::getRaw() const {
+ return mClient;
+}
+
+Error ComposerClient::getDisplayCapabilities(
+ Display display, std::vector<IComposerClient::DisplayCapability>* outCapabilities) {
+ std::vector<IComposerClient::DisplayCapability> capabilities;
+ Error error = Error::NONE;
+ mClient->getDisplayCapabilities_2_4(display,
+ [&](const auto& tmpError, const auto& tmpCapabilities) {
+ error = tmpError;
+ *outCapabilities = tmpCapabilities;
+ });
+ return error;
+}
+
+} // namespace vts
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
new file mode 100644
index 0000000..0a301c6
--- /dev/null
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
@@ -0,0 +1,83 @@
+/*
+ * 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 <memory>
+#include <vector>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
+#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
+#include <composer-vts/2.3/ComposerVts.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace vts {
+
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::Hdr;
+using common::V1_2::PixelFormat;
+using V2_1::Display;
+using V2_1::Error;
+using V2_4::IComposer;
+using V2_4::IComposerClient;
+
+class ComposerClient;
+
+// A wrapper to IComposer.
+class Composer : public V2_3::vts::Composer {
+ public:
+ Composer();
+ explicit Composer(const std::string& name);
+
+ std::unique_ptr<ComposerClient> createClient();
+
+ protected:
+ explicit Composer(const sp<IComposer>& composer);
+
+ private:
+ const sp<IComposer> mComposer;
+};
+
+// A wrapper to IComposerClient.
+class ComposerClient : public V2_3::vts::ComposerClient {
+ public:
+ explicit ComposerClient(const sp<IComposerClient>& client)
+ : V2_3::vts::ComposerClient(client), mClient(client) {}
+
+ sp<IComposerClient> getRaw() const;
+
+ Error getDisplayCapabilities(
+ Display display,
+ std::vector<IComposerClient::DisplayCapability>* outDisplayCapabilities);
+
+ private:
+ const sp<IComposerClient> mClient;
+};
+
+} // namespace vts
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp
new file mode 100644
index 0000000..d437f24
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/Android.bp
@@ -0,0 +1,48 @@
+//
+// 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: "VtsHalGraphicsComposerV2_4TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: ["VtsHalGraphicsComposerV2_4TargetTest.cpp"],
+
+ // TODO(b/64437680): Assume these libs are always available on the device.
+ shared_libs: [
+ "libfmq",
+ "libhidltransport",
+ "libsync",
+ ],
+ static_libs: [
+ "android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.1-vts",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.2-vts",
+ "android.hardware.graphics.composer@2.3",
+ "android.hardware.graphics.composer@2.3-vts",
+ "android.hardware.graphics.composer@2.4",
+ "android.hardware.graphics.composer@2.4-vts",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@2.0-vts",
+ "android.hardware.graphics.mapper@2.1",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ "android.hardware.graphics.composer@2.2-command-buffer",
+ "android.hardware.graphics.composer@2.3-command-buffer",
+ "android.hardware.graphics.composer@2.4-command-buffer",
+ ],
+}
diff --git a/graphics/composer/2.4/vts/functional/OWNERS b/graphics/composer/2.4/vts/functional/OWNERS
new file mode 100644
index 0000000..b3ea6be
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/OWNERS
@@ -0,0 +1,8 @@
+# Graphics team
+lpy@google.com
+stoza@google.com
+vhau@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
new file mode 100644
index 0000000..0fccc58
--- /dev/null
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -0,0 +1,197 @@
+/*
+ * 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 "graphics_composer_hidl_hal_test@2.4"
+
+#include <algorithm>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <composer-command-buffer/2.4/ComposerCommandBuffer.h>
+#include <composer-vts/2.1/GraphicsComposerCallback.h>
+#include <composer-vts/2.1/TestCommandReader.h>
+#include <composer-vts/2.4/ComposerVts.h>
+#include <mapper-vts/2.0/MapperVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_4 {
+namespace vts {
+namespace {
+
+using common::V1_0::BufferUsage;
+using common::V1_1::RenderIntent;
+using common::V1_2::ColorMode;
+using common::V1_2::Dataspace;
+using common::V1_2::PixelFormat;
+using mapper::V2_0::IMapper;
+using mapper::V2_0::vts::Gralloc;
+
+// Test environment for graphics.composer
+class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static GraphicsComposerHidlEnvironment* Instance() {
+ static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<IComposer>(); }
+
+ private:
+ GraphicsComposerHidlEnvironment() {}
+
+ GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment);
+};
+
+class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(
+ mComposer = std::make_unique<Composer>(
+ GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+ ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
+
+ mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
+ mComposerClient->registerCallback(mComposerCallback);
+
+ // assume the first display is primary and is never removed
+ mPrimaryDisplay = waitForFirstDisplay();
+
+ mInvalidDisplayId = GetInvalidDisplayId();
+
+ // explicitly disable vsync
+ mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
+ mComposerCallback->setVsyncAllowed(false);
+
+ mWriter = std::make_unique<CommandWriterBase>(1024);
+ mReader = std::make_unique<V2_1::vts::TestCommandReader>();
+ }
+
+ void TearDown() override {
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_EQ(0, mReader->mCompositionChanges.size());
+ if (mComposerCallback != nullptr) {
+ EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
+ EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
+ EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+ }
+ }
+
+ // returns an invalid display id (one that has not been registered to a
+ // display. Currently assuming that a device will never have close to
+ // std::numeric_limit<uint64_t>::max() displays registered while running tests
+ Display GetInvalidDisplayId() {
+ std::vector<Display> validDisplays = mComposerCallback->getDisplays();
+ uint64_t id = std::numeric_limits<uint64_t>::max();
+ while (id > 0) {
+ if (std::find(validDisplays.begin(), validDisplays.end(), id) == validDisplays.end()) {
+ return id;
+ }
+ id--;
+ }
+
+ return 0;
+ }
+
+ void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+
+ std::unique_ptr<Composer> mComposer;
+ std::unique_ptr<ComposerClient> mComposerClient;
+ sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
+ // the first display and is assumed never to be removed
+ Display mPrimaryDisplay;
+ Display mInvalidDisplayId;
+ std::unique_ptr<CommandWriterBase> mWriter;
+ std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
+
+ private:
+ Display waitForFirstDisplay() {
+ while (true) {
+ std::vector<Display> displays = mComposerCallback->getDisplays();
+ if (displays.empty()) {
+ usleep(5 * 1000);
+ continue;
+ }
+
+ return displays[0];
+ }
+ }
+};
+
+// Tests for IComposerClient::Command.
+class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
+ protected:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::SetUp());
+
+ ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
+
+ mWriter = std::make_unique<CommandWriterBase>(1024);
+ mReader = std::make_unique<V2_1::vts::TestCommandReader>();
+ }
+
+ void TearDown() override {
+ ASSERT_EQ(0, mReader->mErrors.size());
+ ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
+ }
+
+ const native_handle_t* allocate() {
+ IMapper::BufferDescriptorInfo info{};
+ info.width = 64;
+ info.height = 64;
+ info.layerCount = 1;
+ info.format = static_cast<common::V1_0::PixelFormat>(PixelFormat::RGBA_8888);
+ info.usage =
+ static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+
+ return mGralloc->allocate(info);
+ }
+
+ void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+
+ std::unique_ptr<CommandWriterBase> mWriter;
+ std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
+
+ private:
+ std::unique_ptr<Gralloc> mGralloc;
+};
+
+TEST_F(GraphicsComposerHidlTest, getDisplayCapabilitiesBadDisplay) {
+ std::vector<IComposerClient::DisplayCapability> capabilities;
+ const auto error = mComposerClient->getDisplayCapabilities(mInvalidDisplayId, &capabilities);
+ EXPECT_EQ(Error::BAD_DISPLAY, error);
+}
+
+} // namespace
+} // namespace vts
+} // namespace V2_4
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+int main(int argc, char** argv) {
+ using android::hardware::graphics::composer::V2_4::vts::GraphicsComposerHidlEnvironment;
+ ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ return status;
+}
diff --git a/neuralnetworks/1.0/vts/functional/Callbacks.cpp b/neuralnetworks/1.0/vts/functional/Callbacks.cpp
index 2b5723d..37afcf0 100644
--- a/neuralnetworks/1.0/vts/functional/Callbacks.cpp
+++ b/neuralnetworks/1.0/vts/functional/Callbacks.cpp
@@ -14,130 +14,78 @@
* limitations under the License.
*/
+#define LOG_TAG "Callbacks"
+
#include "1.0/Callbacks.h"
+
#include <android-base/logging.h>
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace implementation {
+namespace android::hardware::neuralnetworks::V1_0::implementation {
-CallbackBase::CallbackBase() : mNotified(false) {}
-
-CallbackBase::~CallbackBase() {
- // Note that we cannot call CallbackBase::join_thread from here:
- // CallbackBase is intended to be reference counted, and it is possible that
- // the reference count drops to zero in the bound thread, causing the
- // bound thread to call this destructor. If a thread tries to join
- // itself, it throws an exception, producing a message like the
- // following:
- //
- // terminating with uncaught exception of type std::__1::system_error:
- // thread::join failed: Resource deadlock would occur
-}
-
-void CallbackBase::wait() {
- std::unique_lock<std::mutex> lock(mMutex);
- mCondition.wait(lock, [this]{return mNotified;});
- join_thread_locked();
-}
-
-bool CallbackBase::on_finish(std::function<bool(void)> post_work) {
- std::lock_guard<std::mutex> lock(mMutex);
- if (mPostWork != nullptr) {
- LOG(ERROR) << "CallbackBase::on_finish -- a post-work function has already been bound to "
- "this callback object";
- return false;
- }
- if (post_work == nullptr) {
- LOG(ERROR) << "CallbackBase::on_finish -- the new post-work function is invalid";
- return false;
- }
- mPostWork = std::move(post_work);
- return true;
-}
-
-bool CallbackBase::bind_thread(std::thread&& asyncThread) {
- std::lock_guard<std::mutex> lock(mMutex);
- if (mThread.joinable()) {
- LOG(ERROR) << "CallbackBase::bind_thread -- a thread has already been bound to this "
- "callback object";
- return false;
- }
- if (!asyncThread.joinable()) {
- LOG(ERROR) << "CallbackBase::bind_thread -- the new thread is not joinable";
- return false;
- }
- mThread = std::move(asyncThread);
- return true;
-}
-
-void CallbackBase::join_thread() {
- std::lock_guard<std::mutex> lock(mMutex);
- join_thread_locked();
-}
-
-void CallbackBase::notify() {
- {
- std::lock_guard<std::mutex> lock(mMutex);
- mNotified = true;
- if (mPostWork != nullptr) {
- bool success = mPostWork();
- if (!success) {
- LOG(ERROR) << "CallbackBase::notify -- post work failed";
- }
- }
- }
- mCondition.notify_all();
-}
-
-void CallbackBase::join_thread_locked() {
- if (mThread.joinable()) {
- mThread.join();
- }
-}
-
-PreparedModelCallback::PreparedModelCallback() :
- mErrorStatus(ErrorStatus::GENERAL_FAILURE), mPreparedModel(nullptr) {}
-
-PreparedModelCallback::~PreparedModelCallback() {}
+// PreparedModelCallback methods begin here
Return<void> PreparedModelCallback::notify(ErrorStatus errorStatus,
- const sp<V1_0::IPreparedModel>& preparedModel) {
- mErrorStatus = errorStatus;
- mPreparedModel = preparedModel;
- CallbackBase::notify();
+ const sp<IPreparedModel>& preparedModel) {
+ {
+ std::lock_guard<std::mutex> hold(mMutex);
+
+ // quick-return if object has already been notified
+ if (mNotified) {
+ return Void();
+ }
+
+ // store results and mark as notified
+ mErrorStatus = errorStatus;
+ mPreparedModel = preparedModel;
+ mNotified = true;
+ }
+
+ mCondition.notify_all();
return Void();
}
-ErrorStatus PreparedModelCallback::getStatus() {
+void PreparedModelCallback::wait() const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCondition.wait(lock, [this] { return mNotified; });
+}
+
+ErrorStatus PreparedModelCallback::getStatus() const {
wait();
return mErrorStatus;
}
-sp<V1_0::IPreparedModel> PreparedModelCallback::getPreparedModel() {
+sp<IPreparedModel> PreparedModelCallback::getPreparedModel() const {
wait();
return mPreparedModel;
}
-ExecutionCallback::ExecutionCallback() : mErrorStatus(ErrorStatus::GENERAL_FAILURE) {}
-
-ExecutionCallback::~ExecutionCallback() {}
+// ExecutionCallback methods begin here
Return<void> ExecutionCallback::notify(ErrorStatus errorStatus) {
- mErrorStatus = errorStatus;
- CallbackBase::notify();
+ {
+ std::lock_guard<std::mutex> hold(mMutex);
+
+ // quick-return if object has already been notified
+ if (mNotified) {
+ return Void();
+ }
+
+ mErrorStatus = errorStatus;
+ mNotified = true;
+ }
+ mCondition.notify_all();
+
return Void();
}
-ErrorStatus ExecutionCallback::getStatus() {
+void ExecutionCallback::wait() const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCondition.wait(lock, [this] { return mNotified; });
+}
+
+ErrorStatus ExecutionCallback::getStatus() const {
wait();
return mErrorStatus;
}
-} // namespace implementation
-} // namespace V1_0
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::neuralnetworks::V1_0::implementation
diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h b/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h
index 36318ea..820bb10 100644
--- a/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h
+++ b/neuralnetworks/1.0/vts/functional/include/1.0/Callbacks.h
@@ -17,310 +17,187 @@
#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H
#define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H
+#include <android-base/thread_annotations.h>
#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
#include <hidl/Status.h>
-#include <chrono>
#include <condition_variable>
-#include <functional>
#include <mutex>
-#include <thread>
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_0 {
-namespace implementation {
-
-/**
- * The CallbackBase class is used internally by the NeuralNetworks runtime to
+/*
+ * The Callback classes are used internally by the NeuralNetworks runtime to
* synchronize between different threads. An asynchronous task is launched
* paired with a callback object. When a client thread requires the output being
* generated by the asynchronous task, the client thread can wait for the result
- * and be blocked until it has completed or a timeout condition has been
- * reached. Any wait* may safely be called concurrently, even on the same
- * callback object. When the asynchronous task has finished its workload, it
- * must immediately call "notify". If the asynchronous task has failed to launch,
- * the function that tried to launch the asynchronous task must immediately call
- * "notify". This "notify" call awakens any client threads waiting on the
- * callback object.
+ * and be blocked until it has completed. Any wait may safely be called
+ * concurrently, even on the same callback object. When the asynchronous task
+ * has finished its workload, it must immediately call "notify". If the
+ * asynchronous task has failed to launch, the function that tried to launch the
+ * asynchronous task must immediately call "notify". This "notify" call
+ * awakens any client threads waiting on the callback object.
*
- * The CallbackBase class implements some of the base synchronization common to
- * both PrepareModelCallback and ExecutionCallback. For consistency, any HIDL
- * callback class must inherit from CallbackBase as well as the HIDL callback
- * interface it implements.
- *
- * This class exists to enable synchronization across HIDL. When synchronization
- * is only required in the same process, consider using std::future, std::mutex,
- * std::condition_variable, or std::experimental::latch instead.
+ * These classes exist to enable synchronization across HIDL. When
+ * synchronization is only required in the same process, consider using
+ * std::future, std::mutex, std::condition_variable, or std::experimental::latch
+ * instead.
*/
-class CallbackBase {
- public:
- CallbackBase();
- ~CallbackBase();
- /**
- * CallbackBase::wait blocks until notify has been called on the callback
- * object.
- */
- void wait();
-
- /**
- * CallbackBase::wait_for blocks until notify has been called on the
- * callback object or the time duration from the time the wait_for function
- * was called has expired, whichever comes first.
- *
- * @return Status std::cv_status::no_timeout if the callback was notified
- * before the time duration expired, std::cv_status::timeout
- * otherwise.
- */
- template <class Rep, class Period>
- std::cv_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration);
-
- /**
- * CallbackBase::on_finish binds a function to the callback object. This
- * bound function will be executed when CallbackBase::notify is called,
- * before any calls to wait* return. (Note that CallbackBase::wait_for can
- * return std::cv_status::timeout before CallbackBase::notify is called for
- * the first time, and hence before the bound function is executed.)
- *
- * The bound function must not synchronize with or otherwise access the
- * callback object it is bound to, as this could cause a deadlock.
- *
- * CallbackBase::on_finish can be called at most once on a given callback
- * object, and the call to CallbackBase::on_finish must finish before
- * CallbackBase::notify is called.
- *
- * @param post_work Function to be invoked the first time
- * CallbackBase::notify is called. Must have a target --
- * i.e., must not compare equal to nullptr. post_work
- * returns true if it successfully completes, false if it
- * fails.
- * @return bool True if the function was successfully bound, false if
- * unsuccessful.
- *
- * TODO: Why does the return value of the callback matter?
- */
- bool on_finish(std::function<bool(void)> post_work);
-
- /**
- * CallbackBase::bind_thread binds a thread to the event for later use by
- * CallbackBase::join_thread.
- *
- * The thread must be passed using std::move.
- *
- * Once a thread is bound with CallbackBase::bind_thread, the client code
- * should ensure that one of the following occurs before the event is
- * destroyed:
- * - CallbackBase::join_thread has been called.
- * - CallbackBase::wait has been called.
- * - CallbackBase::wait_for has been called and returned other than
- * std::cv_status::no_timeout.
- *
- * The bound thread shall not call any CallbackBase method with the
- * exception of CallbackBase::notify, which it must call when the thread has
- * finished its computation.
- *
- * CallbackBase::bind_thread can be called at most once on a given callback
- * object.
- *
- * @param asyncThread Thread to be bound to the callback object. The thread
- * object must represent a thread of execution -- i.e.,
- * asyncThread.joinable() must be true.
- * @return bool True if successful, false if thread was not properly bound.
- */
- bool bind_thread(std::thread&& asyncThread);
-
- /**
- * CallbackBase::join_thread ensures that the thread (if any) bound to this
- * event with CallbackBase::bind_thread has fully finished and cleaned its
- * resources. It is legal to call this function multiple times, concurrently
- * or sequentially.
- */
- void join_thread();
-
- protected:
- /**
- * CallbackBase::notify enables all prior and future wait* calls on the
- * callback object to proceed. The call to CallbackBase::notify happens
- * before any wait* calls on this callback object return (except in the case
- * of wait_for timing out). The asynchronous call the callback object is
- * paired with must ensure that any update to state that should be visible
- * to the caller of wait* happens before the call to CallbackBase::notify.
- *
- * CallbackBase::notify must be called exactly once on a given callback
- * object.
- */
- void notify();
-
- private:
- // Same as CallbackBase::join_thread but assumes we already hold a lock on
- // mMutex.
- void join_thread_locked();
-
- bool mNotified;
- std::mutex mMutex;
- std::condition_variable mCondition;
- std::function<bool(void)> mPostWork;
- std::thread mThread;
-};
+namespace android::hardware::neuralnetworks::V1_0::implementation {
/**
* The PreparedModelCallback class is used to receive the error status of
* preparing a model as well as the prepared model from a task executing
- * asynchronously with respect to the runtime. If a calling thread calls wait*
+ * asynchronously with respect to the runtime. If a calling thread calls wait
* or get* on a PreparedModelCallback object and the corresponding asynchronous
* task has not finished preparing the model, the calling thread will block
- * until the asynchronous task has called notify. For more information on the
- * synchronization behavior, refer to the CallbackBase class.
+ * until the asynchronous task has called notify.
*
- * This class inherits the basic blocking and signaling calls from
- * CallbackBase, and implements the HIDL notify call from
- * IPreparedModelCallback. This callback object is passed as an argument to
- * IDevice::prepareModel.
+ * If the callback object is notified more than once, only the results of the
+ * first call to notify are used, and the results from subsequent calls are
+ * discarded.
+ *
+ * This callback object is passed as an argument to IDevice::prepareModel*.
*/
-class PreparedModelCallback : public CallbackBase, public IPreparedModelCallback {
+class PreparedModelCallback : public IPreparedModelCallback {
public:
- PreparedModelCallback();
- ~PreparedModelCallback() override;
-
/**
* IPreparedModelCallback::notify marks the callback object with the return
* status of the asynchronous model preparation along with the prepared
- * model and calls CallbackBase::notify, enabling all prior and future
- * wait* calls on the PreparedModelCallback object to proceed.
- * For more information on the synchronization behavior, refer to the
- * CallbackBase class.
+ * model, and allows all prior and future wait calls on the
+ * PreparedModelCallback object to proceed.
*
- * IPreparedModelCallback::notify must be called exactly once on a given
+ * IPreparedModelCallback::notify must be called on a given
* PreparedModelCallback object.
*
+ * If the callback object is notified more than once, only the results of
+ * the first call to notify are used, and the results from subsequent calls
+ * are discarded.
+ *
* @param status Error status returned from asynchronously preparing the
- * model; will be:
- * - NONE if the asynchronous preparation was successful
- * - DEVICE_UNAVAILABLE if driver is offline or busy
- * - GENERAL_FAILURE if there is an unspecified error
- * - INVALID_ARGUMENT if the input model is invalid
+ * model; will be:
+ * - NONE if the asynchronous preparation was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if the input model is invalid
* @param preparedModel Returned model that has been prepared for execution,
- * nullptr if the model was unable to be prepared.
+ * nullptr if the model was unable to be prepared.
*/
- Return<void> notify(ErrorStatus status, const sp<V1_0::IPreparedModel>& preparedModel) override;
+ Return<void> notify(ErrorStatus status, const sp<IPreparedModel>& preparedModel) override;
+
+ /**
+ * PreparedModelCallback::wait blocks until notify has been called on the
+ * callback object.
+ */
+ void wait() const;
/**
* Retrieves the error status returned from the asynchronous task launched
- * by IDevice::prepareModel. If IDevice::prepareModel has not finished
+ * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished
* asynchronously preparing the model, this call will block until the
* asynchronous task notifies the object.
*
* @return status Error status returned from asynchronously preparing the
- * model; will be:
- * - NONE if the asynchronous preparation was successful
- * - DEVICE_UNAVAILABLE if driver is offline or busy
- * - GENERAL_FAILURE if there is an unspecified error
- * - INVALID_ARGUMENT if the input model is invalid
+ * model; will be:
+ * - NONE if the asynchronous preparation was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if the input model is invalid
*/
- ErrorStatus getStatus();
+ ErrorStatus getStatus() const;
/**
* Retrieves the model that has been prepared for execution from the
- * asynchronous task launched by IDevice::prepareModel. If
- * IDevice::prepareModel has not finished asynchronously preparing the
+ * asynchronous task launched by IDevice::prepareModel*. If
+ * IDevice::prepareModel* has not finished asynchronously preparing the
* model, this call will block until the asynchronous task notifies the
* object.
*
* @return preparedModel Returned model that has been prepared for
- * execution, nullptr if the model was unable to be
- * prepared.
+ * execution, nullptr if the model was unable to be prepared.
*/
- sp<V1_0::IPreparedModel> getPreparedModel();
+ sp<IPreparedModel> getPreparedModel() const;
private:
- ErrorStatus mErrorStatus;
- sp<V1_0::IPreparedModel> mPreparedModel;
+ mutable std::mutex mMutex;
+ mutable std::condition_variable mCondition;
+ bool mNotified GUARDED_BY(mMutex) = false;
+ ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
+ sp<IPreparedModel> mPreparedModel;
};
/**
- * The ExecutionCallback class is used to receive the error status of the
- * execution from a task executing asynchronously with respect to the runtime.
- * If a calling thread calls wait* or get* on a PreparedModelCallback object and
- * the corresponding asynchronous task has not finished the execution, the
- * calling thread will block until the asynchronous task has called notify.
- * For more information on the synchronization behavior, refer to the
- * CallbackBase class.
+ * The ExecutionCallback class is used to receive the results of the execution
+ * from a task executing asynchronously with respect to the runtime. If a
+ * calling thread calls wait or get* on a ExecutionCallback object and the
+ * corresponding asynchronous task has not finished the execution, the calling
+ * thread will block until the asynchronous task has called notify.
*
- * This class inherits the basic blocking and signaling calls from
- * CallbackBase, and implements the HIDL notify call from IExecutionCallback.
- * This callback object is passed as an argument to IPreparedModel::execute.
+ * If the callback object is notified more than once, only the results of the
+ * first call to notify are used, and the results from subsequent calls are
+ * discarded.
+ *
+ * This callback object is passed as an argument to IPreparedModel::execute*.
*/
-class ExecutionCallback : public CallbackBase, public IExecutionCallback {
+class ExecutionCallback : public IExecutionCallback {
public:
- ExecutionCallback();
- ~ExecutionCallback() override;
-
/**
* IExecutionCallback::notify marks the callback object with the return
- * status of the asynchronous execution that held this callback and enable
- * all prior and future wait* calls on the ExecutionCallback object to
- * proceed. For more information on the synchronization behavior, refer to
- * the CallbackBase class.
+ * status of the asynchronous execution that held this callback and enables
+ * all prior and future wait calls on the ExecutionCallback object to
+ * proceed.
*
- * IExecutionCallback::notify must be called exactly once on a given
- * ExecutionCallback object.
+ * IExecutionCallback::notify must be called on a given ExecutionCallback
+ * object.
+ *
+ * If the callback object is notified more than once, only the results of
+ * the first call to notify are used, and the results from subsequent calls
+ * are discarded.
*
* @param status Error status returned from launching the asynchronous task
- * (if the launch fails) or from the asynchronous task itself
- * (if the launch succeeds). Must be:
- * - NONE if the asynchronous execution was successful
- * - DEVICE_UNAVAILABLE if driver is offline or busy
- * - GENERAL_FAILURE if there is an unspecified error
- * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is
- * not large enough to store the resultant values
- * - INVALID_ARGUMENT if the input request is invalid
+ * (if the launch fails) or from the asynchronous task itself (if the
+ * launch succeeds). Must be:
+ * - NONE if the asynchronous execution was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large
+ * enough to store the resultant values
+ * - INVALID_ARGUMENT if the input request is invalid
*/
Return<void> notify(ErrorStatus status) override;
/**
+ * ExecutionCallback::wait blocks until notify has been called on the
+ * callback object.
+ */
+ void wait() const;
+
+ /**
* Retrieves the error status returned from the asynchronous task launched
* by IPreparedModel::execute. If IPreparedModel::execute has not finished
* asynchronously executing, this call will block until the asynchronous
* task notifies the object.
*
* @return status Error status returned from launching the asynchronous task
- * (if the launch fails) or from the asynchronous task itself
- * (if the launch succeeds). Must be:
- * - NONE if the asynchronous execution was successful
- * - DEVICE_UNAVAILABLE if driver is offline or busy
- * - GENERAL_FAILURE if the asynchronous task resulted in an
- * unspecified error
- * - OUTPUT_INSUFFICIENT_SIZE if at least one output
- * operand buffer is not large enough to store the
- * corresponding output
- * - INVALID_ARGUMENT if one of the input arguments to
- * prepareModel is invalid
+ * (if the launch fails) or from the asynchronous task itself (if the
+ * launch succeeds). Must be:
+ * - NONE if the asynchronous execution was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified
+ * error
+ * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is
+ * not large enough to store the corresponding output
+ * - INVALID_ARGUMENT if one of the input arguments to prepareModel is
+ * invalid
*/
- ErrorStatus getStatus();
+ ErrorStatus getStatus() const;
private:
+ mutable std::mutex mMutex;
+ mutable std::condition_variable mCondition;
+ bool mNotified GUARDED_BY(mMutex) = false;
ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
};
-// template function implementation(s) below this point
-
-template <class Rep, class Period>
-std::cv_status CallbackBase::wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) {
- std::unique_lock<std::mutex> lock(mMutex);
- std::cv_status status =
- mCondition.wait_for(lock, timeout_duration, [this] { return mNotified; });
- if (status != std::cv_status::timeout) {
- join_thread_locked();
- }
- return status;
-}
-
-} // namespace implementation
-} // namespace V1_0
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::neuralnetworks::V1_0::implementation
#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_0_CALLBACKS_H
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index b48646f..31b8532 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -56,9 +56,6 @@
"GeneratedTestsV1_0.cpp",
"ValidateBurst.cpp",
],
- cflags: [
- "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE"
- ],
}
// Tests for V1_1 models using the V1_2 HAL.
@@ -69,9 +66,6 @@
"GeneratedTestsV1_1.cpp",
"ValidateBurst.cpp",
],
- cflags: [
- "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE"
- ],
}
// Tests for V1_2 models.
@@ -84,9 +78,6 @@
"GeneratedTestsV1_2.cpp",
"ValidateBurst.cpp",
],
- cflags: [
- "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE"
- ],
}
cc_test {
@@ -98,7 +89,6 @@
"ValidateBurst.cpp",
],
cflags: [
- "-DNN_TEST_DYNAMIC_OUTPUT_SHAPE",
"-DPRESUBMIT_NOT_VTS",
],
}
diff --git a/neuralnetworks/1.2/vts/functional/Callbacks.cpp b/neuralnetworks/1.2/vts/functional/Callbacks.cpp
index cfaf91d..a607a08 100644
--- a/neuralnetworks/1.2/vts/functional/Callbacks.cpp
+++ b/neuralnetworks/1.2/vts/functional/Callbacks.cpp
@@ -14,160 +14,128 @@
* limitations under the License.
*/
+#define LOG_TAG "Callbacks"
+
#include "1.2/Callbacks.h"
+
#include <android-base/logging.h>
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace implementation {
+#include <limits>
-CallbackBase::CallbackBase() : mNotified(false) {}
+namespace android::hardware::neuralnetworks::V1_2::implementation {
-CallbackBase::~CallbackBase() {
- // Note that we cannot call CallbackBase::join_thread from here:
- // CallbackBase is intended to be reference counted, and it is possible that
- // the reference count drops to zero in the bound thread, causing the
- // bound thread to call this destructor. If a thread tries to join
- // itself, it throws an exception, producing a message like the
- // following:
- //
- // terminating with uncaught exception of type std::__1::system_error:
- // thread::join failed: Resource deadlock would occur
-}
+constexpr Timing kNoTiming = {.timeOnDevice = std::numeric_limits<uint64_t>::max(),
+ .timeInDriver = std::numeric_limits<uint64_t>::max()};
-void CallbackBase::wait() {
- std::unique_lock<std::mutex> lock(mMutex);
- mCondition.wait(lock, [this] { return mNotified; });
- join_thread_locked();
-}
-
-bool CallbackBase::on_finish(std::function<bool(void)> post_work) {
- std::lock_guard<std::mutex> lock(mMutex);
- if (mPostWork != nullptr) {
- LOG(ERROR) << "CallbackBase::on_finish -- a post-work function has already been bound to "
- "this callback object";
- return false;
- }
- if (post_work == nullptr) {
- LOG(ERROR) << "CallbackBase::on_finish -- the new post-work function is invalid";
- return false;
- }
- mPostWork = std::move(post_work);
- return true;
-}
-
-bool CallbackBase::bind_thread(std::thread&& asyncThread) {
- std::lock_guard<std::mutex> lock(mMutex);
- if (mThread.joinable()) {
- LOG(ERROR) << "CallbackBase::bind_thread -- a thread has already been bound to this "
- "callback object";
- return false;
- }
- if (!asyncThread.joinable()) {
- LOG(ERROR) << "CallbackBase::bind_thread -- the new thread is not joinable";
- return false;
- }
- mThread = std::move(asyncThread);
- return true;
-}
-
-void CallbackBase::join_thread() {
- std::lock_guard<std::mutex> lock(mMutex);
- join_thread_locked();
-}
-
-void CallbackBase::notify() {
- {
- std::lock_guard<std::mutex> lock(mMutex);
- mNotified = true;
- if (mPostWork != nullptr) {
- bool success = mPostWork();
- if (!success) {
- LOG(ERROR) << "CallbackBase::notify -- post work failed";
- }
- }
- }
- mCondition.notify_all();
-}
-
-void CallbackBase::join_thread_locked() {
- if (mThread.joinable()) {
- mThread.join();
- }
-}
-
-PreparedModelCallback::PreparedModelCallback()
- : mErrorStatus(ErrorStatus::GENERAL_FAILURE), mPreparedModel(nullptr) {}
-
-PreparedModelCallback::~PreparedModelCallback() {}
+// PreparedModelCallback methods begin here
Return<void> PreparedModelCallback::notify(ErrorStatus errorStatus,
const sp<V1_0::IPreparedModel>& preparedModel) {
- mErrorStatus = errorStatus;
- mPreparedModel = preparedModel;
- CallbackBase::notify();
+ {
+ std::lock_guard<std::mutex> hold(mMutex);
+
+ // quick-return if object has already been notified
+ if (mNotified) {
+ return Void();
+ }
+
+ // store results and mark as notified
+ mErrorStatus = errorStatus;
+ mPreparedModel = preparedModel;
+ mNotified = true;
+ }
+
+ mCondition.notify_all();
return Void();
}
Return<void> PreparedModelCallback::notify_1_2(ErrorStatus errorStatus,
const sp<V1_2::IPreparedModel>& preparedModel) {
- mErrorStatus = errorStatus;
- mPreparedModel = preparedModel;
- CallbackBase::notify();
- return Void();
+ return notify(errorStatus, preparedModel);
}
-ErrorStatus PreparedModelCallback::getStatus() {
+void PreparedModelCallback::wait() const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCondition.wait(lock, [this] { return mNotified; });
+}
+
+ErrorStatus PreparedModelCallback::getStatus() const {
wait();
return mErrorStatus;
}
-sp<V1_0::IPreparedModel> PreparedModelCallback::getPreparedModel() {
+sp<V1_0::IPreparedModel> PreparedModelCallback::getPreparedModel() const {
wait();
return mPreparedModel;
}
-ExecutionCallback::ExecutionCallback() : mErrorStatus(ErrorStatus::GENERAL_FAILURE) {}
-
-ExecutionCallback::~ExecutionCallback() {}
+// ExecutionCallback methods begin here
Return<void> ExecutionCallback::notify(ErrorStatus errorStatus) {
- mErrorStatus = errorStatus;
- mOutputShapes = {};
- mTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX};
- CallbackBase::notify();
+ notifyInternal(errorStatus, {}, kNoTiming);
return Void();
}
Return<void> ExecutionCallback::notify_1_2(ErrorStatus errorStatus,
const hidl_vec<OutputShape>& outputShapes,
const Timing& timing) {
- mErrorStatus = errorStatus;
- mOutputShapes = outputShapes;
- mTiming = timing;
- CallbackBase::notify();
+ if (errorStatus == ErrorStatus::OUTPUT_INSUFFICIENT_SIZE) {
+ // outputShapes must not be empty if OUTPUT_INSUFFICIENT_SIZE.
+ if (outputShapes.size() == 0) {
+ LOG(ERROR) << "Notified with empty output shape vector when OUTPUT_INSUFFICIENT_SIZE";
+ notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming);
+ return Void();
+ }
+ } else if (errorStatus != ErrorStatus::NONE) {
+ // outputShapes must be empty if errorStatus is neither NONE nor OUTPUT_INSUFFICIENT_SIZE.
+ if (outputShapes.size() != 0) {
+ LOG(ERROR) << "Notified with non-empty output shape vector when error status is "
+ "neither NONE nor OUTPUT_INSUFFICIENT_SIZE";
+ notifyInternal(ErrorStatus::GENERAL_FAILURE, {}, kNoTiming);
+ return Void();
+ }
+ }
+ notifyInternal(errorStatus, outputShapes, timing);
return Void();
}
-ErrorStatus ExecutionCallback::getStatus() {
+void ExecutionCallback::wait() const {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCondition.wait(lock, [this] { return mNotified; });
+}
+
+ErrorStatus ExecutionCallback::getStatus() const {
wait();
return mErrorStatus;
}
-const std::vector<OutputShape>& ExecutionCallback::getOutputShapes() {
+const std::vector<OutputShape>& ExecutionCallback::getOutputShapes() const {
wait();
return mOutputShapes;
}
-Timing ExecutionCallback::getTiming() {
+Timing ExecutionCallback::getTiming() const {
wait();
return mTiming;
}
-} // namespace implementation
-} // namespace V1_2
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
+void ExecutionCallback::notifyInternal(ErrorStatus errorStatus,
+ const hidl_vec<OutputShape>& outputShapes,
+ const Timing& timing) {
+ {
+ std::lock_guard<std::mutex> hold(mMutex);
+
+ // quick-return if object has already been notified
+ if (mNotified) {
+ return;
+ }
+
+ mErrorStatus = errorStatus;
+ mOutputShapes = outputShapes;
+ mTiming = timing;
+ mNotified = true;
+ }
+ mCondition.notify_all();
+}
+
+} // namespace android::hardware::neuralnetworks::V1_2::implementation
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index b66dd64..8711f47 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -26,6 +26,7 @@
#include <cstdio>
#include <cstdlib>
#include <random>
+#include <thread>
#include "1.2/Callbacks.h"
#include "GeneratedTestHarness.h"
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp
index 1928b8c..6e03534 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestsV1_2.cpp
@@ -46,21 +46,6 @@
// in frameworks/ml/nn/runtime/tests/generated/
#include "vts/V1_2/all_generated_V1_2_vts_tests.cpp"
-// Generated from spec/strided_slice_invalid_output_dims.mod.py.
-// TODO(b/132155416): Make this part of all_generated_V1_2_vts_tests.cpp.
-namespace strided_slice_invalid_output_dims {
-#include "generated/strided_slice_invalid_output_dims.example.cpp"
-#include "generated/strided_slice_invalid_output_dims.model.cpp"
-} // namespace strided_slice_invalid_output_dims
-
-// TODO(b/132155416): Make this part of all_generated_V1_2_vts_tests.cpp.
-TEST_F(ValidationTest, strided_slice_invalid_output_dims) {
- const Model model = strided_slice_invalid_output_dims::createTestModel();
- const std::vector<Request> requests =
- createRequests(strided_slice_invalid_output_dims::get_examples());
- validateFailure(model, requests);
-}
-
} // namespace functional
} // namespace vts
} // namespace V1_2
diff --git a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp b/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp
deleted file mode 100644
index 0640833..0000000
--- a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.example.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-// clang-format off
-// Generated file (from: strided_slice_invalid_output_dims.mod.py). Do not edit
-std::vector<MixedTypedExample>& get_examples() {
-static std::vector<MixedTypedExample> examples = {
-// Begin of an example
-{
-.operands = {
-//Input(s)
-{ // See tools/test_generator/include/TestHarness.h:MixedTyped
- // int -> Dimensions map
- .operandDimensions = {{0, {2, 3}}},
- // int -> FLOAT32 map
- .float32Operands = {{0, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}}},
- // int -> INT32 map
- .int32Operands = {},
- // int -> QUANT8_ASYMM map
- .quant8AsymmOperands = {},
- // int -> QUANT16_SYMM map
- .quant16SymmOperands = {},
- // int -> FLOAT16 map
- .float16Operands = {},
- // int -> BOOL8 map
- .bool8Operands = {},
- // int -> QUANT8_SYMM_PER_CHANNEL map
- .quant8ChannelOperands = {},
- // int -> QUANT16_ASYMM map
- .quant16AsymmOperands = {},
- // int -> QUANT8_SYMM map
- .quant8SymmOperands = {},
-},
-//Output(s)
-{ // See tools/test_generator/include/TestHarness.h:MixedTyped
- // int -> Dimensions map
- .operandDimensions = {{0, {3}}},
- // int -> FLOAT32 map
- .float32Operands = {{0, {1.0f, 2.0f, 3.0f}}},
- // int -> INT32 map
- .int32Operands = {},
- // int -> QUANT8_ASYMM map
- .quant8AsymmOperands = {},
- // int -> QUANT16_SYMM map
- .quant16SymmOperands = {},
- // int -> FLOAT16 map
- .float16Operands = {},
- // int -> BOOL8 map
- .bool8Operands = {},
- // int -> QUANT8_SYMM_PER_CHANNEL map
- .quant8ChannelOperands = {},
- // int -> QUANT16_ASYMM map
- .quant16AsymmOperands = {},
- // int -> QUANT8_SYMM map
- .quant8SymmOperands = {},
-}
-},
-}, // End of an example
-};
-return examples;
-};
-
-std::vector<MixedTypedExample>& get_examples_dynamic_output_shape() {
-static std::vector<MixedTypedExample> examples_dynamic_output_shape = {
-// Begin of an example
-{
-.operands = {
-//Input(s)
-{ // See tools/test_generator/include/TestHarness.h:MixedTyped
- // int -> Dimensions map
- .operandDimensions = {{0, {2, 3}}},
- // int -> FLOAT32 map
- .float32Operands = {{0, {1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f}}},
- // int -> INT32 map
- .int32Operands = {},
- // int -> QUANT8_ASYMM map
- .quant8AsymmOperands = {},
- // int -> QUANT16_SYMM map
- .quant16SymmOperands = {},
- // int -> FLOAT16 map
- .float16Operands = {},
- // int -> BOOL8 map
- .bool8Operands = {},
- // int -> QUANT8_SYMM_PER_CHANNEL map
- .quant8ChannelOperands = {},
- // int -> QUANT16_ASYMM map
- .quant16AsymmOperands = {},
- // int -> QUANT8_SYMM map
- .quant8SymmOperands = {},
-},
-//Output(s)
-{ // See tools/test_generator/include/TestHarness.h:MixedTyped
- // int -> Dimensions map
- .operandDimensions = {{0, {3}}},
- // int -> FLOAT32 map
- .float32Operands = {{0, {1.0f, 2.0f, 3.0f}}},
- // int -> INT32 map
- .int32Operands = {},
- // int -> QUANT8_ASYMM map
- .quant8AsymmOperands = {},
- // int -> QUANT16_SYMM map
- .quant16SymmOperands = {},
- // int -> FLOAT16 map
- .float16Operands = {},
- // int -> BOOL8 map
- .bool8Operands = {},
- // int -> QUANT8_SYMM_PER_CHANNEL map
- .quant8ChannelOperands = {},
- // int -> QUANT16_ASYMM map
- .quant16AsymmOperands = {},
- // int -> QUANT8_SYMM map
- .quant8SymmOperands = {},
-}
-},
-}, // End of an example
-};
-return examples_dynamic_output_shape;
-};
-
diff --git a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp b/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp
deleted file mode 100644
index 106655a..0000000
--- a/neuralnetworks/1.2/vts/functional/generated/strided_slice_invalid_output_dims.model.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-// clang-format off
-// Generated file (from: strided_slice_invalid_output_dims.mod.py). Do not edit
-// Create the model
-Model createTestModel() {
- const std::vector<Operand> operands = {
- {
- .type = OperandType::TENSOR_FLOAT32,
- .dimensions = {2, 3},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_INPUT,
- .location = {.poolIndex = 0, .offset = 0, .length = 0},
- },
- {
- .type = OperandType::TENSOR_INT32,
- .dimensions = {2},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 0, .length = 8},
- },
- {
- .type = OperandType::TENSOR_INT32,
- .dimensions = {2},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 8, .length = 8},
- },
- {
- .type = OperandType::TENSOR_INT32,
- .dimensions = {2},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 16, .length = 8},
- },
- {
- .type = OperandType::INT32,
- .dimensions = {},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 24, .length = 4},
- },
- {
- .type = OperandType::INT32,
- .dimensions = {},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 28, .length = 4},
- },
- {
- .type = OperandType::INT32,
- .dimensions = {},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 32, .length = 4},
- },
- {
- .type = OperandType::TENSOR_FLOAT32,
- .dimensions = {3},
- .numberOfConsumers = 0,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_OUTPUT,
- .location = {.poolIndex = 0, .offset = 0, .length = 0},
- }
- };
-
- const std::vector<Operation> operations = {
- {
- .type = OperationType::STRIDED_SLICE,
- .inputs = {0, 1, 2, 3, 4, 5, 6},
- .outputs = {7},
- }
- };
-
- const std::vector<uint32_t> inputIndexes = {0};
- const std::vector<uint32_t> outputIndexes = {7};
- std::vector<uint8_t> operandValues = {
- 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0
- };
- const std::vector<hidl_memory> pools = {};
-
- return {
- .operands = operands,
- .operations = operations,
- .inputIndexes = inputIndexes,
- .outputIndexes = outputIndexes,
- .operandValues = operandValues,
- .pools = pools,
- };
-}
-
-inline bool is_ignored(int i) {
- static std::set<int> ignore = {};
- return ignore.find(i) != ignore.end();
-}
-
-// Create the model
-Model createTestModel_dynamic_output_shape() {
- const std::vector<Operand> operands = {
- {
- .type = OperandType::TENSOR_FLOAT32,
- .dimensions = {2, 3},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_INPUT,
- .location = {.poolIndex = 0, .offset = 0, .length = 0},
- },
- {
- .type = OperandType::TENSOR_INT32,
- .dimensions = {2},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 0, .length = 8},
- },
- {
- .type = OperandType::TENSOR_INT32,
- .dimensions = {2},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 8, .length = 8},
- },
- {
- .type = OperandType::TENSOR_INT32,
- .dimensions = {2},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 16, .length = 8},
- },
- {
- .type = OperandType::INT32,
- .dimensions = {},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 24, .length = 4},
- },
- {
- .type = OperandType::INT32,
- .dimensions = {},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 28, .length = 4},
- },
- {
- .type = OperandType::INT32,
- .dimensions = {},
- .numberOfConsumers = 1,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 32, .length = 4},
- },
- {
- .type = OperandType::TENSOR_FLOAT32,
- .dimensions = {0},
- .numberOfConsumers = 0,
- .scale = 0.0f,
- .zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_OUTPUT,
- .location = {.poolIndex = 0, .offset = 0, .length = 0},
- }
- };
-
- const std::vector<Operation> operations = {
- {
- .type = OperationType::STRIDED_SLICE,
- .inputs = {0, 1, 2, 3, 4, 5, 6},
- .outputs = {7},
- }
- };
-
- const std::vector<uint32_t> inputIndexes = {0};
- const std::vector<uint32_t> outputIndexes = {7};
- std::vector<uint8_t> operandValues = {
- 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0
- };
- const std::vector<hidl_memory> pools = {};
-
- return {
- .operands = operands,
- .operations = operations,
- .inputIndexes = inputIndexes,
- .outputIndexes = outputIndexes,
- .operandValues = operandValues,
- .pools = pools,
- };
-}
-
-inline bool is_ignored_dynamic_output_shape(int i) {
- static std::set<int> ignore = {};
- return ignore.find(i) != ignore.end();
-}
-
diff --git a/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h b/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h
index 212a887..2992c0c 100644
--- a/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h
+++ b/neuralnetworks/1.2/vts/functional/include/1.2/Callbacks.h
@@ -17,299 +17,218 @@
#ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H
#define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H
+#include <android-base/thread_annotations.h>
+#include <android/hardware/neuralnetworks/1.0/IExecutionCallback.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
#include <android/hardware/neuralnetworks/1.2/IExecutionCallback.h>
#include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
#include <hidl/Status.h>
-#include <chrono>
#include <condition_variable>
-#include <functional>
#include <mutex>
-#include <thread>
-namespace android {
-namespace hardware {
-namespace neuralnetworks {
-namespace V1_2 {
-namespace implementation {
+/*
+ * The Callback classes are used internally by the NeuralNetworks runtime to
+ * synchronize between different threads. An asynchronous task is launched
+ * paired with a callback object. When a client thread requires the output being
+ * generated by the asynchronous task, the client thread can wait for the result
+ * and be blocked until it has completed. Any wait may safely be called
+ * concurrently, even on the same callback object. When the asynchronous task
+ * has finished its workload, it must immediately call "notify*". If the
+ * asynchronous task has failed to launch, the function that tried to launch the
+ * asynchronous task must immediately call "notify*". This "notify*" call
+ * awakens any client threads waiting on the callback object.
+ *
+ * These classes exist to enable synchronization across HIDL. When
+ * synchronization is only required in the same process, consider using
+ * std::future, std::mutex, std::condition_variable, or std::experimental::latch
+ * instead.
+ */
+
+namespace android::hardware::neuralnetworks::V1_2::implementation {
using V1_0::ErrorStatus;
/**
- * The CallbackBase class is used internally by the NeuralNetworks runtime to
- * synchronize between different threads. An asynchronous task is launched
- * paired with a callback object. When a client thread requires the output being
- * generated by the asynchronous task, the client thread can wait for the result
- * and be blocked until it has completed or a timeout condition has been
- * reached. Any wait* may safely be called concurrently, even on the same
- * callback object. When the asynchronous task has finished its workload, it
- * must immediately call "notify". If the asynchronous task has failed to launch,
- * the function that tried to launch the asynchronous task must immediately call
- * "notify". This "notify" call awakens any client threads waiting on the
- * callback object.
- *
- * The CallbackBase class implements some of the base synchronization common to
- * both PrepareModelCallback and ExecutionCallback. For consistency, any HIDL
- * callback class must inherit from CallbackBase as well as the HIDL callback
- * interface it implements.
- *
- * This class exists to enable synchronization across HIDL. When synchronization
- * is only required in the same process, consider using std::future, std::mutex,
- * std::condition_variable, or std::experimental::latch instead.
- */
-class CallbackBase {
- public:
- CallbackBase();
- ~CallbackBase();
-
- /**
- * CallbackBase::wait blocks until notify has been called on the callback
- * object.
- */
- void wait();
-
- /**
- * CallbackBase::wait_for blocks until notify has been called on the
- * callback object or the time duration from the time the wait_for function
- * was called has expired, whichever comes first.
- *
- * @return Status std::cv_status::no_timeout if the callback was notified
- * before the time duration expired, std::cv_status::timeout
- * otherwise.
- */
- template <class Rep, class Period>
- std::cv_status wait_for(const std::chrono::duration<Rep, Period>& timeout_duration);
-
- /**
- * CallbackBase::on_finish binds a function to the callback object. This
- * bound function will be executed when CallbackBase::notify is called,
- * before any calls to wait* return. (Note that CallbackBase::wait_for can
- * return std::cv_status::timeout before CallbackBase::notify is called for
- * the first time, and hence before the bound function is executed.)
- *
- * The bound function must not synchronize with or otherwise access the
- * callback object it is bound to, as this could cause a deadlock.
- *
- * CallbackBase::on_finish can be called at most once on a given callback
- * object, and the call to CallbackBase::on_finish must finish before
- * CallbackBase::notify is called.
- *
- * @param post_work Function to be invoked the first time
- * CallbackBase::notify is called. Must have a target --
- * i.e., must not compare equal to nullptr. post_work
- * returns true if it successfully completes, false if it
- * fails.
- * @return bool True if the function was successfully bound, false if
- * unsuccessful.
- *
- * TODO: Why does the return value of the callback matter?
- */
- bool on_finish(std::function<bool(void)> post_work);
-
- /**
- * CallbackBase::bind_thread binds a thread to the event for later use by
- * CallbackBase::join_thread.
- *
- * The thread must be passed using std::move.
- *
- * Once a thread is bound with CallbackBase::bind_thread, the client code
- * should ensure that one of the following occurs before the event is
- * destroyed:
- * - CallbackBase::join_thread has been called.
- * - CallbackBase::wait has been called.
- * - CallbackBase::wait_for has been called and returned other than
- * std::cv_status::no_timeout.
- *
- * The bound thread shall not call any CallbackBase method with the
- * exception of CallbackBase::notify, which it must call when the thread has
- * finished its computation.
- *
- * CallbackBase::bind_thread can be called at most once on a given callback
- * object.
- *
- * @param asyncThread Thread to be bound to the callback object. The thread
- * object must represent a thread of execution -- i.e.,
- * asyncThread.joinable() must be true.
- * @return bool True if successful, false if thread was not properly bound.
- */
- bool bind_thread(std::thread&& asyncThread);
-
- /**
- * CallbackBase::join_thread ensures that the thread (if any) bound to this
- * event with CallbackBase::bind_thread has fully finished and cleaned its
- * resources. It is legal to call this function multiple times, concurrently
- * or sequentially.
- */
- void join_thread();
-
- protected:
- /**
- * CallbackBase::notify enables all prior and future wait* calls on the
- * callback object to proceed. The call to CallbackBase::notify happens
- * before any wait* calls on this callback object return (except in the case
- * of wait_for timing out). The asynchronous call the callback object is
- * paired with must ensure that any update to state that should be visible
- * to the caller of wait* happens before the call to CallbackBase::notify.
- *
- * CallbackBase::notify must be called exactly once on a given callback
- * object.
- */
- void notify();
-
- private:
- // Same as CallbackBase::join_thread but assumes we already hold a lock on
- // mMutex.
- void join_thread_locked();
-
- bool mNotified;
- std::mutex mMutex;
- std::condition_variable mCondition;
- std::function<bool(void)> mPostWork;
- std::thread mThread;
-};
-
-/**
* The PreparedModelCallback class is used to receive the error status of
* preparing a model as well as the prepared model from a task executing
- * asynchronously with respect to the runtime. If a calling thread calls wait*
+ * asynchronously with respect to the runtime. If a calling thread calls wait
* or get* on a PreparedModelCallback object and the corresponding asynchronous
* task has not finished preparing the model, the calling thread will block
- * until the asynchronous task has either called notify or notify_1_2. For more
- * information on the synchronization behavior, refer to the CallbackBase class.
+ * until the asynchronous task has either called notify or notify_1_2.
*
- * This class inherits the basic blocking and signaling calls from
- * CallbackBase, and implements the HIDL notify and notify_1_2 calls from
- * IPreparedModelCallback. This callback object is passed as an argument to
- * IDevice::prepareModel.
+ * If the callback object is notified more than once, only the results of the
+ * first call to notify* are used, and the results from subsequent calls are
+ * discarded.
+ *
+ * This callback object is passed as an argument to IDevice::prepareModel*.
*/
-class PreparedModelCallback : public CallbackBase, public IPreparedModelCallback {
+class PreparedModelCallback : public IPreparedModelCallback {
public:
- PreparedModelCallback();
- ~PreparedModelCallback() override;
-
/**
- * IPreparedModelCallback::notify and IPreparedModelCallback::notify_1_2
- * mark the callback object with the return status of the asynchronous
- * model preparation along with the prepared model, and call
- * CallbackBase::notify, enabling all prior and future wait* calls on the
- * PreparedModelCallback object to proceed. For more information on the
- * synchronization behavior, refer to the CallbackBase class.
+ * IPreparedModelCallback::notify marks the callback object with the return
+ * status of the asynchronous model preparation along with the prepared
+ * model, and allows all prior and future wait calls on the
+ * PreparedModelCallback object to proceed.
*
- * Either IPreparedModelCallback::notify or IPreparedModelCallback::notify_1_2
- * must be called exactly once on a given PreparedModelCallback object.
+ * Either IPreparedModelCallback::notify or
+ * IPreparedModelCallback::notify_1_2 must be called on a given
+ * PreparedModelCallback object.
+ *
+ * If the callback object is notified more than once, only the results of
+ * the first call to notify* are used, and the results from subsequent calls
+ * are discarded.
*
* @param status Error status returned from asynchronously preparing the
- * model; will be:
- * - NONE if the asynchronous preparation was successful
- * - DEVICE_UNAVAILABLE if driver is offline or busy
- * - GENERAL_FAILURE if there is an unspecified error
- * - INVALID_ARGUMENT if the input model is invalid
+ * model; will be:
+ * - NONE if the asynchronous preparation was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if the input model is invalid
* @param preparedModel Returned model that has been prepared for execution,
- * nullptr if the model was unable to be prepared.
+ * nullptr if the model was unable to be prepared.
*/
Return<void> notify(ErrorStatus status, const sp<V1_0::IPreparedModel>& preparedModel) override;
+
+ /**
+ * IPreparedModelCallback::notify_1_2 marks the callback object with the
+ * return status of the asynchronous model preparation along with the
+ * prepared model, and allows all prior and future wait calls on the
+ * PreparedModelCallback object to proceed.
+ *
+ * Either IPreparedModelCallback::notify or
+ * IPreparedModelCallback::notify_1_2 must be called on a given
+ * PreparedModelCallback object.
+ *
+ * If the callback object is notified more than once, only the results of
+ * the first call to notify* are used, and the results from subsequent calls
+ * are discarded.
+ *
+ * @param status Error status returned from asynchronously preparing the
+ * model; will be:
+ * - NONE if the asynchronous preparation was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if the input model is invalid
+ * @param preparedModel Returned model that has been prepared for execution,
+ * nullptr if the model was unable to be prepared.
+ */
Return<void> notify_1_2(ErrorStatus status,
const sp<V1_2::IPreparedModel>& preparedModel) override;
/**
+ * PreparedModelCallback::wait blocks until notify* has been called on the
+ * callback object.
+ */
+ void wait() const;
+
+ /**
* Retrieves the error status returned from the asynchronous task launched
- * by IDevice::prepareModel. If IDevice::prepareModel has not finished
+ * by IDevice::prepareModel*. If IDevice::prepareModel* has not finished
* asynchronously preparing the model, this call will block until the
* asynchronous task notifies the object.
*
* @return status Error status returned from asynchronously preparing the
- * model; will be:
- * - NONE if the asynchronous preparation was successful
- * - DEVICE_UNAVAILABLE if driver is offline or busy
- * - GENERAL_FAILURE if there is an unspecified error
- * - INVALID_ARGUMENT if the input model is invalid
+ * model; will be:
+ * - NONE if the asynchronous preparation was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - INVALID_ARGUMENT if the input model is invalid
*/
- ErrorStatus getStatus();
+ ErrorStatus getStatus() const;
/**
* Retrieves the model that has been prepared for execution from the
- * asynchronous task launched by IDevice::prepareModel. If
- * IDevice::prepareModel has not finished asynchronously preparing the
+ * asynchronous task launched by IDevice::prepareModel*. If
+ * IDevice::prepareModel* has not finished asynchronously preparing the
* model, this call will block until the asynchronous task notifies the
* object.
*
* @return preparedModel Returned model that has been prepared for
- * execution, nullptr if the model was unable to be
- * prepared.
+ * execution, nullptr if the model was unable to be prepared.
*/
- sp<V1_0::IPreparedModel> getPreparedModel();
+ sp<V1_0::IPreparedModel> getPreparedModel() const;
private:
- ErrorStatus mErrorStatus;
+ mutable std::mutex mMutex;
+ mutable std::condition_variable mCondition;
+ bool mNotified GUARDED_BY(mMutex) = false;
+ ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
sp<V1_0::IPreparedModel> mPreparedModel;
};
/**
- * The ExecutionCallback class is used to receive the error status of the
- * execution from a task executing asynchronously with respect to the runtime.
- * If a calling thread calls wait* or get* on a PreparedModelCallback object and
- * the corresponding asynchronous task has not finished the execution, the
- * calling thread will block until the asynchronous task has either called notify
- * or notify_1_2. For more information on the synchronization behavior, refer to
- * the CallbackBase class.
+ * The ExecutionCallback class is used to receive the results of the execution
+ * from a task executing asynchronously with respect to the runtime. If a
+ * calling thread calls wait or get* on a ExecutionCallback object and the
+ * corresponding asynchronous task has not finished the execution, the calling
+ * thread will block until the asynchronous task has either called notify or
+ * notify_1_2.
*
- * This class inherits the basic blocking and signaling calls from
- * CallbackBase, and implements the HIDL notify and notify_1_2 calls from
- * IExecutionCallback. This callback object is passed as an argument to
- * IPreparedModel::execute.
+ * If the callback object is notified more than once, only the results of the
+ * first call to notify* are used, and the results from subsequent calls are
+ * discarded.
+ *
+ * This callback object is passed as an argument to IPreparedModel::execute*.
*/
-class ExecutionCallback : public CallbackBase, public IExecutionCallback {
+class ExecutionCallback : public IExecutionCallback {
public:
- ExecutionCallback();
- ~ExecutionCallback() override;
-
/**
- * IExecutionCallback::notify and IExecutionCallback::notify_1_2 mark the
- * callback object with the return status of the asynchronous execution that
- * held this callback and enable all prior and future wait* calls on the
- * ExecutionCallback object to proceed. For more information on the
- * synchronization behavior, refer to the CallbackBase class.
+ * IExecutionCallback::notify marks the callback object with the return
+ * status of the asynchronous execution that held this callback and enables
+ * all prior and future wait calls on the ExecutionCallback object to
+ * proceed.
*
* Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must
- * be called exactly once on a given ExecutionCallback object.
+ * be called on a given ExecutionCallback object.
+ *
+ * If the callback object is notified more than once, only the results of
+ * the first call to notify* are used, and the results from subsequent calls
+ * are discarded.
*
* @param status Error status returned from launching the asynchronous task
- * (if the launch fails) or from the asynchronous task itself
- * (if the launch succeeds). Must be:
- * - NONE if the asynchronous execution was successful
- * - DEVICE_UNAVAILABLE if driver is offline or busy
- * - GENERAL_FAILURE if there is an unspecified error
- * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is
- * not large enough to store the resultant values
- * - INVALID_ARGUMENT if the input request is invalid
+ * (if the launch fails) or from the asynchronous task itself (if the
+ * launch succeeds). Must be:
+ * - NONE if the asynchronous execution was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if there is an unspecified error
+ * - OUTPUT_INSUFFICIENT_SIZE if provided output buffer is not large
+ * enough to store the resultant values
+ * - INVALID_ARGUMENT if the input request is invalid
*/
Return<void> notify(ErrorStatus status) override;
/**
- * Similar to IExecutionCallback::notify, but for V1_2::IPreparedModel to
- * also notify output shapes along with error status.
+ * IExecutionCallback::notify_1_2 marks the callback object with the results
+ * (error status, dynamic output shapes, and timing information) of the
+ * asynchronous execution that held this callback and enables all prior and
+ * future wait calls on the ExecutionCallback object to proceed.
+ *
+ * Either IExecutionCallback::notify or IExecutionCallback::notify_1_2 must
+ * be called on a given ExecutionCallback object.
+ *
+ * If the callback object is notified more than once, only the results of
+ * the first call to notify* are used, and the results from subsequent calls
+ * are discarded.
*
* @param status Error status returned from launching the asynchronous task
- * (if the launch fails) or from the asynchronous task itself
- * (if the launch succeeds). Must be:
- * - NONE if the asynchronous execution was successful
- * - DEVICE_UNAVAILABLE if driver is offline or busy
- * - GENERAL_FAILURE if the asynchronous task resulted in an
- * unspecified error
- * - OUTPUT_INSUFFICIENT_SIZE if at least one output
- * operand buffer is not large enough to store the
- * corresponding output
- * - INVALID_ARGUMENT if one of the input arguments to
- * prepareModel is invalid
+ * (if the launch fails) or from the asynchronous task itself (if the
+ * launch succeeds). Must be:
+ * - NONE if the asynchronous execution was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified
+ * error
+ * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is
+ * not large enough to store the corresponding output
+ * - INVALID_ARGUMENT if one of the input arguments to prepareModel is
+ * invalid
* @param outputShapes A list of shape information of model output operands.
- * The index into "outputShapes" corresponds to the index
- * of the output operand in the Request outputs vector.
- * outputShapes must be empty unless the status is either
- * NONE or OUTPUT_INSUFFICIENT_SIZE.
- * @return Timing Duration of execution. Unless MeasureTiming::YES was passed when
- * launching the execution and status is NONE, all times must
- * be reported as UINT64_MAX. A driver may choose to report
- * any time as UINT64_MAX, indicating that particular measurement is
- * not available.
+ * The index into "outputShapes" corresponds to the index of the output
+ * operand in the Request outputs vector. outputShapes must be empty
+ * unless the status is either NONE or OUTPUT_INSUFFICIENT_SIZE.
+ * @param Timing Duration of execution. Unless MeasureTiming::YES was passed
+ * when launching the execution and status is NONE, all times must be
+ * reported as UINT64_MAX. A driver may choose to report any time as
+ * UINT64_MAX, indicating that particular measurement is not available.
*/
Return<void> notify_1_2(ErrorStatus status, const hidl_vec<OutputShape>& outputShapes,
const Timing& timing) override;
@@ -321,81 +240,87 @@
}
/**
+ * ExecutionCallback::wait blocks until notify* has been called on the
+ * callback object.
+ */
+ void wait() const;
+
+ /**
* Retrieves the error status returned from the asynchronous task launched
* by either IPreparedModel::execute or IPreparedModel::execute_1_2. If
* IPreparedModel::execute or IPreparedModel::execute_1_2 has not finished
- * asynchronously executing, this call will block until the asynchronous task
- * notifies the object.
+ * asynchronously executing, this call will block until the asynchronous
+ * task notifies the object.
*
* @return status Error status returned from launching the asynchronous task
- * (if the launch fails) or from the asynchronous task itself
- * (if the launch succeeds). Must be:
- * - NONE if the asynchronous execution was successful
- * - DEVICE_UNAVAILABLE if driver is offline or busy
- * - GENERAL_FAILURE if the asynchronous task resulted in an
- * unspecified error
- * - OUTPUT_INSUFFICIENT_SIZE if at least one output
- * operand buffer is not large enough to store the
- * corresponding output
- * - INVALID_ARGUMENT if one of the input arguments to
- * prepareModel is invalid
+ * (if the launch fails) or from the asynchronous task itself (if the
+ * launch succeeds). Must be:
+ * - NONE if the asynchronous execution was successful
+ * - DEVICE_UNAVAILABLE if driver is offline or busy
+ * - GENERAL_FAILURE if the asynchronous task resulted in an unspecified
+ * error
+ * - OUTPUT_INSUFFICIENT_SIZE if at least one output operand buffer is
+ * not large enough to store the corresponding output
+ * - INVALID_ARGUMENT if one of the input arguments to prepareModel is
+ * invalid
*/
- ErrorStatus getStatus();
+ ErrorStatus getStatus() const;
/**
* Retrieves the output shapes returned from the asynchronous task launched
- * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not finished
- * asynchronously executing, this call will block until the asynchronous task
- * notifies the object.
+ * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not
+ * finished asynchronously executing, this call will block until the
+ * asynchronous task notifies the object.
*
- * If the asynchronous task was launched by IPreparedModel::execute, an empty vector
- * will be returned.
+ * If the asynchronous task was launched by IPreparedModel::execute, an
+ * empty vector will be returned.
*
- * @return outputShapes A list of shape information of model output operands.
- * The index into "outputShapes" corresponds to the index
- * of the output operand in the Request outputs vector.
- * outputShapes must be empty unless the status is either
- * NONE or OUTPUT_INSUFFICIENT_SIZE.
+ * @return outputShapes A list of shape information of model output
+ * operands. The index into "outputShapes" corresponds to the index of
+ * the output operand in the Request outputs vector. outputShapes must
+ * be empty unless the status is either NONE or
+ * OUTPUT_INSUFFICIENT_SIZE. outputShaps may be empty if the status is
+ * NONE and all model output operands are fully-specified at execution
+ * time. outputShapes must have the same number of elements as the
+ * number of model output operands if the status is
+ * OUTPUT_INSUFFICIENT_SIZE, or if the status is NONE and the model has
+ * at least one output operand that is not fully-specified.
*/
- const std::vector<OutputShape>& getOutputShapes();
+ const std::vector<OutputShape>& getOutputShapes() const;
/**
- * Retrieves the duration of execution ofthe asynchronous task launched
- * by IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not finished
- * asynchronously executing, this call will block until the asynchronous task
- * notifies the object.
+ * Retrieves the duration of execution of the asynchronous task launched by
+ * IPreparedModel::execute_1_2. If IPreparedModel::execute_1_2 has not
+ * finished asynchronously executing, this call will block until the
+ * asynchronous task notifies the object.
*
- * If the asynchronous task was launched by IPreparedModel::execute, every time
- * must be UINT64_MAX.
+ * If the asynchronous task was launched by IPreparedModel::execute, every
+ * time must be UINT64_MAX.
*
- * @return timing Duration of the execution. Every time must be UINT64_MAX unless
- * the status is NONE.
+ * @return timing Duration of the execution. Every time must be UINT64_MAX
+ * unless the status is NONE.
*/
- Timing getTiming();
+ Timing getTiming() const;
private:
+ /*
+ * ExecutionCallback::notifyInternal stores the results of the execution
+ * (status, output shapes, and timing information) in the ExecutionCallback
+ * object before any call to wait or get* return. It then enables all prior
+ * and future wait calls on the ExecutionCallback object to proceed.
+ */
+ void notifyInternal(ErrorStatus errorStatus, const hidl_vec<OutputShape>& outputShapes,
+ const Timing& timing);
+
+ // members
+ mutable std::mutex mMutex;
+ mutable std::condition_variable mCondition;
+ bool mNotified GUARDED_BY(mMutex) = false;
ErrorStatus mErrorStatus = ErrorStatus::GENERAL_FAILURE;
std::vector<OutputShape> mOutputShapes = {};
Timing mTiming = {};
};
-// template function implementation(s) below this point
-
-template <class Rep, class Period>
-std::cv_status CallbackBase::wait_for(const std::chrono::duration<Rep, Period>& timeout_duration) {
- std::unique_lock<std::mutex> lock(mMutex);
- std::cv_status status =
- mCondition.wait_for(lock, timeout_duration, [this] { return mNotified; });
- if (status != std::cv_status::timeout) {
- join_thread_locked();
- }
- return status;
-}
-
-} // namespace implementation
-} // namespace V1_2
-} // namespace neuralnetworks
-} // namespace hardware
-} // namespace android
+} // namespace android::hardware::neuralnetworks::V1_2::implementation
#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_2_CALLBACKS_H
diff --git a/neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py b/neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py
deleted file mode 100644
index e8d30f3..0000000
--- a/neuralnetworks/1.2/vts/functional/spec/strided_slice_invalid_output_dims.mod.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#
-# 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.
-#
-
-# This test makes sure that executing STRIDED_SLICE results in a failure when
-# the output dimensions do not match shrinkAxisMask.
-#
-# The test generator does not support generating tests resulting in execution
-# failure, so the gTest part of this test has been written by hand.
-# TODO(b/132155416): Move this under frameworks/ml/nn/runtime/test/specs/V1_2.
-#
-# Based on strided_slice_float_11.mod.py.
-
-model = Model()
-i1 = Input("input", "TENSOR_FLOAT32", "{2, 3}")
-begins = Parameter("begins", "TENSOR_INT32", "{2}", [0, 0])
-# The value "2" below makes the test invalid. See http://b/79856511#comment2.
-ends = Parameter("ends", "TENSOR_INT32", "{2}", [2, 3])
-strides = Parameter("strides", "TENSOR_INT32", "{2}", [1, 1])
-beginMask = Int32Scalar("beginMask", 0)
-endMask = Int32Scalar("endMask", 0)
-shrinkAxisMask = Int32Scalar("shrinkAxisMask", 1)
-
-output = Output("output", "TENSOR_FLOAT32", "{3}")
-
-model = model.Operation("STRIDED_SLICE", i1, begins, ends, strides, beginMask, endMask, shrinkAxisMask).To(output)
-
-Example({
- i1: [1, 2, 3, 4, 5, 6],
- output: [1, 2, 3],
-})
diff --git a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
index 26f2c90..f81af9b 100644
--- a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
@@ -169,6 +169,11 @@
/*
* Test IRadio.startNetworkScan() for the response returned.
+ *
+ * REQUEST_NOT_SUPPORTED is temporarily returned because of vendors failed to fully implement
+ * startNetworkScan in HAL @1.4 (see b/137298570 and b/135595082). Starting from @1.5, however,
+ * REQUEST_NOT_SUPPORTED will be disallowed for all tests. Modems have "GSM" rat scan need to
+ * support scanning requests combined with some parameters.
*/
TEST_F(RadioHidlTest_v1_4, startNetworkScan) {
serial = GetRandomSerialNumber();
@@ -191,10 +196,17 @@
if (cardStatus.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::SIM_ABSENT}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- // OPERATION_NOT_ALLOWED should not be allowed; however, some vendors do not support the
- // required manual GSM search functionality. This is tracked in b/112206766.
- ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
- {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED}));
+ // OPERATION_NOT_ALLOWED should not be allowed; however, some vendors do
+ // not support the required manual GSM search functionality. This is
+ // tracked in b/112206766. REQUEST_NOT_SUPPORTED is temporarily added back
+ // because of vendors failed to implement startNetworkScan in HAL 1.4 (see
+ // b/137298570 and b/135595082). Starting from 1.5, however,
+ // REQUEST_NOT_SUPPORTED will be disallowed. Modems have "GSM" rat scan
+ // need to support scanning requests combined with some parameters.
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+ {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED,
+ RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -220,8 +232,9 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_4->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -256,8 +269,9 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_4->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -291,8 +305,9 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_4->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -326,8 +341,9 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_4->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -361,8 +377,9 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_4->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -396,8 +413,9 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_4->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -431,8 +449,9 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(
- CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(CheckAnyOfErrors(
+ radioRsp_v1_4->rspInfo.error,
+ {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -468,8 +487,10 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::NONE, RadioError::SIM_ABSENT}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
- {RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+ {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
+ RadioError::REQUEST_NOT_SUPPORTED}));
}
}
@@ -507,8 +528,10 @@
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
{RadioError::NONE, RadioError::SIM_ABSENT}));
} else if (cardStatus.base.base.cardState == CardState::PRESENT) {
- ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
- {RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
+ ASSERT_TRUE(
+ CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+ {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
+ RadioError::REQUEST_NOT_SUPPORTED}));
}
}
diff --git a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
index affdf8b..fa0e2e9 100644
--- a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
+++ b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
@@ -29,7 +29,9 @@
void SensorsHidlEnvironmentBase::HidlTearDown() {
mStopThread = true;
- mPollThread.detach();
+ if (mPollThread.joinable()) {
+ mPollThread.detach();
+ }
}
void SensorsHidlEnvironmentBase::catEvents(std::vector<Event>* output) {
diff --git a/thermal/2.0/default/android.hardware.thermal@2.0-service.rc b/thermal/2.0/default/android.hardware.thermal@2.0-service.rc
index 046c771..4ff8bd6 100644
--- a/thermal/2.0/default/android.hardware.thermal@2.0-service.rc
+++ b/thermal/2.0/default/android.hardware.thermal@2.0-service.rc
@@ -1,4 +1,5 @@
service vendor.thermal-hal-2-0-mock /vendor/bin/hw/android.hardware.thermal@2.0-service.mock
+ interface android.hardware.thermal@1.0::IThermal default
interface android.hardware.thermal@2.0::IThermal default
class hal
user system
diff --git a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
index 26a58b2..7aaad02 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
@@ -56,6 +56,8 @@
protected:
std::string getPrimaryWlanIfaceName() {
std::array<char, PROPERTY_VALUE_MAX> buffer;
+ auto res = property_get("wifi.sap.interface", buffer.data(), nullptr);
+ if (res > 0) return buffer.data();
property_get("wifi.interface", buffer.data(), "wlan0");
return buffer.data();
}