Merge "Add SubHal header for Sensors HAL 2.1" into rvc-dev
diff --git a/audio/core/all-versions/default/StreamOut.cpp b/audio/core/all-versions/default/StreamOut.cpp
index 150d641..1519c48 100644
--- a/audio/core/all-versions/default/StreamOut.cpp
+++ b/audio/core/all-versions/default/StreamOut.cpp
@@ -455,20 +455,22 @@
sp<IStreamOutCallback> callback = self->mCallback;
if (callback.get() == nullptr) return 0;
ALOGV("asyncCallback() event %d", event);
+ Return<void> result;
switch (event) {
case STREAM_CBK_EVENT_WRITE_READY:
- callback->onWriteReady();
+ result = callback->onWriteReady();
break;
case STREAM_CBK_EVENT_DRAIN_READY:
- callback->onDrainReady();
+ result = callback->onDrainReady();
break;
case STREAM_CBK_EVENT_ERROR:
- callback->onError();
+ result = callback->onError();
break;
default:
ALOGW("asyncCallback() unknown event %d", event);
break;
}
+ ALOGW_IF(!result.isOk(), "Client callback failed: %s", result.description().c_str());
return 0;
}
@@ -629,16 +631,18 @@
sp<IStreamOutEventCallback> eventCallback = self->mEventCallback;
if (eventCallback.get() == nullptr) return 0;
ALOGV("%s event %d", __func__, event);
+ Return<void> result;
switch (event) {
case STREAM_EVENT_CBK_TYPE_CODEC_FORMAT_CHANGED: {
hidl_vec<uint8_t> audioMetadata;
audioMetadata.setToExternal((uint8_t*)param, strlen((char*)param));
- eventCallback->onCodecFormatChanged(audioMetadata);
+ result = eventCallback->onCodecFormatChanged(audioMetadata);
} break;
default:
ALOGW("%s unknown event %d", __func__, event);
break;
}
+ ALOGW_IF(!result.isOk(), "Client callback failed: %s", result.description().c_str());
return 0;
}
#endif
diff --git a/audio/core/all-versions/vts/functional/ConfigHelper.h b/audio/core/all-versions/vts/functional/ConfigHelper.h
index a2f4116..8ef2b43 100644
--- a/audio/core/all-versions/vts/functional/ConfigHelper.h
+++ b/audio/core/all-versions/vts/functional/ConfigHelper.h
@@ -40,7 +40,7 @@
return devs.getDevice(AUDIO_DEVICE_IN_BUILTIN_MIC, {}, AUDIO_FORMAT_DEFAULT);
};
auto primaryMic = getMic(policyConfig.getPrimaryModule()->getDeclaredDevices());
- auto availableMic = getMic(policyConfig.getAvailableInputDevices());
+ auto availableMic = getMic(policyConfig.getInputDevices());
return primaryMic != nullptr && primaryMic->equals(availableMic);
}
diff --git a/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp b/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp
index f9e4aa3..9c0135b 100644
--- a/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp
+++ b/audio/effect/all-versions/vts/functional/ValidateAudioEffectsConfiguration.cpp
@@ -18,6 +18,12 @@
#include <iterator>
#include <media/EffectsConfig.h>
+// clang-format off
+#include PATH(android/hardware/audio/effect/FILE_VERSION/IEffectsFactory.h)
+// clang-format on
+
+#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
#include "utility/ValidateXml.h"
@@ -29,6 +35,11 @@
RecordProperty("description",
"Verify that the effects configuration file is valid according to the schema");
using namespace android::effectsConfig;
+ if (android::hardware::getAllHalInstanceNames(
+ ::android::hardware::audio::effect::CPP_VERSION::IEffectsFactory::descriptor)
+ .size() == 0) {
+ GTEST_SKIP() << "No Effects HAL version " STRINGIFY(CPP_VERSION) " on this device";
+ }
std::vector<const char*> locations(std::begin(DEFAULT_LOCATIONS), std::end(DEFAULT_LOCATIONS));
const char* xsd = "/data/local/tmp/audio_effects_conf_" STRINGIFY(CPP_VERSION) ".xsd";
diff --git a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
index 390d4ee..070242f 100644
--- a/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/effect/all-versions/vts/functional/VtsHalAudioEffectTargetTest.cpp
@@ -155,11 +155,20 @@
0xfe3199be, 0xaed0, 0x413f, 0x87bb,
std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}};
+enum { PARAM_FACTORY_NAME, PARAM_EFFECT_UUID };
+using EffectParameter = std::tuple<std::string, Uuid>;
+
+static inline std::string EffectParameterToString(
+ const ::testing::TestParamInfo<EffectParameter>& info) {
+ return ::android::hardware::PrintInstanceNameToString(::testing::TestParamInfo<std::string>{
+ std::get<PARAM_FACTORY_NAME>(info.param), info.index});
+}
+
// The main test class for Audio Effect HIDL HAL.
-class AudioEffectHidlTest : public ::testing::TestWithParam<std::string> {
+class AudioEffectHidlTest : public ::testing::TestWithParam<EffectParameter> {
public:
void SetUp() override {
- effectsFactory = IEffectsFactory::getService(GetParam());
+ effectsFactory = IEffectsFactory::getService(std::get<PARAM_FACTORY_NAME>(GetParam()));
ASSERT_NE(nullptr, effectsFactory.get());
findAndCreateEffect(getEffectType());
@@ -180,7 +189,7 @@
RecordProperty("description", description);
}
- virtual Uuid getEffectType() { return EQUALIZER_EFFECT_TYPE; }
+ Uuid getEffectType() const { return std::get<PARAM_EFFECT_UUID>(GetParam()); }
void findAndCreateEffect(const Uuid& type);
void findEffectInstance(const Uuid& type, Uuid* uuid);
@@ -369,7 +378,9 @@
description("Verify Disable -> Enable -> Disable sequence for an effect");
Return<Result> ret = effect->disable();
EXPECT_TRUE(ret.isOk());
- EXPECT_EQ(Result::INVALID_ARGUMENTS, ret);
+ // Note: some legacy effects may return -EINVAL (INVALID_ARGUMENTS),
+ // more canonical is to return -ENOSYS (NOT_SUPPORTED)
+ EXPECT_TRUE(ret == Result::NOT_SUPPORTED || ret == Result::INVALID_ARGUMENTS);
ret = effect->enable();
EXPECT_TRUE(ret.isOk());
EXPECT_EQ(Result::OK, ret);
@@ -519,15 +530,19 @@
// The main test class for Equalizer Audio Effect HIDL HAL.
class EqualizerAudioEffectHidlTest : public AudioEffectHidlTest {
- public:
+ public:
void SetUp() override {
AudioEffectHidlTest::SetUp();
equalizer = IEqualizerEffect::castFrom(effect);
ASSERT_NE(nullptr, equalizer.get());
}
- protected:
- Uuid getEffectType() override { return EQUALIZER_EFFECT_TYPE; }
+ void TearDown() override {
+ equalizer.clear();
+ AudioEffectHidlTest::TearDown();
+ }
+
+ protected:
void getNumBands(uint16_t* numBands);
void getLevelRange(int16_t* minLevel, int16_t* maxLevel);
void getBandFrequencyRange(uint16_t band, uint32_t* minFreq, uint32_t* centerFreq,
@@ -765,16 +780,19 @@
// The main test class for Equalizer Audio Effect HIDL HAL.
class LoudnessEnhancerAudioEffectHidlTest : public AudioEffectHidlTest {
- public:
+ public:
void SetUp() override {
AudioEffectHidlTest::SetUp();
enhancer = ILoudnessEnhancerEffect::castFrom(effect);
ASSERT_NE(nullptr, enhancer.get());
}
- protected:
- Uuid getEffectType() override { return LOUDNESS_ENHANCER_EFFECT_TYPE; }
+ void TearDown() override {
+ enhancer.clear();
+ AudioEffectHidlTest::TearDown();
+ }
+ protected:
sp<ILoudnessEnhancerEffect> enhancer;
};
@@ -799,19 +817,31 @@
EXPECT_EQ(gain, actualGain);
}
+INSTANTIATE_TEST_SUITE_P(EffectsFactory, AudioEffectsFactoryHidlTest,
+ ::testing::ValuesIn(::android::hardware::getAllHalInstanceNames(
+ IEffectsFactory::descriptor)),
+ ::android::hardware::PrintInstanceNameToString);
INSTANTIATE_TEST_SUITE_P(
- EffectsFactory, AudioEffectsFactoryHidlTest,
- testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
- android::hardware::PrintInstanceNameToString);
+ Equalizer_IEffect, AudioEffectHidlTest,
+ ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames(
+ IEffectsFactory::descriptor)),
+ ::testing::Values(EQUALIZER_EFFECT_TYPE)),
+ EffectParameterToString);
INSTANTIATE_TEST_SUITE_P(
- Equalizer, AudioEffectHidlTest,
- testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
- android::hardware::PrintInstanceNameToString);
+ LoudnessEnhancer_IEffect, AudioEffectHidlTest,
+ ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames(
+ IEffectsFactory::descriptor)),
+ ::testing::Values(LOUDNESS_ENHANCER_EFFECT_TYPE)),
+ EffectParameterToString);
INSTANTIATE_TEST_SUITE_P(
Equalizer, EqualizerAudioEffectHidlTest,
- testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
- android::hardware::PrintInstanceNameToString);
+ ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames(
+ IEffectsFactory::descriptor)),
+ ::testing::Values(EQUALIZER_EFFECT_TYPE)),
+ EffectParameterToString);
INSTANTIATE_TEST_SUITE_P(
LoudnessEnhancer, LoudnessEnhancerAudioEffectHidlTest,
- testing::ValuesIn(android::hardware::getAllHalInstanceNames(IEffectsFactory::descriptor)),
- android::hardware::PrintInstanceNameToString);
+ ::testing::Combine(::testing::ValuesIn(::android::hardware::getAllHalInstanceNames(
+ IEffectsFactory::descriptor)),
+ ::testing::Values(LOUDNESS_ENHANCER_EFFECT_TYPE)),
+ EffectParameterToString);
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index cde8048..368a6d4 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -38,16 +38,15 @@
#include <hidl/HidlTransportSupport.h>
#include <hwbinder/ProcessState.h>
-#include <log/log.h>
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
-#include <android/log.h>
#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
#include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android-base/logging.h>
#include <system/camera_metadata.h>
#include <ui/DisplayConfig.h>
#include <ui/DisplayState.h>
@@ -98,18 +97,19 @@
std::string service_name = GetParam();
pEnumerator = IEvsEnumerator::getService(service_name);
ASSERT_NE(pEnumerator.get(), nullptr);
+ LOG(INFO) << "Test target service: " << service_name;
mIsHwModule = pEnumerator->isHardware();
}
virtual void TearDown() override {
// Attempt to close any active camera
- for (auto &&c : activeCameras) {
- sp<IEvsCamera_1_1> cam = c.promote();
+ for (auto &&cam : activeCameras) {
if (cam != nullptr) {
pEnumerator->closeCamera(cam);
}
}
+ activeCameras.clear();
}
protected:
@@ -120,11 +120,12 @@
// Get the camera list
pEnumerator->getCameraList_1_1(
[this](hidl_vec <CameraDesc> cameraList) {
- ALOGI("Camera list callback received %zu cameras",
- cameraList.size());
+ LOG(INFO) << "Camera list callback received "
+ << cameraList.size()
+ << " cameras";
cameraInfo.reserve(cameraList.size());
for (auto&& cam: cameraList) {
- ALOGI("Found camera %s", cam.v1.cameraId.c_str());
+ LOG(INFO) << "Found camera " << cam.v1.cameraId;
cameraInfo.push_back(cam);
}
}
@@ -137,10 +138,12 @@
// Get the ultrasonics array list
pEnumerator->getUltrasonicsArrayList([this](hidl_vec<UltrasonicsArrayDesc> ultraList) {
- ALOGI("Ultrasonics array list callback received %zu arrays", ultraList.size());
+ LOG(INFO) << "Ultrasonics array list callback received "
+ << ultraList.size()
+ << " arrays";
ultrasonicsArraysInfo.reserve(ultraList.size());
for (auto&& ultraArray : ultraList) {
- ALOGI("Found ultrasonics array %s", ultraArray.ultrasonicsArrayId.c_str());
+ LOG(INFO) << "Found ultrasonics array " << ultraArray.ultrasonicsArrayId;
ultrasonicsArraysInfo.push_back(ultraArray);
}
});
@@ -195,7 +198,7 @@
if (!flag) {
// EVS assumes that the device w/o a valid metadata is a physical
// device.
- ALOGI("%s is not a logical camera device.", id.c_str());
+ LOG(INFO) << id << " is not a logical camera device.";
physicalCameras.emplace(id);
return physicalCameras;
}
@@ -205,7 +208,9 @@
int rc = find_camera_metadata_ro_entry(metadata,
ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS,
&entry);
- ALOGE_IF(rc, "No physical camera ID is found for a logical camera device");
+ if (rc != 0) {
+ LOG(ERROR) << "No physical camera ID is found for a logical camera device";
+ }
const uint8_t *ids = entry.data.u8;
size_t start = 0;
@@ -219,7 +224,10 @@
}
}
- ALOGI("%s consists of %d physical camera devices.", id.c_str(), (int)physicalCameras.size());
+ LOG(INFO) << id
+ << " consists of "
+ << physicalCameras.size()
+ << " physical camera devices";
return physicalCameras;
}
@@ -228,7 +236,7 @@
std::vector<CameraDesc> cameraInfo; // Empty unless/until loadCameraList() is called
bool mIsHwModule; // boolean to tell current module under testing
// is HW module implementation.
- std::deque<wp<IEvsCamera_1_1>> activeCameras; // A list of active camera handles that are
+ std::deque<sp<IEvsCamera_1_1>> activeCameras; // A list of active camera handles that are
// needed to be cleaned up.
std::vector<UltrasonicsArrayDesc>
ultrasonicsArraysInfo; // Empty unless/until
@@ -247,7 +255,7 @@
* call to closeCamera. Then repeats the test to ensure all cameras can be reopened.
*/
TEST_P(EvsHidlTest, CameraOpenClean) {
- ALOGI("Starting CameraOpenClean test");
+ LOG(INFO) << "Starting CameraOpenClean test";
// Get the camera list
loadCameraList();
@@ -261,15 +269,12 @@
bool isLogicalCam = false;
auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
if (mIsHwModule && isLogicalCam) {
- ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+ LOG(INFO) << "Skip a logical device, " << cam.v1.cameraId << " for HW target.";
continue;
}
for (int pass = 0; pass < 2; pass++) {
- activeCameras.clear();
- sp<IEvsCamera_1_1> pCam =
- IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
- .withDefault(nullptr);
+ sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg);
ASSERT_NE(pCam, nullptr);
for (auto&& devName : devices) {
@@ -286,7 +291,7 @@
// Verify that this camera self-identifies correctly
pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
- ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+ LOG(DEBUG) << "Found camera " << desc.v1.cameraId;
EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
}
);
@@ -295,15 +300,16 @@
const auto id = 0xFFFFFFFF; // meaningless id
hidl_vec<uint8_t> values;
auto err = pCam->setExtendedInfo_1_1(id, values);
- ASSERT_EQ(EvsResult::INVALID_ARG, err);
+ ASSERT_NE(EvsResult::INVALID_ARG, err);
pCam->getExtendedInfo_1_1(id, [](const auto& result, const auto& data) {
- ASSERT_EQ(EvsResult::INVALID_ARG, result);
+ ASSERT_NE(EvsResult::INVALID_ARG, result);
ASSERT_EQ(0, data.size());
});
// Explicitly close the camera so resources are released right away
pEnumerator->closeCamera(pCam);
+ activeCameras.clear();
}
}
}
@@ -316,7 +322,7 @@
* the system to be tolerant of shutdown/restart race conditions.
*/
TEST_P(EvsHidlTest, CameraOpenAggressive) {
- ALOGI("Starting CameraOpenAggressive test");
+ LOG(INFO) << "Starting CameraOpenAggressive test";
// Get the camera list
loadCameraList();
@@ -330,7 +336,7 @@
bool isLogicalCam = false;
getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
if (mIsHwModule && isLogicalCam) {
- ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+ LOG(INFO) << "Skip a logical device, " << cam.v1.cameraId << " for HW target.";
continue;
}
@@ -345,7 +351,7 @@
// Verify that this camera self-identifies correctly
pCam->getCameraInfo_1_1([&cam](CameraDesc desc) {
- ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+ LOG(DEBUG) << "Found camera " << desc.v1.cameraId;
EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
}
);
@@ -371,16 +377,18 @@
// Close the superceded camera
pEnumerator->closeCamera(pCam);
+ activeCameras.pop_front();
// Verify that the second camera instance self-identifies correctly
pCam2->getCameraInfo_1_1([&cam](CameraDesc desc) {
- ALOGD("Found camera %s", desc.v1.cameraId.c_str());
+ LOG(DEBUG) << "Found camera " << desc.v1.cameraId;
EXPECT_EQ(cam.v1.cameraId, desc.v1.cameraId);
}
);
// Close the second camera instance
pEnumerator->closeCamera(pCam2);
+ activeCameras.pop_front();
}
// Sleep here to ensure the destructor cleanup has time to run so we don't break follow on tests
@@ -393,7 +401,7 @@
* Measure and qualify the stream start up time and streaming frame rate of each reported camera
*/
TEST_P(EvsHidlTest, CameraStreamPerformance) {
- ALOGI("Starting CameraStreamPerformance test");
+ LOG(INFO) << "Starting CameraStreamPerformance test";
// Get the camera list
loadCameraList();
@@ -407,11 +415,10 @@
bool isLogicalCam = false;
auto devices = getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
if (mIsHwModule && isLogicalCam) {
- ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+ LOG(INFO) << "Skip a logical device " << cam.v1.cameraId;
continue;
}
- activeCameras.clear();
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
@@ -444,8 +451,10 @@
kMaxStreamStartMilliseconds * devices.size());
printf("%s: Measured time to first frame %0.2f ms\n",
cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds);
- ALOGI("%s: Measured time to first frame %0.2f ms",
- cam.v1.cameraId.c_str(), timeToFirstFrame * kNanoToMilliseconds);
+ LOG(INFO) << cam.v1.cameraId
+ << ": Measured time to first frame "
+ << std::scientific << timeToFirstFrame * kNanoToMilliseconds
+ << " ms.";
// Check aspect ratio
unsigned width = 0, height = 0;
@@ -468,11 +477,14 @@
nsecs_t runTime = end - firstFrame;
float framesPerSecond = framesReceived / (runTime * kNanoToSeconds);
printf("Measured camera rate %3.2f fps\n", framesPerSecond);
- ALOGI("Measured camera rate %3.2f fps", framesPerSecond);
+ LOG(INFO) << "Measured camera rate "
+ << std::scientific << framesPerSecond
+ << " fps.";
EXPECT_GE(framesPerSecond, kMinimumFramesPerSecond);
// Explicitly release the camera
pEnumerator->closeCamera(pCam);
+ activeCameras.clear();
}
}
@@ -483,7 +495,7 @@
* than one frame time. The camera must cleanly skip frames until the client is ready again.
*/
TEST_P(EvsHidlTest, CameraStreamBuffering) {
- ALOGI("Starting CameraStreamBuffering test");
+ LOG(INFO) << "Starting CameraStreamBuffering test";
// Arbitrary constant (should be > 1 and less than crazy)
static const unsigned int kBuffersToHold = 6;
@@ -500,11 +512,10 @@
bool isLogicalCam = false;
getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
if (mIsHwModule && isLogicalCam) {
- ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+ LOG(INFO) << "Skip a logical device " << cam.v1.cameraId << " for HW target.";
continue;
}
- activeCameras.clear();
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
@@ -557,6 +568,7 @@
// Explicitly release the camera
pEnumerator->closeCamera(pCam);
+ activeCameras.clear();
}
}
@@ -568,7 +580,7 @@
* which a human could observe to see the operation of the system on the physical display.
*/
TEST_P(EvsHidlTest, CameraToDisplayRoundTrip) {
- ALOGI("Starting CameraToDisplayRoundTrip test");
+ LOG(INFO) << "Starting CameraToDisplayRoundTrip test";
// Get the camera list
loadCameraList();
@@ -587,14 +599,14 @@
// Request exclusive access to the first EVS display
sp<IEvsDisplay_1_1> pDisplay = pEnumerator->openDisplay_1_1(targetDisplayId);
ASSERT_NE(pDisplay, nullptr);
- ALOGI("Display %d is in use.", targetDisplayId);
+ LOG(INFO) << "Display " << targetDisplayId << " is alreay in use.";
// Get the display descriptor
pDisplay->getDisplayInfo_1_1([](const auto& config, const auto& state) {
android::DisplayConfig* pConfig = (android::DisplayConfig*)config.data();
const auto width = pConfig->resolution.getWidth();
const auto height = pConfig->resolution.getHeight();
- ALOGI(" Resolution: %dx%d", width, height);
+ LOG(INFO) << " Resolution: " << width << "x" << height;
ASSERT_GT(width, 0);
ASSERT_GT(height, 0);
@@ -607,11 +619,10 @@
bool isLogicalCam = false;
getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
if (mIsHwModule && isLogicalCam) {
- ALOGI("Skip a logical device %s for HW module", cam.v1.cameraId.c_str());
+ LOG(INFO) << "Skip a logical device " << cam.v1.cameraId << " for HW target.";
continue;
}
- activeCameras.clear();
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
.withDefault(nullptr);
@@ -654,6 +665,7 @@
// Explicitly release the camera
pEnumerator->closeCamera(pCam);
+ activeCameras.clear();
}
// Explicitly release the display
@@ -667,7 +679,7 @@
* underlying camera.
*/
TEST_P(EvsHidlTest, MultiCameraStream) {
- ALOGI("Starting MultiCameraStream test");
+ LOG(INFO) << "Starting MultiCameraStream test";
if (mIsHwModule) {
// This test is not for HW module implementation.
@@ -683,7 +695,6 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
- activeCameras.clear();
// Create two camera clients.
sp<IEvsCamera_1_1> pCam0 =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
@@ -735,7 +746,9 @@
nsecs_t runTime = end - firstFrame;
float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
- ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1);
+ LOG(INFO) << "Measured camera rate "
+ << std::scientific << framesPerSecond0 << " fps and "
+ << framesPerSecond1 << " fps";
EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
@@ -760,6 +773,7 @@
// Explicitly release the camera
pEnumerator->closeCamera(pCam0);
pEnumerator->closeCamera(pCam1);
+ activeCameras.clear();
// TODO(b/145459970, b/145457727): below sleep() is added to ensure the
// destruction of active camera objects; this may be related with two
@@ -774,7 +788,7 @@
* Verify that a client can adjust a camera parameter.
*/
TEST_P(EvsHidlTest, CameraParameter) {
- ALOGI("Starting CameraParameter test");
+ LOG(INFO) << "Starting CameraParameter test";
// Get the camera list
loadCameraList();
@@ -791,11 +805,10 @@
if (isLogicalCam) {
// TODO(b/145465724): Support camera parameter programming on
// logical devices.
- ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+ LOG(INFO) << "Skip a logical device " << cam.v1.cameraId;
continue;
}
- activeCameras.clear();
// Create a camera client
sp<IEvsCamera_1_1> pCam =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
@@ -908,6 +921,7 @@
// Explicitly release the camera
pEnumerator->closeCamera(pCam);
+ activeCameras.clear();
}
}
@@ -918,7 +932,7 @@
* terminates or releases a role.
*/
TEST_P(EvsHidlTest, CameraMasterRelease) {
- ALOGI("Starting CameraMasterRelease test");
+ LOG(INFO) << "Starting CameraMasterRelease test";
if (mIsHwModule) {
// This test is not for HW module implementation.
@@ -939,11 +953,10 @@
if (isLogicalCam) {
// TODO(b/145465724): Support camera parameter programming on
// logical devices.
- ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+ LOG(INFO) << "Skip a logical device " << cam.v1.cameraId;
continue;
}
- activeCameras.clear();
// Create two camera clients.
sp<IEvsCamera_1_1> pCamMaster =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
@@ -1012,7 +1025,7 @@
EvsEventDesc aTargetEvent;
aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification, true)) {
- ALOGW("A timer is expired before a target event is fired.");
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
@@ -1057,7 +1070,7 @@
EvsEventDesc aTargetEvent;
aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification, true)) {
- ALOGW("A timer is expired before a target event is fired.");
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
@@ -1089,6 +1102,7 @@
// Explicitly release the camera
pEnumerator->closeCamera(pCamMaster);
pEnumerator->closeCamera(pCamNonMaster);
+ activeCameras.clear();
}
}
@@ -1099,7 +1113,7 @@
* camera parameters.
*/
TEST_P(EvsHidlTest, MultiCameraParameter) {
- ALOGI("Starting MultiCameraParameter test");
+ LOG(INFO) << "Starting MultiCameraParameter test";
if (mIsHwModule) {
// This test is not for HW module implementation.
@@ -1120,11 +1134,10 @@
if (isLogicalCam) {
// TODO(b/145465724): Support camera parameter programming on
// logical devices.
- ALOGI("Skip a logical device %s", cam.v1.cameraId.c_str());
+ LOG(INFO) << "Skip a logical device " << cam.v1.cameraId;
continue;
}
- activeCameras.clear();
// Create two camera clients.
sp<IEvsCamera_1_1> pCamMaster =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
@@ -1256,7 +1269,7 @@
aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
aTargetEvent.payload[1] = val0;
if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
- ALOGW("A timer is expired before a target event is fired.");
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
);
@@ -1273,7 +1286,7 @@
aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
aTargetEvent.payload[1] = val0;
if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
- ALOGW("A timer is expired before a target event is fired.");
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
);
@@ -1374,7 +1387,7 @@
EvsEventDesc aTargetEvent;
aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification0, true)) {
- ALOGW("A timer is expired before a target event is fired.");
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
);
@@ -1466,7 +1479,7 @@
aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
aTargetEvent.payload[1] = val0;
if (!frameHandlerMaster->waitForEvent(aTargetEvent, aNotification0)) {
- ALOGW("A timer is expired before a target event is fired.");
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
);
@@ -1482,7 +1495,7 @@
aTargetEvent.payload[0] = static_cast<uint32_t>(cmd);
aTargetEvent.payload[1] = val0;
if (!frameHandlerNonMaster->waitForEvent(aTargetEvent, aNotification1)) {
- ALOGW("A timer is expired before a target event is fired.");
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
);
@@ -1562,6 +1575,7 @@
// Explicitly release the camera
pEnumerator->closeCamera(pCamMaster);
pEnumerator->closeCamera(pCamNonMaster);
+ activeCameras.clear();
}
}
@@ -1572,7 +1586,7 @@
* a master role from other EVS clients without the display.
*/
TEST_P(EvsHidlTest, HighPriorityCameraClient) {
- ALOGI("Starting HighPriorityCameraClient test");
+ LOG(INFO) << "Starting HighPriorityCameraClient test";
if (mIsHwModule) {
// This test is not for HW module implementation.
@@ -1592,8 +1606,6 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
- activeCameras.clear();
-
// Create two clients
sp<IEvsCamera_1_1> pCam0 =
IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg))
@@ -1687,7 +1699,7 @@
aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
aTargetEvent.payload[1] = 0;
if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
- ALOGW("A timer is expired before a target event is fired.");
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
);
@@ -1740,7 +1752,7 @@
aTargetEvent.payload[0] = static_cast<uint32_t>(cam1Cmds[0]);
aTargetEvent.payload[1] = val0;
if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
- ALOGW("A timer is expired before a target event is fired.");
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
);
@@ -1791,7 +1803,7 @@
EvsEventDesc aTargetEvent;
aTargetEvent.aType = EvsEventType::MASTER_RELEASED;
if (!frameHandler1->waitForEvent(aTargetEvent, aNotification, true)) {
- ALOGW("A timer is expired before a target event is fired.");
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
);
@@ -1833,7 +1845,7 @@
aTargetEvent.payload[0] = static_cast<uint32_t>(CameraParam::AUTO_FOCUS);
aTargetEvent.payload[1] = 0;
if (!frameHandler1->waitForEvent(aTargetEvent, aNotification)) {
- ALOGW("A timer is expired before a target event is fired.");
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
);
@@ -1882,7 +1894,7 @@
aTargetEvent.payload[0] = static_cast<uint32_t>(cam0Cmds[0]);
aTargetEvent.payload[1] = val0;
if (!frameHandler0->waitForEvent(aTargetEvent, aNotification)) {
- ALOGW("A timer is expired before a target event is fired.");
+ LOG(WARNING) << "A timer is expired before a target event is fired.";
}
}
);
@@ -1931,6 +1943,8 @@
// Explicitly release the camera
pEnumerator->closeCamera(pCam0);
pEnumerator->closeCamera(pCam1);
+ activeCameras.clear();
+
}
// Explicitly release the display
@@ -1945,7 +1959,7 @@
* configurations from EVS and uses one of them to start a video stream.
*/
TEST_P(EvsHidlTest, CameraUseStreamConfigToDisplay) {
- ALOGI("Starting CameraUseStreamConfigToDisplay test");
+ LOG(INFO) << "Starting CameraUseStreamConfigToDisplay test";
// Get the camera list
loadCameraList();
@@ -1956,7 +1970,6 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
- activeCameras.clear();
// choose a configuration that has a frame rate faster than minReqFps.
Stream targetCfg = {};
const int32_t minReqFps = 15;
@@ -2036,6 +2049,7 @@
// Explicitly release the camera
pEnumerator->closeCamera(pCam);
+ activeCameras.clear();
}
// Explicitly release the display
@@ -2049,7 +2063,7 @@
* underlying camera with same configuration.
*/
TEST_P(EvsHidlTest, MultiCameraStreamUseConfig) {
- ALOGI("Starting MultiCameraStream test");
+ LOG(INFO) << "Starting MultiCameraStream test";
if (mIsHwModule) {
// This test is not for HW module implementation.
@@ -2061,7 +2075,6 @@
// Test each reported camera
for (auto&& cam: cameraInfo) {
- activeCameras.clear();
// choose a configuration that has a frame rate faster than minReqFps.
Stream targetCfg = {};
const int32_t minReqFps = 15;
@@ -2094,9 +2107,8 @@
static_cast<PixelFormat>(HAL_PIXEL_FORMAT_RGBA_8888);
if (!foundCfg) {
- ALOGI("Device %s does not provide a list of supported stream configurations, skipped",
- cam.v1.cameraId.c_str());
-
+ LOG(INFO) << "Device " << cam.v1.cameraId
+ << " does not provide a list of supported stream configurations, skipped";
continue;
}
@@ -2162,7 +2174,9 @@
nsecs_t runTime = end - firstFrame;
float framesPerSecond0 = framesReceived0 / (runTime * kNanoToSeconds);
float framesPerSecond1 = framesReceived1 / (runTime * kNanoToSeconds);
- ALOGI("Measured camera rate %3.2f fps and %3.2f fps", framesPerSecond0, framesPerSecond1);
+ LOG(INFO) << "Measured camera rate "
+ << std::scientific << framesPerSecond0 << " fps and "
+ << framesPerSecond1 << " fps";
EXPECT_GE(framesPerSecond0, kMinimumFramesPerSecond);
EXPECT_GE(framesPerSecond1, kMinimumFramesPerSecond);
@@ -2187,6 +2201,7 @@
// Explicitly release the camera
pEnumerator->closeCamera(pCam0);
pEnumerator->closeCamera(pCam1);
+ activeCameras.clear();
}
}
@@ -2198,7 +2213,7 @@
* identifiers.
*/
TEST_P(EvsHidlTest, LogicalCameraMetadata) {
- ALOGI("Starting LogicalCameraMetadata test");
+ LOG(INFO) << "Starting LogicalCameraMetadata test";
// Get the camera list
loadCameraList();
@@ -2222,7 +2237,7 @@
* can be reopened.
*/
TEST_P(EvsHidlTest, UltrasonicsArrayOpenClean) {
- ALOGI("Starting UltrasonicsArrayOpenClean test");
+ LOG(INFO) << "Starting UltrasonicsArrayOpenClean test";
// Get the ultrasonics array list
loadUltrasonicsArrayList();
@@ -2236,7 +2251,7 @@
// Verify that this ultrasonics array self-identifies correctly
pUltrasonicsArray->getUltrasonicArrayInfo([&ultraInfo](UltrasonicsArrayDesc desc) {
- ALOGD("Found ultrasonics array %s", ultraInfo.ultrasonicsArrayId.c_str());
+ LOG(DEBUG) << "Found ultrasonics array " << ultraInfo.ultrasonicsArrayId;
EXPECT_EQ(ultraInfo.ultrasonicsArrayId, desc.ultrasonicsArrayId);
});
@@ -2249,14 +2264,14 @@
// Starts a stream and verifies all data received is valid.
TEST_P(EvsHidlTest, UltrasonicsVerifyStreamData) {
- ALOGI("Starting UltrasonicsVerifyStreamData");
+ LOG(INFO) << "Starting UltrasonicsVerifyStreamData";
// Get the ultrasonics array list
loadUltrasonicsArrayList();
// For each ultrasonics array.
for (auto&& ultraInfo : ultrasonicsArraysInfo) {
- ALOGD("Testing ultrasonics array: %s", ultraInfo.ultrasonicsArrayId.c_str());
+ LOG(DEBUG) << "Testing ultrasonics array: " << ultraInfo.ultrasonicsArrayId;
sp<IEvsUltrasonicsArray> pUltrasonicsArray =
pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId);
@@ -2285,14 +2300,14 @@
// Sets frames in flight before and after start of stream and verfies success.
TEST_P(EvsHidlTest, UltrasonicsSetFramesInFlight) {
- ALOGI("Starting UltrasonicsSetFramesInFlight");
+ LOG(INFO) << "Starting UltrasonicsSetFramesInFlight";
// Get the ultrasonics array list
loadUltrasonicsArrayList();
// For each ultrasonics array.
for (auto&& ultraInfo : ultrasonicsArraysInfo) {
- ALOGD("Testing ultrasonics array: %s", ultraInfo.ultrasonicsArrayId.c_str());
+ LOG(DEBUG) << "Testing ultrasonics array: " << ultraInfo.ultrasonicsArrayId;
sp<IEvsUltrasonicsArray> pUltrasonicsArray =
pEnumerator->openUltrasonicsArray(ultraInfo.ultrasonicsArrayId);
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
index e3cbf2e..f2d3c13 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleObjectPool.h
@@ -206,7 +206,7 @@
InternalPool(VehiclePropertyType type, size_t vectorSize)
: mPropType(type), mVectorSize(vectorSize) {}
- RecyclableType obtain() {
+ RecyclableType obtain() override {
return ObjectPool<VehiclePropValue>::obtain();
}
protected:
diff --git a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
index 24b777c..6087bfa 100644
--- a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
@@ -58,6 +58,8 @@
return false;
}
// update the propertyValue.
+ // The timestamp in propertyStore should only be updated by the server side. It indicates
+ // the time when the event is generated by the server.
valueToUpdate->timestamp = propValue.timestamp;
valueToUpdate->value = propValue.value;
if (updateStatus) {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 6d5f23f..84354c1 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -15,8 +15,9 @@
*/
#define LOG_TAG "DefaultVehicleHal_v2_0"
-#include <android/log.h>
#include <android-base/macros.h>
+#include <android/log.h>
+#include <sys/system_properties.h>
#include "EmulatedVehicleHal.h"
#include "JsonFakeValueGenerator.h"
@@ -126,7 +127,9 @@
*outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG;
break;
}
-
+ if (v.get()) {
+ v->timestamp = elapsedRealtimeNano();
+ }
return v;
}
@@ -186,6 +189,14 @@
return StatusCode::NOT_AVAILABLE;
}
+ if (mInEmulator && propValue.prop == toInt(VehicleProperty::DISPLAY_BRIGHTNESS)) {
+ // Emulator does not support remote brightness control, b/139959479
+ // do not send it down so that it does not bring unnecessary property change event
+ // return other error code, such NOT_AVAILABLE, causes Emulator to be freezing
+ // TODO: return StatusCode::NOT_AVAILABLE once the above issue is fixed
+ return StatusCode::OK;
+ }
+
/**
* After checking all conditions, such as the property is available, a real vhal will
* sent the events to Car ECU to take actions.
@@ -211,6 +222,17 @@
return false;
}
+// determine if it's running inside Android Emulator
+static bool isInEmulator() {
+ char propValue[PROP_VALUE_MAX];
+ bool isEmulator = (__system_property_get("ro.kernel.qemu", propValue) != 0);
+ if (!isEmulator) {
+ isEmulator = (__system_property_get("ro.hardware", propValue) != 0) &&
+ (!strcmp(propValue, "ranchu") || !strcmp(propValue, "goldfish"));
+ }
+ return isEmulator;
+}
+
// Parse supported properties list and generate vector of property values to hold current values.
void EmulatedVehicleHal::onCreate() {
static constexpr bool shouldUpdateStatus = true;
@@ -261,6 +283,8 @@
}
initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME));
initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME));
+ mInEmulator = isInEmulator();
+ ALOGD("mInEmulator=%s", mInEmulator ? "true" : "false");
}
std::vector<VehiclePropConfig> EmulatedVehicleHal::listProperties() {
@@ -283,6 +307,7 @@
}
if (v.get()) {
+ v->timestamp = elapsedRealtimeNano();
doHalEvent(std::move(v));
}
}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index ebf1995..dc05145 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -86,6 +86,7 @@
std::unordered_set<int32_t> mHvacPowerProps;
RecurrentTimer mRecurrentTimer;
VehicleHalClient* mVehicleClient;
+ bool mInEmulator;
};
} // impl
diff --git a/bluetooth/1.1/IBluetoothHci.hal b/bluetooth/1.1/IBluetoothHci.hal
index 0f69c6e..2a520c1 100644
--- a/bluetooth/1.1/IBluetoothHci.hal
+++ b/bluetooth/1.1/IBluetoothHci.hal
@@ -35,8 +35,8 @@
initialize_1_1(@1.1::IBluetoothHciCallbacks callback);
/**
- * Send an ISO data packet (as specified in the Bluetooth Specification
- * V6.0) to the Bluetooth controller.
+ * Send an ISO data packet (as specified in the Bluetooth Core
+ * Specification v5.2) to the Bluetooth controller.
* Packets must be processed in order.
* @param data HCI data packet to be sent
*/
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index f518a15..677b496 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -20,6 +20,7 @@
#include <algorithm>
#include <array>
+#include <regex>
#include <linux/videodev2.h>
#include "android-base/macros.h"
#include "CameraMetadata.h"
@@ -46,10 +47,20 @@
} // anonymous namespace
+const std::regex kDevicePathRE("/dev/video([0-9]+)");
+
ExternalCameraDevice::ExternalCameraDevice(
- const std::string& cameraId, const ExternalCameraConfig& cfg) :
- mCameraId(cameraId),
- mCfg(cfg) {}
+ const std::string& devicePath, const ExternalCameraConfig& cfg) :
+ mCameraId("-1"),
+ mDevicePath(devicePath),
+ mCfg(cfg) {
+ std::smatch sm;
+ if (std::regex_match(mDevicePath, sm, kDevicePathRE)) {
+ mCameraId = std::to_string(mCfg.cameraIdOffset + std::stoi(sm[1]));
+ } else {
+ ALOGE("%s: device path match failed for %s", __FUNCTION__, mDevicePath.c_str());
+ }
+}
ExternalCameraDevice::~ExternalCameraDevice() {}
@@ -129,20 +140,20 @@
return Void();
}
- unique_fd fd(::open(mCameraId.c_str(), O_RDWR));
+ unique_fd fd(::open(mDevicePath.c_str(), O_RDWR));
if (fd.get() < 0) {
int numAttempt = 0;
do {
ALOGW("%s: v4l2 device %s open failed, wait 33ms and try again",
- __FUNCTION__, mCameraId.c_str());
+ __FUNCTION__, mDevicePath.c_str());
usleep(OPEN_RETRY_SLEEP_US); // sleep and try again
- fd.reset(::open(mCameraId.c_str(), O_RDWR));
+ fd.reset(::open(mDevicePath.c_str(), O_RDWR));
numAttempt++;
} while (fd.get() < 0 && numAttempt <= MAX_RETRY);
if (fd.get() < 0) {
ALOGE("%s: v4l2 device open %s failed: %s",
- __FUNCTION__, mCameraId.c_str(), strerror(errno));
+ __FUNCTION__, mDevicePath.c_str(), strerror(errno));
mLock.unlock();
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
return Void();
@@ -203,9 +214,9 @@
status_t ExternalCameraDevice::initCameraCharacteristics() {
if (mCameraCharacteristics.isEmpty()) {
// init camera characteristics
- unique_fd fd(::open(mCameraId.c_str(), O_RDWR));
+ unique_fd fd(::open(mDevicePath.c_str(), O_RDWR));
if (fd.get() < 0) {
- ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mCameraId.c_str());
+ ALOGE("%s: v4l2 device open %s failed", __FUNCTION__, mDevicePath.c_str());
return DEAD_OBJECT;
}
diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp
index 62a4c87..8f4626c 100644
--- a/camera/device/3.4/default/ExternalCameraUtils.cpp
+++ b/camera/device/3.4/default/ExternalCameraUtils.cpp
@@ -703,6 +703,7 @@
namespace common {
namespace {
+ const int kDefaultCameraIdOffset = 100;
const int kDefaultJpegBufSize = 5 << 20; // 5MB
const int kDefaultNumVideoBuffer = 4;
const int kDefaultNumStillBuffer = 2;
@@ -738,6 +739,11 @@
return ret;
}
+ XMLElement *cameraIdOffset = providerCfg->FirstChildElement("CameraIdOffset");
+ if (cameraIdOffset != nullptr) {
+ ret.cameraIdOffset = std::atoi(cameraIdOffset->GetText());
+ }
+
XMLElement *ignore = providerCfg->FirstChildElement("ignore");
if (ignore == nullptr) {
ALOGI("%s: no internal ignored device specified", __FUNCTION__);
@@ -874,6 +880,7 @@
}
ExternalCameraConfig::ExternalCameraConfig() :
+ cameraIdOffset(kDefaultCameraIdOffset),
maxJpegBufSize(kDefaultJpegBufSize),
numVideoBuffers(kDefaultNumVideoBuffer),
numStillBuffers(kDefaultNumStillBuffer),
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
index 1958fcb..88726f4 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
@@ -149,6 +149,7 @@
bool mInitialized = false;
bool mInitFailed = false;
std::string mCameraId;
+ std::string mDevicePath;
const ExternalCameraConfig& mCfg;
std::vector<SupportedV4L2Format> mSupportedFormats;
CroppingType mCroppingType;
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
index 74f75eb..b354406 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
@@ -68,6 +68,9 @@
static const char* kDefaultCfgPath;
static ExternalCameraConfig loadFromCfg(const char* cfgPath = kDefaultCfgPath);
+ // CameraId base offset for numerical representation
+ uint32_t cameraIdOffset;
+
// List of internal V4L2 video nodes external camera HAL must ignore.
std::unordered_set<std::string> mInternalDevices;
diff --git a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
index 60a1a10..8fd8e58 100644
--- a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
@@ -272,16 +272,17 @@
// convert hal requests to offline request
std::deque<std::shared_ptr<HalRequest>> offlineReqs(halReqs.size());
+ size_t i = 0;
for (auto& v4lReq : halReqs) {
- std::shared_ptr<HalRequest> halReq = std::make_shared<HalRequest>();
- halReq->frameNumber = v4lReq->frameNumber;
- halReq->setting = v4lReq->setting;
- halReq->shutterTs = v4lReq->shutterTs;
- halReq->buffers = v4lReq->buffers;
+ offlineReqs[i] = std::make_shared<HalRequest>();
+ offlineReqs[i]->frameNumber = v4lReq->frameNumber;
+ offlineReqs[i]->setting = v4lReq->setting;
+ offlineReqs[i]->shutterTs = v4lReq->shutterTs;
+ offlineReqs[i]->buffers = v4lReq->buffers;
sp<V3_4::implementation::V4L2Frame> v4l2Frame =
static_cast<V3_4::implementation::V4L2Frame*>(v4lReq->frameIn.get());
- halReq->frameIn = new AllocatedV4L2Frame(v4l2Frame);
- offlineReqs.push_back(halReq);
+ offlineReqs[i]->frameIn = new AllocatedV4L2Frame(v4l2Frame);
+ i++;
// enqueue V4L2 frame
enqueueV4l2Frame(v4l2Frame);
}
diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal
index 4e2252c..d32bc91 100644
--- a/camera/metadata/3.5/types.hal
+++ b/camera/metadata/3.5/types.hal
@@ -35,28 +35,29 @@
* '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
*/
enum CameraMetadataTag : @3.4::CameraMetadataTag {
- /** android.control.availableBokehMaxSizes [static, int32[], ndk_public]
+ /** android.control.availableExtendedSceneModeMaxSizes [static, int32[], ndk_public]
*
- * <p>The list of bokeh modes for ANDROID_CONTROL_BOKEH_MODE that are supported by this camera
- * device, and each bokeh mode's maximum streaming (non-stall) size with bokeh effect.</p>
+ * <p>The list of extended scene modes for ANDROID_CONTROL_EXTENDED_SCENE_MODE that are supported
+ * by this camera device, and each extended scene mode's maximum streaming (non-stall) size
+ * with effect.</p>
*
- * @see ANDROID_CONTROL_BOKEH_MODE
+ * @see ANDROID_CONTROL_EXTENDED_SCENE_MODE
*/
- ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3,
+ ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_CONTROL_END_3_3,
- /** android.control.availableBokehZoomRatioRanges [static, float[], ndk_public]
+ /** android.control.availableExtendedSceneModeZoomRatioRanges [static, float[], ndk_public]
*
- * <p>The ranges of supported zoom ratio for non-OFF ANDROID_CONTROL_BOKEH_MODE.</p>
+ * <p>The ranges of supported zoom ratio for non-DISABLED ANDROID_CONTROL_EXTENDED_SCENE_MODE.</p>
*
- * @see ANDROID_CONTROL_BOKEH_MODE
+ * @see ANDROID_CONTROL_EXTENDED_SCENE_MODE
*/
- ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES,
+ ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES,
- /** android.control.bokehMode [dynamic, enum, public]
+ /** android.control.extendedSceneMode [dynamic, enum, public]
*
- * <p>Whether bokeh mode is enabled for a particular capture request.</p>
+ * <p>Whether extended scene mode is enabled for a particular capture request.</p>
*/
- ANDROID_CONTROL_BOKEH_MODE,
+ ANDROID_CONTROL_EXTENDED_SCENE_MODE,
/** android.control.zoomRatioRange [static, float[], public]
*
@@ -95,13 +96,22 @@
* Enumeration definitions for the various entries that need them
*/
-/** android.control.bokehMode enumeration values
- * @see ANDROID_CONTROL_BOKEH_MODE
+/** android.control.mode enumeration values added since v3.2
+ * @see ANDROID_CONTROL_MODE
*/
-enum CameraMetadataEnumAndroidControlBokehMode : uint32_t {
- ANDROID_CONTROL_BOKEH_MODE_OFF,
- ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE,
- ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS,
+enum CameraMetadataEnumAndroidControlMode :
+ @3.2::CameraMetadataEnumAndroidControlMode {
+ ANDROID_CONTROL_MODE_USE_EXTENDED_SCENE_MODE,
+};
+
+/** android.control.extendedSceneMode enumeration values
+ * @see ANDROID_CONTROL_EXTENDED_SCENE_MODE
+ */
+enum CameraMetadataEnumAndroidControlExtendedSceneMode : uint32_t {
+ ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED = 0,
+ ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_STILL_CAPTURE,
+ ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_CONTINUOUS,
+ ANDROID_CONTROL_EXTENDED_SCENE_MODE_VENDOR_START = 0x40,
};
/** android.lens.poseReference enumeration values added since v3.3
diff --git a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
index 2bfced2..64a51f6 100644
--- a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
@@ -44,17 +44,19 @@
const char* kDevicePath = "/dev/";
constexpr char kPrefix[] = "video";
constexpr int kPrefixLen = sizeof(kPrefix) - 1;
+constexpr int kDevicePrefixLen = sizeof(kDevicePath) + kPrefixLen + 1;
-bool matchDeviceName(const hidl_string& deviceName, std::string* deviceVersion,
- std::string* cameraId) {
+bool matchDeviceName(int cameraIdOffset,
+ const hidl_string& deviceName, std::string* deviceVersion,
+ std::string* cameraDevicePath) {
std::string deviceNameStd(deviceName.c_str());
std::smatch sm;
if (std::regex_match(deviceNameStd, sm, kDeviceNameRE)) {
if (deviceVersion != nullptr) {
*deviceVersion = sm[1];
}
- if (cameraId != nullptr) {
- *cameraId = sm[2];
+ if (cameraDevicePath != nullptr) {
+ *cameraDevicePath = "/dev/video" + std::to_string(std::stoi(sm[2]) - cameraIdOffset);
}
return true;
}
@@ -146,8 +148,9 @@
const hidl_string& cameraDeviceName,
ICameraProvider::getCameraDeviceInterface_V3_x_cb _hidl_cb) {
- std::string cameraId, deviceVersion;
- bool match = matchDeviceName(cameraDeviceName, &deviceVersion, &cameraId);
+ std::string cameraDevicePath, deviceVersion;
+ bool match = matchDeviceName(mCfg.cameraIdOffset, cameraDeviceName,
+ &deviceVersion, &cameraDevicePath);
if (!match) {
_hidl_cb(Status::ILLEGAL_ARGUMENT, nullptr);
return Void();
@@ -164,19 +167,19 @@
case 4: {
ALOGV("Constructing v3.4 external camera device");
deviceImpl = new device::V3_4::implementation::ExternalCameraDevice(
- cameraId, mCfg);
+ cameraDevicePath, mCfg);
break;
}
case 5: {
ALOGV("Constructing v3.5 external camera device");
deviceImpl = new device::V3_5::implementation::ExternalCameraDevice(
- cameraId, mCfg);
+ cameraDevicePath, mCfg);
break;
}
case 6: {
ALOGV("Constructing v3.6 external camera device");
deviceImpl = new device::V3_6::implementation::ExternalCameraDevice(
- cameraId, mCfg);
+ cameraDevicePath, mCfg);
break;
}
default:
@@ -186,7 +189,7 @@
}
if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
- ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
+ ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraDevicePath.c_str());
_hidl_cb(Status::INTERNAL_ERROR, nullptr);
return Void();
}
@@ -210,12 +213,14 @@
ALOGI("ExtCam: adding %s to External Camera HAL!", devName);
Mutex::Autolock _l(mLock);
std::string deviceName;
+ std::string cameraId = std::to_string(mCfg.cameraIdOffset +
+ std::atoi(devName + kDevicePrefixLen));
if (mPreferredHal3MinorVersion == 6) {
- deviceName = std::string("device@3.6/external/") + devName;
+ deviceName = std::string("device@3.6/external/") + cameraId;
} else if (mPreferredHal3MinorVersion == 5) {
- deviceName = std::string("device@3.5/external/") + devName;
+ deviceName = std::string("device@3.5/external/") + cameraId;
} else {
- deviceName = std::string("device@3.4/external/") + devName;
+ deviceName = std::string("device@3.4/external/") + cameraId;
}
mCameraStatusMap[deviceName] = CameraDeviceStatus::PRESENT;
if (mCallbacks != nullptr) {
@@ -259,12 +264,14 @@
void ExternalCameraProviderImpl_2_4::deviceRemoved(const char* devName) {
Mutex::Autolock _l(mLock);
std::string deviceName;
+ std::string cameraId = std::to_string(mCfg.cameraIdOffset +
+ std::atoi(devName + kDevicePrefixLen));
if (mPreferredHal3MinorVersion == 6) {
- deviceName = std::string("device@3.6/external/") + devName;
+ deviceName = std::string("device@3.6/external/") + cameraId;
} else if (mPreferredHal3MinorVersion == 5) {
- deviceName = std::string("device@3.5/external/") + devName;
+ deviceName = std::string("device@3.5/external/") + cameraId;
} else {
- deviceName = std::string("device@3.4/external/") + devName;
+ deviceName = std::string("device@3.4/external/") + cameraId;
}
if (mCameraStatusMap.find(deviceName) != mCameraStatusMap.end()) {
mCameraStatusMap.erase(deviceName);
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index c9d76da..05b8b47 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -784,7 +784,7 @@
const CameraMetadata& chars, int deviceVersion,
const hidl_vec<hidl_string>& deviceNames);
void verifyCameraCharacteristics(Status status, const CameraMetadata& chars);
- void verifyBokehCharacteristics(const camera_metadata_t* metadata);
+ void verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata);
void verifyZoomCharacteristics(const camera_metadata_t* metadata);
void verifyRecommendedConfigs(const CameraMetadata& metadata);
void verifyMonochromeCharacteristics(const CameraMetadata& chars, int deviceVersion);
@@ -6588,77 +6588,98 @@
poseReference >= ANDROID_LENS_POSE_REFERENCE_PRIMARY_CAMERA);
}
- verifyBokehCharacteristics(metadata);
+ verifyExtendedSceneModeCharacteristics(metadata);
verifyZoomCharacteristics(metadata);
}
-void CameraHidlTest::verifyBokehCharacteristics(const camera_metadata_t* metadata) {
+void CameraHidlTest::verifyExtendedSceneModeCharacteristics(const camera_metadata_t* metadata) {
camera_metadata_ro_entry entry;
int retcode = 0;
+ retcode = find_camera_metadata_ro_entry(metadata, ANDROID_CONTROL_AVAILABLE_MODES, &entry);
+ if ((0 == retcode) && (entry.count > 0)) {
+ for (auto i = 0; i < entry.count; i++) {
+ ASSERT_TRUE(entry.data.u8[i] >= ANDROID_CONTROL_MODE_OFF &&
+ entry.data.u8[i] <= ANDROID_CONTROL_MODE_USE_EXTENDED_SCENE_MODE);
+ }
+ } else {
+ ADD_FAILURE() << "Get camera controlAvailableModes failed!";
+ }
+
// Check key availability in capabilities, request and result.
retcode = find_camera_metadata_ro_entry(metadata,
ANDROID_REQUEST_AVAILABLE_REQUEST_KEYS, &entry);
- bool hasBokehRequestKey = false;
+ bool hasExtendedSceneModeRequestKey = false;
if ((0 == retcode) && (entry.count > 0)) {
- hasBokehRequestKey = std::find(entry.data.i32, entry.data.i32+entry.count,
- ANDROID_CONTROL_BOKEH_MODE) != entry.data.i32+entry.count;
+ hasExtendedSceneModeRequestKey =
+ std::find(entry.data.i32, entry.data.i32 + entry.count,
+ ANDROID_CONTROL_EXTENDED_SCENE_MODE) != entry.data.i32 + entry.count;
} else {
ADD_FAILURE() << "Get camera availableRequestKeys failed!";
}
retcode = find_camera_metadata_ro_entry(metadata,
ANDROID_REQUEST_AVAILABLE_RESULT_KEYS, &entry);
- bool hasBokehResultKey = false;
+ bool hasExtendedSceneModeResultKey = false;
if ((0 == retcode) && (entry.count > 0)) {
- hasBokehResultKey = std::find(entry.data.i32, entry.data.i32+entry.count,
- ANDROID_CONTROL_BOKEH_MODE) != entry.data.i32+entry.count;
+ hasExtendedSceneModeResultKey =
+ std::find(entry.data.i32, entry.data.i32 + entry.count,
+ ANDROID_CONTROL_EXTENDED_SCENE_MODE) != entry.data.i32 + entry.count;
} else {
ADD_FAILURE() << "Get camera availableResultKeys failed!";
}
retcode = find_camera_metadata_ro_entry(metadata,
ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, &entry);
- bool hasBokehMaxSizesKey = false;
- bool hasBokehZoomRatioRangesKey = false;
+ bool hasExtendedSceneModeMaxSizesKey = false;
+ bool hasExtendedSceneModeZoomRatioRangesKey = false;
if ((0 == retcode) && (entry.count > 0)) {
- hasBokehMaxSizesKey = std::find(entry.data.i32, entry.data.i32+entry.count,
- ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES) != entry.data.i32+entry.count;
- hasBokehZoomRatioRangesKey = std::find(entry.data.i32, entry.data.i32+entry.count,
- ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES) != entry.data.i32+entry.count;
+ hasExtendedSceneModeMaxSizesKey =
+ std::find(entry.data.i32, entry.data.i32 + entry.count,
+ ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES) !=
+ entry.data.i32 + entry.count;
+ hasExtendedSceneModeZoomRatioRangesKey =
+ std::find(entry.data.i32, entry.data.i32 + entry.count,
+ ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES) !=
+ entry.data.i32 + entry.count;
} else {
ADD_FAILURE() << "Get camera availableCharacteristicsKeys failed!";
}
camera_metadata_ro_entry maxSizesEntry;
- retcode = find_camera_metadata_ro_entry(metadata,
- ANDROID_CONTROL_AVAILABLE_BOKEH_MAX_SIZES, &maxSizesEntry);
- bool hasBokehMaxSizes = (0 == retcode && maxSizesEntry.count > 0);
+ retcode = find_camera_metadata_ro_entry(
+ metadata, ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_MAX_SIZES, &maxSizesEntry);
+ bool hasExtendedSceneModeMaxSizes = (0 == retcode && maxSizesEntry.count > 0);
camera_metadata_ro_entry zoomRatioRangesEntry;
- retcode = find_camera_metadata_ro_entry(metadata,
- ANDROID_CONTROL_AVAILABLE_BOKEH_ZOOM_RATIO_RANGES, &zoomRatioRangesEntry);
- bool hasBokehZoomRatioRanges = (0 == retcode && zoomRatioRangesEntry.count > 0);
+ retcode = find_camera_metadata_ro_entry(
+ metadata, ANDROID_CONTROL_AVAILABLE_EXTENDED_SCENE_MODE_ZOOM_RATIO_RANGES,
+ &zoomRatioRangesEntry);
+ bool hasExtendedSceneModeZoomRatioRanges = (0 == retcode && zoomRatioRangesEntry.count > 0);
- // Bokeh keys must all be available, or all be unavailable.
- bool noBokeh = !hasBokehRequestKey && !hasBokehResultKey && !hasBokehMaxSizesKey &&
- !hasBokehZoomRatioRangesKey && !hasBokehMaxSizes && !hasBokehZoomRatioRanges;
- if (noBokeh) {
+ // Extended scene mode keys must all be available, or all be unavailable.
+ bool noExtendedSceneMode =
+ !hasExtendedSceneModeRequestKey && !hasExtendedSceneModeResultKey &&
+ !hasExtendedSceneModeMaxSizesKey && !hasExtendedSceneModeZoomRatioRangesKey &&
+ !hasExtendedSceneModeMaxSizes && !hasExtendedSceneModeZoomRatioRanges;
+ if (noExtendedSceneMode) {
return;
}
- bool hasBokeh = hasBokehRequestKey && hasBokehResultKey && hasBokehMaxSizesKey &&
- hasBokehZoomRatioRangesKey && hasBokehMaxSizes && hasBokehZoomRatioRanges;
- ASSERT_TRUE(hasBokeh);
+ bool hasExtendedSceneMode = hasExtendedSceneModeRequestKey && hasExtendedSceneModeResultKey &&
+ hasExtendedSceneModeMaxSizesKey &&
+ hasExtendedSceneModeZoomRatioRangesKey &&
+ hasExtendedSceneModeMaxSizes && hasExtendedSceneModeZoomRatioRanges;
+ ASSERT_TRUE(hasExtendedSceneMode);
- // Must have OFF, and must have one of STILL_CAPTURE and CONTINUOUS.
- // Only valid combinations: {OFF, CONTINUOUS}, {OFF, STILL_CAPTURE}, and
- // {OFF, CONTINUOUS, STILL_CAPTURE}.
+ // Must have DISABLED, and must have one of BOKEH_STILL_CAPTURE, BOKEH_CONTINUOUS, or a VENDOR
+ // mode.
ASSERT_TRUE((maxSizesEntry.count == 6 && zoomRatioRangesEntry.count == 2) ||
(maxSizesEntry.count == 9 && zoomRatioRangesEntry.count == 4));
- bool hasOffMode = false;
- bool hasStillCaptureMode = false;
- bool hasContinuousMode = false;
+ bool hasDisabledMode = false;
+ bool hasBokehStillCaptureMode = false;
+ bool hasBokehContinuousMode = false;
+ bool hasVendorMode = false;
std::vector<AvailableStream> outputStreams;
ASSERT_EQ(Status::OK, getAvailableOutputStreams(metadata, outputStreams));
for (int i = 0, j = 0; i < maxSizesEntry.count && j < zoomRatioRangesEntry.count; i += 3) {
@@ -6666,24 +6687,29 @@
int32_t maxWidth = maxSizesEntry.data.i32[i+1];
int32_t maxHeight = maxSizesEntry.data.i32[i+2];
switch (mode) {
- case ANDROID_CONTROL_BOKEH_MODE_OFF:
- hasOffMode = true;
+ case ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED:
+ hasDisabledMode = true;
ASSERT_TRUE(maxWidth == 0 && maxHeight == 0);
break;
- case ANDROID_CONTROL_BOKEH_MODE_STILL_CAPTURE:
- hasStillCaptureMode = true;
+ case ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_STILL_CAPTURE:
+ hasBokehStillCaptureMode = true;
j += 2;
break;
- case ANDROID_CONTROL_BOKEH_MODE_CONTINUOUS:
- hasContinuousMode = true;
+ case ANDROID_CONTROL_EXTENDED_SCENE_MODE_BOKEH_CONTINUOUS:
+ hasBokehContinuousMode = true;
j += 2;
break;
default:
- ADD_FAILURE() << "Invalid bokehMode advertised: " << mode;
+ if (mode < ANDROID_CONTROL_EXTENDED_SCENE_MODE_VENDOR_START) {
+ ADD_FAILURE() << "Invalid extended scene mode advertised: " << mode;
+ } else {
+ hasVendorMode = true;
+ j += 2;
+ }
break;
}
- if (mode != ANDROID_CONTROL_BOKEH_MODE_OFF) {
+ if (mode != ANDROID_CONTROL_EXTENDED_SCENE_MODE_DISABLED) {
// Make sure size is supported.
bool sizeSupported = false;
for (const auto& stream : outputStreams) {
@@ -6703,8 +6729,8 @@
ASSERT_LE(minZoomRatio, maxZoomRatio);
}
}
- ASSERT_TRUE(hasOffMode);
- ASSERT_TRUE(hasStillCaptureMode || hasContinuousMode);
+ ASSERT_TRUE(hasDisabledMode);
+ ASSERT_TRUE(hasBokehStillCaptureMode || hasBokehContinuousMode || hasVendorMode);
}
void CameraHidlTest::verifyZoomCharacteristics(const camera_metadata_t* metadata) {
diff --git a/camera/provider/2.6/ICameraProvider.hal b/camera/provider/2.6/ICameraProvider.hal
index 5651550..ed1d31d 100644
--- a/camera/provider/2.6/ICameraProvider.hal
+++ b/camera/provider/2.6/ICameraProvider.hal
@@ -76,6 +76,13 @@
* configuration settings exposed through camera metadata), should the sum
* of resource costs for the combination be <= 100.
*
+ * The lists of camera id combinations returned by this method may contain
+ * hidden physical camera ids. If a combination does contain hidden physical
+ * camera ids, the camera framework must be able to open any logical cameras
+ * that contain these hidden physical camera ids in their
+ * ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS list, in addition to the other
+ * camera ids advertised in the combination, for concurrent operation.
+ *
* @return status Status code for the operation
* @return cameraIds a list of camera id combinations that support
* concurrent stream configurations with the minimum guarantees
diff --git a/cas/1.2/vts/functional/Android.bp b/cas/1.2/vts/functional/Android.bp
index 9bc372c..2d6517f 100644
--- a/cas/1.2/vts/functional/Android.bp
+++ b/cas/1.2/vts/functional/Android.bp
@@ -31,6 +31,8 @@
shared_libs: [
"libbinder",
],
- test_suites: ["general-tests"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
-
diff --git a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
index 8439ceb..58e0f2e 100644
--- a/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
+++ b/cas/1.2/vts/functional/VtsHalCasV1_2TargetTest.cpp
@@ -16,8 +16,6 @@
#define LOG_TAG "mediacas_hidl_hal_test"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/cas/1.0/IDescramblerBase.h>
#include <android/hardware/cas/1.0/types.h>
@@ -28,8 +26,11 @@
#include <android/hardware/cas/native/1.0/IDescrambler.h>
#include <android/hardware/cas/native/1.0/types.h>
#include <binder/MemoryDealer.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
+#include <hidl/ServiceManagement.h>
#include <hidl/Status.h>
#include <hidlmemory/FrameworkUtils.h>
#include <utils/Condition.h>
@@ -293,27 +294,14 @@
EXPECT_EQ(mEventArg, static_cast<int32_t>(mode));
}
-// Test environment for Cas HIDL HAL.
-class CasHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
- // get the test environment singleton
- static CasHidlEnvironment* Instance() {
- static CasHidlEnvironment* instance = new CasHidlEnvironment;
- return instance;
- }
-
- virtual void registerTestServices() override { registerTestService<IMediaCasService>(); }
-};
-
-class MediaCasHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class MediaCasHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
- mService = ::testing::VtsHalHidlTargetTestBase::getService<IMediaCasService>(
- CasHidlEnvironment::Instance()->getServiceName<IMediaCasService>());
+ mService = IMediaCasService::getService(GetParam());
ASSERT_NE(mService, nullptr);
}
- sp<IMediaCasService> mService;
+ sp<IMediaCasService> mService = nullptr;
protected:
static void description(const std::string& description) {
@@ -497,7 +485,7 @@
return ::testing::AssertionResult(returnVoid.isOk());
}
-TEST_F(MediaCasHidlTest, TestClearKeyApisWithSession) {
+TEST_P(MediaCasHidlTest, TestClearKeyApisWithSession) {
description("Test that valid call sequences with SessionEvent send and receive");
ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
@@ -609,11 +597,7 @@
} // anonymous namespace
-int main(int argc, char** argv) {
- ::testing::AddGlobalTestEnvironment(CasHidlEnvironment::Instance());
- ::testing::InitGoogleTest(&argc, argv);
- CasHidlEnvironment::Instance()->init(&argc, argv);
- int status = RUN_ALL_TESTS();
- LOG(INFO) << "Test result = " << status;
- return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, MediaCasHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(IMediaCasService::descriptor)),
+ android::hardware::PrintInstanceNameToString);
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index 7883dd9..33157a6 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -83,8 +83,8 @@
"compatibility_matrix.current.xml",
],
kernel_configs: [
- "kernel_config_current_4.14",
- "kernel_config_current_4.19",
- "kernel_config_current_5.4",
+ "kernel_config_r_4.14",
+ "kernel_config_r_4.19",
+ "kernel_config_r_5.4",
]
}
diff --git a/compatibility_matrices/compatibility_matrix.1.xml b/compatibility_matrices/compatibility_matrix.1.xml
index d82829d..cccf24f 100644
--- a/compatibility_matrices/compatibility_matrix.1.xml
+++ b/compatibility_matrices/compatibility_matrix.1.xml
@@ -71,7 +71,7 @@
<instance>legacy/0</instance>
</interface>
</hal>
- <hal format="hidl" optional="false">
+ <hal format="hidl" optional="true">
<name>android.hardware.configstore</name>
<version>1.0</version>
<interface>
diff --git a/compatibility_matrices/compatibility_matrix.2.xml b/compatibility_matrices/compatibility_matrix.2.xml
index 98e6cfa..d4f9809 100644
--- a/compatibility_matrices/compatibility_matrix.2.xml
+++ b/compatibility_matrices/compatibility_matrix.2.xml
@@ -79,7 +79,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="false">
+ <hal format="hidl" optional="true">
<name>android.hardware.configstore</name>
<version>1.0</version>
<interface>
diff --git a/compatibility_matrices/compatibility_matrix.3.xml b/compatibility_matrices/compatibility_matrix.3.xml
index 9933b33..5888ab9 100644
--- a/compatibility_matrices/compatibility_matrix.3.xml
+++ b/compatibility_matrices/compatibility_matrix.3.xml
@@ -111,7 +111,7 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="false">
+ <hal format="hidl" optional="true">
<name>android.hardware.configstore</name>
<version>1.0-1</version>
<interface>
diff --git a/compatibility_matrices/compatibility_matrix.4.xml b/compatibility_matrices/compatibility_matrix.4.xml
index 01ec172..e5e012c 100644
--- a/compatibility_matrices/compatibility_matrix.4.xml
+++ b/compatibility_matrices/compatibility_matrix.4.xml
@@ -181,12 +181,6 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.gnss</name>
- <!--
- - Both versions are listed here as a workaround for libvintf since 2.0 extends 1.1.
- - Devices launched with Q must support gnss@2.0, see VtsTrebleVendorVintfTest
- - test DeviceManifestTest#GnssHalVersionCompatibility.
- -->
- <version>1.1</version>
<version>2.0</version>
<interface>
<name>IGnss</name>
@@ -429,7 +423,6 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.thermal</name>
- <version>1.0-1</version>
<version>2.0</version>
<interface>
<name>IThermal</name>
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index de1ee84..f28a8b2 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -40,9 +40,21 @@
</interface>
</hal>
<hal format="hidl" optional="true">
- <name>android.hardware.automotive.evs</name>
+ <name>android.hardware.automotive.can</name>
<version>1.0</version>
<interface>
+ <name>ICanBus</name>
+ <regex-instance>.*</regex-instance>
+ </interface>
+ <interface>
+ <name>ICanController</name>
+ <regex-instance>.*</regex-instance>
+ </interface>
+ </hal>
+ <hal format="hidl" optional="true">
+ <name>android.hardware.automotive.evs</name>
+ <version>1.0-1</version>
+ <interface>
<name>IEvsEnumerator</name>
<instance>default</instance>
<regex-instance>[a-z]+/[0-9]+</regex-instance>
@@ -197,12 +209,6 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.gnss</name>
- <!--
- - Both versions are listed here as a workaround for libvintf since 2.0 extends 1.1.
- - Devices launched with Q must support gnss@2.0, see VtsTrebleVendorVintfTest
- - test DeviceManifestTest#GnssHalVersionCompatibility.
- -->
- <version>1.1</version>
<version>2.0-1</version>
<interface>
<name>IGnss</name>
@@ -255,6 +261,13 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="aidl" optional="true">
+ <name>android.hardware.identity</name>
+ <interface>
+ <name>IIdentityCredentialStore</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="hidl" optional="true">
<name>android.hardware.ir</name>
<version>1.0</version>
@@ -451,7 +464,6 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.thermal</name>
- <version>1.0</version>
<version>2.0</version>
<interface>
<name>IThermal</name>
@@ -475,6 +487,14 @@
</interface>
</hal>
<hal format="hidl" optional="true">
+ <name>android.hardware.tv.tuner</name>
+ <version>1.0</version>
+ <interface>
+ <name>ITuner</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="hidl" optional="true">
<name>android.hardware.usb</name>
<version>1.0-2</version>
<interface>
diff --git a/compatibility_matrices/compatibility_matrix.legacy.xml b/compatibility_matrices/compatibility_matrix.legacy.xml
index 224811f..8a4d2ee 100644
--- a/compatibility_matrices/compatibility_matrix.legacy.xml
+++ b/compatibility_matrices/compatibility_matrix.legacy.xml
@@ -71,7 +71,7 @@
<instance>legacy/0</instance>
</interface>
</hal>
- <hal format="hidl" optional="false">
+ <hal format="hidl" optional="true">
<name>android.hardware.configstore</name>
<version>1.0</version>
<interface>
diff --git a/configstore/1.1/default/Android.mk b/configstore/1.1/default/Android.mk
index e7edc34..6b7bb00 100644
--- a/configstore/1.1/default/Android.mk
+++ b/configstore/1.1/default/Android.mk
@@ -35,3 +35,14 @@
LOCAL_SRC_FILES := seccomp_policy/configstore@1.1-$(TARGET_ARCH).policy
include $(BUILD_PREBUILT)
endif
+
+# disable configstore
+include $(CLEAR_VARS)
+LOCAL_MODULE := disable_configstore
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_SRC_FILES:= disable_configstore.cpp
+LOCAL_OVERRIDES_MODULES := android.hardware.configstore@1.1-service
+LOCAL_VENDOR_MODULE := true
+LOCAL_UNINSTALLABLE_MODULE := true
+
+include $(BUILD_EXECUTABLE)
diff --git a/configstore/1.1/default/disable_configstore.cpp b/configstore/1.1/default/disable_configstore.cpp
new file mode 100644
index 0000000..b727ddb
--- /dev/null
+++ b/configstore/1.1/default/disable_configstore.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (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.1
+ *
+ * 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.
+ */
+
+int main() {
+ return 1;
+}
diff --git a/current.txt b/current.txt
index 42981ad..47b7206 100644
--- a/current.txt
+++ b/current.txt
@@ -589,6 +589,7 @@
a05277065c28ebecd58118bd240fb8c55757361e8648c01f7c4dacdb7f2a95dc android.hardware.camera.metadata@3.3::types
9cb3df2bde2c6cd5fd96b7c41555420cacd7e276a556c684af91b7461c86460f android.hardware.gnss@1.0::IGnssCallback
af334f1fc85c62b343f84b74d0495eed6f495f7fecedb53463db10c202310058 android.hardware.gnss.measurement_corrections@1.0::types
+33a6b20c43af00fdfb305df891bc5911c06d9a9130b912759649932e5a4a6e6d android.hardware.gnss.visibility_control@1.0::IGnssVisibilityControlCallback
bceee81ec1b59324abd05932b5620fda5a6589597c9cb3953ba7f3ea02cccd3e android.hardware.camera.provider@2.4::ICameraProvider
2ce820dc4f3c6d85721b65150ed2157c6e2e2055f866fb6c6ba4790f14408d66 android.hardware.camera.provider@2.4::ICameraProviderCallback
b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
@@ -605,7 +606,6 @@
5751f230e86a36111e7c5b995577cbf89d8df76c8e6c7641199198f3db3a93f7 android.hardware.wifi@1.3::IWifiStaIface
# HALs released in Android R
-822369cf4dc16a6f6b9622bcf86cbdc0b692dc82193fc15e967767175cbfdd8f android.hardware.audio@6.0::types
7241bd4596a927cd46d4b82f5e29e2cbe57f194aa1b25555f1d1d352e8b15c61 android.hardware.audio@6.0::IDevice
2402876cbc23c0de3690a665eca84fd3857d1808dba5cad25ce272f81ecef8c9 android.hardware.audio@6.0::IDevicesFactory
bca5379d5065e2e08b6ad7308ffc8a71a972fc0698bec678ea32eea786d01cb5 android.hardware.audio@6.0::IPrimaryDevice
@@ -614,8 +614,8 @@
164826a380f4c1700183003f62d7532e367b67381c30ea44f946c0cf00008f85 android.hardware.audio@6.0::IStreamOut
997fdaad7a9d17ee7e01feb7031a753e2365e72ad30b11d950e9183fabdf3844 android.hardware.audio@6.0::IStreamOutCallback
e7ca0db9a1098210f327a9b152fa6afe6bf019c41e5264c64829d04d50c0a526 android.hardware.audio@6.0::IStreamOutEventCallback
+822369cf4dc16a6f6b9622bcf86cbdc0b692dc82193fc15e967767175cbfdd8f android.hardware.audio@6.0::types
bee662c62d997d8065e2bcb5c1e7a9578931f22ce28fd02c219fdb4d0630abf7 android.hardware.audio.common@6.0::types
-817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types
525bec6b44f1103869c269a128d51b8dccd73af5340ba863c8886c68357c7faf android.hardware.audio.effect@6.0::IAcousticEchoCancelerEffect
8d76bbe3719d051a8e9a1dcf9244f37f5b0a491feb249fa48391edf7cb4f3131 android.hardware.audio.effect@6.0::IAutomaticGainControlEffect
461b1114cb35d89f87e5694e0792ba53c112a7fa9a14d9b95188cf9c4764be23 android.hardware.audio.effect@6.0::IBassBoostEffect
@@ -630,18 +630,19 @@
5237c42d3913ef569f07bec802568084b615155d05a7951e75085da54856508c android.hardware.audio.effect@6.0::IPresetReverbEffect
282193799d60bff27a84c65a36218c1e7d8f582f5828e2e059383d1b90aa56bd android.hardware.audio.effect@6.0::IVirtualizerEffect
0868e00f7c5ee16723bda1a8f57099763d04100ae7126a1c2d3a9a87c844a7e8 android.hardware.audio.effect@6.0::IVisualizerEffect
+817930d58412d662cb45e641c50cb62c727e4a3e3ffe7029a53cad9677b97d58 android.hardware.audio.effect@6.0::types
7e8e1c3d0173c5d503dd01cecff8e3864478557ca6b9e8cc2291598b1a4aea62 android.hardware.biometrics.face@1.1::IBiometricsFace
-ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types
6828bbf18dc5d0f00c73341a10c8e4d574346c1abb1c2ed682ba5e9f8a3240d9 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprint
82cad99f5feb2ea9bcd4579055edf4af8feb9fc602a6e4827ddd727d254d4991 android.hardware.biometrics.fingerprint@2.2::IBiometricsFingerprintClientCallback
-79e115c8f8970b8b914bafc66df5425e065fda4dcda97222966ef12451d2a1cc android.hardware.bluetooth@1.1::IBluetoothHci
+ae6315fd42196478ac08441cb489d854118001bca5b9b9fd58af5110952be30e android.hardware.biometrics.fingerprint@2.2::types
+362fd1c21641c2224f3b80c30d9797b988fa3f344243d531ba73c553779a5763 android.hardware.bluetooth@1.1::IBluetoothHci
40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks
07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl
74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types
b8c63679e1a3874b356f3e691aecce1191d38f59063cf2ed2dce8a9d4cabf00e android.hardware.camera.device@3.6::ICameraDevice
-99aae72ae75a8ddf63ccffbc585f3a55f4d0847b4adff3d7a0f8bd9e2305bec1 android.hardware.camera.provider@2.6::ICameraProvider
-8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback
a35d5151b48505f06a775b38c0e2e265f80a845d92802324c643565807f81c53 android.hardware.camera.device@3.6::types
+21086e1c7a2acc0ebe0ff8561b11f3c2009be687a92d79b608a5f00b16c5f598 android.hardware.camera.provider@2.6::ICameraProvider
+8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback
c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas
9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener
f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService
@@ -650,25 +651,21 @@
3581d0ba61663cdd45807494dcd697d01c074f27587df9140655f94346969cfe android.hardware.contexthub@1.1::types
66931c2506fbb5af61f20138cb05e0a09e7bf67d6964c231d27c648933bb33ec android.hardware.drm@1.3::ICryptoFactory
994d08ab27d613022c258a9ec48cece7adf2a305e92df5d76ef923e2c6665f64 android.hardware.drm@1.3::IDrmFactory
-d9df99be0f59d8f33a9699fe316c67bfd11818aa69440bb1123ba43e717cea85 android.hardware.dumpstate@1.1::types
186bc152ae189ab48f3a761a44ddf5edd0d483073c5b6ca1f802f8b50488b754 android.hardware.dumpstate@1.1::IDumpstateDevice
-769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types
+d9df99be0f59d8f33a9699fe316c67bfd11818aa69440bb1123ba43e717cea85 android.hardware.dumpstate@1.1::types
c319e68b03829958404402c2d9c682019678087d60495807c0a7444e0a6af981 android.hardware.gnss@2.1::IGnss
ba5ac712b2a656dc07c83ab4a7a2c2f3bee1bbcb752e8b8ffa9b672f3b5b0728 android.hardware.gnss@2.1::IGnssAntennaInfo
0bc3ed97cbc3f6abc89c68f4e9f4d124f9f723431997dc88c2186cf4d2ad47ee android.hardware.gnss@2.1::IGnssAntennaInfoCallback
3541d83adfeac16ee3e45d183a58dffe06012ccb5aa5bcd2e4f6eeae269f69cd android.hardware.gnss@2.1::IGnssCallback
737d750017738f0753d13ba01a3310e0161f294b8ae80b3fd63eaa227e9d9c66 android.hardware.gnss@2.1::IGnssConfiguration
7913a11206a577b12ade86a7cf3f95c2639cb514d086673f279bf99238c9917e android.hardware.gnss@2.1::IGnssMeasurement
-0a16e5913e94d995cfcf959a1c6f10b0b8e9dfdb5f45ac6e7244711ddd740272 android.hardware.gnss@2.1::IGnssMeasurementCallback
+df52e2c39ed701a355b5e0fdbf83fe5fa7d04bfecd715116b39373d46dc3c682 android.hardware.gnss@2.1::IGnssMeasurementCallback
+769d346927a94fd40ee80a5a976d8d15cf022ef99c5900738f4a82f26c0ed229 android.hardware.gnss@2.1::types
6670e7780803a8c696c6391fda5589a334b1b37dc7be9393792ed35035413633 android.hardware.gnss.measurement_corrections@1.1::IMeasurementCorrections
956c1576ca0d6f11b42980ef59052062836b6763fe973af6cb709da50787f710 android.hardware.gnss.measurement_corrections@1.1::types
ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth
26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback
e2f8bc1868fd4a3fd587c172773ea5a8c2f5a3deaf7958394102ca455252b255 android.hardware.health@2.1::types
-0589e410f519e36514e7ece18f283f022df0f70efd2c12821d822f67f74aba98 android.hardware.identity@1.0::types
-bbeee9604128ede83ee755b67e73b5ad29e6e1dbac9ec41fea6ffe2745b0c50a android.hardware.identity@1.0::IIdentityCredential
-96ce8aad80f4c476f25261f790d357c117e79e18474c7dadd850dac704bbe65e android.hardware.identity@1.0::IIdentityCredentialStore
-8da9c938e58f7d636ddd2f92c646f99d9a9e79612e6441b6380ab12744251873 android.hardware.identity@1.0::IWritableIdentityCredential
27ae3724053940462114228872b3ffaf0b8e6177d5ba97f5a76339d12b8a99dd android.hardware.keymaster@4.1::IKeymasterDevice
adb0efdf1462e9b2e742c0dcadd598666aac551f178be06e755bfcdf5797abd0 android.hardware.keymaster@4.1::IOperation
ddcf89cd8ee2df0d32aee55050826446fb64f7aafde0a7cd946c64f61b1a364c android.hardware.keymaster@4.1::types
@@ -680,8 +677,16 @@
6e904be0ddca5ae1de8eba020e6c38ed935ea7d80cd08f47787f137a0ca58555 android.hardware.neuralnetworks@1.3::IFencedExecutionCallback
2b0b10d2ea7a18a4048cd0eb83d35c19a817aeee95f65807fc31f4ef21381397 android.hardware.neuralnetworks@1.3::IPreparedModel
eee3430cc86c97c7b407495863d8fb61da6f1a64b7721e77b9b4909b11b174e9 android.hardware.neuralnetworks@1.3::IPreparedModelCallback
-c9320b04ec302624985180a02d591bea5e435601fc411a6cabb58878e4e1ad68 android.hardware.neuralnetworks@1.3::types
-b335c3c732c799b299fa61c6de6260ab4d20cbd0ec21acd6db14d8156c745d0b android.hardware.tv.tuner@1.0::types
+e442ab1b440327fe4e8a3b0b8ac6874e9bc6342e91fe976eb9fea77c63961ec8 android.hardware.neuralnetworks@1.3::types
+b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardware.radio@1.5::IRadio
+fcbb0742a88215ee7a6d7ce0825d253eb2b50391fc6c8c48667f9fd7f6d4549e android.hardware.radio@1.5::IRadioIndication
+b809193970a91ca637a4b0184767315601d32e3ef3d5992ffbc7a8d14a14f015 android.hardware.radio@1.5::IRadioResponse
+6b8dcd5e3e33a524cc7ebb14671a76ad3a2d333467397ce82acc4024346386f8 android.hardware.radio@1.5::types
+3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors
+3d4141c6373cd9ca02fe221a7d12343840de2255d032c38248fe8e35816b58b2 android.hardware.sensors@2.1::ISensorsCallback
+8051cc50fc90ed447f058a8b15d81f35a65f1bd9004b1de4f127edeb89b47978 android.hardware.sensors@2.1::types
+b37f78e3fdc79af8b32a545b2b426f1fd1355b359d9e7835f3bf1ed0aa4518d8 android.hardware.soundtrigger@2.3::ISoundTriggerHw
+4a6517ea4ad807855428b0101d8e1a486497bd88ab4300ba3b2be43d46d32580 android.hardware.soundtrigger@2.3::types
adab52e647d1a1ccfbdabdfc9c73352f8e834b61322e505bc6e3d3a0d3acc259 android.hardware.tv.tuner@1.0::IDemux
548e1a16fc4f779346e14968a63cd6f160e1e2c8b8c99256b2bac24a24b52a9a android.hardware.tv.tuner@1.0::IDescrambler
b84597d59f0f1d03c9997d60eb15280f3950c287d46016240d89859789db4d47 android.hardware.tv.tuner@1.0::IDvr
@@ -694,6 +699,8 @@
b2310785bdb55f97bbbb2176e2ee73ed8d2a7ce5895bd20c997b90c5f2868ad8 android.hardware.tv.tuner@1.0::ILnbCallback
4788787e662293d526ff7789fc24e82533e7f6ff99a967ebc3e3ec6b17628796 android.hardware.tv.tuner@1.0::ITimeFilter
c350c7783843e0c7cf30f90c918770b0d3c09fc0fe5e532e2f2e7210fcfe71c9 android.hardware.tv.tuner@1.0::ITuner
+b335c3c732c799b299fa61c6de6260ab4d20cbd0ec21acd6db14d8156c745d0b android.hardware.tv.tuner@1.0::types
+7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget
3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd
2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types
@@ -702,13 +709,3 @@
2ce1f7fb52e49f80b13a9b153d491bce530552f02357ea729acae922a8659f93 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
77531c8d048f8f8ae532babd0ca86332a865ec9aace1b051226ef2b21123e645 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types
-99f5c26b952271d1246c957e1d0271fa39445ee65cc93aa7c187834f98914a33 android.hardware.radio@1.5::types
-b454df853441c12f6e425e8a60dd29fda20f5e6e39b93d1103e4b37495db38aa android.hardware.radio@1.5::IRadio
-e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication
-829d3827eeb5a8f563e80fe627419b3231012fc02bc2e79782ec5e9ad9f799a4 android.hardware.radio@1.5::IRadioResponse
-3ca6616381080bdd6c08141ad12775a94ae868c58b02b1274ae3326f7de724ab android.hardware.sensors@2.1::ISensors
-3d4141c6373cd9ca02fe221a7d12343840de2255d032c38248fe8e35816b58b2 android.hardware.sensors@2.1::ISensorsCallback
-8051cc50fc90ed447f058a8b15d81f35a65f1bd9004b1de4f127edeb89b47978 android.hardware.sensors@2.1::types
-4a6517ea4ad807855428b0101d8e1a486497bd88ab4300ba3b2be43d46d32580 android.hardware.soundtrigger@2.3::types
-b37f78e3fdc79af8b32a545b2b426f1fd1355b359d9e7835f3bf1ed0aa4518d8 android.hardware.soundtrigger@2.3::ISoundTriggerHw
-7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget
diff --git a/drm/1.3/vts/functional/Android.bp b/drm/1.3/vts/functional/Android.bp
index 4be1575..ac1f912 100644
--- a/drm/1.3/vts/functional/Android.bp
+++ b/drm/1.3/vts/functional/Android.bp
@@ -30,12 +30,12 @@
"android.hardware.drm@1.3",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
+ "libcrypto",
"libhidlmemory",
"libnativehelper",
],
static_libs: [
"android.hardware.drm@1.0-helper",
- "libcrypto_static",
"libdrmvtshelper",
],
export_include_dirs: [
@@ -63,12 +63,12 @@
"android.hardware.drm@1.3",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
+ "libcrypto",
"libhidlmemory",
"libnativehelper",
],
static_libs: [
"android.hardware.drm@1.0-helper",
- "libcrypto_static",
"libdrmvtshelper",
],
test_suites: [
diff --git a/gnss/2.0/default/GnssMeasurement.cpp b/gnss/2.0/default/GnssMeasurement.cpp
index d778d50..a3ea807 100644
--- a/gnss/2.0/default/GnssMeasurement.cpp
+++ b/gnss/2.0/default/GnssMeasurement.cpp
@@ -49,8 +49,8 @@
Return<void> GnssMeasurement::close() {
ALOGD("close");
- std::unique_lock<std::mutex> lock(mMutex);
stop();
+ std::unique_lock<std::mutex> lock(mMutex);
sCallback = nullptr;
return Void();
}
diff --git a/gnss/2.0/default/GnssMeasurement.h b/gnss/2.0/default/GnssMeasurement.h
index d8ffd59..73eaa13 100644
--- a/gnss/2.0/default/GnssMeasurement.h
+++ b/gnss/2.0/default/GnssMeasurement.h
@@ -61,10 +61,14 @@
void stop();
void reportMeasurement(const GnssData&);
+ // Guarded by mMutex
static sp<IGnssMeasurementCallback> sCallback;
+
std::atomic<long> mMinIntervalMillis;
std::atomic<bool> mIsActive;
std::thread mThread;
+
+ // Synchronization lock for sCallback
mutable std::mutex mMutex;
};
diff --git a/gnss/2.1/IGnssMeasurementCallback.hal b/gnss/2.1/IGnssMeasurementCallback.hal
index 0e6abbd..60a5423 100644
--- a/gnss/2.1/IGnssMeasurementCallback.hal
+++ b/gnss/2.1/IGnssMeasurementCallback.hal
@@ -30,13 +30,13 @@
*/
enum GnssMeasurementFlags : @1.0::IGnssMeasurementCallback.GnssMeasurementFlags {
/**
- * A valid receiver inter-signal bias is stored in the data structure.
+ * A valid full inter-signal bias is stored in the data structure.
*/
- HAS_RECEIVER_ISB = 1 << 16,
+ HAS_FULL_ISB = 1 << 16,
/**
- * A valid receiver inter-signal bias uncertainty is stored in the data structure.
+ * A valid full inter-signal bias uncertainty is stored in the data structure.
*/
- HAS_RECEIVER_ISB_UNCERTAINTY = 1 << 17,
+ HAS_FULL_ISB_UNCERTAINTY = 1 << 17,
/**
* A valid satellite inter-signal bias is stored in the data structure.
*/
@@ -77,42 +77,58 @@
bitfield<GnssMeasurementFlags> flags;
/**
- * The receiver inter-signal bias (ISB) in nanoseconds.
+ * The full inter-signal bias (ISB) in nanoseconds.
*
- * This value is the estimated receiver-side inter-system (different from the constellation
- * in GnssClock.referenceSignalTypeForIsb) bias and inter-frequency (different from the
- * carrier frequency in GnssClock.referenceSignalTypeForIsb) bias. The reported receiver ISB
- * must include signal delays caused by
+ * This value is the sum of the estimated receiver-side and the space-segment-side
+ * inter-system bias, inter-frequency bias and inter-code bias, including
*
- * - Receiver inter-constellation bias
- * - Receiver inter-frequency bias
- * - Receiver inter-code bias
+ * - Receiver inter-constellation bias (with respect to the constellation in
+ * GnssClock.referenceSignalTypeForIsb)
+ * - Receiver inter-frequency bias (with respect to the carrier frequency in
+ * GnssClock.referenceSignalTypeForIsb)
+ * - Receiver inter-code bias (with respect to the code type in
+ * GnssClock.referenceSignalTypeForIsb)
+ * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPS-UTC Time Offset
+ * (TauGps), BDS-GLO Time Offset (BGTO)) (with respect to the constellation in
+ * GnssClock.referenceSignalTypeForIsb)
+ * - Group delay (e.g., Total Group Delay (TGD))
+ * - Satellite inter-frequency bias (GLO only) (with respect to the carrier frequency in
+ * GnssClock.referenceSignalTypeForIsb)
+ * - Satellite inter-code bias (e.g., Differential Code Bias (DCB)) (with respect to the
+ * code type in GnssClock.referenceSignalTypeForIsb)
+ *
+ * If a component of the above is already compensated in the provided
+ * GnssMeasurement.receivedSvTimeInNs, then it must not be included in the reported full
+ * ISB.
*
* The value does not include the inter-frequency Ionospheric bias.
*
- * The receiver ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds.
+ * The full ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds.
*/
- double receiverInterSignalBiasNs;
+ double fullInterSignalBiasNs;
/**
- * 1-sigma uncertainty associated with the receiver inter-signal bias in nanoseconds.
+ * 1-sigma uncertainty associated with the full inter-signal bias in nanoseconds.
*/
- double receiverInterSignalBiasUncertaintyNs;
+ double fullInterSignalBiasUncertaintyNs;
/**
* The satellite inter-signal bias in nanoseconds.
*
- * This value is the satellite-and-control-segment-side inter-system (different from the
- * constellation in GnssClock.referenceSignalTypeForIsb) bias and inter-frequency (different
- * from the carrier frequency in GnssClock.referenceSignalTypeForIsb) bias, including:
+ * This value is the sum of the space-segment-side inter-system bias, inter-frequency bias
+ * and inter-code bias, including
*
- * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPT-UTC Time Offset (TauGps),
- * BDS-GLO Time Offset (BGTO))
+ * - Master clock bias (e.g., GPS-GAL Time Offset (GGTO), GPS-UTC Time Offset
+ * (TauGps), BDS-GLO Time Offset (BGTO)) (with respect to the constellation in
+ * GnssClock.referenceSignalTypeForIsb)
* - Group delay (e.g., Total Group Delay (TGD))
- * - Satellite inter-signal bias, which includes satellite inter-frequency bias (GLO only),
- * and satellite inter-code bias (e.g., Differential Code Bias (DCB)).
+ * - Satellite inter-frequency bias (GLO only) (with respect to the carrier frequency in
+ * GnssClock.referenceSignalTypeForIsb)
+ * - Satellite inter-code bias (e.g., Differential Code Bias (DCB)) (with respect to the
+ * code type in GnssClock.referenceSignalTypeForIsb)
*
- * The receiver ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0 nanoseconds.
+ * The satellite ISB of GnssClock.referenceSignalTypeForIsb is defined to be 0.0
+ * nanoseconds.
*/
double satelliteInterSignalBiasNs;
diff --git a/gnss/2.1/default/GnssAntennaInfo.cpp b/gnss/2.1/default/GnssAntennaInfo.cpp
index d32a0af..ed183a9 100644
--- a/gnss/2.1/default/GnssAntennaInfo.cpp
+++ b/gnss/2.1/default/GnssAntennaInfo.cpp
@@ -55,8 +55,8 @@
Return<void> GnssAntennaInfo::close() {
ALOGD("close");
- std::unique_lock<std::mutex> lock(mMutex);
stop();
+ std::unique_lock<std::mutex> lock(mMutex);
sCallback = nullptr;
return Void();
}
diff --git a/gnss/2.1/default/GnssAntennaInfo.h b/gnss/2.1/default/GnssAntennaInfo.h
index f4bfd24..94b2111 100644
--- a/gnss/2.1/default/GnssAntennaInfo.h
+++ b/gnss/2.1/default/GnssAntennaInfo.h
@@ -47,10 +47,14 @@
void reportAntennaInfo(
const hidl_vec<IGnssAntennaInfoCallback::GnssAntennaInfo>& antennaInfo) const;
+ // Guarded by mMutex
static sp<IGnssAntennaInfoCallback> sCallback;
+
std::atomic<long> mMinIntervalMillis;
std::atomic<bool> mIsActive;
std::thread mThread;
+
+ // Synchronization lock for sCallback
mutable std::mutex mMutex;
};
@@ -60,4 +64,4 @@
} // namespace hardware
} // namespace android
-#endif // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
\ No newline at end of file
+#endif // ANDROID_HARDWARE_GNSS_V2_1_GNSSCONFIGURATION_H
diff --git a/gnss/2.1/default/GnssMeasurement.cpp b/gnss/2.1/default/GnssMeasurement.cpp
index 34e20e5..63bbc0a 100644
--- a/gnss/2.1/default/GnssMeasurement.cpp
+++ b/gnss/2.1/default/GnssMeasurement.cpp
@@ -47,8 +47,8 @@
Return<void> GnssMeasurement::close() {
ALOGD("close");
- std::unique_lock<std::mutex> lock(mMutex);
stop();
+ std::unique_lock<std::mutex> lock(mMutex);
sCallback_2_1 = nullptr;
sCallback_2_0 = nullptr;
return Void();
diff --git a/gnss/2.1/default/GnssMeasurement.h b/gnss/2.1/default/GnssMeasurement.h
index 3ed7bc5..d446419 100644
--- a/gnss/2.1/default/GnssMeasurement.h
+++ b/gnss/2.1/default/GnssMeasurement.h
@@ -66,11 +66,17 @@
void reportMeasurement(const GnssDataV2_0&);
void reportMeasurement(const GnssDataV2_1&);
+ // Guarded by mMutex
static sp<V2_1::IGnssMeasurementCallback> sCallback_2_1;
+
+ // Guarded by mMutex
static sp<V2_0::IGnssMeasurementCallback> sCallback_2_0;
+
std::atomic<long> mMinIntervalMillis;
std::atomic<bool> mIsActive;
std::thread mThread;
+
+ // Synchronization lock for sCallback_2_1 and sCallback_2_0
mutable std::mutex mMutex;
};
diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
index 7b054c0..33feb5e 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
@@ -98,7 +98,7 @@
* TestGnssMeasurementFields:
* Sets a GnssMeasurementCallback, waits for a measurement, and verifies
* 1. basebandCN0DbHz is valid
- * 2. ISB fields are valid if HAS_INTER_SIGNAL_BIAS is true.
+ * 2. ISB fields are valid
*/
TEST_P(GnssHalTest, TestGnssMeasurementFields) {
const int kFirstGnssMeasurementTimeoutSeconds = 10;
@@ -126,9 +126,8 @@
// Verify basebandCn0DbHz is valid.
ASSERT_TRUE(measurement.basebandCN0DbHz > 0.0 && measurement.basebandCN0DbHz <= 65.0);
- if (((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_RECEIVER_ISB) > 0) &&
- ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_RECEIVER_ISB_UNCERTAINTY) >
- 0) &&
+ if (((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_FULL_ISB) > 0) &&
+ ((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_FULL_ISB_UNCERTAINTY) > 0) &&
((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB) > 0) &&
((uint32_t)(measurement.flags & GnssMeasurementFlags::HAS_SATELLITE_ISB_UNCERTAINTY) >
0)) {
@@ -143,8 +142,8 @@
ASSERT_TRUE(carrierFrequencyHz > 0);
ASSERT_TRUE(codeType != "");
- ASSERT_TRUE(std::abs(measurement.receiverInterSignalBiasNs) < 1.0e6);
- ASSERT_TRUE(measurement.receiverInterSignalBiasUncertaintyNs >= 0);
+ ASSERT_TRUE(std::abs(measurement.fullInterSignalBiasNs) < 1.0e6);
+ ASSERT_TRUE(measurement.fullInterSignalBiasUncertaintyNs >= 0);
ASSERT_TRUE(std::abs(measurement.satelliteInterSignalBiasNs) < 1.0e6);
ASSERT_TRUE(measurement.satelliteInterSignalBiasUncertaintyNs >= 0);
}
diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp
index 2e5b873..386090e 100644
--- a/gnss/common/utils/default/Utils.cpp
+++ b/gnss/common/utils/default/Utils.cpp
@@ -39,12 +39,12 @@
.v2_0 = gnssDataV2_0.measurements[0],
.flags = (uint32_t)(GnssMeasurementFlagsV2_1::HAS_CARRIER_FREQUENCY |
GnssMeasurementFlagsV2_1::HAS_CARRIER_PHASE |
- GnssMeasurementFlagsV2_1::HAS_RECEIVER_ISB |
- GnssMeasurementFlagsV2_1::HAS_RECEIVER_ISB_UNCERTAINTY |
+ GnssMeasurementFlagsV2_1::HAS_FULL_ISB |
+ GnssMeasurementFlagsV2_1::HAS_FULL_ISB_UNCERTAINTY |
GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB |
GnssMeasurementFlagsV2_1::HAS_SATELLITE_ISB_UNCERTAINTY),
- .receiverInterSignalBiasNs = 10.0,
- .receiverInterSignalBiasUncertaintyNs = 100.0,
+ .fullInterSignalBiasNs = 30.0,
+ .fullInterSignalBiasUncertaintyNs = 250.0,
.satelliteInterSignalBiasNs = 20.0,
.satelliteInterSignalBiasUncertaintyNs = 150.0,
.basebandCN0DbHz = 25.0,
diff --git a/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal b/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal
index 5a582c2..5ee2923 100644
--- a/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal
+++ b/gnss/visibility_control/1.0/IGnssVisibilityControlCallback.hal
@@ -82,6 +82,9 @@
/**
* Package name of the Android proxy application representing the non-framework
* entity that requested location. Set to empty string if unknown.
+ *
+ * For user-initiated emergency use cases, this field must be set to empty string
+ * and the inEmergencyMode field must be set to true.
*/
string proxyAppPackageName;
@@ -157,4 +160,4 @@
* @return success True if the framework determines that the device is in emergency session.
*/
isInEmergencySession() generates (bool success);
-};
\ No newline at end of file
+};
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
index 4942462..4e0c5ef 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/PixelFormat.aidl
@@ -403,10 +403,6 @@
* cr_offset = y_size
* cb_offset = y_size + c_size
*
- * This range is reserved for vendor extensions. Formats in this range
- * must support BufferUsage::GPU_TEXTURE. Clients must assume they do not
- * have an alpha component.
- *
* This format must be accepted by the allocator when used with the
* following usage flags:
*
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl
index 3fca53b..c04cef0 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayoutComponent.aidl
@@ -39,7 +39,7 @@
/**
* The type of this plane layout component.
*
- * android.hardware.graphics.common.PlaneLayoutComponent defines the standard
+ * android.hardware.graphics.common.PlaneLayoutComponentType defines the standard
* plane layout component types. Vendors may extend this type to include any
* non-standard plane layout component types. For instructions on how to
* create a vendor extension, refer to ExtendableType.aidl.
diff --git a/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
index 1185945..3d792f9 100644
--- a/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
+++ b/graphics/mapper/2.1/vts/functional/VtsHalGraphicsMapperV2_1TargetTest.cpp
@@ -94,7 +94,7 @@
mDummyDescriptorInfo.width);
ASSERT_EQ(Error::BAD_BUFFER, ret)
<< "validateBufferSize with raw buffer handle did not fail with BAD_BUFFER";
- native_handle_delete(rawBufferHandle);
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawBufferHandle));
}
/**
@@ -179,11 +179,11 @@
ASSERT_NO_FATAL_FAILURE(rawBufferHandle = const_cast<native_handle_t*>(
mGralloc->allocate(mDummyDescriptorInfo, false)));
mGralloc->getMapper()->getTransportSize(
- invalidHandle, [&](const auto& tmpError, const auto&, const auto&) {
- ASSERT_EQ(Error::BAD_BUFFER, tmpError)
- << "getTransportSize with raw buffer handle did not fail with BAD_BUFFER";
- });
- native_handle_delete(rawBufferHandle);
+ rawBufferHandle, [&](const auto& tmpError, const auto&, const auto&) {
+ ASSERT_EQ(Error::BAD_BUFFER, tmpError)
+ << "getTransportSize with raw buffer handle did not fail with BAD_BUFFER";
+ });
+ ASSERT_NO_FATAL_FAILURE(mGralloc->freeBuffer(rawBufferHandle));
}
/**
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 6cc5e34..a783eaa 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -2124,8 +2124,14 @@
Error err;
mGralloc->getAllocator()->allocate(
- descriptor, 1,
- [&](const auto& tmpError, const auto&, const auto&) { err = tmpError; });
+ descriptor, 1, [&](const auto& tmpError, const auto&, const auto& tmpBuffers) {
+ err = tmpError;
+ if (err == Error::NONE) {
+ ASSERT_EQ(1, tmpBuffers.size());
+ ASSERT_NO_FATAL_FAILURE(bufferHandle =
+ mGralloc->importBuffer(tmpBuffers[0]));
+ }
+ });
if (err == Error::UNSUPPORTED) {
continue;
}
diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
index 10ce4c2..cc14271 100644
--- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
@@ -176,6 +176,10 @@
* @param itemsRequest
* If non-empty, contains request data that is signed by the reader. See above.
*
+ * @param signingKeyBlob is either empty or a signingKeyBlob (see generateSigningKeyPair(),
+ * below) containing the signing key to use to sign the data retrieved. If this
+ * is not in the right format the call fails with STATUS_INVALID_DATA.
+ *
* @param sessionTranscript
* Either empty or the CBOR of the SessionTranscript. See above.
*
@@ -195,8 +199,7 @@
* and remove the corresponding requests from the counts.
*/
void startRetrieval(in SecureAccessControlProfile[] accessControlProfiles,
- in HardwareAuthToken authToken,
- in byte[] itemsRequest,
+ in HardwareAuthToken authToken, in byte[] itemsRequest, in byte[] signingKeyBlob,
in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts);
/**
@@ -254,10 +257,6 @@
* If signingKeyBlob or the sessionTranscript parameter passed to startRetrieval() is
* empty then the returned MAC will be empty.
*
- * @param signingKeyBlob is either empty or a signingKeyBlob (see generateSigningKeyPair(),
- * below) containing the signing key to use to sign the data retrieved. If this
- * is not in the right format the call fails with STATUS_INVALID_DATA.
- *
* @param out mac is empty if signingKeyBlob or the sessionTranscript passed to
* startRetrieval() is empty. Otherwise it is a COSE_Mac0 with empty payload
* and the detached content is set to DeviceAuthentication as defined below.
@@ -304,7 +303,7 @@
*
* @param out deviceNameSpaces the bytes of DeviceNameSpaces.
*/
- void finishRetrieval(in byte[] signingKeyBlob, out byte[] mac, out byte[] deviceNameSpaces);
+ void finishRetrieval(out byte[] mac, out byte[] deviceNameSpaces);
/**
* Generate a key pair to be used for signing session data and retrieved data items.
diff --git a/identity/aidl/default/IdentityCredential.cpp b/identity/aidl/default/IdentityCredential.cpp
index d5b3a0f..341fae6 100644
--- a/identity/aidl/default/IdentityCredential.cpp
+++ b/identity/aidl/default/IdentityCredential.cpp
@@ -256,8 +256,8 @@
ndk::ScopedAStatus IdentityCredential::startRetrieval(
const vector<SecureAccessControlProfile>& accessControlProfiles,
const HardwareAuthToken& authToken, const vector<int8_t>& itemsRequestS,
- const vector<int8_t>& sessionTranscriptS, const vector<int8_t>& readerSignatureS,
- const vector<int32_t>& requestCounts) {
+ const vector<int8_t>& signingKeyBlobS, const vector<int8_t>& sessionTranscriptS,
+ const vector<int8_t>& readerSignatureS, const vector<int32_t>& requestCounts) {
auto sessionTranscript = byteStringToUnsigned(sessionTranscriptS);
auto itemsRequest = byteStringToUnsigned(itemsRequestS);
auto readerSignature = byteStringToUnsigned(readerSignatureS);
@@ -498,6 +498,7 @@
currentNameSpace_ = "";
itemsRequest_ = itemsRequest;
+ signingKeyBlob_ = byteStringToUnsigned(signingKeyBlobS);
numStartRetrievalCalls_ += 1;
return ndk::ScopedAStatus::ok();
@@ -650,11 +651,8 @@
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus IdentityCredential::finishRetrieval(const vector<int8_t>& signingKeyBlobS,
- vector<int8_t>* outMac,
+ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector<int8_t>* outMac,
vector<int8_t>* outDeviceNameSpaces) {
- auto signingKeyBlob = byteStringToUnsigned(signingKeyBlobS);
-
if (currentNameSpaceDeviceNameSpacesMap_.size() > 0) {
deviceNameSpacesMap_.add(currentNameSpace_,
std::move(currentNameSpaceDeviceNameSpacesMap_));
@@ -664,7 +662,8 @@
// If there's no signing key or no sessionTranscript or no reader ephemeral
// public key, we return the empty MAC.
optional<vector<uint8_t>> mac;
- if (signingKeyBlob.size() > 0 && sessionTranscript_.size() > 0 && readerPublicKey_.size() > 0) {
+ if (signingKeyBlob_.size() > 0 && sessionTranscript_.size() > 0 &&
+ readerPublicKey_.size() > 0) {
cppbor::Array array;
array.add("DeviceAuthentication");
array.add(sessionTranscriptItem_->clone());
@@ -674,7 +673,7 @@
vector<uint8_t> docTypeAsBlob(docType_.begin(), docType_.end());
optional<vector<uint8_t>> signingKey =
- support::decryptAes128Gcm(storageKey_, signingKeyBlob, docTypeAsBlob);
+ support::decryptAes128Gcm(storageKey_, signingKeyBlob_, docTypeAsBlob);
if (!signingKey) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_INVALID_DATA,
diff --git a/identity/aidl/default/IdentityCredential.h b/identity/aidl/default/IdentityCredential.h
index 49ed0d4..fc29254 100644
--- a/identity/aidl/default/IdentityCredential.h
+++ b/identity/aidl/default/IdentityCredential.h
@@ -54,14 +54,14 @@
ndk::ScopedAStatus startRetrieval(
const vector<SecureAccessControlProfile>& accessControlProfiles,
const HardwareAuthToken& authToken, const vector<int8_t>& itemsRequest,
- const vector<int8_t>& sessionTranscript, const vector<int8_t>& readerSignature,
- const vector<int32_t>& requestCounts) override;
+ const vector<int8_t>& signingKeyBlob, const vector<int8_t>& sessionTranscript,
+ const vector<int8_t>& readerSignature, const vector<int32_t>& requestCounts) override;
ndk::ScopedAStatus startRetrieveEntryValue(
const string& nameSpace, const string& name, int32_t entrySize,
const vector<int32_t>& accessControlProfileIds) override;
ndk::ScopedAStatus retrieveEntryValue(const vector<int8_t>& encryptedContent,
vector<int8_t>* outContent) override;
- ndk::ScopedAStatus finishRetrieval(const vector<int8_t>& signingKeyBlob, vector<int8_t>* outMac,
+ ndk::ScopedAStatus finishRetrieval(vector<int8_t>* outMac,
vector<int8_t>* outDeviceNameSpaces) override;
ndk::ScopedAStatus generateSigningKeyPair(vector<int8_t>* outSigningKeyBlob,
Certificate* outSigningKeyCertificate) override;
@@ -88,6 +88,7 @@
// Set at startRetrieval() time.
map<int32_t, int> profileIdToAccessCheckResult_;
+ vector<uint8_t> signingKeyBlob_;
vector<uint8_t> sessionTranscript_;
std::unique_ptr<cppbor::Item> sessionTranscriptItem_;
vector<uint8_t> itemsRequest_;
diff --git a/identity/aidl/default/WritableIdentityCredential.cpp b/identity/aidl/default/WritableIdentityCredential.cpp
index ba2062d..89f7f35 100644
--- a/identity/aidl/default/WritableIdentityCredential.cpp
+++ b/identity/aidl/default/WritableIdentityCredential.cpp
@@ -16,6 +16,9 @@
#define LOG_TAG "WritableIdentityCredential"
+#include "WritableIdentityCredential.h"
+#include "IdentityCredentialStore.h"
+
#include <android/hardware/identity/support/IdentityCredentialSupport.h>
#include <android-base/logging.h>
@@ -23,6 +26,8 @@
#include <cppbor/cppbor.h>
#include <cppbor/cppbor_parse.h>
+#include <utility>
+
#include "IdentityCredentialStore.h"
#include "Util.h"
#include "WritableIdentityCredential.h"
@@ -33,26 +38,6 @@
using namespace ::android::hardware::identity;
bool WritableIdentityCredential::initialize() {
- optional<vector<uint8_t>> keyPair = support::createEcKeyPair();
- if (!keyPair) {
- LOG(ERROR) << "Error creating credentialKey";
- return false;
- }
-
- optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair.value());
- if (!pubKey) {
- LOG(ERROR) << "Error getting public part of credentialKey";
- return false;
- }
- credentialPubKey_ = pubKey.value();
-
- optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair.value());
- if (!privKey) {
- LOG(ERROR) << "Error getting private part of credentialKey";
- return false;
- }
- credentialPrivKey_ = privKey.value();
-
optional<vector<uint8_t>> random = support::getRandom(16);
if (!random) {
LOG(ERROR) << "Error creating storageKey";
@@ -63,88 +48,54 @@
return true;
}
-// TODO: use |attestationApplicationId| and |attestationChallenge| and also
-// ensure the returned certificate chain satisfy the requirements listed in
-// the docs for IWritableIdentityCredential::getAttestationCertificate()
-//
+// This function generates the attestation certificate using the passed in
+// |attestationApplicationId| and |attestationChallenge|. It will generate an
+// attestation certificate with current time and expires one year from now. The
+// certificate shall contain all values as specified in hal.
ndk::ScopedAStatus WritableIdentityCredential::getAttestationCertificate(
- const vector<int8_t>& /*attestationApplicationId*/,
- const vector<int8_t>& /*attestationChallenge*/, vector<Certificate>* outCertificateChain) {
- // For now, we dynamically generate an attestion key on each and every
- // request and use that to sign CredentialKey. In a real implementation this
- // would look very differently.
- optional<vector<uint8_t>> attestationKeyPair = support::createEcKeyPair();
- if (!attestationKeyPair) {
- return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
- IIdentityCredentialStore::STATUS_FAILED, "Error creating attestationKey"));
- }
-
- optional<vector<uint8_t>> attestationPubKey =
- support::ecKeyPairGetPublicKey(attestationKeyPair.value());
- if (!attestationPubKey) {
+ const vector<int8_t>& attestationApplicationId, //
+ const vector<int8_t>& attestationChallenge, //
+ vector<Certificate>* outCertificateChain) {
+ if (!credentialPrivKey_.empty() || !credentialPubKey_.empty() || !certificateChain_.empty()) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_FAILED,
- "Error getting public part of attestationKey"));
+ "Error attestation certificate previously generated"));
}
- optional<vector<uint8_t>> attestationPrivKey =
- support::ecKeyPairGetPrivateKey(attestationKeyPair.value());
- if (!attestationPrivKey) {
+ vector<uint8_t> challenge(attestationChallenge.begin(), attestationChallenge.end());
+ vector<uint8_t> appId(attestationApplicationId.begin(), attestationApplicationId.end());
+
+ optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> keyAttestationPair =
+ support::createEcKeyPairAndAttestation(challenge, appId);
+ if (!keyAttestationPair) {
+ LOG(ERROR) << "Error creating credentialKey and attestation";
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_FAILED,
- "Error getting private part of attestationKey"));
+ "Error creating credentialKey and attestation"));
}
- string serialDecimal;
- string issuer;
- string subject;
- time_t validityNotBefore = time(nullptr);
- time_t validityNotAfter = validityNotBefore + 365 * 24 * 3600;
+ vector<uint8_t> keyPair = keyAttestationPair.value().first;
+ certificateChain_ = keyAttestationPair.value().second;
- // First create a certificate for |credentialPubKey| which is signed by
- // |attestationPrivKey|.
- //
- serialDecimal = "0"; // TODO: set serial to |attestationChallenge|
- issuer = "Android Open Source Project";
- subject = "Android IdentityCredential CredentialKey";
- optional<vector<uint8_t>> credentialPubKeyCertificate = support::ecPublicKeyGenerateCertificate(
- credentialPubKey_, attestationPrivKey.value(), serialDecimal, issuer, subject,
- validityNotBefore, validityNotAfter);
- if (!credentialPubKeyCertificate) {
+ optional<vector<uint8_t>> pubKey = support::ecKeyPairGetPublicKey(keyPair);
+ if (!pubKey) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_FAILED,
- "Error creating certificate for credentialPubKey"));
+ "Error getting public part of credentialKey"));
}
+ credentialPubKey_ = pubKey.value();
- // This is followed by a certificate for |attestationPubKey| self-signed by
- // |attestationPrivKey|.
- serialDecimal = "0"; // TODO: set serial
- issuer = "Android Open Source Project";
- subject = "Android IdentityCredential AttestationKey";
- optional<vector<uint8_t>> attestationKeyCertificate = support::ecPublicKeyGenerateCertificate(
- attestationPubKey.value(), attestationPrivKey.value(), serialDecimal, issuer, subject,
- validityNotBefore, validityNotAfter);
- if (!attestationKeyCertificate) {
+ optional<vector<uint8_t>> privKey = support::ecKeyPairGetPrivateKey(keyPair);
+ if (!privKey) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_FAILED,
- "Error creating certificate for attestationPubKey"));
+ "Error getting private part of credentialKey"));
}
+ credentialPrivKey_ = privKey.value();
- // Concatenate the certificates to form the chain.
- vector<uint8_t> certificateChain;
- certificateChain.insert(certificateChain.end(), credentialPubKeyCertificate.value().begin(),
- credentialPubKeyCertificate.value().end());
- certificateChain.insert(certificateChain.end(), attestationKeyCertificate.value().begin(),
- attestationKeyCertificate.value().end());
-
- optional<vector<vector<uint8_t>>> splitCertChain =
- support::certificateChainSplit(certificateChain);
- if (!splitCertChain) {
- return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
- IIdentityCredentialStore::STATUS_FAILED, "Error splitting certificate chain"));
- }
+ // convert from vector<vector<uint8_t>>> to vector<Certificate>*
*outCertificateChain = vector<Certificate>();
- for (const vector<uint8_t>& cert : splitCertChain.value()) {
+ for (const vector<uint8_t>& cert : certificateChain_) {
Certificate c = Certificate();
c.encodedCertificate = byteStringToSigned(cert);
outCertificateChain->push_back(std::move(c));
diff --git a/identity/aidl/default/WritableIdentityCredential.h b/identity/aidl/default/WritableIdentityCredential.h
index b380f89..b182862 100644
--- a/identity/aidl/default/WritableIdentityCredential.h
+++ b/identity/aidl/default/WritableIdentityCredential.h
@@ -64,10 +64,13 @@
string docType_;
bool testCredential_;
- // These are set in initialize().
+ // This is set in initialize().
vector<uint8_t> storageKey_;
+
+ // These are set in getAttestationCertificate().
vector<uint8_t> credentialPrivKey_;
vector<uint8_t> credentialPubKey_;
+ vector<vector<uint8_t>> certificateChain_;
// These fields are initialized during startPersonalization()
size_t numAccessControlProfileRemaining_;
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index 21ff440..cecc814 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -7,10 +7,11 @@
srcs: ["VtsHalIdentityTargetTest.cpp"],
shared_libs: [
"libbinder",
- "libcppbor",
- "android.hardware.identity-support-lib",
+ "libcrypto",
],
static_libs: [
+ "libcppbor",
+ "android.hardware.identity-support-lib",
"android.hardware.identity-cpp",
"android.hardware.keymaster-cpp",
],
diff --git a/identity/aidl/vts/VtsHalIdentityTargetTest.cpp b/identity/aidl/vts/VtsHalIdentityTargetTest.cpp
index 5abe5a2..ea37fdc 100644
--- a/identity/aidl/vts/VtsHalIdentityTargetTest.cpp
+++ b/identity/aidl/vts/VtsHalIdentityTargetTest.cpp
@@ -352,10 +352,15 @@
readerCertificate.value());
ASSERT_TRUE(readerSignature);
+ // Generate the key that will be used to sign AuthenticatedData.
+ vector<uint8_t> signingKeyBlob;
+ Certificate signingKeyCertificate;
+ ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
+
ASSERT_TRUE(credential
->startRetrieval(returnedSecureProfiles, authToken, itemsRequestBytes,
- sessionTranscriptBytes, readerSignature.value(),
- testEntriesEntryCounts)
+ signingKeyBlob, sessionTranscriptBytes,
+ readerSignature.value(), testEntriesEntryCounts)
.isOk());
for (const auto& entry : testEntries) {
@@ -377,14 +382,9 @@
EXPECT_EQ(content, entry.valueCbor);
}
- // Generate the key that will be used to sign AuthenticatedData.
- vector<uint8_t> signingKeyBlob;
- Certificate signingKeyCertificate;
- ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
-
vector<uint8_t> mac;
vector<uint8_t> deviceNameSpacesBytes;
- ASSERT_TRUE(credential->finishRetrieval(signingKeyBlob, &mac, &deviceNameSpacesBytes).isOk());
+ ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesBytes).isOk());
cborPretty = support::cborPrettyPrint(deviceNameSpacesBytes, 32, {});
ASSERT_EQ(
"{\n"
diff --git a/identity/support/Android.bp b/identity/support/Android.bp
index 7b4546b..2b6c695 100644
--- a/identity/support/Android.bp
+++ b/identity/support/Android.bp
@@ -23,10 +23,14 @@
"include",
],
shared_libs: [
+ "android.hardware.keymaster@4.0",
"libcrypto",
"libbase",
"libhidlbase",
"libhardware",
+ "libkeymaster_portable",
+ "libsoft_attestation_cert",
+ "libpuresoftkeymasterdevice",
],
static_libs: [
"libcppbor",
diff --git a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
index 4533ad9..507e914 100644
--- a/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
+++ b/identity/support/include/android/hardware/identity/support/IdentityCredentialSupport.h
@@ -21,6 +21,7 @@
#include <optional>
#include <string>
#include <tuple>
+#include <utility>
#include <vector>
namespace android {
@@ -106,6 +107,17 @@
// ---------------------------------------------------------------------------
// EC crypto functionality / abstraction (only supports P-256).
// ---------------------------------------------------------------------------
+// Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
+// PKCS#8 encoded key-pair. Also generates an attestation
+// certificate using the |challenge| and |applicationId|, and returns the generated
+// certificate in X.509 certificate chain format.
+//
+// The attestation time fields used will be the current time, and expires in one year.
+//
+// The first parameter of the return value is the keyPair generated, second return in
+// the pair is the attestation certificate generated.
+optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
+ const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId);
// Creates an 256-bit EC key using the NID_X9_62_prime256v1 curve, returns the
// PKCS#8 encoded key-pair.
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index e2828bf..bf6a5c3 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -47,6 +47,13 @@
#include <cppbor.h>
#include <cppbor_parse.h>
+#include <android/hardware/keymaster/4.0/types.h>
+#include <keymaster/authorization_set.h>
+#include <keymaster/contexts/pure_soft_keymaster_context.h>
+#include <keymaster/contexts/soft_attestation_cert.h>
+#include <keymaster/keymaster_tags.h>
+#include <keymaster/km_openssl/attestation_utils.h>
+
namespace android {
namespace hardware {
namespace identity {
@@ -816,6 +823,138 @@
return hmac;
}
+// Generates the attestation certificate with the parameters passed in. Note
+// that the passed in |activeTimeMilliSeconds| |expireTimeMilliSeconds| are in
+// milli seconds since epoch. We are setting them to milliseconds due to
+// requirement in AuthorizationSet KM_DATE fields. The certificate created is
+// actually in seconds.
+optional<vector<vector<uint8_t>>> createAttestation(const EVP_PKEY* key,
+ const vector<uint8_t>& applicationId,
+ const vector<uint8_t>& challenge,
+ uint64_t activeTimeMilliSeconds,
+ uint64_t expireTimeMilliSeconds) {
+ ::keymaster::AuthorizationSet auth_set(
+ ::keymaster::AuthorizationSetBuilder()
+ .Authorization(::keymaster::TAG_ATTESTATION_CHALLENGE, challenge.data(),
+ challenge.size())
+ .Authorization(::keymaster::TAG_ACTIVE_DATETIME, activeTimeMilliSeconds)
+ // Even though identity attestation hal said the application
+ // id should be in software enforced authentication set,
+ // keymaster portable lib expect the input in this
+ // parameter because the software enforced in input to keymaster
+ // refers to the key software enforced properties. And this
+ // parameter refers to properties of the attestation which
+ // includes app id.
+ .Authorization(::keymaster::TAG_ATTESTATION_APPLICATION_ID,
+ applicationId.data(), applicationId.size())
+ .Authorization(::keymaster::TAG_USAGE_EXPIRE_DATETIME, expireTimeMilliSeconds));
+
+ // Unique id and device id is not applicable for identity credential attestation,
+ // so we don't need to set those or application id.
+ ::keymaster::AuthorizationSet swEnforced(::keymaster::AuthorizationSetBuilder().Authorization(
+ ::keymaster::TAG_CREATION_DATETIME, activeTimeMilliSeconds));
+
+ ::keymaster::AuthorizationSet hwEnforced(
+ ::keymaster::AuthorizationSetBuilder()
+ .Authorization(::keymaster::TAG_PURPOSE, KM_PURPOSE_SIGN)
+ .Authorization(::keymaster::TAG_KEY_SIZE, 256)
+ .Authorization(::keymaster::TAG_ALGORITHM, KM_ALGORITHM_EC)
+ .Authorization(::keymaster::TAG_NO_AUTH_REQUIRED)
+ .Authorization(::keymaster::TAG_DIGEST, KM_DIGEST_SHA_2_256)
+ .Authorization(::keymaster::TAG_EC_CURVE, KM_EC_CURVE_P_256)
+ .Authorization(::keymaster::TAG_IDENTITY_CREDENTIAL_KEY));
+
+ const keymaster_cert_chain_t* attestation_chain =
+ ::keymaster::getAttestationChain(KM_ALGORITHM_EC, nullptr);
+
+ if (attestation_chain == nullptr) {
+ LOG(ERROR) << "Error getting attestation chain";
+ return {};
+ }
+
+ const keymaster_key_blob_t* attestation_signing_key =
+ ::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr);
+ if (attestation_signing_key == nullptr) {
+ LOG(ERROR) << "Error getting attestation key";
+ return {};
+ }
+
+ keymaster_error_t error;
+ ::keymaster::CertChainPtr cert_chain_out;
+ ::keymaster::PureSoftKeymasterContext context;
+
+ // set identity version to 10 per hal requirements specified in IWriteableCredential.hal
+ // For now, the identity version in the attestation is set in the keymaster
+ // version field in the portable keymaster lib, which is a bit misleading.
+ uint identity_version = 10;
+ error = generate_attestation_from_EVP(key, swEnforced, hwEnforced, auth_set, context,
+ identity_version, *attestation_chain,
+ *attestation_signing_key, &cert_chain_out);
+
+ if (KM_ERROR_OK != error || !cert_chain_out) {
+ LOG(ERROR) << "Error generate attestation from EVP key" << error;
+ return {};
+ }
+
+ // translate certificate format from keymaster_cert_chain_t to vector<uint8_t>.
+ vector<vector<uint8_t>> attestationCertificate;
+ for (int i = 0; i < cert_chain_out->entry_count; i++) {
+ attestationCertificate.insert(
+ attestationCertificate.end(),
+ vector<uint8_t>(
+ cert_chain_out->entries[i].data,
+ cert_chain_out->entries[i].data + cert_chain_out->entries[i].data_length));
+ }
+
+ return attestationCertificate;
+}
+
+optional<std::pair<vector<uint8_t>, vector<vector<uint8_t>>>> createEcKeyPairAndAttestation(
+ const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId) {
+ auto ec_key = ::keymaster::EC_KEY_Ptr(EC_KEY_new());
+ auto pkey = ::keymaster::EVP_PKEY_Ptr(EVP_PKEY_new());
+ auto group = ::keymaster::EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+
+ if (ec_key.get() == nullptr || pkey.get() == nullptr) {
+ LOG(ERROR) << "Memory allocation failed";
+ return {};
+ }
+
+ if (EC_KEY_set_group(ec_key.get(), group.get()) != 1 ||
+ EC_KEY_generate_key(ec_key.get()) != 1 || EC_KEY_check_key(ec_key.get()) < 0) {
+ LOG(ERROR) << "Error generating key";
+ return {};
+ }
+
+ if (EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get()) != 1) {
+ LOG(ERROR) << "Error getting private key";
+ return {};
+ }
+
+ uint64_t now = time(nullptr);
+ uint64_t secondsInOneYear = 365 * 24 * 60 * 60;
+ uint64_t expireTimeMs = (now + secondsInOneYear) * 1000;
+
+ optional<vector<vector<uint8_t>>> attestationCert =
+ createAttestation(pkey.get(), applicationId, challenge, now * 1000, expireTimeMs);
+ if (!attestationCert) {
+ LOG(ERROR) << "Error create attestation from key and challenge";
+ return {};
+ }
+
+ int size = i2d_PrivateKey(pkey.get(), nullptr);
+ if (size == 0) {
+ LOG(ERROR) << "Error generating public key encoding";
+ return {};
+ }
+
+ vector<uint8_t> keyPair(size);
+ unsigned char* p = keyPair.data();
+ i2d_PrivateKey(pkey.get(), &p);
+
+ return make_pair(keyPair, attestationCert.value());
+}
+
optional<vector<uint8_t>> createEcKeyPair() {
auto ec_key = EC_KEY_Ptr(EC_KEY_new());
auto pkey = EVP_PKEY_Ptr(EVP_PKEY_new());
diff --git a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
index 6c186f6..40eb142 100644
--- a/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
+++ b/keymaster/4.1/support/include/keymasterV4_1/keymaster_tags.h
@@ -101,6 +101,7 @@
DECLARE_KM_4_1_TYPED_TAG(EARLY_BOOT_ONLY);
DECLARE_KM_4_1_TYPED_TAG(DEVICE_UNIQUE_ATTESTATION);
DECLARE_KM_4_1_TYPED_TAG(STORAGE_KEY);
+DECLARE_KM_4_1_TYPED_TAG(IDENTITY_CREDENTIAL_KEY);
} // namespace android::hardware::keymaster::V4_1
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index e28605d..ae1e3a2 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -125,7 +125,9 @@
// Test driver for those generated from ml/nn/runtime/test/spec
void Execute(const sp<IDevice>& device, const TestModel& testModel) {
const Model model = createModel(testModel);
- const Request request = createRequest(testModel);
+
+ ExecutionContext context;
+ const Request request = context.createRequest(testModel);
// Create IPreparedModel.
sp<IPreparedModel> preparedModel;
@@ -143,7 +145,7 @@
ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus());
// Retrieve execution results.
- const std::vector<TestBuffer> outputs = getOutputBuffers(request);
+ const std::vector<TestBuffer> outputs = context.getOutputBuffers(request);
// We want "close-enough" results.
checkResults(testModel, outputs);
@@ -158,6 +160,10 @@
return TestModelManager::get().getTestModels(filter);
}
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter) {
+ return TestModelManager::get().getTestModels(filter);
+}
+
std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
const auto& [namedDevice, namedModel] = info.param;
return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
index f230a02..1a55c2f 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
@@ -37,6 +37,9 @@
using FilterFn = std::function<bool(const test_helper::TestModel&)>;
std::vector<NamedModel> getNamedModels(const FilterFn& filter);
+using FilterNameFn = std::function<bool(const std::string&)>;
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter);
+
std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);
#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \
diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp
index 0dba85a..3613e69 100644
--- a/neuralnetworks/1.0/vts/functional/Utils.cpp
+++ b/neuralnetworks/1.0/vts/functional/Utils.cpp
@@ -21,10 +21,13 @@
#include <android-base/logging.h>
#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware_buffer.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
+#include <vndk/hardware_buffer.h>
+#include <gtest/gtest.h>
#include <algorithm>
#include <iostream>
#include <vector>
@@ -37,10 +40,64 @@
using V1_0::Request;
using V1_0::RequestArgument;
-constexpr uint32_t kInputPoolIndex = 0;
-constexpr uint32_t kOutputPoolIndex = 1;
+std::unique_ptr<TestAshmem> TestAshmem::create(uint32_t size) {
+ auto ashmem = std::make_unique<TestAshmem>(size);
+ return ashmem->mIsValid ? std::move(ashmem) : nullptr;
+}
-Request createRequest(const TestModel& testModel) {
+void TestAshmem::initialize(uint32_t size) {
+ mIsValid = false;
+ ASSERT_GT(size, 0);
+ mHidlMemory = nn::allocateSharedMemory(size);
+ ASSERT_TRUE(mHidlMemory.valid());
+ mMappedMemory = mapMemory(mHidlMemory);
+ ASSERT_NE(mMappedMemory, nullptr);
+ mPtr = static_cast<uint8_t*>(static_cast<void*>(mMappedMemory->getPointer()));
+ ASSERT_NE(mPtr, nullptr);
+ mIsValid = true;
+}
+
+std::unique_ptr<TestBlobAHWB> TestBlobAHWB::create(uint32_t size) {
+ auto ahwb = std::make_unique<TestBlobAHWB>(size);
+ return ahwb->mIsValid ? std::move(ahwb) : nullptr;
+}
+
+void TestBlobAHWB::initialize(uint32_t size) {
+ mIsValid = false;
+ ASSERT_GT(size, 0);
+ const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+ const AHardwareBuffer_Desc desc = {
+ .width = size,
+ .height = 1,
+ .layers = 1,
+ .format = AHARDWAREBUFFER_FORMAT_BLOB,
+ .usage = usage,
+ .stride = size,
+ };
+ ASSERT_EQ(AHardwareBuffer_allocate(&desc, &mAhwb), 0);
+ ASSERT_NE(mAhwb, nullptr);
+
+ void* buffer = nullptr;
+ ASSERT_EQ(AHardwareBuffer_lock(mAhwb, usage, -1, nullptr, &buffer), 0);
+ ASSERT_NE(buffer, nullptr);
+ mPtr = static_cast<uint8_t*>(buffer);
+
+ const native_handle_t* handle = AHardwareBuffer_getNativeHandle(mAhwb);
+ ASSERT_NE(handle, nullptr);
+ mHidlMemory = hidl_memory("hardware_buffer_blob", handle, desc.width);
+ mIsValid = true;
+}
+
+TestBlobAHWB::~TestBlobAHWB() {
+ if (mAhwb) {
+ AHardwareBuffer_unlock(mAhwb, nullptr);
+ AHardwareBuffer_release(mAhwb);
+ }
+}
+
+Request ExecutionContext::createRequest(const TestModel& testModel, MemoryType memoryType) {
+ CHECK(memoryType == MemoryType::ASHMEM || memoryType == MemoryType::BLOB_AHWB);
+
// Model inputs.
hidl_vec<RequestArgument> inputs(testModel.main.inputIndexes.size());
size_t inputSize = 0;
@@ -80,16 +137,19 @@
}
// Allocate memory pools.
- hidl_vec<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
- nn::allocateSharedMemory(outputSize)};
- CHECK_NE(pools[kInputPoolIndex].size(), 0u);
- CHECK_NE(pools[kOutputPoolIndex].size(), 0u);
- sp<IMemory> inputMemory = mapMemory(pools[kInputPoolIndex]);
- CHECK(inputMemory.get() != nullptr);
- uint8_t* inputPtr = static_cast<uint8_t*>(static_cast<void*>(inputMemory->getPointer()));
- CHECK(inputPtr != nullptr);
+ if (memoryType == MemoryType::ASHMEM) {
+ mInputMemory = TestAshmem::create(inputSize);
+ mOutputMemory = TestAshmem::create(outputSize);
+ } else {
+ mInputMemory = TestBlobAHWB::create(inputSize);
+ mOutputMemory = TestBlobAHWB::create(outputSize);
+ }
+ EXPECT_NE(mInputMemory, nullptr);
+ EXPECT_NE(mOutputMemory, nullptr);
+ hidl_vec<hidl_memory> pools = {mInputMemory->getHidlMemory(), mOutputMemory->getHidlMemory()};
// Copy input data to the memory pool.
+ uint8_t* inputPtr = mInputMemory->getPointer();
for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) {
const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]];
if (op.data.size() > 0) {
@@ -102,18 +162,13 @@
return {.inputs = std::move(inputs), .outputs = std::move(outputs), .pools = std::move(pools)};
}
-std::vector<TestBuffer> getOutputBuffers(const Request& request) {
- sp<IMemory> outputMemory = mapMemory(request.pools[kOutputPoolIndex]);
- CHECK(outputMemory.get() != nullptr);
- uint8_t* outputPtr = static_cast<uint8_t*>(static_cast<void*>(outputMemory->getPointer()));
- CHECK(outputPtr != nullptr);
-
+std::vector<TestBuffer> ExecutionContext::getOutputBuffers(const Request& request) const {
// Copy out output results.
+ uint8_t* outputPtr = mOutputMemory->getPointer();
std::vector<TestBuffer> outputBuffers;
for (const auto& output : request.outputs) {
outputBuffers.emplace_back(output.location.length, outputPtr + output.location.offset);
}
-
return outputBuffers;
}
diff --git a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
index cc15263..79d8594 100644
--- a/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.0/vts/functional/ValidateModel.cpp
@@ -24,6 +24,8 @@
using implementation::PreparedModelCallback;
+using PrepareModelMutation = std::function<void(Model*)>;
+
///////////////////////// UTILITY FUNCTIONS /////////////////////////
static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
@@ -54,12 +56,13 @@
}
// Primary validation function. This function will take a valid model, apply a
-// mutation to it to invalidate the model, then pass it to interface calls that
-// use the model. Note that the model here is passed by value, and any mutation
-// to the model does not leave this function.
-static void validate(const sp<IDevice>& device, const std::string& message, Model model,
- const std::function<void(Model*)>& mutation) {
- mutation(&model);
+// mutation to invalidate the model, then pass these to supportedOperations and
+// prepareModel.
+static void validate(const sp<IDevice>& device, const std::string& message,
+ const Model& originalModel, const PrepareModelMutation& mutate) {
+ Model model = originalModel;
+ mutate(&model);
+
validateGetSupportedOperations(device, message, model);
validatePrepareModel(device, message, model);
}
diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
index 05eefd1..0baa85b 100644
--- a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
@@ -24,15 +24,17 @@
using implementation::ExecutionCallback;
+using ExecutionMutation = std::function<void(Request*)>;
+
///////////////////////// UTILITY FUNCTIONS /////////////////////////
// Primary validation function. This function will take a valid request, apply a
// mutation to it to invalidate the request, then pass it to interface calls
-// that use the request. Note that the request here is passed by value, and any
-// mutation to the request does not leave this function.
+// that use the request.
static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
- Request request, const std::function<void(Request*)>& mutation) {
- mutation(&request);
+ const Request& originalRequest, const ExecutionMutation& mutate) {
+ Request request = originalRequest;
+ mutate(&request);
SCOPED_TRACE(message + " [execute]");
sp<ExecutionCallback> executionCallback = new ExecutionCallback();
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
index cb22250..2c17796 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
@@ -129,11 +129,17 @@
TEST_P(ValidationTest, Test) {
const Model model = createModel(kTestModel);
- const Request request = createRequest(kTestModel);
+ ExecutionContext context;
+ const Request request = context.createRequest(kTestModel);
ASSERT_FALSE(kTestModel.expectFailure);
validateEverything(kDevice, model, request);
}
-INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
+INSTANTIATE_GENERATED_TEST(ValidationTest, [](const std::string& testName) {
+ // Skip validation for the "inputs_as_internal" and "all_tensors_as_inputs"
+ // generated tests.
+ return testName.find("inputs_as_internal") == std::string::npos &&
+ testName.find("all_tensors_as_inputs") == std::string::npos;
+});
} // namespace android::hardware::neuralnetworks::V1_0::vts::functional
diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
index 6d4534c..3292f79 100644
--- a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
+++ b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
@@ -19,6 +19,8 @@
#include <android-base/logging.h>
#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware_buffer.h>
+#include <android/hidl/memory/1.0/IMemory.h>
#include <algorithm>
#include <iosfwd>
#include <string>
@@ -28,11 +30,73 @@
namespace android::hardware::neuralnetworks {
-// Create HIDL Request from the TestModel struct.
-V1_0::Request createRequest(const test_helper::TestModel& testModel);
+// Convenience class to manage the lifetime of memory resources.
+class TestMemoryBase {
+ DISALLOW_COPY_AND_ASSIGN(TestMemoryBase);
-// After execution, copy out output results from the output memory pool.
-std::vector<::test_helper::TestBuffer> getOutputBuffers(const V1_0::Request& request);
+ public:
+ TestMemoryBase() = default;
+ virtual ~TestMemoryBase() = default;
+ uint8_t* getPointer() const { return mPtr; }
+ hidl_memory getHidlMemory() const { return mHidlMemory; }
+
+ protected:
+ uint8_t* mPtr = nullptr;
+ hidl_memory mHidlMemory;
+ bool mIsValid = false;
+};
+
+class TestAshmem : public TestMemoryBase {
+ public:
+ static std::unique_ptr<TestAshmem> create(uint32_t size);
+
+ // Prefer TestAshmem::create.
+ // The constructor calls initialize, which constructs the memory resources. This is a workaround
+ // that gtest macros cannot be used directly in a constructor.
+ TestAshmem(uint32_t size) { initialize(size); }
+
+ private:
+ void initialize(uint32_t size);
+ sp<hidl::memory::V1_0::IMemory> mMappedMemory;
+};
+
+class TestBlobAHWB : public TestMemoryBase {
+ public:
+ static std::unique_ptr<TestBlobAHWB> create(uint32_t size);
+
+ // Prefer TestBlobAHWB::create.
+ // The constructor calls initialize, which constructs the memory resources. This is a
+ // workaround that gtest macros cannot be used directly in a constructor.
+ TestBlobAHWB(uint32_t size) { initialize(size); }
+ ~TestBlobAHWB();
+
+ private:
+ void initialize(uint32_t size);
+ AHardwareBuffer* mAhwb = nullptr;
+};
+
+enum class MemoryType { ASHMEM, BLOB_AHWB, DEVICE };
+
+// Manages the lifetime of memory resources used in an execution.
+class ExecutionContext {
+ DISALLOW_COPY_AND_ASSIGN(ExecutionContext);
+
+ public:
+ static constexpr uint32_t kInputPoolIndex = 0;
+ static constexpr uint32_t kOutputPoolIndex = 1;
+
+ ExecutionContext() = default;
+
+ // Create HIDL Request from the TestModel struct.
+ V1_0::Request createRequest(const test_helper::TestModel& testModel,
+ MemoryType memoryType = MemoryType::ASHMEM);
+
+ // After execution, copy out output results from the output memory pool.
+ std::vector<test_helper::TestBuffer> getOutputBuffers(const V1_0::Request& request) const;
+
+ private:
+ std::unique_ptr<TestMemoryBase> mInputMemory, mOutputMemory;
+};
// Delete element from hidl_vec. hidl_vec doesn't support a "remove" operation,
// so this is efficiently accomplished by moving the element to the end and
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
index cee15a3..a233835 100644
--- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
@@ -133,7 +133,9 @@
// Test driver for those generated from ml/nn/runtime/test/spec
void Execute(const sp<IDevice>& device, const TestModel& testModel) {
const Model model = createModel(testModel);
- const Request request = createRequest(testModel);
+
+ ExecutionContext context;
+ const Request request = context.createRequest(testModel);
// Create IPreparedModel.
sp<IPreparedModel> preparedModel;
@@ -151,7 +153,7 @@
ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus());
// Retrieve execution results.
- const std::vector<TestBuffer> outputs = getOutputBuffers(request);
+ const std::vector<TestBuffer> outputs = context.getOutputBuffers(request);
// We want "close-enough" results.
checkResults(testModel, outputs);
@@ -166,6 +168,10 @@
return TestModelManager::get().getTestModels(filter);
}
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter) {
+ return TestModelManager::get().getTestModels(filter);
+}
+
std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
const auto& [namedDevice, namedModel] = info.param;
return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
index cf449ea..4b1a96e 100644
--- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
@@ -37,6 +37,9 @@
using FilterFn = std::function<bool(const test_helper::TestModel&)>;
std::vector<NamedModel> getNamedModels(const FilterFn& filter);
+using FilterNameFn = std::function<bool(const std::string&)>;
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter);
+
std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);
#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \
diff --git a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
index 0629a1e..3b6f0f8 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateModel.cpp
@@ -30,6 +30,8 @@
using V1_0::OperandType;
using V1_0::implementation::PreparedModelCallback;
+using PrepareModelMutation = std::function<void(Model*, ExecutionPreference*)>;
+
///////////////////////// UTILITY FUNCTIONS /////////////////////////
static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
@@ -67,16 +69,19 @@
}
// Primary validation function. This function will take a valid model, apply a
-// mutation to it to invalidate the model, then pass it to interface calls that
-// use the model. Note that the model here is passed by value, and any mutation
-// to the model does not leave this function.
-static void validate(const sp<IDevice>& device, const std::string& message, Model model,
- const std::function<void(Model*)>& mutation,
- ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) {
- mutation(&model);
+// mutation to invalidate either the model or the execution preference, then
+// pass these to supportedOperations and/or prepareModel if that method is
+// called with an invalid argument.
+static void validate(const sp<IDevice>& device, const std::string& message,
+ const Model& originalModel, const PrepareModelMutation& mutate) {
+ Model model = originalModel;
+ ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER;
+ mutate(&model, &preference);
+
if (validExecutionPreference(preference)) {
validateGetSupportedOperations(device, message, model);
}
+
validatePrepareModel(device, message, model, preference);
}
@@ -115,9 +120,11 @@
const std::string message = "mutateOperandTypeTest: operand " +
std::to_string(operand) + " set to value " +
std::to_string(invalidOperandType);
- validate(device, message, model, [operand, invalidOperandType](Model* model) {
- model->operands[operand].type = static_cast<OperandType>(invalidOperandType);
- });
+ validate(device, message, model,
+ [operand, invalidOperandType](Model* model, ExecutionPreference*) {
+ model->operands[operand].type =
+ static_cast<OperandType>(invalidOperandType);
+ });
}
}
}
@@ -144,9 +151,10 @@
const uint32_t invalidRank = getInvalidRank(model.operands[operand].type);
const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
" has rank of " + std::to_string(invalidRank);
- validate(device, message, model, [operand, invalidRank](Model* model) {
- model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
- });
+ validate(device, message, model,
+ [operand, invalidRank](Model* model, ExecutionPreference*) {
+ model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
+ });
}
}
@@ -173,9 +181,10 @@
const float invalidScale = getInvalidScale(model.operands[operand].type);
const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
" has scale of " + std::to_string(invalidScale);
- validate(device, message, model, [operand, invalidScale](Model* model) {
- model->operands[operand].scale = invalidScale;
- });
+ validate(device, message, model,
+ [operand, invalidScale](Model* model, ExecutionPreference*) {
+ model->operands[operand].scale = invalidScale;
+ });
}
}
@@ -204,9 +213,10 @@
const std::string message = "mutateOperandZeroPointTest: operand " +
std::to_string(operand) + " has zero point of " +
std::to_string(invalidZeroPoint);
- validate(device, message, model, [operand, invalidZeroPoint](Model* model) {
- model->operands[operand].zeroPoint = invalidZeroPoint;
- });
+ validate(device, message, model,
+ [operand, invalidZeroPoint](Model* model, ExecutionPreference*) {
+ model->operands[operand].zeroPoint = invalidZeroPoint;
+ });
}
}
}
@@ -282,9 +292,10 @@
const std::string message = "mutateOperationOperandTypeTest: operand " +
std::to_string(operand) + " set to type " +
toString(invalidOperandType);
- validate(device, message, model, [operand, invalidOperandType](Model* model) {
- mutateOperand(&model->operands[operand], invalidOperandType);
- });
+ validate(device, message, model,
+ [operand, invalidOperandType](Model* model, ExecutionPreference*) {
+ mutateOperand(&model->operands[operand], invalidOperandType);
+ });
}
}
}
@@ -304,10 +315,11 @@
const std::string message = "mutateOperationTypeTest: operation " +
std::to_string(operation) + " set to value " +
std::to_string(invalidOperationType);
- validate(device, message, model, [operation, invalidOperationType](Model* model) {
- model->operations[operation].type =
- static_cast<OperationType>(invalidOperationType);
- });
+ validate(device, message, model,
+ [operation, invalidOperationType](Model* model, ExecutionPreference*) {
+ model->operations[operation].type =
+ static_cast<OperationType>(invalidOperationType);
+ });
}
}
}
@@ -321,9 +333,10 @@
const std::string message = "mutateOperationInputOperandIndexTest: operation " +
std::to_string(operation) + " input " +
std::to_string(input);
- validate(device, message, model, [operation, input, invalidOperand](Model* model) {
- model->operations[operation].inputs[input] = invalidOperand;
- });
+ validate(device, message, model,
+ [operation, input, invalidOperand](Model* model, ExecutionPreference*) {
+ model->operations[operation].inputs[input] = invalidOperand;
+ });
}
}
}
@@ -337,9 +350,10 @@
const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
std::to_string(operation) + " output " +
std::to_string(output);
- validate(device, message, model, [operation, output, invalidOperand](Model* model) {
- model->operations[operation].outputs[output] = invalidOperand;
- });
+ validate(device, message, model,
+ [operation, output, invalidOperand](Model* model, ExecutionPreference*) {
+ model->operations[operation].outputs[output] = invalidOperand;
+ });
}
}
}
@@ -372,7 +386,7 @@
for (size_t operand = 0; operand < model.operands.size(); ++operand) {
const std::string message = "removeOperandTest: operand " + std::to_string(operand);
validate(device, message, model,
- [operand](Model* model) { removeOperand(model, operand); });
+ [operand](Model* model, ExecutionPreference*) { removeOperand(model, operand); });
}
}
@@ -388,8 +402,9 @@
static void removeOperationTest(const sp<IDevice>& device, const Model& model) {
for (size_t operation = 0; operation < model.operations.size(); ++operation) {
const std::string message = "removeOperationTest: operation " + std::to_string(operation);
- validate(device, message, model,
- [operation](Model* model) { removeOperation(model, operation); });
+ validate(device, message, model, [operation](Model* model, ExecutionPreference*) {
+ removeOperation(model, operation);
+ });
}
}
@@ -409,11 +424,12 @@
const std::string message = "removeOperationInputTest: operation " +
std::to_string(operation) + ", input " +
std::to_string(input);
- validate(device, message, model, [operation, input](Model* model) {
- uint32_t operand = model->operations[operation].inputs[input];
- model->operands[operand].numberOfConsumers--;
- hidl_vec_removeAt(&model->operations[operation].inputs, input);
- });
+ validate(device, message, model,
+ [operation, input](Model* model, ExecutionPreference*) {
+ uint32_t operand = model->operations[operation].inputs[input];
+ model->operands[operand].numberOfConsumers--;
+ hidl_vec_removeAt(&model->operations[operation].inputs, input);
+ });
}
}
}
@@ -426,9 +442,10 @@
const std::string message = "removeOperationOutputTest: operation " +
std::to_string(operation) + ", output " +
std::to_string(output);
- validate(device, message, model, [operation, output](Model* model) {
- hidl_vec_removeAt(&model->operations[operation].outputs, output);
- });
+ validate(device, message, model,
+ [operation, output](Model* model, ExecutionPreference*) {
+ hidl_vec_removeAt(&model->operations[operation].outputs, output);
+ });
}
}
}
@@ -444,7 +461,7 @@
static void addOperationInputTest(const sp<IDevice>& device, const Model& model) {
for (size_t operation = 0; operation < model.operations.size(); ++operation) {
const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
- validate(device, message, model, [operation](Model* model) {
+ validate(device, message, model, [operation](Model* model, ExecutionPreference*) {
uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT);
hidl_vec_push_back(&model->operations[operation].inputs, index);
hidl_vec_push_back(&model->inputIndexes, index);
@@ -458,7 +475,7 @@
for (size_t operation = 0; operation < model.operations.size(); ++operation) {
const std::string message =
"addOperationOutputTest: operation " + std::to_string(operation);
- validate(device, message, model, [operation](Model* model) {
+ validate(device, message, model, [operation](Model* model, ExecutionPreference*) {
uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
hidl_vec_push_back(&model->operations[operation].outputs, index);
hidl_vec_push_back(&model->outputIndexes, index);
@@ -474,12 +491,13 @@
};
static void mutateExecutionPreferenceTest(const sp<IDevice>& device, const Model& model) {
- for (int32_t preference : invalidExecutionPreferences) {
+ for (int32_t invalidPreference : invalidExecutionPreferences) {
const std::string message =
- "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
- validate(
- device, message, model, [](Model*) {},
- static_cast<ExecutionPreference>(preference));
+ "mutateExecutionPreferenceTest: preference " + std::to_string(invalidPreference);
+ validate(device, message, model,
+ [invalidPreference](Model*, ExecutionPreference* preference) {
+ *preference = static_cast<ExecutionPreference>(invalidPreference);
+ });
}
}
diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
index 9684eb2..2914335 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
@@ -28,15 +28,17 @@
using V1_0::Request;
using V1_0::implementation::ExecutionCallback;
+using ExecutionMutation = std::function<void(Request*)>;
+
///////////////////////// UTILITY FUNCTIONS /////////////////////////
// Primary validation function. This function will take a valid request, apply a
// mutation to it to invalidate the request, then pass it to interface calls
-// that use the request. Note that the request here is passed by value, and any
-// mutation to the request does not leave this function.
+// that use the request.
static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
- Request request, const std::function<void(Request*)>& mutation) {
- mutation(&request);
+ const Request& originalRequest, const ExecutionMutation& mutate) {
+ Request request = originalRequest;
+ mutate(&request);
SCOPED_TRACE(message + " [execute]");
sp<ExecutionCallback> executionCallback = new ExecutionCallback();
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
index d56d40b..54e8802 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
@@ -132,11 +132,17 @@
TEST_P(ValidationTest, Test) {
const Model model = createModel(kTestModel);
- const Request request = createRequest(kTestModel);
+ ExecutionContext context;
+ const Request request = context.createRequest(kTestModel);
ASSERT_FALSE(kTestModel.expectFailure);
validateEverything(kDevice, model, request);
}
-INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
+INSTANTIATE_GENERATED_TEST(ValidationTest, [](const std::string& testName) {
+ // Skip validation for the "inputs_as_internal" and "all_tensors_as_inputs"
+ // generated tests.
+ return testName.find("inputs_as_internal") == std::string::npos &&
+ testName.find("all_tensors_as_inputs") == std::string::npos;
+});
} // namespace android::hardware::neuralnetworks::V1_1::vts::functional
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 31a1a81..7c1faee 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -28,7 +28,7 @@
],
header_libs: [
"libbase_headers",
- ]
+ ],
}
cc_test {
@@ -39,9 +39,9 @@
"CompilationCachingTests.cpp",
"GeneratedTestHarness.cpp",
"TestAssertions.cpp",
+ "ValidateBurst.cpp",
"ValidateModel.cpp",
"ValidateRequest.cpp",
- "ValidateBurst.cpp",
"VtsHalNeuralnetworks.cpp",
],
local_include_dirs: ["include"],
@@ -50,18 +50,17 @@
"libnativewindow",
],
static_libs: [
+ "VtsHalNeuralNetworksV1_0_utils",
+ "VtsHalNeuralNetworksV1_2Callbacks",
"android.hardware.neuralnetworks@1.0",
"android.hardware.neuralnetworks@1.1",
"android.hardware.neuralnetworks@1.2",
- "android.hardware.neuralnetworks@1.3",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libgmock",
"libhidlmemory",
"libneuralnetworks_generated_test_harness",
"libneuralnetworks_utils",
- "VtsHalNeuralNetworksV1_0_utils",
- "VtsHalNeuralNetworksV1_2Callbacks",
],
whole_static_libs: [
"neuralnetworks_generated_V1_0_example",
@@ -71,5 +70,8 @@
header_libs: [
"libneuralnetworks_headers",
],
- test_suites: ["general-tests", "vts-core"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 10dec79..449b8f3 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -32,7 +32,6 @@
#include "GeneratedTestHarness.h"
#include "MemoryUtils.h"
#include "TestHarness.h"
-#include "Utils.h"
#include "VtsHalNeuralnetworks.h"
// Forward declaration of the mobilenet generated test models in
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
index 4c8fede..35275b4 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
@@ -43,7 +43,6 @@
#include "ExecutionBurstController.h"
#include "MemoryUtils.h"
#include "TestHarness.h"
-#include "Utils.h"
#include "VtsHalNeuralnetworks.h"
namespace android::hardware::neuralnetworks::V1_2::vts::functional {
@@ -69,6 +68,7 @@
Executor executor;
MeasureTiming measureTiming;
OutputType outputType;
+ MemoryType memoryType;
};
} // namespace
@@ -217,7 +217,8 @@
return;
}
- Request request = createRequest(testModel);
+ ExecutionContext context;
+ Request request = context.createRequest(testModel, testConfig.memoryType);
if (testConfig.outputType == OutputType::INSUFFICIENT) {
makeOutputInsufficientSize(/*outputIndex=*/0, &request);
}
@@ -273,7 +274,7 @@
int n;
std::tie(n, outputShapes, timing, std::ignore) =
controller->compute(request, testConfig.measureTiming, keys);
- executionStatus = nn::convertToV1_0(nn::convertResultCodeToErrorStatus(n));
+ executionStatus = nn::legacyConvertResultCodeToErrorStatus(n);
break;
}
@@ -327,7 +328,7 @@
}
// Retrieve execution results.
- const std::vector<TestBuffer> outputs = getOutputBuffers(request);
+ const std::vector<TestBuffer> outputs = context.getOutputBuffers(request);
// We want "close-enough" results.
checkResults(testModel, outputs);
@@ -338,24 +339,30 @@
std::vector<OutputType> outputTypesList;
std::vector<MeasureTiming> measureTimingList;
std::vector<Executor> executorList;
+ std::vector<MemoryType> memoryTypeList;
if (testDynamicOutputShape) {
outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT};
measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+ memoryTypeList = {MemoryType::ASHMEM};
} else {
outputTypesList = {OutputType::FULLY_SPECIFIED};
measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+ memoryTypeList = {MemoryType::ASHMEM, MemoryType::BLOB_AHWB};
}
for (const OutputType outputType : outputTypesList) {
for (const MeasureTiming measureTiming : measureTimingList) {
for (const Executor executor : executorList) {
- const TestConfig testConfig = {.executor = executor,
- .measureTiming = measureTiming,
- .outputType = outputType};
- EvaluatePreparedModel(preparedModel, testModel, testConfig);
+ for (const MemoryType memoryType : memoryTypeList) {
+ const TestConfig testConfig = {.executor = executor,
+ .measureTiming = measureTiming,
+ .outputType = outputType,
+ .memoryType = memoryType};
+ EvaluatePreparedModel(preparedModel, testModel, testConfig);
+ }
}
}
}
@@ -383,6 +390,10 @@
return TestModelManager::get().getTestModels(filter);
}
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter) {
+ return TestModelManager::get().getTestModels(filter);
+}
+
std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
const auto& [namedDevice, namedModel] = info.param;
return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
index dfc980c..98295ff 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
@@ -41,6 +41,9 @@
using FilterFn = std::function<bool(const test_helper::TestModel&)>;
std::vector<NamedModel> getNamedModels(const FilterFn& filter);
+using FilterNameFn = std::function<bool(const std::string&)>;
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter);
+
std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);
#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \
diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
index ec9629b..4476266 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
@@ -23,7 +23,6 @@
#include "ExecutionBurstServer.h"
#include "GeneratedTestHarness.h"
#include "TestHarness.h"
-#include "Utils.h"
#include <android-base/logging.h>
#include <chrono>
@@ -38,6 +37,8 @@
using V1_0::Request;
using ExecutionBurstCallback = ExecutionBurstController::ExecutionBurstCallback;
+using BurstExecutionMutation = std::function<void(std::vector<FmqRequestDatum>*)>;
+
// This constant value represents the length of an FMQ that is large enough to
// return a result from a burst execution for all of the generated test cases.
constexpr size_t kExecutionBurstChannelLength = 1024;
@@ -116,13 +117,13 @@
// Primary validation function. This function will take a valid serialized
// request, apply a mutation to it to invalidate the serialized request, then
-// pass it to interface calls that use the serialized request. Note that the
-// serialized request here is passed by value, and any mutation to the
-// serialized request does not leave this function.
+// pass it to interface calls that use the serialized request.
static void validate(RequestChannelSender* sender, ResultChannelReceiver* receiver,
- const std::string& message, std::vector<FmqRequestDatum> serialized,
- const std::function<void(std::vector<FmqRequestDatum>*)>& mutation) {
- mutation(&serialized);
+ const std::string& message,
+ const std::vector<FmqRequestDatum>& originalSerialized,
+ const BurstExecutionMutation& mutate) {
+ std::vector<FmqRequestDatum> serialized = originalSerialized;
+ mutate(&serialized);
// skip if packet is too large to send
if (serialized.size() > kExecutionBurstChannelLength) {
@@ -296,8 +297,7 @@
// collect serialized result by running regular burst
const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] =
controllerRegular->compute(request, MeasureTiming::NO, keys);
- const ErrorStatus statusRegular =
- nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nRegular));
+ const ErrorStatus statusRegular = nn::legacyConvertResultCodeToErrorStatus(nRegular);
EXPECT_FALSE(fallbackRegular);
// skip test if regular burst output isn't useful for testing a failure
@@ -313,7 +313,7 @@
// large enough to return the serialized result
const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] =
controllerSmall->compute(request, MeasureTiming::NO, keys);
- const ErrorStatus statusSmall = nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nSmall));
+ const ErrorStatus statusSmall = nn::legacyConvertResultCodeToErrorStatus(nSmall);
EXPECT_NE(ErrorStatus::NONE, statusSmall);
EXPECT_EQ(0u, outputShapesSmall.size());
EXPECT_TRUE(badTiming(timingSmall));
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index 30530be..7451f09 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -29,6 +29,8 @@
using V1_1::ExecutionPreference;
using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
+using PrepareModelMutation = std::function<void(Model*, ExecutionPreference*)>;
+
///////////////////////// UTILITY FUNCTIONS /////////////////////////
static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
@@ -67,16 +69,19 @@
}
// Primary validation function. This function will take a valid model, apply a
-// mutation to it to invalidate the model, then pass it to interface calls that
-// use the model. Note that the model here is passed by value, and any mutation
-// to the model does not leave this function.
-static void validate(const sp<IDevice>& device, const std::string& message, Model model,
- const std::function<void(Model*)>& mutation,
- ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) {
- mutation(&model);
+// mutation to invalidate either the model or the execution preference, then
+// pass these to supportedOperations and/or prepareModel if that method is
+// called with an invalid argument.
+static void validate(const sp<IDevice>& device, const std::string& message,
+ const Model& originalModel, const PrepareModelMutation& mutate) {
+ Model model = originalModel;
+ ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER;
+ mutate(&model, &preference);
+
if (validExecutionPreference(preference)) {
validateGetSupportedOperations(device, message, model);
}
+
validatePrepareModel(device, message, model, preference);
}
@@ -115,9 +120,11 @@
const std::string message = "mutateOperandTypeTest: operand " +
std::to_string(operand) + " set to value " +
std::to_string(invalidOperandType);
- validate(device, message, model, [operand, invalidOperandType](Model* model) {
- model->operands[operand].type = static_cast<OperandType>(invalidOperandType);
- });
+ validate(device, message, model,
+ [operand, invalidOperandType](Model* model, ExecutionPreference*) {
+ model->operands[operand].type =
+ static_cast<OperandType>(invalidOperandType);
+ });
}
}
}
@@ -155,9 +162,10 @@
}
const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
" has rank of " + std::to_string(invalidRank);
- validate(device, message, model, [operand, invalidRank](Model* model) {
- model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
- });
+ validate(device, message, model,
+ [operand, invalidRank](Model* model, ExecutionPreference*) {
+ model->operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
+ });
}
}
@@ -192,9 +200,10 @@
const float invalidScale = getInvalidScale(model.operands[operand].type);
const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
" has scale of " + std::to_string(invalidScale);
- validate(device, message, model, [operand, invalidScale](Model* model) {
- model->operands[operand].scale = invalidScale;
- });
+ validate(device, message, model,
+ [operand, invalidScale](Model* model, ExecutionPreference*) {
+ model->operands[operand].scale = invalidScale;
+ });
}
}
@@ -234,9 +243,10 @@
const std::string message = "mutateOperandZeroPointTest: operand " +
std::to_string(operand) + " has zero point of " +
std::to_string(invalidZeroPoint);
- validate(device, message, model, [operand, invalidZeroPoint](Model* model) {
- model->operands[operand].zeroPoint = invalidZeroPoint;
- });
+ validate(device, message, model,
+ [operand, invalidZeroPoint](Model* model, ExecutionPreference*) {
+ model->operands[operand].zeroPoint = invalidZeroPoint;
+ });
}
}
}
@@ -386,9 +396,10 @@
const std::string message = "mutateOperationOperandTypeTest: operand " +
std::to_string(operand) + " set to type " +
toString(invalidOperandType);
- validate(device, message, model, [operand, invalidOperandType](Model* model) {
- mutateOperand(&model->operands[operand], invalidOperandType);
- });
+ validate(device, message, model,
+ [operand, invalidOperandType](Model* model, ExecutionPreference*) {
+ mutateOperand(&model->operands[operand], invalidOperandType);
+ });
}
}
}
@@ -407,10 +418,11 @@
const std::string message = "mutateOperationTypeTest: operation " +
std::to_string(operation) + " set to value " +
std::to_string(invalidOperationType);
- validate(device, message, model, [operation, invalidOperationType](Model* model) {
- model->operations[operation].type =
- static_cast<OperationType>(invalidOperationType);
- });
+ validate(device, message, model,
+ [operation, invalidOperationType](Model* model, ExecutionPreference*) {
+ model->operations[operation].type =
+ static_cast<OperationType>(invalidOperationType);
+ });
}
}
}
@@ -424,9 +436,10 @@
const std::string message = "mutateOperationInputOperandIndexTest: operation " +
std::to_string(operation) + " input " +
std::to_string(input);
- validate(device, message, model, [operation, input, invalidOperand](Model* model) {
- model->operations[operation].inputs[input] = invalidOperand;
- });
+ validate(device, message, model,
+ [operation, input, invalidOperand](Model* model, ExecutionPreference*) {
+ model->operations[operation].inputs[input] = invalidOperand;
+ });
}
}
}
@@ -440,9 +453,10 @@
const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
std::to_string(operation) + " output " +
std::to_string(output);
- validate(device, message, model, [operation, output, invalidOperand](Model* model) {
- model->operations[operation].outputs[output] = invalidOperand;
- });
+ validate(device, message, model,
+ [operation, output, invalidOperand](Model* model, ExecutionPreference*) {
+ model->operations[operation].outputs[output] = invalidOperand;
+ });
}
}
}
@@ -503,7 +517,7 @@
}
const std::string message = "removeOperandTest: operand " + std::to_string(operand);
validate(device, message, model,
- [operand](Model* model) { removeOperand(model, operand); });
+ [operand](Model* model, ExecutionPreference*) { removeOperand(model, operand); });
}
}
@@ -519,8 +533,9 @@
static void removeOperationTest(const sp<IDevice>& device, const Model& model) {
for (size_t operation = 0; operation < model.operations.size(); ++operation) {
const std::string message = "removeOperationTest: operation " + std::to_string(operation);
- validate(device, message, model,
- [operation](Model* model) { removeOperation(model, operation); });
+ validate(device, message, model, [operation](Model* model, ExecutionPreference*) {
+ removeOperation(model, operation);
+ });
}
}
@@ -601,11 +616,12 @@
const std::string message = "removeOperationInputTest: operation " +
std::to_string(operation) + ", input " +
std::to_string(input);
- validate(device, message, model, [operation, input](Model* model) {
- uint32_t operand = model->operations[operation].inputs[input];
- model->operands[operand].numberOfConsumers--;
- hidl_vec_removeAt(&model->operations[operation].inputs, input);
- });
+ validate(device, message, model,
+ [operation, input](Model* model, ExecutionPreference*) {
+ uint32_t operand = model->operations[operation].inputs[input];
+ model->operands[operand].numberOfConsumers--;
+ hidl_vec_removeAt(&model->operations[operation].inputs, input);
+ });
}
}
}
@@ -618,9 +634,10 @@
const std::string message = "removeOperationOutputTest: operation " +
std::to_string(operation) + ", output " +
std::to_string(output);
- validate(device, message, model, [operation, output](Model* model) {
- hidl_vec_removeAt(&model->operations[operation].outputs, output);
- });
+ validate(device, message, model,
+ [operation, output](Model* model, ExecutionPreference*) {
+ hidl_vec_removeAt(&model->operations[operation].outputs, output);
+ });
}
}
}
@@ -651,7 +668,7 @@
continue;
}
const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
- validate(device, message, model, [operation](Model* model) {
+ validate(device, message, model, [operation](Model* model, ExecutionPreference*) {
uint32_t index = addOperand(model, OperandLifeTime::MODEL_INPUT);
hidl_vec_push_back(&model->operations[operation].inputs, index);
hidl_vec_push_back(&model->inputIndexes, index);
@@ -665,7 +682,7 @@
for (size_t operation = 0; operation < model.operations.size(); ++operation) {
const std::string message =
"addOperationOutputTest: operation " + std::to_string(operation);
- validate(device, message, model, [operation](Model* model) {
+ validate(device, message, model, [operation](Model* model, ExecutionPreference*) {
uint32_t index = addOperand(model, OperandLifeTime::MODEL_OUTPUT);
hidl_vec_push_back(&model->operations[operation].outputs, index);
hidl_vec_push_back(&model->outputIndexes, index);
@@ -681,12 +698,13 @@
};
static void mutateExecutionPreferenceTest(const sp<IDevice>& device, const Model& model) {
- for (int32_t preference : invalidExecutionPreferences) {
+ for (int32_t invalidPreference : invalidExecutionPreferences) {
const std::string message =
- "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
- validate(
- device, message, model, [](Model*) {},
- static_cast<ExecutionPreference>(preference));
+ "mutateExecutionPreferenceTest: preference " + std::to_string(invalidPreference);
+ validate(device, message, model,
+ [invalidPreference](Model*, ExecutionPreference* preference) {
+ *preference = static_cast<ExecutionPreference>(invalidPreference);
+ });
}
}
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
index 7b5ff9b..934d893 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -22,7 +22,6 @@
#include "ExecutionBurstController.h"
#include "GeneratedTestHarness.h"
#include "TestHarness.h"
-#include "Utils.h"
#include "VtsHalNeuralnetworks.h"
namespace android::hardware::neuralnetworks::V1_2::vts::functional {
@@ -31,6 +30,8 @@
using V1_0::ErrorStatus;
using V1_0::Request;
+using ExecutionMutation = std::function<void(Request*)>;
+
///////////////////////// UTILITY FUNCTIONS /////////////////////////
static bool badTiming(Timing timing) {
@@ -39,11 +40,11 @@
// Primary validation function. This function will take a valid request, apply a
// mutation to it to invalidate the request, then pass it to interface calls
-// that use the request. Note that the request here is passed by value, and any
-// mutation to the request does not leave this function.
+// that use the request.
static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
- Request request, const std::function<void(Request*)>& mutation) {
- mutation(&request);
+ const Request& originalRequest, const ExecutionMutation& mutate) {
+ Request request = originalRequest;
+ mutate(&request);
// We'd like to test both with timing requested and without timing
// requested. Rather than running each test both ways, we'll decide whether
@@ -107,7 +108,7 @@
// execute and verify
const auto [n, outputShapes, timing, fallback] = burst->compute(request, measure, keys);
- const ErrorStatus status = nn::convertToV1_0(nn::convertResultCodeToErrorStatus(n));
+ const ErrorStatus status = nn::legacyConvertResultCodeToErrorStatus(n);
EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
EXPECT_EQ(outputShapes.size(), 0);
EXPECT_TRUE(badTiming(timing));
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
index 4fbd0e2..a60ec4d 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
@@ -153,7 +153,8 @@
TEST_P(ValidationTest, Test) {
const Model model = createModel(kTestModel);
- const Request request = createRequest(kTestModel);
+ ExecutionContext context;
+ const Request request = context.createRequest(kTestModel);
if (kTestModel.expectFailure) {
validateFailure(kDevice, model, request);
} else {
@@ -161,7 +162,12 @@
}
}
-INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
+INSTANTIATE_GENERATED_TEST(ValidationTest, [](const std::string& testName) {
+ // Skip validation for the "inputs_as_internal" and "all_tensors_as_inputs"
+ // generated tests.
+ return testName.find("inputs_as_internal") == std::string::npos &&
+ testName.find("all_tensors_as_inputs") == std::string::npos;
+});
sp<IPreparedModel> getPreparedModel_1_2(const sp<implementation::PreparedModelCallback>& callback) {
sp<V1_0::IPreparedModel> preparedModelV1_0 = callback->getPreparedModel();
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index daaf22e..25ec915 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -5168,6 +5168,8 @@
* * {@link OperandType::TENSOR_FLOAT16}
* * {@link OperandType::TENSOR_FLOAT32}
*
+ * Supported tensor rank: from 1.
+ *
* Inputs:
* * 0: A tensor, specifying the input. May be zero-sized.
* * 1: A scalar, specifying the alpha parameter.
@@ -5197,6 +5199,8 @@
* * {@link OperandType::TENSOR_QUANT8_ASYMM}
* * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
*
+ * Supported tensor rank: from 1.
+ *
* Inputs:
* * 0: A tensor, specifying the input. May be zero-sized.
*
@@ -5215,6 +5219,8 @@
* * {@link OperandType::TENSOR_FLOAT32}
* * {@link OperandType::TENSOR_INT32}
*
+ * Supported tensor rank: from 1.
+ *
* Inputs:
* * 0: A 1-D tensor, specifying the desired output tensor shape.
* * 1: A scalar, specifying the value to fill the output tensors with.
@@ -5248,6 +5254,8 @@
* * {@link OperandType::TENSOR_QUANT8_SYMM}
* * {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED}
*
+ * Supported tensor rank: from 1.
+ *
* Inputs:
* * 0: The input tensor.
*
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
index f936267..545a5be 100644
--- a/neuralnetworks/1.3/vts/functional/Android.bp
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -40,6 +40,7 @@
"BasicTests.cpp",
"CompilationCachingTests.cpp",
"GeneratedTestHarness.cpp",
+ "MemoryDomainTests.cpp",
"QualityOfServiceTests.cpp",
"TestAssertions.cpp",
"ValidateBurst.cpp",
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index 83a8d94..4dbac16 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -72,21 +72,10 @@
namespace {
-enum class Executor { ASYNC, SYNC, BURST, FENCED };
-
enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT, MISSED_DEADLINE };
-enum class MemoryType { SHARED, DEVICE };
-
enum class IOType { INPUT, OUTPUT };
-static void waitForSyncFence(int syncFd) {
- constexpr int kInfiniteTimeout = -1;
- ASSERT_GT(syncFd, 0);
- int r = sync_wait(syncFd, kInfiniteTimeout);
- ASSERT_GE(r, 0);
-}
-
struct TestConfig {
Executor executor;
MeasureTiming measureTiming;
@@ -277,6 +266,13 @@
} // namespace
+void waitForSyncFence(int syncFd) {
+ constexpr int kInfiniteTimeout = -1;
+ ASSERT_GT(syncFd, 0);
+ int r = sync_wait(syncFd, kInfiniteTimeout);
+ ASSERT_GE(r, 0);
+}
+
Model createModel(const TestModel& testModel) {
uint32_t constCopySize = 0;
uint32_t constRefSize = 0;
@@ -338,21 +334,39 @@
}
}
-constexpr uint32_t kInputPoolIndex = 0;
-constexpr uint32_t kOutputPoolIndex = 1;
-constexpr uint32_t kDeviceMemoryBeginIndex = 2;
+class ExecutionContextV1_3 {
+ public:
+ ExecutionContextV1_3(sp<IDevice> device, sp<IPreparedModel> preparedModel)
+ : kDevice(std::move(device)), kPreparedModel(std::move(preparedModel)) {}
-static std::pair<Request, std::vector<sp<IBuffer>>> createRequest(
- const sp<IDevice>& device, const sp<IPreparedModel>& preparedModel,
- const TestModel& testModel, bool preferDeviceMemory) {
+ std::optional<Request> createRequest(const TestModel& testModel, MemoryType memoryType);
+ std::vector<TestBuffer> getOutputBuffers(const TestModel& testModel,
+ const Request& request) const;
+
+ private:
+ // Get a TestBuffer with data copied from an IBuffer object.
+ void getBuffer(const sp<IBuffer>& buffer, size_t size, TestBuffer* testBuffer) const;
+
+ static constexpr uint32_t kInputPoolIndex = 0;
+ static constexpr uint32_t kOutputPoolIndex = 1;
+ static constexpr uint32_t kDeviceMemoryBeginIndex = 2;
+
+ const sp<IDevice> kDevice;
+ const sp<IPreparedModel> kPreparedModel;
+ std::unique_ptr<TestMemoryBase> mInputMemory, mOutputMemory;
+ std::vector<sp<IBuffer>> mBuffers;
+};
+
+std::optional<Request> ExecutionContextV1_3::createRequest(const TestModel& testModel,
+ MemoryType memoryType) {
// Memory pools are organized as:
// - 0: Input shared memory pool
// - 1: Output shared memory pool
// - [2, 2+i): Input device memories
// - [2+i, 2+i+o): Output device memories
- DeviceMemoryAllocator allocator(device, preparedModel, testModel);
- std::vector<sp<IBuffer>> buffers;
+ DeviceMemoryAllocator allocator(kDevice, kPreparedModel, testModel);
std::vector<uint32_t> tokens;
+ mBuffers.clear();
// Model inputs.
hidl_vec<RequestArgument> inputs(testModel.main.inputIndexes.size());
@@ -363,13 +377,13 @@
// Omitted input.
inputs[i] = {.hasNoValue = true};
continue;
- } else if (preferDeviceMemory) {
+ } else if (memoryType == MemoryType::DEVICE) {
SCOPED_TRACE("Input index = " + std::to_string(i));
auto [buffer, token] = allocator.allocate<IOType::INPUT>(i);
if (buffer != nullptr) {
- DataLocation loc = {.poolIndex = static_cast<uint32_t>(buffers.size() +
+ DataLocation loc = {.poolIndex = static_cast<uint32_t>(mBuffers.size() +
kDeviceMemoryBeginIndex)};
- buffers.push_back(std::move(buffer));
+ mBuffers.push_back(std::move(buffer));
tokens.push_back(token);
inputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
continue;
@@ -389,13 +403,13 @@
size_t outputSize = 0;
for (uint32_t i = 0; i < testModel.main.outputIndexes.size(); i++) {
const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]];
- if (preferDeviceMemory) {
+ if (memoryType == MemoryType::DEVICE) {
SCOPED_TRACE("Output index = " + std::to_string(i));
auto [buffer, token] = allocator.allocate<IOType::OUTPUT>(i);
if (buffer != nullptr) {
- DataLocation loc = {.poolIndex = static_cast<uint32_t>(buffers.size() +
+ DataLocation loc = {.poolIndex = static_cast<uint32_t>(mBuffers.size() +
kDeviceMemoryBeginIndex)};
- buffers.push_back(std::move(buffer));
+ mBuffers.push_back(std::move(buffer));
tokens.push_back(token);
outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
continue;
@@ -418,21 +432,29 @@
outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
}
+ if (memoryType == MemoryType::DEVICE && mBuffers.empty()) {
+ return std::nullopt;
+ }
+
// Memory pools.
- hidl_vec<Request::MemoryPool> pools(kDeviceMemoryBeginIndex + buffers.size());
- pools[kInputPoolIndex].hidlMemory(nn::allocateSharedMemory(std::max<size_t>(inputSize, 1)));
- pools[kOutputPoolIndex].hidlMemory(nn::allocateSharedMemory(std::max<size_t>(outputSize, 1)));
- CHECK_NE(pools[kInputPoolIndex].hidlMemory().size(), 0u);
- CHECK_NE(pools[kOutputPoolIndex].hidlMemory().size(), 0u);
- for (uint32_t i = 0; i < buffers.size(); i++) {
+ hidl_vec<Request::MemoryPool> pools(kDeviceMemoryBeginIndex + mBuffers.size());
+ if (memoryType == MemoryType::BLOB_AHWB) {
+ mInputMemory = TestBlobAHWB::create(std::max<size_t>(inputSize, 1));
+ mOutputMemory = TestBlobAHWB::create(std::max<size_t>(outputSize, 1));
+ } else {
+ mInputMemory = TestAshmem::create(std::max<size_t>(inputSize, 1));
+ mOutputMemory = TestAshmem::create(std::max<size_t>(outputSize, 1));
+ }
+ EXPECT_NE(mInputMemory, nullptr);
+ EXPECT_NE(mOutputMemory, nullptr);
+ pools[kInputPoolIndex].hidlMemory(mInputMemory->getHidlMemory());
+ pools[kOutputPoolIndex].hidlMemory(mOutputMemory->getHidlMemory());
+ for (uint32_t i = 0; i < mBuffers.size(); i++) {
pools[kDeviceMemoryBeginIndex + i].token(tokens[i]);
}
// Copy input data to the input shared memory pool.
- sp<IMemory> inputMemory = mapMemory(pools[kInputPoolIndex].hidlMemory());
- CHECK(inputMemory.get() != nullptr);
- uint8_t* inputPtr = static_cast<uint8_t*>(static_cast<void*>(inputMemory->getPointer()));
- CHECK(inputPtr != nullptr);
+ uint8_t* inputPtr = mInputMemory->getPointer();
for (uint32_t i = 0; i < testModel.main.inputIndexes.size(); i++) {
if (!inputs[i].hasNoValue && inputs[i].location.poolIndex == kInputPoolIndex) {
const auto& op = testModel.main.operands[testModel.main.inputIndexes[i]];
@@ -441,14 +463,38 @@
std::copy(begin, end, inputPtr + inputs[i].location.offset);
}
}
-
- Request request = {
+ return Request{
.inputs = std::move(inputs), .outputs = std::move(outputs), .pools = std::move(pools)};
- return {std::move(request), std::move(buffers)};
+}
+
+std::vector<TestBuffer> ExecutionContextV1_3::getOutputBuffers(const TestModel& testModel,
+ const Request& request) const {
+ // Copy out output results.
+ uint8_t* outputPtr = mOutputMemory->getPointer();
+ std::vector<TestBuffer> outputBuffers;
+ for (uint32_t i = 0; i < request.outputs.size(); i++) {
+ const auto& outputLoc = request.outputs[i].location;
+ if (outputLoc.poolIndex == kOutputPoolIndex) {
+ outputBuffers.emplace_back(outputLoc.length, outputPtr + outputLoc.offset);
+ } else {
+ const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]];
+ if (op.data.size() == 0) {
+ outputBuffers.emplace_back(0, nullptr);
+ } else {
+ SCOPED_TRACE("Output index = " + std::to_string(i));
+ const uint32_t bufferIndex = outputLoc.poolIndex - kDeviceMemoryBeginIndex;
+ TestBuffer buffer;
+ getBuffer(mBuffers[bufferIndex], op.data.size(), &buffer);
+ outputBuffers.push_back(std::move(buffer));
+ }
+ }
+ }
+ return outputBuffers;
}
// Get a TestBuffer with data copied from an IBuffer object.
-static void getBuffer(const sp<IBuffer>& buffer, size_t size, TestBuffer* testBuffer) {
+void ExecutionContextV1_3::getBuffer(const sp<IBuffer>& buffer, size_t size,
+ TestBuffer* testBuffer) const {
// IBuffer -> Shared memory.
hidl_memory tmp = nn::allocateSharedMemory(size);
const auto ret = buffer->copyTo(tmp);
@@ -464,33 +510,11 @@
*testBuffer = TestBuffer(size, outputPtr);
}
-static std::vector<TestBuffer> getOutputBuffers(const TestModel& testModel, const Request& request,
- const std::vector<sp<IBuffer>>& buffers) {
- sp<IMemory> outputMemory = mapMemory(request.pools[kOutputPoolIndex].hidlMemory());
- CHECK(outputMemory.get() != nullptr);
- uint8_t* outputPtr = static_cast<uint8_t*>(static_cast<void*>(outputMemory->getPointer()));
- CHECK(outputPtr != nullptr);
-
- // Copy out output results.
- std::vector<TestBuffer> outputBuffers;
- for (uint32_t i = 0; i < request.outputs.size(); i++) {
- const auto& outputLoc = request.outputs[i].location;
- if (outputLoc.poolIndex == kOutputPoolIndex) {
- outputBuffers.emplace_back(outputLoc.length, outputPtr + outputLoc.offset);
- } else {
- const auto& op = testModel.main.operands[testModel.main.outputIndexes[i]];
- if (op.data.size() == 0) {
- outputBuffers.emplace_back();
- } else {
- SCOPED_TRACE("Output index = " + std::to_string(i));
- const uint32_t bufferIndex = outputLoc.poolIndex - kDeviceMemoryBeginIndex;
- TestBuffer buffer;
- getBuffer(buffers[bufferIndex], op.data.size(), &buffer);
- outputBuffers.push_back(std::move(buffer));
- }
- }
- }
- return outputBuffers;
+static bool hasZeroSizedOutput(const TestModel& testModel) {
+ return std::any_of(testModel.main.outputIndexes.begin(), testModel.main.outputIndexes.end(),
+ [&testModel](uint32_t index) {
+ return testModel.main.operands[index].data.size() == 0;
+ });
}
static Return<ErrorStatus> ExecutePreparedModel(const sp<IPreparedModel>& preparedModel,
@@ -536,13 +560,14 @@
return;
}
- auto [request, buffers] =
- createRequest(device, preparedModel, testModel,
- /*preferDeviceMemory=*/testConfig.memoryType == MemoryType::DEVICE);
+ ExecutionContextV1_3 context(device, preparedModel);
+ auto maybeRequest = context.createRequest(testModel, testConfig.memoryType);
// Skip if testing memory domain but no device memory has been allocated.
- if (testConfig.memoryType == MemoryType::DEVICE && buffers.empty()) {
+ if (!maybeRequest.has_value()) {
return;
}
+
+ Request request = std::move(maybeRequest.value());
if (testConfig.outputType == OutputType::INSUFFICIENT) {
makeOutputInsufficientSize(/*outputIndex=*/0, &request);
}
@@ -641,6 +666,7 @@
ASSERT_EQ(syncFenceHandle.getNativeHandle(), nullptr);
ASSERT_EQ(fencedCallback, nullptr);
executionStatus = result;
+ timing = {UINT64_MAX, UINT64_MAX};
} else if (syncFenceHandle.getNativeHandle()) {
// If a sync fence is returned, try start another run waiting for the sync fence.
ret = preparedModel->executeFenced(request, {syncFenceHandle},
@@ -689,6 +715,11 @@
switch (testConfig.outputType) {
case OutputType::FULLY_SPECIFIED:
+ if (testConfig.executor == Executor::FENCED && hasZeroSizedOutput(testModel)) {
+ // Executor::FENCED does not support zero-sized output.
+ ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, executionStatus);
+ return;
+ }
// If the model output operands are fully specified, outputShapes must be either
// either empty, or have the same number of elements as the number of outputs.
ASSERT_EQ(ErrorStatus::NONE, executionStatus);
@@ -732,7 +763,7 @@
}
// Retrieve execution results.
- const std::vector<TestBuffer> outputs = getOutputBuffers(testModel, request, buffers);
+ const std::vector<TestBuffer> outputs = context.getOutputBuffers(testModel, request);
// We want "close-enough" results.
checkResults(testModel, outputs);
@@ -743,29 +774,32 @@
std::vector<OutputType> outputTypesList;
std::vector<MeasureTiming> measureTimingList;
std::vector<Executor> executorList;
- MemoryType memoryType = MemoryType::SHARED;
+ std::vector<MemoryType> memoryTypeList;
switch (testKind) {
case TestKind::GENERAL: {
outputTypesList = {OutputType::FULLY_SPECIFIED};
measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST};
+ memoryTypeList = {MemoryType::ASHMEM};
} break;
case TestKind::DYNAMIC_SHAPE: {
outputTypesList = {OutputType::UNSPECIFIED, OutputType::INSUFFICIENT};
measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
executorList = {Executor::ASYNC, Executor::SYNC, Executor::BURST, Executor::FENCED};
+ memoryTypeList = {MemoryType::ASHMEM};
} break;
case TestKind::MEMORY_DOMAIN: {
outputTypesList = {OutputType::FULLY_SPECIFIED};
measureTimingList = {MeasureTiming::NO};
executorList = {Executor::ASYNC, Executor::SYNC, Executor::FENCED};
- memoryType = MemoryType::DEVICE;
+ memoryTypeList = {MemoryType::BLOB_AHWB, MemoryType::DEVICE};
} break;
case TestKind::FENCED_COMPUTE: {
outputTypesList = {OutputType::FULLY_SPECIFIED};
measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
executorList = {Executor::FENCED};
+ memoryTypeList = {MemoryType::ASHMEM};
} break;
case TestKind::QUANTIZATION_COUPLING: {
LOG(FATAL) << "Wrong TestKind for EvaluatePreparedModel";
@@ -776,14 +810,17 @@
measureTimingList = {MeasureTiming::NO, MeasureTiming::YES};
// Burst does not support V1_3 loop timeout.
executorList = {Executor::ASYNC, Executor::SYNC, Executor::FENCED};
+ memoryTypeList = {MemoryType::ASHMEM};
} break;
}
for (const OutputType outputType : outputTypesList) {
for (const MeasureTiming measureTiming : measureTimingList) {
for (const Executor executor : executorList) {
- const TestConfig testConfig(executor, measureTiming, outputType, memoryType);
- EvaluatePreparedModel(device, preparedModel, testModel, testConfig);
+ for (const MemoryType memoryType : memoryTypeList) {
+ const TestConfig testConfig(executor, measureTiming, outputType, memoryType);
+ EvaluatePreparedModel(device, preparedModel, testModel, testConfig);
+ }
}
}
}
@@ -802,7 +839,7 @@
for (const OutputType outputType : outputTypesList) {
for (const MeasureTiming measureTiming : measureTimingList) {
for (const Executor executor : executorList) {
- const TestConfig testConfig(executor, measureTiming, outputType, MemoryType::SHARED,
+ const TestConfig testConfig(executor, measureTiming, outputType, MemoryType::ASHMEM,
/*reportSkipping=*/false);
bool baseSkipped = false;
EvaluatePreparedModel(device, preparedModel, testModel, testConfig, &baseSkipped);
@@ -879,6 +916,10 @@
return TestModelManager::get().getTestModels(filter);
}
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter) {
+ return TestModelManager::get().getTestModels(filter);
+}
+
std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
const auto& [namedDevice, namedModel] = info.param;
return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
@@ -936,16 +977,12 @@
INSTANTIATE_GENERATED_TEST(MemoryDomainTest,
[](const TestModel& testModel) { return !testModel.expectFailure; });
-INSTANTIATE_GENERATED_TEST(FencedComputeTest, [](const TestModel& testModel) {
- return !testModel.expectFailure &&
- std::all_of(testModel.main.outputIndexes.begin(), testModel.main.outputIndexes.end(),
- [&testModel](uint32_t index) {
- return testModel.main.operands[index].data.size() > 0;
- });
-});
+INSTANTIATE_GENERATED_TEST(FencedComputeTest,
+ [](const TestModel& testModel) { return !testModel.expectFailure; });
INSTANTIATE_GENERATED_TEST(QuantizationCouplingTest, [](const TestModel& testModel) {
- return testModel.hasQuant8CoupledOperands() && testModel.main.operations.size() == 1;
+ return !testModel.expectFailure && testModel.hasQuant8CoupledOperands() &&
+ testModel.main.operations.size() == 1;
});
INSTANTIATE_GENERATED_TEST(InfiniteLoopTimeoutTest, [](const TestModel& testModel) {
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
index 834d335..4f05c48 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.h
@@ -41,6 +41,9 @@
using FilterFn = std::function<bool(const test_helper::TestModel&)>;
std::vector<NamedModel> getNamedModels(const FilterFn& filter);
+using FilterNameFn = std::function<bool(const std::string&)>;
+std::vector<NamedModel> getNamedModels(const FilterNameFn& filter);
+
std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);
#define INSTANTIATE_GENERATED_TEST(TestSuite, filter) \
@@ -77,6 +80,8 @@
void EvaluatePreparedModel(const sp<IDevice>& device, const sp<IPreparedModel>& preparedModel,
const test_helper::TestModel& testModel, TestKind testKind);
+void waitForSyncFence(int syncFd);
+
} // namespace android::hardware::neuralnetworks::V1_3::vts::functional
#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_GENERATED_TEST_HARNESS_H
diff --git a/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp b/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp
new file mode 100644
index 0000000..3c0c885
--- /dev/null
+++ b/neuralnetworks/1.3/vts/functional/MemoryDomainTests.cpp
@@ -0,0 +1,1203 @@
+/*
+ * Copyright (C) 2020 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 "neuralnetworks_hidl_hal_test"
+
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+
+#include "1.3/Callbacks.h"
+#include "1.3/Utils.h"
+#include "GeneratedTestHarness.h"
+#include "MemoryUtils.h"
+#include "TestHarness.h"
+#include "Utils.h"
+#include "VtsHalNeuralnetworks.h"
+
+namespace android::hardware::neuralnetworks::V1_3::vts::functional {
+
+using namespace test_helper;
+using implementation::ExecutionCallback;
+using implementation::PreparedModelCallback;
+using V1_0::RequestArgument;
+using V1_1::ExecutionPreference;
+using V1_2::Constant;
+using V1_2::MeasureTiming;
+using V1_2::OutputShape;
+using V1_2::Timing;
+
+namespace {
+
+const auto kNamedDeviceChoices = testing::ValuesIn(getNamedDevices());
+
+// A 1.3 driver is likely to support at least one of the following operand types.
+const std::vector<TestOperandType> kTestOperandTypeChoicesVector = {
+ TestOperandType::TENSOR_FLOAT32,
+ TestOperandType::TENSOR_FLOAT16,
+ TestOperandType::TENSOR_QUANT8_ASYMM,
+ TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED,
+};
+const auto kTestOperandTypeChoices = testing::ValuesIn(kTestOperandTypeChoicesVector);
+
+bool isInChoices(TestOperandType type) {
+ return std::count(kTestOperandTypeChoicesVector.begin(), kTestOperandTypeChoicesVector.end(),
+ type) > 0;
+}
+
+bool isFloat(TestOperandType type) {
+ CHECK(isInChoices(type));
+ return type == TestOperandType::TENSOR_FLOAT32 || type == TestOperandType::TENSOR_FLOAT16;
+}
+
+// Create dummy buffers for model constants as well as inputs and outputs.
+// We only care about the size here because we will not check accuracy in validation tests.
+void createDummyData(TestModel* testModel) {
+ for (auto& operand : testModel->main.operands) {
+ if (operand.data != nullptr) continue;
+ switch (operand.lifetime) {
+ case TestOperandLifeTime::SUBGRAPH_INPUT:
+ case TestOperandLifeTime::SUBGRAPH_OUTPUT:
+ case TestOperandLifeTime::CONSTANT_COPY:
+ case TestOperandLifeTime::CONSTANT_REFERENCE: {
+ const uint32_t size = nn::nonExtensionOperandSizeOfData(
+ static_cast<OperandType>(operand.type), operand.dimensions);
+ operand.data = TestBuffer(size);
+ } break;
+ default:
+ break;
+ }
+ }
+}
+
+TestOperand createInt32Scalar(int32_t value) {
+ return {
+ .type = TestOperandType::INT32,
+ .dimensions = {},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = TestOperandLifeTime::CONSTANT_COPY,
+ .data = TestBuffer::createFromVector<int32_t>({value}),
+ };
+}
+
+// Construct a test model with multiple CONV_2D operations with the given operand as inputs.
+// The dimensions of the filters are chosen to ensure outputs has the same dimensions as inputs.
+// We choose CONV_2D operation because it is commonly supported by most drivers.
+TestModel createConvModel(const TestOperand& operand, uint32_t numOperations) {
+ CHECK(isInChoices(operand.type));
+
+ TestOperand weight = {.type = operand.type,
+ .dimensions = {operand.dimensions[3], 3, 3, operand.dimensions[3]},
+ .numberOfConsumers = 1,
+ .scale = isFloat(operand.type) ? 0.0f : 1.0f,
+ .zeroPoint = 0,
+ .lifetime = TestOperandLifeTime::CONSTANT_COPY};
+
+ TestOperand bias = {
+ .type = isFloat(operand.type) ? operand.type : TestOperandType::TENSOR_INT32,
+ .dimensions = {operand.dimensions[3]},
+ .numberOfConsumers = 1,
+ .scale = operand.scale * weight.scale,
+ .zeroPoint = 0,
+ .lifetime = TestOperandLifeTime::CONSTANT_COPY};
+
+ TestOperand output = operand;
+ output.numberOfConsumers = 0;
+ output.lifetime = TestOperandLifeTime::SUBGRAPH_OUTPUT;
+
+ const std::vector<TestOperand> operands = {
+ operand,
+ std::move(weight),
+ std::move(bias),
+ createInt32Scalar(1), // same padding
+ createInt32Scalar(1), // width stride
+ createInt32Scalar(1), // height stride
+ createInt32Scalar(0), // activation = NONE
+ std::move(output),
+ };
+
+ TestModel model;
+ for (uint32_t i = 0; i < numOperations; i++) {
+ model.main.operands.insert(model.main.operands.end(), operands.begin(), operands.end());
+ const uint32_t inputIndex = operands.size() * i;
+ const uint32_t outputIndex = inputIndex + operands.size() - 1;
+ std::vector<uint32_t> inputs(operands.size() - 1);
+ std::iota(inputs.begin(), inputs.end(), inputIndex);
+ model.main.operations.push_back({.type = TestOperationType::CONV_2D,
+ .inputs = std::move(inputs),
+ .outputs = {outputIndex}});
+ model.main.inputIndexes.push_back(inputIndex);
+ model.main.outputIndexes.push_back(outputIndex);
+ }
+ createDummyData(&model);
+ return model;
+}
+
+// Construct a test model with a single ADD operation with the given operand as input0 and input1.
+// This is to cover additional cases that the CONV_2D model does not support, e.g. arbitrary input
+// operand rank, scalar input operand. We choose ADD operation because it is commonly supported by
+// most drivers.
+TestModel createSingleAddModel(const TestOperand& operand) {
+ CHECK(isInChoices(operand.type));
+
+ TestOperand act = {
+ .type = TestOperandType::INT32,
+ .dimensions = {},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = TestOperandLifeTime::SUBGRAPH_INPUT,
+ };
+
+ TestOperand output = operand;
+ output.numberOfConsumers = 0;
+ output.lifetime = TestOperandLifeTime::SUBGRAPH_OUTPUT;
+
+ TestModel model = {
+ .main =
+ {
+ .operands =
+ {
+ operand,
+ operand,
+ std::move(act),
+ output,
+ },
+ .operations = {{.type = TestOperationType::ADD,
+ .inputs = {0, 1, 2},
+ .outputs = {3}}},
+ .inputIndexes = {0, 1, 2},
+ .outputIndexes = {3},
+ },
+ };
+ createDummyData(&model);
+ return model;
+}
+
+// A dummy invalid IPreparedModel class for MemoryDomainAllocateTest.InvalidPreparedModel
+class InvalidPreparedModel : public IPreparedModel {
+ public:
+ Return<V1_0::ErrorStatus> execute(const V1_0::Request&,
+ const sp<V1_0::IExecutionCallback>&) override {
+ return V1_0::ErrorStatus::GENERAL_FAILURE;
+ }
+ Return<V1_0::ErrorStatus> execute_1_2(const V1_0::Request&, V1_2::MeasureTiming,
+ const sp<V1_2::IExecutionCallback>&) override {
+ return V1_0::ErrorStatus::GENERAL_FAILURE;
+ }
+ Return<V1_3::ErrorStatus> execute_1_3(const V1_3::Request&, V1_2::MeasureTiming,
+ const V1_3::OptionalTimePoint&,
+ const V1_3::OptionalTimeoutDuration&,
+ const sp<V1_3::IExecutionCallback>&) override {
+ return V1_3::ErrorStatus::GENERAL_FAILURE;
+ }
+ Return<void> executeSynchronously(const V1_0::Request&, V1_2::MeasureTiming,
+ executeSynchronously_cb) override {
+ return Void();
+ }
+ Return<void> executeSynchronously_1_3(const V1_3::Request&, V1_2::MeasureTiming,
+ const V1_3::OptionalTimePoint&,
+ const V1_3::OptionalTimeoutDuration&,
+ executeSynchronously_1_3_cb) override {
+ return Void();
+ }
+ Return<void> configureExecutionBurst(const sp<V1_2::IBurstCallback>&,
+ const MQDescriptorSync<V1_2::FmqRequestDatum>&,
+ const MQDescriptorSync<V1_2::FmqResultDatum>&,
+ configureExecutionBurst_cb) override {
+ return Void();
+ }
+ Return<void> executeFenced(const V1_3::Request&, const hidl_vec<hidl_handle>&,
+ V1_2::MeasureTiming, const V1_3::OptionalTimePoint&,
+ const V1_3::OptionalTimeoutDuration&,
+ const V1_3::OptionalTimeoutDuration&, executeFenced_cb) override {
+ return Void();
+ }
+};
+
+} // namespace
+
+class MemoryDomainTestBase : public testing::Test {
+ protected:
+ MemoryDomainTestBase(sp<IDevice> device, TestOperandType type)
+ : kDevice(std::move(device)),
+ kTestOperandType(type),
+ kTestOperand(kTestOperandMap.at(type)),
+ kTestOperandDataSize(nn::nonExtensionOperandSizeOfData(static_cast<OperandType>(type),
+ kTestOperand.dimensions)) {}
+
+ void SetUp() override {
+ testing::Test::SetUp();
+ ASSERT_NE(kDevice, nullptr);
+ }
+
+ sp<IPreparedModel> createConvPreparedModel(const TestOperand& testOperand,
+ uint32_t numOperations = 1) {
+ const TestModel testModel = createConvModel(testOperand, numOperations);
+ const Model model = createModel(testModel);
+ sp<IPreparedModel> preparedModel;
+ createPreparedModel(kDevice, model, &preparedModel, /*reportSkipping=*/false);
+ return preparedModel;
+ }
+
+ sp<IPreparedModel> createAddPreparedModel(const TestOperand& testOperand) {
+ const TestModel testModel = createSingleAddModel(testOperand);
+ const Model model = createModel(testModel);
+ sp<IPreparedModel> preparedModel;
+ createPreparedModel(kDevice, model, &preparedModel, /*reportSkipping=*/false);
+ return preparedModel;
+ }
+
+ static const std::map<TestOperandType, TestOperand> kTestOperandMap;
+
+ const sp<IDevice> kDevice;
+ const TestOperandType kTestOperandType;
+ const TestOperand& kTestOperand;
+ const uint32_t kTestOperandDataSize;
+};
+
+const std::map<TestOperandType, TestOperand> MemoryDomainTestBase::kTestOperandMap = {
+ {TestOperandType::TENSOR_FLOAT32,
+ {
+ .type = TestOperandType::TENSOR_FLOAT32,
+ .dimensions = {1, 32, 32, 8},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = TestOperandLifeTime::SUBGRAPH_INPUT,
+ }},
+ {TestOperandType::TENSOR_FLOAT16,
+ {
+ .type = TestOperandType::TENSOR_FLOAT16,
+ .dimensions = {1, 32, 32, 8},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = TestOperandLifeTime::SUBGRAPH_INPUT,
+ }},
+ {TestOperandType::TENSOR_QUANT8_ASYMM,
+ {
+ .type = TestOperandType::TENSOR_QUANT8_ASYMM,
+ .dimensions = {1, 32, 32, 8},
+ .numberOfConsumers = 1,
+ .scale = 0.5f,
+ .zeroPoint = 0,
+ .lifetime = TestOperandLifeTime::SUBGRAPH_INPUT,
+ }},
+ {TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED,
+ {
+ .type = TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED,
+ .dimensions = {1, 32, 32, 8},
+ .numberOfConsumers = 1,
+ .scale = 0.5f,
+ .zeroPoint = 0,
+ .lifetime = TestOperandLifeTime::SUBGRAPH_INPUT,
+ }},
+};
+
+using MemoryDomainAllocateTestParam = std::tuple<NamedDevice, TestOperandType>;
+class MemoryDomainAllocateTest : public MemoryDomainTestBase,
+ public testing::WithParamInterface<MemoryDomainAllocateTestParam> {
+ protected:
+ MemoryDomainAllocateTest()
+ : MemoryDomainTestBase(getData(std::get<NamedDevice>(GetParam())),
+ std::get<TestOperandType>(GetParam())) {}
+
+ struct AllocateTestArgs {
+ hidl_vec<uint32_t> dimensions;
+ hidl_vec<sp<IPreparedModel>> preparedModels;
+ hidl_vec<BufferRole> inputRoles;
+ hidl_vec<BufferRole> outputRoles;
+ };
+
+ // Validation test for IDevice::allocate. The driver is expected to fail with INVALID_ARGUMENT,
+ // or GENERAL_FAILURE if memory domain is not supported.
+ void validateAllocate(AllocateTestArgs args) {
+ const auto ret = kDevice->allocate(
+ {.dimensions = std::move(args.dimensions)}, std::move(args.preparedModels),
+ std::move(args.inputRoles), std::move(args.outputRoles),
+ [](ErrorStatus status, const sp<IBuffer>& buffer, uint32_t token) {
+ EXPECT_TRUE(status == ErrorStatus::INVALID_ARGUMENT ||
+ status == ErrorStatus::GENERAL_FAILURE);
+ EXPECT_EQ(buffer, nullptr);
+ EXPECT_EQ(token, 0);
+ });
+ ASSERT_TRUE(ret.isOk());
+ }
+
+ void testConflictOperands(const sp<IPreparedModel>& model1, const sp<IPreparedModel>& model2) {
+ validateAllocate({
+ .preparedModels = {model1, model2},
+ .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
+ {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+ });
+ validateAllocate({
+ .preparedModels = {model1, model2},
+ .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+ .outputRoles = {{.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+ });
+ validateAllocate({
+ .preparedModels = {model1, model2},
+ .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
+ {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+ });
+ }
+};
+
+TEST_P(MemoryDomainAllocateTest, EmptyRole) {
+ // Test with empty prepared models and roles.
+ validateAllocate({});
+
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ if (preparedModel == nullptr) return;
+
+ // Test again with non-empty prepared models but empty roles.
+ validateAllocate({
+ .preparedModels = {preparedModel},
+ });
+}
+
+TEST_P(MemoryDomainAllocateTest, NullptrPreparedModel) {
+ // Test with nullptr prepared model as input role.
+ validateAllocate({
+ .preparedModels = {nullptr},
+ .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+ });
+
+ // Test with nullptr prepared model as output role.
+ validateAllocate({
+ .preparedModels = {nullptr},
+ .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+ });
+}
+
+TEST_P(MemoryDomainAllocateTest, InvalidPreparedModel) {
+ sp<InvalidPreparedModel> invalidPreparedModel = new InvalidPreparedModel();
+
+ // Test with invalid prepared model as input role.
+ validateAllocate({
+ .preparedModels = {invalidPreparedModel},
+ .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+ });
+
+ // Test with invalid prepared model as output role.
+ validateAllocate({
+ .preparedModels = {invalidPreparedModel},
+ .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+ });
+}
+
+TEST_P(MemoryDomainAllocateTest, InvalidModelIndex) {
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ if (preparedModel == nullptr) return;
+
+ // This should fail, because the model index is out of bound.
+ validateAllocate({
+ .preparedModels = {preparedModel},
+ .inputRoles = {{.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+ });
+
+ // This should fail, because the model index is out of bound.
+ validateAllocate({
+ .preparedModels = {preparedModel},
+ .outputRoles = {{.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+ });
+}
+
+TEST_P(MemoryDomainAllocateTest, InvalidIOIndex) {
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ if (preparedModel == nullptr) return;
+
+ // This should fail, because the model only has one input.
+ validateAllocate({
+ .preparedModels = {preparedModel},
+ .inputRoles = {{.modelIndex = 0, .ioIndex = 1, .frequency = 1.0f}},
+ });
+
+ // This should fail, because the model only has one output.
+ validateAllocate({
+ .preparedModels = {preparedModel},
+ .outputRoles = {{.modelIndex = 0, .ioIndex = 1, .frequency = 1.0f}},
+ });
+}
+
+TEST_P(MemoryDomainAllocateTest, InvalidFrequency) {
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ if (preparedModel == nullptr) return;
+
+ for (float invalidFreq : {10.0f, 0.0f, -0.5f}) {
+ // Test with invalid frequency for input roles.
+ validateAllocate({
+ .preparedModels = {preparedModel},
+ .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = invalidFreq}},
+ });
+ // Test with invalid frequency for output roles.
+ validateAllocate({
+ .preparedModels = {preparedModel},
+ .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = invalidFreq}},
+ });
+ }
+}
+
+TEST_P(MemoryDomainAllocateTest, SameRoleSpecifiedTwice) {
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ if (preparedModel == nullptr) return;
+
+ // Same role with same model index.
+ validateAllocate({
+ .preparedModels = {preparedModel},
+ .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
+ {.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+ });
+ validateAllocate({
+ .preparedModels = {preparedModel},
+ .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
+ {.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+ });
+
+ // Different model indexes, but logically referring to the same role.
+ validateAllocate({
+ .preparedModels = {preparedModel, preparedModel},
+ .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
+ {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+ });
+ validateAllocate({
+ .preparedModels = {preparedModel, preparedModel},
+ .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f},
+ {.modelIndex = 1, .ioIndex = 0, .frequency = 1.0f}},
+ });
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictOperandType) {
+ const std::map<TestOperandType, TestOperandType> conflictTypeMap = {
+ {TestOperandType::TENSOR_FLOAT32, TestOperandType::TENSOR_FLOAT16},
+ {TestOperandType::TENSOR_FLOAT16, TestOperandType::TENSOR_FLOAT32},
+ {TestOperandType::TENSOR_QUANT8_ASYMM, TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED},
+ {TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED, TestOperandType::TENSOR_QUANT8_ASYMM},
+ };
+
+ TestOperand conflictTestOperand = kTestOperand;
+ const auto it = conflictTypeMap.find(kTestOperandType);
+ ASSERT_FALSE(it == conflictTypeMap.end());
+ conflictTestOperand.type = it->second;
+
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ auto conflictPreparedModel = createConvPreparedModel(conflictTestOperand);
+ if (preparedModel == nullptr || conflictPreparedModel == nullptr) return;
+ testConflictOperands(preparedModel, conflictPreparedModel);
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictScale) {
+ if (isFloat(kTestOperandType)) return;
+
+ TestOperand conflictTestOperand = kTestOperand;
+ ASSERT_NE(conflictTestOperand.scale, 1.0f);
+ conflictTestOperand.scale = 1.0f;
+
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ auto conflictPreparedModel = createConvPreparedModel(conflictTestOperand);
+ if (preparedModel == nullptr || conflictPreparedModel == nullptr) return;
+ testConflictOperands(preparedModel, conflictPreparedModel);
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictZeroPoint) {
+ if (isFloat(kTestOperandType)) return;
+
+ TestOperand conflictTestOperand = kTestOperand;
+ ASSERT_NE(conflictTestOperand.zeroPoint, 10);
+ conflictTestOperand.zeroPoint = 10;
+
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ auto conflictPreparedModel = createConvPreparedModel(conflictTestOperand);
+ if (preparedModel == nullptr || conflictPreparedModel == nullptr) return;
+ testConflictOperands(preparedModel, conflictPreparedModel);
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictRankBetweenRoles) {
+ TestOperand conflictTestOperand = kTestOperand;
+ conflictTestOperand.dimensions.pop_back();
+
+ auto preparedModel = createAddPreparedModel(kTestOperand);
+ auto conflictPreparedModel = createAddPreparedModel(conflictTestOperand);
+ if (preparedModel == nullptr || conflictPreparedModel == nullptr) return;
+ testConflictOperands(preparedModel, conflictPreparedModel);
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictDimensionsBetweenRoles) {
+ TestOperand conflictTestOperand = kTestOperand;
+ conflictTestOperand.dimensions[0] = 4;
+
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ auto conflictPreparedModel = createConvPreparedModel(conflictTestOperand);
+ if (preparedModel == nullptr || conflictPreparedModel == nullptr) return;
+ testConflictOperands(preparedModel, conflictPreparedModel);
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictRankBetweenRoleAndDesc) {
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ if (preparedModel == nullptr) return;
+
+ auto badDimensions = kTestOperand.dimensions;
+ badDimensions.pop_back();
+
+ validateAllocate({
+ .dimensions = badDimensions,
+ .preparedModels = {preparedModel},
+ .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+ });
+ validateAllocate({
+ .dimensions = badDimensions,
+ .preparedModels = {preparedModel},
+ .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+ });
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictDimensionsBetweenRoleAndDesc) {
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ if (preparedModel == nullptr) return;
+
+ auto badDimensions = kTestOperand.dimensions;
+ badDimensions[0] = 4;
+
+ validateAllocate({
+ .dimensions = badDimensions,
+ .preparedModels = {preparedModel},
+ .inputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+ });
+ validateAllocate({
+ .dimensions = badDimensions,
+ .preparedModels = {preparedModel},
+ .outputRoles = {{.modelIndex = 0, .ioIndex = 0, .frequency = 1.0f}},
+ });
+}
+
+TEST_P(MemoryDomainAllocateTest, ConflictRankWithScalarRole) {
+ auto preparedModel = createAddPreparedModel(kTestOperand);
+ if (preparedModel == nullptr) return;
+
+ // This should fail, because the target operand is a scalar but a non-empty dimension is
+ // specified.
+ validateAllocate({
+ .dimensions = {1},
+ .preparedModels = {preparedModel},
+ .inputRoles = {{.modelIndex = 0, .ioIndex = 2, .frequency = 1.0f}},
+ });
+}
+
+std::string printMemoryDomainAllocateTest(
+ const testing::TestParamInfo<MemoryDomainAllocateTestParam>& info) {
+ const auto& [namedDevice, operandType] = info.param;
+ const std::string type = toString(static_cast<OperandType>(operandType));
+ return gtestCompliantName(getName(namedDevice) + "_" + type);
+}
+
+INSTANTIATE_TEST_CASE_P(TestMemoryDomain, MemoryDomainAllocateTest,
+ testing::Combine(kNamedDeviceChoices, kTestOperandTypeChoices),
+ printMemoryDomainAllocateTest);
+
+class MemoryDomainCopyTestBase : public MemoryDomainTestBase {
+ protected:
+ MemoryDomainCopyTestBase(sp<IDevice> device, TestOperandType type)
+ : MemoryDomainTestBase(std::move(device), type) {}
+
+ // Allocates device memory for roles of a single prepared model.
+ // Returns {IBuffer, token} if success; returns {nullptr, 0} if not supported.
+ std::pair<sp<IBuffer>, uint32_t> allocateBuffer(const sp<IPreparedModel>& preparedModel,
+ const std::vector<uint32_t>& inputIndexes,
+ const std::vector<uint32_t>& outputIndexes,
+ const std::vector<uint32_t>& dimensions) {
+ if (preparedModel == nullptr) {
+ return {nullptr, 0};
+ }
+
+ hidl_vec<BufferRole> inputRoles(inputIndexes.size()), outputRoles(outputIndexes.size());
+ auto trans = [](uint32_t ind) -> BufferRole {
+ return {.modelIndex = 0, .ioIndex = ind, .frequency = 1.0f};
+ };
+ std::transform(inputIndexes.begin(), inputIndexes.end(), inputRoles.begin(), trans);
+ std::transform(outputIndexes.begin(), outputIndexes.end(), outputRoles.begin(), trans);
+
+ sp<IBuffer> buffer;
+ uint32_t token = 0;
+ const auto ret = kDevice->allocate(
+ {.dimensions = dimensions}, {preparedModel}, std::move(inputRoles),
+ std::move(outputRoles),
+ [&buffer, &token](ErrorStatus err, const sp<IBuffer>& buf, uint32_t tok) {
+ if (err == ErrorStatus::NONE) {
+ EXPECT_NE(buf, nullptr);
+ EXPECT_GT(tok, 0);
+ buffer = buf;
+ token = tok;
+ } else {
+ EXPECT_EQ(err, ErrorStatus::GENERAL_FAILURE);
+ EXPECT_EQ(buf, nullptr);
+ EXPECT_EQ(tok, 0);
+ }
+ });
+ EXPECT_TRUE(ret.isOk());
+ return {std::move(buffer), token};
+ }
+
+ std::pair<sp<IBuffer>, uint32_t> allocateBuffer(const sp<IPreparedModel>& preparedModel,
+ const std::vector<uint32_t>& inputIndexes,
+ const std::vector<uint32_t>& outputIndexes) {
+ return allocateBuffer(preparedModel, inputIndexes, outputIndexes, {});
+ }
+
+ hidl_memory allocateSharedMemory(uint32_t size) {
+ hidl_memory memory = nn::allocateSharedMemory(size);
+ EXPECT_EQ(memory.size(), size);
+ return memory;
+ }
+
+ void testCopyFrom(const sp<IBuffer>& buffer, const hidl_memory& memory,
+ const std::vector<uint32_t>& dimensions, ErrorStatus expectedStatus) {
+ const auto ret = buffer->copyFrom(memory, dimensions);
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(static_cast<ErrorStatus>(ret), expectedStatus);
+ }
+
+ void testCopyTo(const sp<IBuffer>& buffer, const hidl_memory& memory,
+ ErrorStatus expectedStatus) {
+ const auto ret = buffer->copyTo(memory);
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(static_cast<ErrorStatus>(ret), expectedStatus);
+ }
+
+ void initializeDeviceMemory(const sp<IBuffer>& buffer) {
+ hidl_memory memory = nn::allocateSharedMemory(kTestOperandDataSize);
+ ASSERT_EQ(memory.size(), kTestOperandDataSize);
+ testCopyFrom(buffer, memory, kTestOperand.dimensions, ErrorStatus::NONE);
+ }
+};
+
+using MemoryDomainCopyTestParam = std::tuple<NamedDevice, TestOperandType>;
+class MemoryDomainCopyTest : public MemoryDomainCopyTestBase,
+ public testing::WithParamInterface<MemoryDomainCopyTestParam> {
+ protected:
+ MemoryDomainCopyTest()
+ : MemoryDomainCopyTestBase(getData(std::get<NamedDevice>(GetParam())),
+ std::get<TestOperandType>(GetParam())) {}
+};
+
+TEST_P(MemoryDomainCopyTest, CopyFrom_InvalidMemorySize) {
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+ if (buffer == nullptr) return;
+
+ uint32_t badMemorySize1 = kTestOperandDataSize / 2, badMemorySize2 = kTestOperandDataSize * 2;
+ hidl_memory badMemory1 = allocateSharedMemory(badMemorySize1);
+ hidl_memory badMemory2 = allocateSharedMemory(badMemorySize2);
+ testCopyFrom(buffer, badMemory1, {}, ErrorStatus::INVALID_ARGUMENT);
+ testCopyFrom(buffer, badMemory2, {}, ErrorStatus::INVALID_ARGUMENT);
+}
+
+TEST_P(MemoryDomainCopyTest, CopyFrom_InvalidMemorySize_DynamicShape) {
+ TestOperand testOperand = kTestOperand;
+ testOperand.dimensions[0] = 0;
+ auto preparedModel = createConvPreparedModel(testOperand);
+ auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+ if (buffer == nullptr) return;
+
+ uint32_t badMemorySize1 = kTestOperandDataSize / 2, badMemorySize2 = kTestOperandDataSize * 2;
+ hidl_memory badMemory1 = allocateSharedMemory(badMemorySize1);
+ hidl_memory badMemory2 = allocateSharedMemory(badMemorySize2);
+ hidl_memory goodMemory = allocateSharedMemory(kTestOperandDataSize);
+
+ auto badDimensions = kTestOperand.dimensions;
+ badDimensions[0] = 2;
+
+ testCopyFrom(buffer, badMemory1, kTestOperand.dimensions, ErrorStatus::INVALID_ARGUMENT);
+ testCopyFrom(buffer, badMemory2, kTestOperand.dimensions, ErrorStatus::INVALID_ARGUMENT);
+ testCopyFrom(buffer, goodMemory, kTestOperand.dimensions, ErrorStatus::NONE);
+ testCopyFrom(buffer, goodMemory, badDimensions, ErrorStatus::INVALID_ARGUMENT);
+}
+
+TEST_P(MemoryDomainCopyTest, CopyFrom_InvalidDimensions) {
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+ if (buffer == nullptr) return;
+
+ hidl_memory memory = allocateSharedMemory(kTestOperandDataSize);
+
+ std::vector<uint32_t> badDimensions;
+ badDimensions = kTestOperand.dimensions;
+ badDimensions.pop_back();
+ testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT);
+
+ badDimensions = kTestOperand.dimensions;
+ badDimensions[0] = 2;
+ testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT);
+
+ badDimensions = kTestOperand.dimensions;
+ badDimensions[0] = 0;
+ testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT);
+
+ testCopyFrom(buffer, memory, {}, ErrorStatus::NONE);
+ testCopyFrom(buffer, memory, kTestOperand.dimensions, ErrorStatus::NONE);
+}
+
+TEST_P(MemoryDomainCopyTest, CopyFrom_InvalidDimensions_DynamicShape) {
+ TestOperand testOperand = kTestOperand;
+ testOperand.dimensions[0] = 0;
+ auto preparedModel = createConvPreparedModel(testOperand);
+ auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+ if (buffer == nullptr) return;
+
+ hidl_memory memory = allocateSharedMemory(kTestOperandDataSize);
+
+ std::vector<uint32_t> badDimensions;
+ badDimensions = kTestOperand.dimensions;
+ badDimensions.pop_back();
+ testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT);
+
+ badDimensions = kTestOperand.dimensions;
+ badDimensions[0] = 2;
+ badDimensions[3] = 4;
+ testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT);
+
+ badDimensions = kTestOperand.dimensions;
+ badDimensions[0] = 1;
+ badDimensions[3] = 0;
+ testCopyFrom(buffer, memory, badDimensions, ErrorStatus::INVALID_ARGUMENT);
+
+ testCopyFrom(buffer, memory, {}, ErrorStatus::INVALID_ARGUMENT);
+ testCopyFrom(buffer, memory, kTestOperand.dimensions, ErrorStatus::NONE);
+}
+
+TEST_P(MemoryDomainCopyTest, CopyTo_UninitializedMemory) {
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+ if (buffer == nullptr) return;
+
+ hidl_memory memory = allocateSharedMemory(kTestOperandDataSize);
+ testCopyTo(buffer, memory, ErrorStatus::GENERAL_FAILURE);
+}
+
+TEST_P(MemoryDomainCopyTest, CopyTo_InvalidMemorySize) {
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+ if (buffer == nullptr) return;
+
+ uint32_t badMemorySize1 = kTestOperandDataSize / 2, badMemorySize2 = kTestOperandDataSize * 2;
+ hidl_memory badMemory1 = allocateSharedMemory(badMemorySize1);
+ hidl_memory badMemory2 = allocateSharedMemory(badMemorySize2);
+ hidl_memory goodMemory = allocateSharedMemory(kTestOperandDataSize);
+
+ initializeDeviceMemory(buffer);
+ testCopyTo(buffer, badMemory1, ErrorStatus::INVALID_ARGUMENT);
+ testCopyTo(buffer, badMemory2, ErrorStatus::INVALID_ARGUMENT);
+ testCopyTo(buffer, goodMemory, ErrorStatus::NONE);
+}
+
+TEST_P(MemoryDomainCopyTest, CopyTo_InvalidMemorySize_DynamicShape) {
+ TestOperand testOperand = kTestOperand;
+ testOperand.dimensions[0] = 0;
+ auto preparedModel = createConvPreparedModel(testOperand);
+ auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+ if (buffer == nullptr) return;
+
+ uint32_t badMemorySize1 = kTestOperandDataSize / 2, badMemorySize2 = kTestOperandDataSize * 2;
+ hidl_memory badMemory1 = allocateSharedMemory(badMemorySize1);
+ hidl_memory badMemory2 = allocateSharedMemory(badMemorySize2);
+ hidl_memory goodMemory = allocateSharedMemory(kTestOperandDataSize);
+
+ initializeDeviceMemory(buffer);
+ testCopyTo(buffer, badMemory1, ErrorStatus::INVALID_ARGUMENT);
+ testCopyTo(buffer, badMemory2, ErrorStatus::INVALID_ARGUMENT);
+ testCopyTo(buffer, goodMemory, ErrorStatus::NONE);
+}
+
+std::string printMemoryDomainCopyTest(
+ const testing::TestParamInfo<MemoryDomainCopyTestParam>& info) {
+ const auto& [namedDevice, operandType] = info.param;
+ const std::string type = toString(static_cast<OperandType>(operandType));
+ return gtestCompliantName(getName(namedDevice) + "_" + type);
+}
+
+INSTANTIATE_TEST_CASE_P(TestMemoryDomain, MemoryDomainCopyTest,
+ testing::Combine(kNamedDeviceChoices, kTestOperandTypeChoices),
+ printMemoryDomainCopyTest);
+
+using MemoryDomainExecutionTestParam = std::tuple<NamedDevice, TestOperandType, Executor>;
+class MemoryDomainExecutionTest
+ : public MemoryDomainCopyTestBase,
+ public testing::WithParamInterface<MemoryDomainExecutionTestParam> {
+ protected:
+ MemoryDomainExecutionTest()
+ : MemoryDomainCopyTestBase(getData(std::get<NamedDevice>(GetParam())),
+ std::get<TestOperandType>(GetParam())) {}
+
+ Request::MemoryPool createSharedMemoryPool(uint32_t size) {
+ hidl_memory memory = allocateSharedMemory(size);
+ Request::MemoryPool pool;
+ pool.hidlMemory(memory);
+ return pool;
+ }
+
+ Request::MemoryPool createDeviceMemoryPool(uint32_t token) {
+ Request::MemoryPool pool;
+ pool.token(token);
+ return pool;
+ }
+
+ void testExecution(const sp<IPreparedModel>& preparedModel, const Request& request,
+ ErrorStatus expectedStatus) {
+ switch (kExecutor) {
+ case Executor::ASYNC:
+ EXPECT_EQ(executeAsync(preparedModel, request), expectedStatus);
+ break;
+ case Executor::SYNC:
+ EXPECT_EQ(executeSync(preparedModel, request), expectedStatus);
+ break;
+ case Executor::FENCED:
+ EXPECT_EQ(executeFenced(preparedModel, request), expectedStatus);
+ break;
+ default:
+ ASSERT_TRUE(false);
+ }
+ }
+
+ ErrorStatus executeAsync(const sp<IPreparedModel>& preparedModel, const Request& request) {
+ ErrorStatus executionStatus;
+
+ // launch execution
+ sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+ const auto ret =
+ preparedModel->execute_1_3(request, MeasureTiming::NO, {}, {}, executionCallback);
+ EXPECT_TRUE(ret.isOk());
+ executionStatus = static_cast<ErrorStatus>(ret);
+
+ // retrieve execution status
+ executionCallback->wait();
+ if (executionStatus == ErrorStatus::NONE) {
+ executionStatus = executionCallback->getStatus();
+ } else {
+ EXPECT_EQ(executionStatus, executionCallback->getStatus());
+ }
+ const auto timing = executionCallback->getTiming();
+ EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
+ EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
+ if (executionStatus != ErrorStatus::NONE) {
+ EXPECT_EQ(executionCallback->getOutputShapes().size(), 0);
+ }
+ return executionStatus;
+ }
+
+ ErrorStatus executeSync(const sp<IPreparedModel>& preparedModel, const Request& request) {
+ ErrorStatus executionStatus;
+ const auto ret = preparedModel->executeSynchronously_1_3(
+ request, MeasureTiming::NO, {}, {},
+ [&executionStatus](ErrorStatus error, const hidl_vec<OutputShape>& shapes,
+ const Timing& time) {
+ executionStatus = error;
+ EXPECT_EQ(UINT64_MAX, time.timeOnDevice);
+ EXPECT_EQ(UINT64_MAX, time.timeInDriver);
+ if (executionStatus != ErrorStatus::NONE) {
+ EXPECT_EQ(shapes.size(), 0);
+ }
+ });
+ EXPECT_TRUE(ret.isOk());
+ return executionStatus;
+ }
+
+ ErrorStatus executeFenced(const sp<IPreparedModel>& preparedModel, const Request& request) {
+ ErrorStatus executionStatus;
+ hidl_handle syncFenceHandle;
+ sp<IFencedExecutionCallback> fencedCallback;
+ const auto callbackFunc = [&executionStatus, &syncFenceHandle, &fencedCallback](
+ ErrorStatus error, const hidl_handle& handle,
+ const sp<IFencedExecutionCallback>& callback) {
+ executionStatus = error;
+ syncFenceHandle = handle;
+ fencedCallback = callback;
+ };
+ Return<void> ret = preparedModel->executeFenced(request, {}, MeasureTiming::NO, {}, {}, {},
+ callbackFunc);
+ EXPECT_TRUE(ret.isOk());
+ if (executionStatus != ErrorStatus::NONE) {
+ EXPECT_EQ(syncFenceHandle.getNativeHandle(), nullptr);
+ EXPECT_EQ(fencedCallback, nullptr);
+ return executionStatus;
+ }
+ if (syncFenceHandle.getNativeHandle()) {
+ waitForSyncFence(syncFenceHandle.getNativeHandle()->data[0]);
+ }
+ EXPECT_NE(fencedCallback, nullptr);
+ ret = fencedCallback->getExecutionInfo(
+ [&executionStatus](ErrorStatus error, Timing t, Timing) {
+ executionStatus = error;
+ EXPECT_EQ(UINT64_MAX, t.timeOnDevice);
+ EXPECT_EQ(UINT64_MAX, t.timeInDriver);
+ });
+ EXPECT_TRUE(ret.isOk());
+ return executionStatus;
+ }
+
+ const Executor kExecutor = std::get<Executor>(GetParam());
+};
+
+TEST_P(MemoryDomainExecutionTest, InvalidToken) {
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ if (preparedModel == nullptr) return;
+
+ Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize);
+ Request::MemoryPool badDeviceMemory1 = createDeviceMemoryPool(0); // Invalid token.
+ Request::MemoryPool badDeviceMemory2 = createDeviceMemoryPool(100); // Unknown token.
+ RequestArgument sharedMemoryArg = {
+ .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}};
+ RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}};
+
+ testExecution(preparedModel,
+ {.inputs = {deviceMemoryArg},
+ .outputs = {sharedMemoryArg},
+ .pools = {sharedMemory, badDeviceMemory1}},
+ ErrorStatus::INVALID_ARGUMENT);
+ testExecution(preparedModel,
+ {.inputs = {deviceMemoryArg},
+ .outputs = {sharedMemoryArg},
+ .pools = {sharedMemory, badDeviceMemory2}},
+ ErrorStatus::INVALID_ARGUMENT);
+ testExecution(preparedModel,
+ {.inputs = {sharedMemoryArg},
+ .outputs = {deviceMemoryArg},
+ .pools = {sharedMemory, badDeviceMemory1}},
+ ErrorStatus::INVALID_ARGUMENT);
+ testExecution(preparedModel,
+ {.inputs = {sharedMemoryArg},
+ .outputs = {deviceMemoryArg},
+ .pools = {sharedMemory, badDeviceMemory2}},
+ ErrorStatus::INVALID_ARGUMENT);
+}
+
+TEST_P(MemoryDomainExecutionTest, InvalidPreparedModel) {
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+ if (buffer == nullptr) return;
+ auto badPreparedModel = createConvPreparedModel(kTestOperand);
+ if (badPreparedModel == nullptr) return;
+
+ Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize);
+ Request::MemoryPool deviceMemory = createDeviceMemoryPool(token);
+ RequestArgument sharedMemoryArg = {
+ .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}};
+ RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}};
+
+ // This should fail, because the buffer is not allocated for badPreparedModel.
+ initializeDeviceMemory(buffer);
+ testExecution(badPreparedModel,
+ {.inputs = {deviceMemoryArg},
+ .outputs = {sharedMemoryArg},
+ .pools = {sharedMemory, deviceMemory}},
+ ErrorStatus::INVALID_ARGUMENT);
+ testExecution(badPreparedModel,
+ {.inputs = {sharedMemoryArg},
+ .outputs = {deviceMemoryArg},
+ .pools = {sharedMemory, deviceMemory}},
+ ErrorStatus::INVALID_ARGUMENT);
+}
+
+TEST_P(MemoryDomainExecutionTest, InvalidIOIndex) {
+ auto preparedModel = createConvPreparedModel(kTestOperand, 2);
+ auto [buffer, token] = allocateBuffer(preparedModel, {0}, {});
+ if (buffer == nullptr) return;
+
+ Request::MemoryPool sharedMemory1 = createSharedMemoryPool(kTestOperandDataSize);
+ Request::MemoryPool sharedMemory2 = createSharedMemoryPool(kTestOperandDataSize);
+ Request::MemoryPool sharedMemory3 = createSharedMemoryPool(kTestOperandDataSize);
+ Request::MemoryPool deviceMemory = createDeviceMemoryPool(token);
+ RequestArgument sharedMemoryArg1 = {
+ .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}};
+ RequestArgument sharedMemoryArg2 = {
+ .location = {.poolIndex = 1, .offset = 0, .length = kTestOperandDataSize}};
+ RequestArgument sharedMemoryArg3 = {
+ .location = {.poolIndex = 2, .offset = 0, .length = kTestOperandDataSize}};
+ RequestArgument deviceMemoryArg = {.location = {.poolIndex = 3}};
+
+ // This should fail, because the device memory is not allocated for input 1.
+ initializeDeviceMemory(buffer);
+ testExecution(preparedModel,
+ {.inputs = {sharedMemoryArg1, deviceMemoryArg},
+ .outputs = {sharedMemoryArg2, sharedMemoryArg3},
+ .pools = {sharedMemory1, sharedMemory2, sharedMemory3, deviceMemory}},
+ ErrorStatus::INVALID_ARGUMENT);
+
+ // This should fail, because the device memory is not allocated for output 1.
+ testExecution(preparedModel,
+ {.inputs = {sharedMemoryArg1, sharedMemoryArg2},
+ .outputs = {sharedMemoryArg3, deviceMemoryArg},
+ .pools = {sharedMemory1, sharedMemory2, sharedMemory3, deviceMemory}},
+ ErrorStatus::INVALID_ARGUMENT);
+}
+
+TEST_P(MemoryDomainExecutionTest, InvalidIOType) {
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ auto [inputBuffer, inputToken] = allocateBuffer(preparedModel, {0}, {});
+ auto [outputBuffer, outputToken] = allocateBuffer(preparedModel, {}, {0});
+ if (inputBuffer == nullptr || outputBuffer == nullptr) return;
+
+ Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize);
+ Request::MemoryPool deviceMemory = createDeviceMemoryPool(inputToken);
+ RequestArgument sharedMemoryArg = {
+ .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}};
+ RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}};
+
+ // This should fail, because the device memory is allocated for input but used as output.
+ testExecution(preparedModel,
+ {.inputs = {sharedMemoryArg},
+ .outputs = {deviceMemoryArg},
+ .pools = {sharedMemory, deviceMemory}},
+ ErrorStatus::INVALID_ARGUMENT);
+
+ // This should fail, because the device memory is allocated for output but used as input.
+ deviceMemory.token(outputToken);
+ initializeDeviceMemory(outputBuffer);
+ testExecution(preparedModel,
+ {.inputs = {deviceMemoryArg},
+ .outputs = {sharedMemoryArg},
+ .pools = {sharedMemory, deviceMemory}},
+ ErrorStatus::INVALID_ARGUMENT);
+}
+
+TEST_P(MemoryDomainExecutionTest, UninitializedMemory) {
+ auto preparedModel = createConvPreparedModel(kTestOperand);
+ auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0});
+ if (buffer == nullptr) return;
+
+ Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize);
+ Request::MemoryPool deviceMemory = createDeviceMemoryPool(token);
+ RequestArgument sharedMemoryArg = {
+ .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}};
+ RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}};
+
+ // This should fail, because the device memory is not initialized.
+ testExecution(preparedModel,
+ {.inputs = {deviceMemoryArg},
+ .outputs = {sharedMemoryArg},
+ .pools = {sharedMemory, deviceMemory}},
+ ErrorStatus::GENERAL_FAILURE);
+
+ // This should initialize the device memory.
+ testExecution(preparedModel,
+ {.inputs = {sharedMemoryArg},
+ .outputs = {deviceMemoryArg},
+ .pools = {sharedMemory, deviceMemory}},
+ ErrorStatus::NONE);
+
+ // Test again with initialized device memory.
+ testExecution(preparedModel,
+ {.inputs = {deviceMemoryArg},
+ .outputs = {sharedMemoryArg},
+ .pools = {sharedMemory, deviceMemory}},
+ ErrorStatus::NONE);
+}
+
+TEST_P(MemoryDomainExecutionTest, SameRequestMultipleRoles) {
+ auto preparedModel = createConvPreparedModel(kTestOperand, 2);
+ auto [buffer, token] = allocateBuffer(preparedModel, {0, 1}, {0, 1});
+ if (buffer == nullptr) return;
+
+ Request::MemoryPool sharedMemory1 = createSharedMemoryPool(kTestOperandDataSize);
+ Request::MemoryPool sharedMemory2 = createSharedMemoryPool(kTestOperandDataSize);
+ Request::MemoryPool deviceMemory = createDeviceMemoryPool(token);
+ RequestArgument sharedMemoryArg1 = {
+ .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize}};
+ RequestArgument sharedMemoryArg2 = {
+ .location = {.poolIndex = 1, .offset = 0, .length = kTestOperandDataSize}};
+ RequestArgument deviceMemoryArg = {.location = {.poolIndex = 2}};
+
+ // This should fail, because the same device memory cannot be used for both input and output.
+ initializeDeviceMemory(buffer);
+ testExecution(preparedModel,
+ {.inputs = {deviceMemoryArg, sharedMemoryArg1},
+ .outputs = {deviceMemoryArg, sharedMemoryArg2},
+ .pools = {sharedMemory1, sharedMemory2, deviceMemory}},
+ ErrorStatus::INVALID_ARGUMENT);
+
+ // This should fail, because the same device memory cannot be used for multiple outputs.
+ testExecution(preparedModel,
+ {.inputs = {sharedMemoryArg1, sharedMemoryArg2},
+ .outputs = {deviceMemoryArg, deviceMemoryArg},
+ .pools = {sharedMemory1, sharedMemory2, deviceMemory}},
+ ErrorStatus::INVALID_ARGUMENT);
+
+ // The same device memory can be used for multiple inputs.
+ initializeDeviceMemory(buffer);
+ testExecution(preparedModel,
+ {.inputs = {deviceMemoryArg, deviceMemoryArg},
+ .outputs = {sharedMemoryArg1, sharedMemoryArg2},
+ .pools = {sharedMemory1, sharedMemory2, deviceMemory}},
+ ErrorStatus::NONE);
+}
+
+TEST_P(MemoryDomainExecutionTest, InvalidDimensions) {
+ // FENCED execution does not support dynamic shape.
+ if (kExecutor == Executor::FENCED) return;
+
+ TestOperand testOperand = kTestOperand;
+ testOperand.dimensions[0] = 0;
+ auto preparedModel = createConvPreparedModel(testOperand);
+ auto [buffer, token] = allocateBuffer(preparedModel, {0}, {0}, kTestOperand.dimensions);
+ if (buffer == nullptr) return;
+
+ Request::MemoryPool sharedMemory = createSharedMemoryPool(kTestOperandDataSize);
+ Request::MemoryPool deviceMemory = createDeviceMemoryPool(token);
+ auto badDimensions = kTestOperand.dimensions;
+ badDimensions[0] = 2;
+ RequestArgument sharedMemoryArg = {
+ .location = {.poolIndex = 0, .offset = 0, .length = kTestOperandDataSize},
+ .dimensions = badDimensions};
+ RequestArgument deviceMemoryArg = {.location = {.poolIndex = 1}};
+ RequestArgument deviceMemoryArgWithBadDimensions = {.location = {.poolIndex = 1},
+ .dimensions = badDimensions};
+
+ initializeDeviceMemory(buffer);
+ testExecution(preparedModel,
+ {.inputs = {deviceMemoryArgWithBadDimensions},
+ .outputs = {sharedMemoryArg},
+ .pools = {sharedMemory, deviceMemory}},
+ ErrorStatus::INVALID_ARGUMENT);
+
+ testExecution(preparedModel,
+ {.inputs = {sharedMemoryArg},
+ .outputs = {deviceMemoryArgWithBadDimensions},
+ .pools = {sharedMemory, deviceMemory}},
+ ErrorStatus::INVALID_ARGUMENT);
+
+ testExecution(preparedModel,
+ {.inputs = {sharedMemoryArg},
+ .outputs = {deviceMemoryArg},
+ .pools = {sharedMemory, deviceMemory}},
+ ErrorStatus::GENERAL_FAILURE);
+}
+
+const auto kExecutorChoices = testing::Values(Executor::ASYNC, Executor::SYNC, Executor::FENCED);
+
+std::string printMemoryDomainExecutionTest(
+ const testing::TestParamInfo<MemoryDomainExecutionTestParam>& info) {
+ const auto& [namedDevice, operandType, executor] = info.param;
+ const std::string type = toString(static_cast<OperandType>(operandType));
+ const std::string executorStr = toString(executor);
+ return gtestCompliantName(getName(namedDevice) + "_" + type + "_" + executorStr);
+}
+
+INSTANTIATE_TEST_CASE_P(TestMemoryDomain, MemoryDomainExecutionTest,
+ testing::Combine(kNamedDeviceChoices, kTestOperandTypeChoices,
+ kExecutorChoices),
+ printMemoryDomainExecutionTest);
+
+} // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
index 879989e..2ef1e8f 100644
--- a/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/QualityOfServiceTests.cpp
@@ -214,7 +214,8 @@
}
void runExecutionTest(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
- const Request& request, bool synchronous, DeadlineBoundType deadlineBound) {
+ const Request& request, const ExecutionContext& context, bool synchronous,
+ DeadlineBoundType deadlineBound) {
const ExecutionFunction execute = synchronous ? executeSynchronously : executeAsynchronously;
const auto deadline = makeDeadline(deadlineBound);
@@ -261,7 +262,7 @@
// Retrieve execution results.
ASSERT_TRUE(nn::compliantWithV1_0(request));
const V1_0::Request request10 = nn::convertToV1_0(request);
- const std::vector<TestBuffer> outputs = getOutputBuffers(request10);
+ const std::vector<TestBuffer> outputs = context.getOutputBuffers(request10);
// We want "close-enough" results.
if (status == ErrorStatus::NONE) {
@@ -270,10 +271,11 @@
}
void runExecutionTests(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
- const Request& request) {
+ const Request& request, const ExecutionContext& context) {
for (bool synchronous : {false, true}) {
for (auto deadlineBound : deadlineBounds) {
- runExecutionTest(preparedModel, testModel, request, synchronous, deadlineBound);
+ runExecutionTest(preparedModel, testModel, request, context, synchronous,
+ deadlineBound);
}
}
}
@@ -291,8 +293,9 @@
if (preparedModel == nullptr) return;
// run execution tests
- const Request request = nn::convertToV1_3(createRequest(testModel));
- runExecutionTests(preparedModel, testModel, request);
+ ExecutionContext context;
+ const Request request = nn::convertToV1_3(context.createRequest(testModel));
+ runExecutionTests(preparedModel, testModel, request, context);
}
class DeadlineTest : public GeneratedTestBase {};
diff --git a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp
index 6ff9dfd..c78439c 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp
@@ -23,7 +23,6 @@
#include "ExecutionBurstServer.h"
#include "GeneratedTestHarness.h"
#include "TestHarness.h"
-#include "Utils.h"
#include <android-base/logging.h>
#include <chrono>
@@ -43,6 +42,8 @@
using V1_2::Timing;
using ExecutionBurstCallback = ExecutionBurstController::ExecutionBurstCallback;
+using BurstExecutionMutation = std::function<void(std::vector<FmqRequestDatum>*)>;
+
// This constant value represents the length of an FMQ that is large enough to
// return a result from a burst execution for all of the generated test cases.
constexpr size_t kExecutionBurstChannelLength = 1024;
@@ -122,13 +123,13 @@
// Primary validation function. This function will take a valid serialized
// request, apply a mutation to it to invalidate the serialized request, then
-// pass it to interface calls that use the serialized request. Note that the
-// serialized request here is passed by value, and any mutation to the
-// serialized request does not leave this function.
+// pass it to interface calls that use the serialized request.
static void validate(RequestChannelSender* sender, ResultChannelReceiver* receiver,
- const std::string& message, std::vector<FmqRequestDatum> serialized,
- const std::function<void(std::vector<FmqRequestDatum>*)>& mutation) {
- mutation(&serialized);
+ const std::string& message,
+ const std::vector<FmqRequestDatum>& originalSerialized,
+ const BurstExecutionMutation& mutate) {
+ std::vector<FmqRequestDatum> serialized = originalSerialized;
+ mutate(&serialized);
// skip if packet is too large to send
if (serialized.size() > kExecutionBurstChannelLength) {
@@ -302,8 +303,7 @@
// collect serialized result by running regular burst
const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] =
controllerRegular->compute(request, MeasureTiming::NO, keys);
- const V1_0::ErrorStatus statusRegular =
- nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nRegular));
+ const V1_0::ErrorStatus statusRegular = nn::legacyConvertResultCodeToErrorStatus(nRegular);
EXPECT_FALSE(fallbackRegular);
// skip test if regular burst output isn't useful for testing a failure
@@ -319,8 +319,7 @@
// large enough to return the serialized result
const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] =
controllerSmall->compute(request, MeasureTiming::NO, keys);
- const V1_0::ErrorStatus statusSmall =
- nn::convertToV1_0(nn::convertResultCodeToErrorStatus(nSmall));
+ const V1_0::ErrorStatus statusSmall = nn::legacyConvertResultCodeToErrorStatus(nSmall);
EXPECT_NE(V1_0::ErrorStatus::NONE, statusSmall);
EXPECT_EQ(0u, outputShapesSmall.size());
EXPECT_TRUE(badTiming(timingSmall));
diff --git a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
index 7da2da9..4c0100e 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateModel.cpp
@@ -30,6 +30,8 @@
using HidlToken =
hidl_array<uint8_t, static_cast<uint32_t>(V1_2::Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
+using PrepareModelMutation = std::function<void(Model*, ExecutionPreference*, Priority*)>;
+
///////////////////////// UTILITY FUNCTIONS /////////////////////////
static void validateGetSupportedOperations(const sp<IDevice>& device, const std::string& message,
@@ -44,13 +46,14 @@
}
static void validatePrepareModel(const sp<IDevice>& device, const std::string& message,
- const Model& model, ExecutionPreference preference) {
+ const Model& model, ExecutionPreference preference,
+ Priority priority) {
SCOPED_TRACE(message + " [prepareModel_1_3]");
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
- Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_3(
- model, preference, kDefaultPriority, {}, hidl_vec<hidl_handle>(),
- hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
+ Return<ErrorStatus> prepareLaunchStatus =
+ device->prepareModel_1_3(model, preference, priority, {}, hidl_vec<hidl_handle>(),
+ hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk());
ASSERT_EQ(ErrorStatus::INVALID_ARGUMENT, static_cast<ErrorStatus>(prepareLaunchStatus));
@@ -67,18 +70,26 @@
preference == ExecutionPreference::SUSTAINED_SPEED;
}
+static bool validExecutionPriority(Priority priority) {
+ return priority == Priority::LOW || priority == Priority::MEDIUM || priority == Priority::HIGH;
+}
+
// Primary validation function. This function will take a valid model, apply a
-// mutation to it to invalidate the model, then pass it to interface calls that
-// use the model. Note that the model here is passed by value, and any mutation
-// to the model does not leave this function.
-static void validate(const sp<IDevice>& device, const std::string& message, Model model,
- const std::function<void(Model*)>& mutation,
- ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER) {
- mutation(&model);
- if (validExecutionPreference(preference)) {
+// mutation to invalidate the model, the execution preference, or the priority,
+// then pass these to supportedOperations and/or prepareModel if that method is
+// called with an invalid argument.
+static void validate(const sp<IDevice>& device, const std::string& message,
+ const Model& originalModel, const PrepareModelMutation& mutate) {
+ Model model = originalModel;
+ ExecutionPreference preference = ExecutionPreference::FAST_SINGLE_ANSWER;
+ Priority priority = kDefaultPriority;
+ mutate(&model, &preference, &priority);
+
+ if (validExecutionPreference(preference) && validExecutionPriority(priority)) {
validateGetSupportedOperations(device, message, model);
}
- validatePrepareModel(device, message, model, preference);
+
+ validatePrepareModel(device, message, model, preference, priority);
}
static uint32_t addOperand(Model* model) {
@@ -116,9 +127,11 @@
const std::string message = "mutateOperandTypeTest: operand " +
std::to_string(operand) + " set to value " +
std::to_string(invalidOperandType);
- validate(device, message, model, [operand, invalidOperandType](Model* model) {
- model->main.operands[operand].type = static_cast<OperandType>(invalidOperandType);
- });
+ validate(device, message, model,
+ [operand, invalidOperandType](Model* model, ExecutionPreference*, Priority*) {
+ model->main.operands[operand].type =
+ static_cast<OperandType>(invalidOperandType);
+ });
}
}
}
@@ -156,9 +169,11 @@
}
const std::string message = "mutateOperandRankTest: operand " + std::to_string(operand) +
" has rank of " + std::to_string(invalidRank);
- validate(device, message, model, [operand, invalidRank](Model* model) {
- model->main.operands[operand].dimensions = std::vector<uint32_t>(invalidRank, 0);
- });
+ validate(device, message, model,
+ [operand, invalidRank](Model* model, ExecutionPreference*, Priority*) {
+ model->main.operands[operand].dimensions =
+ std::vector<uint32_t>(invalidRank, 0);
+ });
}
}
@@ -194,9 +209,10 @@
const float invalidScale = getInvalidScale(model.main.operands[operand].type);
const std::string message = "mutateOperandScaleTest: operand " + std::to_string(operand) +
" has scale of " + std::to_string(invalidScale);
- validate(device, message, model, [operand, invalidScale](Model* model) {
- model->main.operands[operand].scale = invalidScale;
- });
+ validate(device, message, model,
+ [operand, invalidScale](Model* model, ExecutionPreference*, Priority*) {
+ model->main.operands[operand].scale = invalidScale;
+ });
}
}
@@ -237,9 +253,10 @@
const std::string message = "mutateOperandZeroPointTest: operand " +
std::to_string(operand) + " has zero point of " +
std::to_string(invalidZeroPoint);
- validate(device, message, model, [operand, invalidZeroPoint](Model* model) {
- model->main.operands[operand].zeroPoint = invalidZeroPoint;
- });
+ validate(device, message, model,
+ [operand, invalidZeroPoint](Model* model, ExecutionPreference*, Priority*) {
+ model->main.operands[operand].zeroPoint = invalidZeroPoint;
+ });
}
}
}
@@ -425,9 +442,10 @@
const std::string message = "mutateOperationOperandTypeTest: operand " +
std::to_string(operand) + " set to type " +
toString(invalidOperandType);
- validate(device, message, model, [operand, invalidOperandType](Model* model) {
- mutateOperand(&model->main.operands[operand], invalidOperandType);
- });
+ validate(device, message, model,
+ [operand, invalidOperandType](Model* model, ExecutionPreference*, Priority*) {
+ mutateOperand(&model->main.operands[operand], invalidOperandType);
+ });
}
}
}
@@ -446,10 +464,12 @@
const std::string message = "mutateOperationTypeTest: operation " +
std::to_string(operation) + " set to value " +
std::to_string(invalidOperationType);
- validate(device, message, model, [operation, invalidOperationType](Model* model) {
- model->main.operations[operation].type =
- static_cast<OperationType>(invalidOperationType);
- });
+ validate(device, message, model,
+ [operation, invalidOperationType](Model* model, ExecutionPreference*,
+ Priority*) {
+ model->main.operations[operation].type =
+ static_cast<OperationType>(invalidOperationType);
+ });
}
}
}
@@ -463,9 +483,11 @@
const std::string message = "mutateOperationInputOperandIndexTest: operation " +
std::to_string(operation) + " input " +
std::to_string(input);
- validate(device, message, model, [operation, input, invalidOperand](Model* model) {
- model->main.operations[operation].inputs[input] = invalidOperand;
- });
+ validate(device, message, model,
+ [operation, input, invalidOperand](Model* model, ExecutionPreference*,
+ Priority*) {
+ model->main.operations[operation].inputs[input] = invalidOperand;
+ });
}
}
}
@@ -480,9 +502,11 @@
const std::string message = "mutateOperationOutputOperandIndexTest: operation " +
std::to_string(operation) + " output " +
std::to_string(output);
- validate(device, message, model, [operation, output, invalidOperand](Model* model) {
- model->main.operations[operation].outputs[output] = invalidOperand;
- });
+ validate(device, message, model,
+ [operation, output, invalidOperand](Model* model, ExecutionPreference*,
+ Priority*) {
+ model->main.operations[operation].outputs[output] = invalidOperand;
+ });
}
}
}
@@ -548,8 +572,9 @@
continue;
}
const std::string message = "removeOperandTest: operand " + std::to_string(operand);
- validate(device, message, model,
- [operand](Model* model) { removeOperand(model, operand); });
+ validate(device, message, model, [operand](Model* model, ExecutionPreference*, Priority*) {
+ removeOperand(model, operand);
+ });
}
}
@@ -566,7 +591,9 @@
for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
const std::string message = "removeOperationTest: operation " + std::to_string(operation);
validate(device, message, model,
- [operation](Model* model) { removeOperation(model, operation); });
+ [operation](Model* model, ExecutionPreference*, Priority*) {
+ removeOperation(model, operation);
+ });
}
}
@@ -654,11 +681,12 @@
const std::string message = "removeOperationInputTest: operation " +
std::to_string(operation) + ", input " +
std::to_string(input);
- validate(device, message, model, [operation, input](Model* model) {
- uint32_t operand = model->main.operations[operation].inputs[input];
- model->main.operands[operand].numberOfConsumers--;
- hidl_vec_removeAt(&model->main.operations[operation].inputs, input);
- });
+ validate(device, message, model,
+ [operation, input](Model* model, ExecutionPreference*, Priority*) {
+ uint32_t operand = model->main.operations[operation].inputs[input];
+ model->main.operands[operand].numberOfConsumers--;
+ hidl_vec_removeAt(&model->main.operations[operation].inputs, input);
+ });
}
}
}
@@ -672,9 +700,10 @@
const std::string message = "removeOperationOutputTest: operation " +
std::to_string(operation) + ", output " +
std::to_string(output);
- validate(device, message, model, [operation, output](Model* model) {
- hidl_vec_removeAt(&model->main.operations[operation].outputs, output);
- });
+ validate(device, message, model,
+ [operation, output](Model* model, ExecutionPreference*, Priority*) {
+ hidl_vec_removeAt(&model->main.operations[operation].outputs, output);
+ });
}
}
}
@@ -707,11 +736,12 @@
continue;
}
const std::string message = "addOperationInputTest: operation " + std::to_string(operation);
- validate(device, message, model, [operation](Model* model) {
- uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_INPUT);
- hidl_vec_push_back(&model->main.operations[operation].inputs, index);
- hidl_vec_push_back(&model->main.inputIndexes, index);
- });
+ validate(device, message, model,
+ [operation](Model* model, ExecutionPreference*, Priority*) {
+ uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_INPUT);
+ hidl_vec_push_back(&model->main.operations[operation].inputs, index);
+ hidl_vec_push_back(&model->main.inputIndexes, index);
+ });
}
}
@@ -721,11 +751,12 @@
for (size_t operation = 0; operation < model.main.operations.size(); ++operation) {
const std::string message =
"addOperationOutputTest: operation " + std::to_string(operation);
- validate(device, message, model, [operation](Model* model) {
- uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_OUTPUT);
- hidl_vec_push_back(&model->main.operations[operation].outputs, index);
- hidl_vec_push_back(&model->main.outputIndexes, index);
- });
+ validate(device, message, model,
+ [operation](Model* model, ExecutionPreference*, Priority*) {
+ uint32_t index = addOperand(model, OperandLifeTime::SUBGRAPH_OUTPUT);
+ hidl_vec_push_back(&model->main.operations[operation].outputs, index);
+ hidl_vec_push_back(&model->main.outputIndexes, index);
+ });
}
}
@@ -737,12 +768,31 @@
};
static void mutateExecutionPreferenceTest(const sp<IDevice>& device, const Model& model) {
- for (int32_t preference : invalidExecutionPreferences) {
+ for (int32_t invalidPreference : invalidExecutionPreferences) {
const std::string message =
- "mutateExecutionPreferenceTest: preference " + std::to_string(preference);
- validate(
- device, message, model, [](Model*) {},
- static_cast<ExecutionPreference>(preference));
+ "mutateExecutionPreferenceTest: preference " + std::to_string(invalidPreference);
+ validate(device, message, model,
+ [invalidPreference](Model*, ExecutionPreference* preference, Priority*) {
+ *preference = static_cast<ExecutionPreference>(invalidPreference);
+ });
+ }
+}
+
+///////////////////////// VALIDATE PRIORITY /////////////////////////
+
+static const int32_t invalidPriorities[] = {
+ static_cast<int32_t>(Priority::LOW) - 1, // lower bound
+ static_cast<int32_t>(Priority::HIGH) + 1, // upper bound
+};
+
+static void mutateExecutionPriorityTest(const sp<IDevice>& device, const Model& model) {
+ for (int32_t invalidPriority : invalidPriorities) {
+ const std::string message =
+ "mutatePriorityTest: priority " + std::to_string(invalidPriority);
+ validate(device, message, model,
+ [invalidPriority](Model*, ExecutionPreference*, Priority* priority) {
+ *priority = static_cast<Priority>(invalidPriority);
+ });
}
}
@@ -764,6 +814,7 @@
addOperationInputTest(device, model);
addOperationOutputTest(device, model);
mutateExecutionPreferenceTest(device, model);
+ mutateExecutionPriorityTest(device, model);
}
} // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
index 5e806e5..1ae8b3f 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
@@ -34,6 +34,8 @@
using V1_2::OutputShape;
using V1_2::Timing;
+using ExecutionMutation = std::function<void(Request*)>;
+
///////////////////////// UTILITY FUNCTIONS /////////////////////////
static bool badTiming(Timing timing) {
@@ -42,11 +44,11 @@
// Primary validation function. This function will take a valid request, apply a
// mutation to it to invalidate the request, then pass it to interface calls
-// that use the request. Note that the request here is passed by value, and any
-// mutation to the request does not leave this function.
+// that use the request.
static void validate(const sp<IPreparedModel>& preparedModel, const std::string& message,
- Request request, const std::function<void(Request*)>& mutation) {
- mutation(&request);
+ const Request& originalRequest, const ExecutionMutation& mutate) {
+ Request request = originalRequest;
+ mutate(&request);
// We'd like to test both with timing requested and without timing
// requested. Rather than running each test both ways, we'll decide whether
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
index 5b07034..df1e453 100644
--- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.cpp
@@ -177,7 +177,8 @@
TEST_P(ValidationTest, Test) {
const Model model = createModel(kTestModel);
- const Request request = nn::convertToV1_3(createRequest(kTestModel));
+ ExecutionContext context;
+ const Request request = nn::convertToV1_3(context.createRequest(kTestModel));
if (kTestModel.expectFailure) {
validateFailure(kDevice, model, request);
} else {
@@ -185,11 +186,31 @@
}
}
-INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
+INSTANTIATE_GENERATED_TEST(ValidationTest, [](const std::string& testName) {
+ // Skip validation for the "inputs_as_internal" and "all_tensors_as_inputs"
+ // generated tests.
+ return testName.find("inputs_as_internal") == std::string::npos &&
+ testName.find("all_tensors_as_inputs") == std::string::npos;
+});
sp<IPreparedModel> getPreparedModel_1_3(const sp<PreparedModelCallback>& callback) {
sp<V1_0::IPreparedModel> preparedModelV1_0 = callback->getPreparedModel();
return IPreparedModel::castFrom(preparedModelV1_0).withDefault(nullptr);
}
+std::string toString(Executor executor) {
+ switch (executor) {
+ case Executor::ASYNC:
+ return "ASYNC";
+ case Executor::SYNC:
+ return "SYNC";
+ case Executor::BURST:
+ return "BURST";
+ case Executor::FENCED:
+ return "FENCED";
+ default:
+ CHECK(false);
+ }
+}
+
} // namespace android::hardware::neuralnetworks::V1_3::vts::functional
diff --git a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
index 4e51052..de082c3 100644
--- a/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.3/vts/functional/VtsHalNeuralnetworks.h
@@ -52,6 +52,10 @@
// Utility function to get PreparedModel from callback and downcast to V1_2.
sp<IPreparedModel> getPreparedModel_1_3(const sp<implementation::PreparedModelCallback>& callback);
+enum class Executor { ASYNC, SYNC, BURST, FENCED };
+
+std::string toString(Executor executor);
+
} // namespace android::hardware::neuralnetworks::V1_3::vts::functional
#endif // ANDROID_HARDWARE_NEURALNETWORKS_V1_3_VTS_HAL_NEURALNETWORKS_H
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
index d04cb36..9b6cc96 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
+++ b/radio/1.0/vts/functional/radio_hidl_hal_misc.cpp
@@ -578,7 +578,7 @@
TEST_P(RadioHidlTest, nvResetConfig) {
serial = GetRandomSerialNumber();
- radio->nvResetConfig(serial, ResetNvType::ERASE);
+ radio->nvResetConfig(serial, ResetNvType::FACTORY_RESET);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp->rspInfo.type);
EXPECT_EQ(serial, radioRsp->rspInfo.serial);
diff --git a/radio/1.5/IRadioIndication.hal b/radio/1.5/IRadioIndication.hal
index c40b473..58e988f 100644
--- a/radio/1.5/IRadioIndication.hal
+++ b/radio/1.5/IRadioIndication.hal
@@ -95,4 +95,21 @@
* CellInfo.
*/
oneway networkScanResult_1_5(RadioIndicationType type, NetworkScanResult result);
+
+ /**
+ * Indicates data call contexts have changed.
+ *
+ * This indication is updated from IRadioIndication@1.4 to report the @1.5 version of
+ * SetupDataCallResult.
+ *
+ * @param type Type of radio indication
+ * @param dcList Array of SetupDataCallResult identical to that returned by
+ * IRadio.getDataCallList(). It is the complete list of current data contexts including
+ * new contexts that have been activated. A data call is only removed from this list
+ * when below conditions matched.
+ * 1. The framework sends a IRadio.deactivateDataCall().
+ * 2. The radio is powered off/on.
+ * 3. Unsolicited disconnect from either modem or network side.
+ */
+ oneway dataCallListChanged_1_5(RadioIndicationType type, vec<SetupDataCallResult> dcList);
};
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
index e87cad2..1380da3 100644
--- a/radio/1.5/IRadioResponse.hal
+++ b/radio/1.5/IRadioResponse.hal
@@ -20,6 +20,7 @@
import @1.0::SendSmsResult;
import @1.4::IRadioResponse;
import @1.5::BarringInfo;
+import @1.5::CardStatus;
import @1.5::CellIdentity;
import @1.5::CellInfo;
import @1.5::PersoSubstate;
@@ -120,6 +121,20 @@
/**
* @param info Response info struct containing response type, serial no. and error
+ * @param dcResponse List of SetupDataCallResult as defined in types.hal
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ * RadioError:NO_RESOURCES
+ * RadioError:REQUEST_NOT_SUPPORTED
+ * RadioError:SIM_ABSENT
+ */
+ oneway getDataCallListResponse_1_5(RadioResponseInfo info, vec<SetupDataCallResult> dcResponse);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
*
* Valid errors returned:
* RadioError:NONE
@@ -303,5 +318,18 @@
* RadioError:REQUEST_NOT_SUPPORTED
*/
oneway supplySimDepersonalizationResponse(RadioResponseInfo info,
- PersoSubstate persoType, int32_t remainingRetries);
+ PersoSubstate persoType, int32_t remainingRetries);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ * @param cardStatus ICC card status as defined by CardStatus in types.hal
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:INTERNAL_ERR
+ * RadioError:NO_RESOURCES
+ * RadioError:REQUEST_NOT_SUPPORTED
+ */
+ oneway getIccCardStatusResponse_1_5(RadioResponseInfo info, CardStatus cardStatus);
};
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index 4d3c2d5..248f56e 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -17,6 +17,7 @@
package android.hardware.radio@1.5;
import @1.0::ApnAuthType;
+import @1.0::AppStatus;
import @1.0::DataProfileId;
import @1.0::DataProfileInfoType;
import @1.0::GsmSignalStrength;
@@ -43,6 +44,7 @@
import @1.2::WcdmaSignalStrength;
import @1.4::AccessNetwork;
import @1.4::ApnTypes;
+import @1.4::CardStatus;
import @1.4::CellIdentityNr;
import @1.4::DataCallFailCause;
import @1.4::DataConnActiveStatus;
@@ -1021,16 +1023,54 @@
* 3GPP2 C.S0068-0.
*/
enum PersoSubstate : @1.0::PersoSubstate {
+ /**
+ * The device is personalized using the content of the Service Provider Name (SPN) in the SIM
+ * card.
+ */
SIM_SPN,
SIM_SPN_PUK,
- /** Equivalent Home PLMN */
+ /**
+ * Service Provider and Equivalent Home PLMN
+ * The device is personalized using both the content of the GID1 (equivalent to service provider
+ * personalization) and the content of the Equivalent Home PLMN (EHPLMN) in the SIM card.
+ * If the GID1 in the SIM is absent, then just the content of the Equivalent Home PLMN
+ * is matched.
+ */
SIM_SP_EHPLMN,
SIM_SP_EHPLMN_PUK,
+ /**
+ * Device is personalized using the first digits of the ICCID of the SIM card.
+ */
SIM_ICCID,
SIM_ICCID_PUK,
+ /**
+ * Device is personalized using the content of the IMPI in the ISIM.
+ */
SIM_IMPI,
SIM_IMPI_PUK,
- /** Network subset service provider */
+ /**
+ * Network Subset and Service Provider
+ * Device is personalized using both the content of GID1 (equivalent to service provider
+ * personalization) and the first digits of the IMSI (equivalent to network subset
+ * personalization).
+ */
SIM_NS_SP,
SIM_NS_SP_PUK,
};
+
+/** Extended from @1.0::AppStatus to update PersoSubstate to 1.5 version. */
+struct AppStatus {
+ @1.0::AppStatus base;
+
+ /** Applicable only if appState == SUBSCRIPTION_PERSO */
+ PersoSubstate persoSubstate;
+};
+
+
+/** Extended from @1.4::CardStatus to use 1.5 version of AppStatus. */
+struct CardStatus {
+ @1.4::CardStatus base;
+
+ /** size <= RadioConst::CARD_MAX_APPS */
+ vec<AppStatus> applications;
+};
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index 003f58e..32c02cb 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -408,7 +408,7 @@
*/
TEST_P(RadioHidlTest_v1_5, togglingUiccApplicationsSimAbsent) {
// This test case only test SIM ABSENT case.
- if (cardStatus.base.base.cardState != CardState::ABSENT) return;
+ if (cardStatus.base.base.base.cardState != CardState::ABSENT) return;
// Disable Uicc applications.
serial = GetRandomSerialNumber();
@@ -435,7 +435,7 @@
*/
TEST_P(RadioHidlTest_v1_5, togglingUiccApplicationsSimPresent) {
// This test case only test SIM ABSENT case.
- if (cardStatus.base.base.cardState != CardState::PRESENT) return;
+ if (cardStatus.base.base.base.cardState != CardState::PRESENT) return;
// Disable Uicc applications.
serial = GetRandomSerialNumber();
@@ -489,9 +489,9 @@
// If SIM is absent, RadioError::SIM_ABSENT should be thrown. Otherwise there shouldn't be any
// error.
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
EXPECT_EQ(RadioError::SIM_ABSENT, radioRsp_v1_5->rspInfo.error);
- } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
}
}
@@ -563,9 +563,9 @@
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
ALOGI("startNetworkScan, rspInfo.error = %s\n", toString(radioRsp_v1_5->rspInfo.error).c_str());
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error, {RadioError::SIM_ABSENT}));
- } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.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. Modems have "GSM" rat scan need to
@@ -592,10 +592,10 @@
ALOGI("startNetworkScan_InvalidArgument, rspInfo.error = %s\n",
toString(radioRsp_v1_5->rspInfo.error).c_str());
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
- } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_5->rspInfo.error,
{RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
@@ -631,10 +631,10 @@
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
ALOGI("startNetworkScan_InvalidInterval1, rspInfo.error = %s\n",
toString(radioRsp_v1_5->rspInfo.error).c_str());
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
- } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_5->rspInfo.error,
{RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
@@ -670,10 +670,10 @@
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
ALOGI("startNetworkScan_InvalidInterval2, rspInfo.error = %s\n",
toString(radioRsp_v1_5->rspInfo.error).c_str());
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
- } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_5->rspInfo.error,
{RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
@@ -709,10 +709,10 @@
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
ALOGI("startNetworkScan_InvalidMaxSearchTime1, rspInfo.error = %s\n",
toString(radioRsp_v1_5->rspInfo.error).c_str());
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
- } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_5->rspInfo.error,
{RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
@@ -748,10 +748,10 @@
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
ALOGI("startNetworkScan_InvalidMaxSearchTime2, rspInfo.error = %s\n",
toString(radioRsp_v1_5->rspInfo.error).c_str());
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
- } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_5->rspInfo.error,
{RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
@@ -787,10 +787,10 @@
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
ALOGI("startNetworkScan_InvalidPeriodicity1, rspInfo.error = %s\n",
toString(radioRsp_v1_5->rspInfo.error).c_str());
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
- } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_5->rspInfo.error,
{RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
@@ -826,10 +826,10 @@
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
ALOGI("startNetworkScan_InvalidPeriodicity2, rspInfo.error = %s\n",
toString(radioRsp_v1_5->rspInfo.error).c_str());
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
- } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_5->rspInfo.error,
{RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
@@ -865,10 +865,10 @@
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
ALOGI("startNetworkScan_GoodRequest1, rspInfo.error = %s\n",
toString(radioRsp_v1_5->rspInfo.error).c_str());
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::NONE, RadioError::SIM_ABSENT}));
- } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::NONE, RadioError::INVALID_ARGUMENTS,
RadioError::REQUEST_NOT_SUPPORTED}));
@@ -905,10 +905,10 @@
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
ALOGI("startNetworkScan_GoodRequest2, rspInfo.error = %s\n",
toString(radioRsp_v1_5->rspInfo.error).c_str());
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::NONE, RadioError::SIM_ABSENT}));
- } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::NONE, RadioError::INVALID_ARGUMENTS,
RadioError::REQUEST_NOT_SUPPORTED}));
@@ -961,11 +961,11 @@
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE,
RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
- } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
RadioError::OP_NOT_ALLOWED_BEFORE_REG_TO_NW}));
@@ -1006,10 +1006,10 @@
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE}));
- } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE}));
}
@@ -1053,10 +1053,10 @@
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::SIM_ABSENT, RadioError::RADIO_NOT_AVAILABLE}));
- } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE}));
}
@@ -1106,12 +1106,12 @@
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::NONE, RadioError::ILLEGAL_SIM_OR_ME,
RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE},
CHECK_GENERAL_ERROR));
- } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
+ } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
{RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE},
@@ -1155,7 +1155,7 @@
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
- if (cardStatus.base.base.cardState == CardState::ABSENT) {
+ if (cardStatus.base.base.base.cardState == CardState::ABSENT) {
ASSERT_TRUE(CheckAnyOfErrors(
radioRsp_v1_5->rspInfo.error,
{RadioError::INVALID_ARGUMENTS, RadioError::INVALID_STATE, RadioError::SIM_ABSENT},
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
index ca6bbeb..7313de4 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
@@ -41,7 +41,7 @@
ASSERT_NE(nullptr, radioConfig.get());
/* Enforce Vts Testing with Sim Status Present only. */
- EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.cardState);
+ EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.base.cardState);
}
/*
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
index 6488609..6a369cc 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -55,7 +55,7 @@
#define RADIO_SERVICE_NAME "slot1"
class RadioHidlTest_v1_5;
-extern ::android::hardware::radio::V1_4::CardStatus cardStatus;
+extern ::android::hardware::radio::V1_5::CardStatus cardStatus;
/* Callback class for radio response v1_5 */
class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioResponse {
@@ -556,6 +556,10 @@
const RadioResponseInfo& info,
const android::hardware::radio::V1_5::SetupDataCallResult& dcResponse);
+ Return<void> getDataCallListResponse_1_5(
+ const RadioResponseInfo& info,
+ const hidl_vec<::android::hardware::radio::V1_5::SetupDataCallResult>& dcResponse);
+
Return<void> setInitialAttachApnResponse_1_5(const RadioResponseInfo& info);
Return<void> setDataProfileResponse_1_5(const RadioResponseInfo& info);
@@ -591,6 +595,10 @@
Return<void> supplySimDepersonalizationResponse(
const RadioResponseInfo& info,
::android::hardware::radio::V1_5::PersoSubstate persoType, int32_t remainingRetries);
+
+ Return<void> getIccCardStatusResponse_1_5(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_5::CardStatus& card_status);
};
/* Callback class for radio indication */
@@ -614,6 +622,10 @@
const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::CellInfo>&
records);
+ Return<void> dataCallListChanged_1_5(
+ RadioIndicationType type,
+ const hidl_vec<::android::hardware::radio::V1_5::SetupDataCallResult>& dcList);
+
/* 1.4 Api */
Return<void> currentEmergencyNumberList(
RadioIndicationType type,
diff --git a/radio/1.5/vts/functional/radio_indication.cpp b/radio/1.5/vts/functional/radio_indication.cpp
index d448a22..1e5ce16 100644
--- a/radio/1.5/vts/functional/radio_indication.cpp
+++ b/radio/1.5/vts/functional/radio_indication.cpp
@@ -18,6 +18,46 @@
RadioIndication_v1_5::RadioIndication_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {}
+/* 1.5 Apis */
+Return<void> RadioIndication_v1_5::uiccApplicationsEnablementChanged(RadioIndicationType /*type*/,
+ bool /*enabled*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::registrationFailed(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/,
+ const hidl_string& /*chosenPlmn*/,
+ ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_5::Domain> /*domain*/,
+ int32_t /*causeCode*/, int32_t /*additionalCauseCode*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::barringInfoChanged(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/,
+ const hidl_vec<::android::hardware::radio::V1_5::BarringInfo>& /*barringInfos*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::networkScanResult_1_5(
+ RadioIndicationType /*type*/,
+ const ::android::hardware::radio::V1_5::NetworkScanResult& /*result*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::cellInfoList_1_5(
+ RadioIndicationType /*type*/,
+ const hidl_vec<::android::hardware::radio::V1_5::CellInfo>& /*records*/) {
+ return Void();
+}
+
+Return<void> RadioIndication_v1_5::dataCallListChanged_1_5(
+ RadioIndicationType /*type*/,
+ const hidl_vec<android::hardware::radio::V1_5::SetupDataCallResult>& /*dcList*/) {
+ return Void();
+}
+
/* 1.4 Apis */
Return<void> RadioIndication_v1_5::currentPhysicalChannelConfigs_1_4(
RadioIndicationType /*type*/,
@@ -328,38 +368,3 @@
const ::android::hardware::hidl_string& /*reason*/) {
return Void();
}
-
-Return<void> RadioIndication_v1_5::uiccApplicationsEnablementChanged(RadioIndicationType /*type*/,
- bool /*enabled*/) {
- return Void();
-}
-
-Return<void> RadioIndication_v1_5::registrationFailed(
- RadioIndicationType /*type*/,
- const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/,
- const ::android::hardware::hidl_string& /*chosenPlmn*/,
- ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_5::Domain> /*domain*/,
- int32_t /*causeCode*/, int32_t /*additionalCauseCode*/) {
- return Void();
-}
-
-Return<void> RadioIndication_v1_5::barringInfoChanged(
- RadioIndicationType /*type*/,
- const ::android::hardware::radio::V1_5::CellIdentity& /*cellIdentity*/,
- const ::android::hardware::hidl_vec<::android::hardware::radio::V1_5::BarringInfo>&
- /*barringInfos*/) {
- return Void();
-}
-
-Return<void> RadioIndication_v1_5::networkScanResult_1_5(
- RadioIndicationType /*type*/,
- const ::android::hardware::radio::V1_5::NetworkScanResult& /*result*/) {
- return Void();
-}
-
-Return<void> RadioIndication_v1_5::cellInfoList_1_5(
- RadioIndicationType /*type*/,
- const ::android::hardware::hidl_vec<
- ::android::hardware::radio::V1_5::CellInfo>& /*records*/) {
- return Void();
-}
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index e4f9ce8..8cbb2d0 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -16,7 +16,7 @@
#include <radio_hidl_hal_utils_v1_5.h>
-::android::hardware::radio::V1_4::CardStatus cardStatus;
+::android::hardware::radio::V1_5::CardStatus cardStatus;
RadioResponse_v1_5::RadioResponse_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {}
@@ -829,9 +829,8 @@
Return<void> RadioResponse_v1_5::getIccCardStatusResponse_1_4(
const RadioResponseInfo& info,
- const ::android::hardware::radio::V1_4::CardStatus& card_status) {
+ const ::android::hardware::radio::V1_4::CardStatus& /*card_status*/) {
rspInfo = info;
- cardStatus = card_status;
parent_v1_5.notify(info.serial);
return Void();
}
@@ -944,6 +943,14 @@
return Void();
}
+Return<void> RadioResponse_v1_5::getDataCallListResponse_1_5(
+ const RadioResponseInfo& info,
+ const hidl_vec<::android::hardware::radio::V1_5::SetupDataCallResult>& /* dcResponse */) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
+
Return<void> RadioResponse_v1_5::setInitialAttachApnResponse_1_5(const RadioResponseInfo& info) {
rspInfo = info;
parent_v1_5.notify(info.serial);
@@ -1021,3 +1028,12 @@
int32_t /*remainingRetries*/) {
return Void();
}
+
+Return<void> RadioResponse_v1_5::getIccCardStatusResponse_1_5(
+ const RadioResponseInfo& info,
+ const ::android::hardware::radio::V1_5::CardStatus& card_status) {
+ rspInfo = info;
+ cardStatus = card_status;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
diff --git a/rebootescrow/aidl/default/HadamardUtils.cpp b/rebootescrow/aidl/default/HadamardUtils.cpp
index d2422b9..adb2010 100644
--- a/rebootescrow/aidl/default/HadamardUtils.cpp
+++ b/rebootescrow/aidl/default/HadamardUtils.cpp
@@ -16,8 +16,6 @@
#include <HadamardUtils.h>
-#include <limits>
-
#include <android-base/logging.h>
namespace aidl {
@@ -92,6 +90,31 @@
return result;
}
+// Constant-time conditional copy, to fix b/146520538
+// ctl must be 0 or 1; we do the copy if it's 1.
+static void CondCopy(uint32_t ctl, void* dest, const void* src, size_t len) {
+ const auto cdest = reinterpret_cast<uint8_t*>(dest);
+ const auto csrc = reinterpret_cast<const uint8_t*>(src);
+ for (size_t i = 0; i < len; i++) {
+ const uint32_t d = cdest[i];
+ const uint32_t s = csrc[i];
+ cdest[i] = d ^ (-ctl & (s ^ d));
+ }
+}
+
+struct CodewordWinner {
+ uint16_t codeword;
+ int32_t score;
+};
+
+// Replace dest with src if it has a higher score
+static void CopyWinner(CodewordWinner* dest, const CodewordWinner& src) {
+ // Scores are between - 2^15 and 2^15, so taking the difference won't
+ // overflow; we use the sign bit of the difference here.
+ CondCopy(static_cast<uint32_t>(dest->score - src.score) >> 31, dest, &src,
+ sizeof(CodewordWinner));
+}
+
// Decode a single codeword. Because of the way codewords are striped together
// this takes the entire input, plus an offset telling it which word to decode.
static uint16_t DecodeWord(size_t word, const std::vector<uint8_t>& encoded) {
@@ -118,20 +141,15 @@
}
}
}
- auto hiscore = std::numeric_limits<int32_t>::min();
- uint16_t winner;
- // TODO(b/146520538): this needs to be constant time
+ // -ENCODE_LENGTH is least possible score, so start one less than that
+ auto best = CodewordWinner{0, -static_cast<int32_t>(ENCODE_LENGTH + 1)};
+ // For every possible codeword value, look at its score, and replace best if it's higher,
+ // in constant time.
for (size_t i = 0; i < ENCODE_LENGTH; i++) {
- if (scores[i] > hiscore) {
- winner = i;
- hiscore = scores[i];
-
- } else if (-scores[i] > hiscore) {
- winner = i | (1 << CODE_K);
- hiscore = -scores[i];
- }
+ CopyWinner(&best, CodewordWinner{static_cast<uint16_t>(i), scores[i]});
+ CopyWinner(&best, CodewordWinner{static_cast<uint16_t>(i | (1 << CODE_K)), -scores[i]});
}
- return winner;
+ return best.codeword;
}
std::vector<uint8_t> DecodeKey(const std::vector<uint8_t>& shuffled) {
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
index 84556b5..406a899 100644
--- a/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/CompositeEffect.aidl
@@ -23,6 +23,9 @@
/* Period of silence preceding primitive. */
int delayMs;
CompositePrimitive primitive;
- /* 0.0 (exclusive) - 1.0 (inclusive) */
+ /*
+ * 0.0 (inclusive) - 1.0 (inclusive),
+ * where 0.0 is minimum "feelable" amplitude.
+ */
float scale;
}
diff --git a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
index 0fdfa5d..8e82db0 100644
--- a/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/CompositePrimitive.aidl
@@ -21,37 +21,53 @@
enum CompositePrimitive {
/**
* No haptic effect. Used to generate extended delays between primitives.
+ *
+ * Support is required.
*/
NOOP,
/**
* This effect should produce a sharp, crisp click sensation.
+ *
+ * Support is required.
*/
CLICK,
/**
* A haptic effect that simulates downwards movement with gravity. Often
* followed by extra energy of hitting and reverberation to augment
* physicality.
+ *
+ * Support is optional.
*/
THUD,
/**
* A haptic effect that simulates spinning momentum.
+ *
+ * Support is optional.
*/
SPIN,
/**
* A haptic effect that simulates quick upward movement against gravity.
+ *
+ * Support is required.
*/
QUICK_RISE,
/**
* A haptic effect that simulates slow upward movement against gravity.
+ *
+ * Support is required.
*/
SLOW_RISE,
/**
* A haptic effect that simulates quick downwards movement with gravity.
+ *
+ * Support is required.
*/
QUICK_FALL,
/**
* This very short effect should produce a light crisp sensation intended
* to be used repetitively for dynamic feedback.
+ *
+ * Support is required.
*/
LIGHT_TICK,
}
diff --git a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
index 6489c1d..0b21248 100644
--- a/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
+++ b/vibrator/aidl/android/hardware/vibrator/IVibrator.aidl
@@ -161,8 +161,8 @@
* List of supported effect primitive.
*
* Return the effect primitives which are supported by the compose API.
- * Implementations are expected to support all primitives of the interface
- * version that they implement.
+ * Implementations are expected to support all required primitives of the
+ * interface version that they implement (see primitive definitions).
*/
CompositePrimitive[] getSupportedPrimitives();
diff --git a/vibrator/aidl/default/Vibrator.cpp b/vibrator/aidl/default/Vibrator.cpp
index 9236b95..b359100 100644
--- a/vibrator/aidl/default/Vibrator.cpp
+++ b/vibrator/aidl/default/Vibrator.cpp
@@ -146,7 +146,7 @@
if (e.delayMs > kComposeDelayMaxMs) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- if (e.scale <= 0.0f || e.scale > 1.0f) {
+ if (e.scale < 0.0f || e.scale > 1.0f) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
if (std::find(supported.begin(), supported.end(), e.primitive) == supported.end()) {
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index 411fe7a..8340517 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -21,6 +21,7 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
+#include <cmath>
#include <future>
using android::ProcessState;
@@ -53,6 +54,11 @@
android::enum_range<CompositePrimitive>().begin(),
android::enum_range<CompositePrimitive>().end()};
+const std::vector<CompositePrimitive> kOptionalPrimitives = {
+ CompositePrimitive::THUD,
+ CompositePrimitive::SPIN,
+};
+
const std::vector<CompositePrimitive> kInvalidPrimitives = {
static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.front()) - 1),
static_cast<CompositePrimitive>(static_cast<int32_t>(kCompositePrimitives.back()) + 1),
@@ -128,7 +134,6 @@
} else {
EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION)
<< toString(effect) << " " << toString(strength);
- EXPECT_EQ(lengthMs, 0);
}
}
}
@@ -157,7 +162,6 @@
EXPECT_GT(lengthMs, 0);
} else {
EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
- EXPECT_EQ(lengthMs, 0);
}
if (!status.isOk()) continue;
@@ -177,7 +181,6 @@
int lengthMs;
Status status = vibrator->perform(effect, strength, callback, &lengthMs);
EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode());
- EXPECT_EQ(lengthMs, 0);
}
}
}
@@ -267,38 +270,56 @@
EXPECT_EQ(Status::EX_NONE, vibrator->getSupportedPrimitives(&supported).exceptionCode());
- std::sort(supported.begin(), supported.end());
+ for (auto primitive : kCompositePrimitives) {
+ bool isPrimitiveSupported =
+ std::find(supported.begin(), supported.end(), primitive) != supported.end();
+ bool isPrimitiveOptional =
+ std::find(kOptionalPrimitives.begin(), kOptionalPrimitives.end(), primitive) !=
+ kOptionalPrimitives.end();
- EXPECT_EQ(kCompositePrimitives, supported);
+ EXPECT_TRUE(isPrimitiveSupported || isPrimitiveOptional) << toString(primitive);
+ }
}
}
TEST_P(VibratorAidl, GetPrimitiveDuration) {
if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
- int32_t duration;
+ std::vector<CompositePrimitive> supported;
+ ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
for (auto primitive : kCompositePrimitives) {
- EXPECT_EQ(Status::EX_NONE,
- vibrator->getPrimitiveDuration(primitive, &duration).exceptionCode());
+ bool isPrimitiveSupported =
+ std::find(supported.begin(), supported.end(), primitive) != supported.end();
+ int32_t duration;
+
+ Status status = vibrator->getPrimitiveDuration(primitive, &duration);
+
+ if (isPrimitiveSupported) {
+ EXPECT_EQ(Status::EX_NONE, status.exceptionCode());
+ } else {
+ EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode());
+ }
}
}
}
TEST_P(VibratorAidl, ComposeValidPrimitives) {
if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+ std::vector<CompositePrimitive> supported;
int32_t maxDelay, maxSize;
+ ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionDelayMax(&maxDelay).exceptionCode());
EXPECT_EQ(Status::EX_NONE, vibrator->getCompositionSizeMax(&maxSize).exceptionCode());
std::vector<CompositeEffect> composite;
- for (auto primitive : kCompositePrimitives) {
+ for (auto primitive : supported) {
CompositeEffect effect;
effect.delayMs = std::rand() % (maxDelay + 1);
effect.primitive = primitive;
- effect.scale = static_cast<float>(std::rand()) / RAND_MAX ?: 1.0f;
+ effect.scale = static_cast<float>(std::rand()) / RAND_MAX;
composite.emplace_back(effect);
if (composite.size() == maxSize) {
@@ -317,7 +338,21 @@
TEST_P(VibratorAidl, ComposeUnsupportedPrimitives) {
if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
- for (auto primitive : kInvalidPrimitives) {
+ auto unsupported = kInvalidPrimitives;
+ std::vector<CompositePrimitive> supported;
+
+ ASSERT_TRUE(vibrator->getSupportedPrimitives(&supported).isOk());
+
+ for (auto primitive : kCompositePrimitives) {
+ bool isPrimitiveSupported =
+ std::find(supported.begin(), supported.end(), primitive) != supported.end();
+
+ if (!isPrimitiveSupported) {
+ unsupported.push_back(primitive);
+ }
+ }
+
+ for (auto primitive : unsupported) {
std::vector<CompositeEffect> composite(1);
for (auto& effect : composite) {
@@ -332,7 +367,33 @@
}
}
-TEST_P(VibratorAidl, CompseDelayBoundary) {
+TEST_P(VibratorAidl, ComposeScaleBoundary) {
+ if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
+ std::vector<CompositeEffect> composite(1);
+ CompositeEffect& effect = composite[0];
+
+ effect.delayMs = 0;
+ effect.primitive = CompositePrimitive::CLICK;
+
+ effect.scale = std::nextafter(0.0f, -1.0f);
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+ vibrator->compose(composite, nullptr).exceptionCode());
+
+ effect.scale = 0.0f;
+ EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
+
+ effect.scale = 1.0f;
+ EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, nullptr).exceptionCode());
+
+ effect.scale = std::nextafter(1.0f, 2.0f);
+ EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT,
+ vibrator->compose(composite, nullptr).exceptionCode());
+
+ vibrator->off();
+ }
+}
+
+TEST_P(VibratorAidl, ComposeDelayBoundary) {
if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
int32_t maxDelay;
@@ -357,7 +418,7 @@
}
}
-TEST_P(VibratorAidl, CompseSizeBoundary) {
+TEST_P(VibratorAidl, ComposeSizeBoundary) {
if (capabilities & IVibrator::CAP_COMPOSE_EFFECTS) {
int32_t maxSize;