Merge "Multihal 2.0 - Implement SubHal discovery"
diff --git a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
index 94ace45..24b777c 100644
--- a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
@@ -50,12 +50,18 @@
VehiclePropValue* valueToUpdate = const_cast<VehiclePropValue*>(getValueOrNullLocked(recId));
if (valueToUpdate == nullptr) {
mPropertyValues.insert({ recId, propValue });
- } else {
- valueToUpdate->timestamp = propValue.timestamp;
- valueToUpdate->value = propValue.value;
- if (updateStatus) {
- valueToUpdate->status = propValue.status;
- }
+ return true;
+ }
+
+ // propValue is outdated and drops it.
+ if (valueToUpdate->timestamp > propValue.timestamp) {
+ return false;
+ }
+ // update the propertyValue.
+ valueToUpdate->timestamp = propValue.timestamp;
+ valueToUpdate->value = propValue.value;
+ if (updateStatus) {
+ valueToUpdate->status = propValue.status;
}
return true;
}
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 ba81a52..b4f1f07 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
@@ -455,7 +455,7 @@
VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
if (updatedPropValue) {
- updatedPropValue->timestamp = elapsedRealtimeNano();
+ updatedPropValue->timestamp = value.timestamp;
updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus);
auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode;
diff --git a/camera/common/1.0/default/Android.bp b/camera/common/1.0/default/Android.bp
index 3e5c6d7..f4390b2 100644
--- a/camera/common/1.0/default/Android.bp
+++ b/camera/common/1.0/default/Android.bp
@@ -21,6 +21,7 @@
"libcamera_metadata",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"libexif",
],
include_dirs: ["system/media/private/camera/include"],
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
index b8c40e9..76f9778 100644
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -27,7 +27,9 @@
using MapperErrorV2 = android::hardware::graphics::mapper::V2_0::Error;
using MapperErrorV3 = android::hardware::graphics::mapper::V3_0::Error;
+using MapperErrorV4 = android::hardware::graphics::mapper::V4_0::Error;
using IMapperV3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using IMapperV4 = android::hardware::graphics::mapper::V4_0::IMapper;
HandleImporter::HandleImporter() : mInitialized(false) {}
@@ -36,6 +38,12 @@
return;
}
+ mMapperV4 = IMapperV4::getService();
+ if (mMapperV4 != nullptr) {
+ mInitialized = true;
+ return;
+ }
+
mMapperV3 = IMapperV3::getService();
if (mMapperV3 != nullptr) {
mInitialized = true;
@@ -53,6 +61,7 @@
}
void HandleImporter::cleanup() {
+ mMapperV4.clear();
mMapperV3.clear();
mMapperV2.clear();
mInitialized = false;
@@ -151,6 +160,10 @@
initializeLocked();
}
+ if (mMapperV4 != nullptr) {
+ return importBufferInternal<IMapperV4, MapperErrorV4>(mMapperV4, handle);
+ }
+
if (mMapperV3 != nullptr) {
return importBufferInternal<IMapperV3, MapperErrorV3>(mMapperV3, handle);
}
@@ -159,7 +172,7 @@
return importBufferInternal<IMapper, MapperErrorV2>(mMapperV2, handle);
}
- ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+ ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
return false;
}
@@ -169,12 +182,17 @@
}
Mutex::Autolock lock(mLock);
- if (mMapperV3 == nullptr && mMapperV2 == nullptr) {
- ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+ if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) {
+ ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
return;
}
- if (mMapperV3 != nullptr) {
+ if (mMapperV4 != nullptr) {
+ auto ret = mMapperV4->freeBuffer(const_cast<native_handle_t*>(handle));
+ if (!ret.isOk()) {
+ ALOGE("%s: mapper freeBuffer failed: %s", __FUNCTION__, ret.description().c_str());
+ }
+ } else if (mMapperV3 != nullptr) {
auto ret = mMapperV3->freeBuffer(const_cast<native_handle_t*>(handle));
if (!ret.isOk()) {
ALOGE("%s: mapper freeBuffer failed: %s",
@@ -222,14 +240,27 @@
initializeLocked();
}
- if (mMapperV3 == nullptr && mMapperV2 == nullptr) {
- ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+ if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) {
+ ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
return ret;
}
hidl_handle acquireFenceHandle;
auto buffer = const_cast<native_handle_t*>(buf);
- if (mMapperV3 != nullptr) {
+ if (mMapperV4 != nullptr) {
+ IMapperV4::Rect accessRegion{0, 0, static_cast<int>(size), 1};
+ // No need to use bytesPerPixel and bytesPerStride because we are using
+ // an 1-D buffer and accressRegion.
+ mMapperV4->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpPtr, const auto& /*bytesPerPixel*/,
+ const auto& /*bytesPerStride*/) {
+ if (tmpError == MapperErrorV4::NONE) {
+ ret = tmpPtr;
+ } else {
+ ALOGE("%s: failed to lock error %d!", __FUNCTION__, tmpError);
+ }
+ });
+ } else if (mMapperV3 != nullptr) {
IMapperV3::Rect accessRegion { 0, 0, static_cast<int>(size), 1 };
// No need to use bytesPerPixel and bytesPerStride because we are using
// an 1-D buffer and accressRegion.
@@ -269,6 +300,10 @@
initializeLocked();
}
+ if (mMapperV4 != nullptr) {
+ return lockYCbCrInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf, cpuUsage, accessRegion);
+ }
+
if (mMapperV3 != nullptr) {
return lockYCbCrInternal<IMapperV3, MapperErrorV3>(
mMapperV3, buf, cpuUsage, accessRegion);
@@ -279,11 +314,14 @@
mMapperV2, buf, cpuUsage, accessRegion);
}
- ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+ ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
return {};
}
int HandleImporter::unlock(buffer_handle_t& buf) {
+ if (mMapperV4 != nullptr) {
+ return unlockInternal<IMapperV4, MapperErrorV4>(mMapperV4, buf);
+ }
if (mMapperV3 != nullptr) {
return unlockInternal<IMapperV3, MapperErrorV3>(mMapperV3, buf);
}
@@ -291,7 +329,7 @@
return unlockInternal<IMapper, MapperErrorV2>(mMapperV2, buf);
}
- ALOGE("%s: mMapperV3 and mMapperV2 are both null!", __FUNCTION__);
+ ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
return -1;
}
diff --git a/camera/common/1.0/default/include/HandleImporter.h b/camera/common/1.0/default/include/HandleImporter.h
index a93d455..fc2bbd1 100644
--- a/camera/common/1.0/default/include/HandleImporter.h
+++ b/camera/common/1.0/default/include/HandleImporter.h
@@ -17,10 +17,11 @@
#ifndef CAMERA_COMMON_1_0_HANDLEIMPORTED_H
#define CAMERA_COMMON_1_0_HANDLEIMPORTED_H
-#include <utils/Mutex.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
#include <cutils/native_handle.h>
+#include <utils/Mutex.h>
using android::hardware::graphics::mapper::V2_0::IMapper;
using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
@@ -70,6 +71,7 @@
bool mInitialized;
sp<IMapper> mMapperV2;
sp<graphics::mapper::V3_0::IMapper> mMapperV3;
+ sp<graphics::mapper::V4_0::IMapper> mMapperV4;
};
} // namespace helper
diff --git a/camera/device/1.0/default/Android.bp b/camera/device/1.0/default/Android.bp
index aa3b941..c3518d3 100644
--- a/camera/device/1.0/default/Android.bp
+++ b/camera/device/1.0/default/Android.bp
@@ -16,6 +16,7 @@
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hardware.graphics.common@1.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp
index edb008e..edc2988 100644
--- a/camera/device/3.2/default/Android.bp
+++ b/camera/device/3.2/default/Android.bp
@@ -14,6 +14,7 @@
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"liblog",
"libhardware",
"libcamera_metadata",
diff --git a/camera/device/3.3/default/Android.bp b/camera/device/3.3/default/Android.bp
index 39d379d..f3c2e0e 100644
--- a/camera/device/3.3/default/Android.bp
+++ b/camera/device/3.3/default/Android.bp
@@ -16,6 +16,7 @@
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"liblog",
"libhardware",
"libcamera_metadata",
diff --git a/camera/device/3.4/default/Android.bp b/camera/device/3.4/default/Android.bp
index c22b13c..8e699d8 100644
--- a/camera/device/3.4/default/Android.bp
+++ b/camera/device/3.4/default/Android.bp
@@ -49,6 +49,7 @@
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"liblog",
"libhardware",
"libcamera_metadata",
@@ -86,6 +87,7 @@
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"liblog",
"libhardware",
"libcamera_metadata",
diff --git a/camera/device/3.5/default/Android.bp b/camera/device/3.5/default/Android.bp
index 26b3b67..dde585e 100644
--- a/camera/device/3.5/default/Android.bp
+++ b/camera/device/3.5/default/Android.bp
@@ -50,6 +50,7 @@
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"liblog",
"libhardware",
"libcamera_metadata",
@@ -83,7 +84,8 @@
"android.hardware.camera.device@3.5",
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"liblog",
"libhardware",
"libcamera_metadata",
diff --git a/camera/device/3.5/types.hal b/camera/device/3.5/types.hal
index 6d861e2..38493b4 100644
--- a/camera/device/3.5/types.hal
+++ b/camera/device/3.5/types.hal
@@ -23,7 +23,8 @@
/**
* If the result metadata cannot be produced for a physical camera device part of a logical
* multi-camera, then HAL must invoke the notification callback and pass a message with ERROR_RESULT
- * code and errorStreamId that contains the stream id associated with that physical device.
+ * code and errorStreamId that contains the stream id associated with that physical device. Such
+ * callback must be made before the final processCaptureResult() call for the corresponding request.
* The behavior during absent result metadata remains unchanged for a logical or a non-logical
* camera device and the errorStreamId must be set to -1.
*/
diff --git a/camera/metadata/3.5/Android.bp b/camera/metadata/3.5/Android.bp
new file mode 100644
index 0000000..4ebd069
--- /dev/null
+++ b/camera/metadata/3.5/Android.bp
@@ -0,0 +1,19 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.camera.metadata@3.5",
+ root: "android.hardware",
+ vndk: {
+ enabled: true,
+ },
+ srcs: [
+ "types.hal",
+ ],
+ interfaces: [
+ "android.hardware.camera.metadata@3.2",
+ "android.hardware.camera.metadata@3.3",
+ "android.hardware.camera.metadata@3.4",
+ ],
+ gen_java: true,
+}
+
diff --git a/camera/metadata/3.5/types.hal b/camera/metadata/3.5/types.hal
new file mode 100644
index 0000000..0fec947
--- /dev/null
+++ b/camera/metadata/3.5/types.hal
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata@3.5;
+
+import android.hardware.camera.metadata@3.2;
+import android.hardware.camera.metadata@3.3;
+import android.hardware.camera.metadata@3.4;
+
+// No new metadata sections added in this revision
+
+/*
+ * Enumeration definitions for the various entries that need them
+ */
+
+/** android.request.availableCapabilities enumeration values added since v3.4
+ * @see ANDROID_REQUEST_AVAILABLE_CAPABILITIES
+ */
+enum CameraMetadataEnumAndroidRequestAvailableCapabilities :
+ @3.4::CameraMetadataEnumAndroidRequestAvailableCapabilities {
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA,
+};
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index cb78fcb..313b29b 100644
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -13,6 +13,7 @@
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"camera.device@1.0-impl",
@@ -52,6 +53,7 @@
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"camera.device@3.3-impl",
@@ -95,6 +97,8 @@
"android.hardware.camera.provider@2.4-external",
"android.hardware.camera.provider@2.4-legacy",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"camera.device@1.0-impl",
@@ -140,6 +144,8 @@
"android.hardware.camera.device@3.5",
"android.hardware.camera.provider@2.4",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"libbinder",
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 2c3ed37..5fe7b19 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -43,9 +43,11 @@
"android.hardware.camera.provider@2.5",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.allocator@4.0",
"android.hardware.graphics.common@1.0",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hidl.allocator@1.0",
"libgrallocusage",
"libhidlmemory",
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index a5369e7..67d5bbe 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -55,9 +55,11 @@
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/allocator/4.0/IAllocator.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <android/hardware/graphics/mapper/2.0/types.h>
#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
#include <android/hidl/memory/1.0/IMapper.h>
#include <android/hidl/memory/1.0/IMemory.h>
@@ -622,7 +624,7 @@
Return<void> returnStreamBuffers(const hidl_vec<StreamBuffer>& buffers) override;
- void setCurrentStreamConfig(const hidl_vec<V3_2::Stream>& streams,
+ void setCurrentStreamConfig(const hidl_vec<V3_4::Stream>& streams,
const hidl_vec<V3_2::HalStream>& halStreams);
void waitForBuffersReturned();
@@ -639,7 +641,7 @@
/* members for requestStreamBuffers() and returnStreamBuffers()*/
std::mutex mLock; // protecting members below
bool mUseHalBufManager = false;
- hidl_vec<V3_2::Stream> mStreams;
+ hidl_vec<V3_4::Stream> mStreams;
hidl_vec<V3_2::HalStream> mHalStreams;
uint64_t mNextBufferId = 1;
using OutstandingBuffers = std::unordered_map<uint64_t, hidl_handle>;
@@ -865,6 +867,8 @@
int32_t partialResultCount;
// For buffer drop errors, the stream ID for the stream that lost a buffer.
+ // For physical sub-camera result errors, the Id of the physical stream
+ // for the physical sub-camera.
// Otherwise -1.
int32_t errorStreamId;
@@ -878,6 +882,8 @@
// return from HAL but framework.
::android::Vector<StreamBuffer> resultOutputBuffers;
+ std::unordered_set<string> expectedPhysicalResults;
+
InFlightRequest() :
shutterTimestamp(0),
errorCodeValid(false),
@@ -907,6 +913,24 @@
partialResultCount(0),
errorStreamId(-1),
hasInputBuffer(hasInput) {}
+
+ InFlightRequest(ssize_t numBuffers, bool hasInput,
+ bool partialResults, uint32_t partialCount,
+ const std::unordered_set<string>& extraPhysicalResult,
+ std::shared_ptr<ResultMetadataQueue> queue = nullptr) :
+ shutterTimestamp(0),
+ errorCodeValid(false),
+ errorCode(ErrorCode::ERROR_BUFFER),
+ usePartialResult(partialResults),
+ numPartialResults(partialCount),
+ resultQueue(queue),
+ haveResultMetadata(false),
+ numBuffersLeft(numBuffers),
+ frameNumber(0),
+ partialResultCount(0),
+ errorStreamId(-1),
+ hasInputBuffer(hasInput),
+ expectedPhysicalResults(extraPhysicalResult) {}
};
// Map from frame number to the in-flight request state
@@ -1124,6 +1148,13 @@
return notify;
}
+ if (physicalCameraMetadata.size() != request->expectedPhysicalResults.size()) {
+ ALOGE("%s: Frame %d: Returned physical metadata count %zu "
+ "must be equal to expected count %zu", __func__, frameNumber,
+ physicalCameraMetadata.size(), request->expectedPhysicalResults.size());
+ ADD_FAILURE();
+ return notify;
+ }
std::vector<::android::hardware::camera::device::V3_2::CameraMetadata> physResultMetadata;
physResultMetadata.resize(physicalCameraMetadata.size());
for (size_t i = 0; i < physicalCameraMetadata.size(); i++) {
@@ -1251,11 +1282,11 @@
}
void CameraHidlTest::DeviceCb::setCurrentStreamConfig(
- const hidl_vec<V3_2::Stream>& streams, const hidl_vec<V3_2::HalStream>& halStreams) {
+ const hidl_vec<V3_4::Stream>& streams, const hidl_vec<V3_2::HalStream>& halStreams) {
ASSERT_EQ(streams.size(), halStreams.size());
ASSERT_NE(streams.size(), 0);
for (size_t i = 0; i < streams.size(); i++) {
- ASSERT_EQ(streams[i].id, halStreams[i].id);
+ ASSERT_EQ(streams[i].v3_2.id, halStreams[i].id);
}
std::lock_guard<std::mutex> l(mLock);
mUseHalBufManager = true;
@@ -1293,16 +1324,6 @@
std::lock_guard<std::mutex> l(mParent->mLock);
for (size_t i = 0; i < messages.size(); i++) {
- ssize_t idx = mParent->mInflightMap.indexOfKey(
- messages[i].msg.shutter.frameNumber);
- if (::android::NAME_NOT_FOUND == idx) {
- ALOGE("%s: Unexpected frame number! received: %u",
- __func__, messages[i].msg.shutter.frameNumber);
- ADD_FAILURE();
- break;
- }
- InFlightRequest *r = mParent->mInflightMap.editValueAt(idx);
-
switch(messages[i].type) {
case MsgType::ERROR:
if (ErrorCode::ERROR_DEVICE == messages[i].msg.error.errorCode) {
@@ -1310,13 +1331,59 @@
__func__);
ADD_FAILURE();
} else {
- r->errorCodeValid = true;
- r->errorCode = messages[i].msg.error.errorCode;
- r->errorStreamId = messages[i].msg.error.errorStreamId;
+ ssize_t idx = mParent->mInflightMap.indexOfKey(
+ messages[i].msg.error.frameNumber);
+ if (::android::NAME_NOT_FOUND == idx) {
+ ALOGE("%s: Unexpected error frame number! received: %u",
+ __func__, messages[i].msg.error.frameNumber);
+ ADD_FAILURE();
+ break;
+ }
+ InFlightRequest *r = mParent->mInflightMap.editValueAt(idx);
+
+ if (ErrorCode::ERROR_RESULT == messages[i].msg.error.errorCode &&
+ messages[i].msg.error.errorStreamId != -1) {
+ if (r->haveResultMetadata) {
+ ALOGE("%s: Camera must report physical camera result error before "
+ "the final capture result!", __func__);
+ ADD_FAILURE();
+ } else {
+ for (size_t j = 0; j < mStreams.size(); j++) {
+ if (mStreams[j].v3_2.id == messages[i].msg.error.errorStreamId) {
+ hidl_string physicalCameraId = mStreams[j].physicalCameraId;
+ bool idExpected = r->expectedPhysicalResults.find(
+ physicalCameraId) != r->expectedPhysicalResults.end();
+ if (!idExpected) {
+ ALOGE("%s: ERROR_RESULT's error stream's physicalCameraId "
+ "%s must be expected", __func__,
+ physicalCameraId.c_str());
+ ADD_FAILURE();
+ } else {
+ r->expectedPhysicalResults.erase(physicalCameraId);
+ }
+ break;
+ }
+ }
+ }
+ } else {
+ r->errorCodeValid = true;
+ r->errorCode = messages[i].msg.error.errorCode;
+ r->errorStreamId = messages[i].msg.error.errorStreamId;
+ }
}
break;
case MsgType::SHUTTER:
+ {
+ ssize_t idx = mParent->mInflightMap.indexOfKey(messages[i].msg.shutter.frameNumber);
+ if (::android::NAME_NOT_FOUND == idx) {
+ ALOGE("%s: Unexpected shutter frame number! received: %u",
+ __func__, messages[i].msg.shutter.frameNumber);
+ ADD_FAILURE();
+ break;
+ }
+ InFlightRequest *r = mParent->mInflightMap.editValueAt(idx);
r->shutterTimestamp = messages[i].msg.shutter.timestamp;
+ }
break;
default:
ALOGE("%s: Unsupported notify message %d", __func__,
@@ -1357,7 +1424,7 @@
for (size_t i = 0; i < bufReqs.size(); i++) {
bool found = false;
for (size_t idx = 0; idx < mStreams.size(); idx++) {
- if (bufReqs[i].streamId == mStreams[idx].id) {
+ if (bufReqs[i].streamId == mStreams[idx].v3_2.id) {
found = true;
indexes[i] = idx;
break;
@@ -1381,7 +1448,7 @@
const auto& halStream = mHalStreams[idx];
const V3_5::BufferRequest& bufReq = bufReqs[i];
if (mOutstandingBufferIds[idx].size() + bufReq.numBuffersRequested > halStream.maxBuffers) {
- bufRets[i].streamId = stream.id;
+ bufRets[i].streamId = stream.v3_2.id;
bufRets[i].val.error(StreamBufferRequestError::MAX_BUFFER_EXCEEDED);
allStreamOk = false;
continue;
@@ -1390,17 +1457,17 @@
hidl_vec<StreamBuffer> tmpRetBuffers(bufReq.numBuffersRequested);
for (size_t j = 0; j < bufReq.numBuffersRequested; j++) {
hidl_handle buffer_handle;
- mParent->allocateGraphicBuffer(stream.width, stream.height,
+ mParent->allocateGraphicBuffer(stream.v3_2.width, stream.v3_2.height,
android_convertGralloc1To0Usage(
halStream.producerUsage, halStream.consumerUsage),
halStream.overrideFormat, &buffer_handle);
- tmpRetBuffers[j] = {stream.id, mNextBufferId, buffer_handle, BufferStatus::OK,
+ tmpRetBuffers[j] = {stream.v3_2.id, mNextBufferId, buffer_handle, BufferStatus::OK,
nullptr, nullptr};
mOutstandingBufferIds[idx].insert(std::make_pair(mNextBufferId++, buffer_handle));
}
atLeastOneStreamOk = true;
- bufRets[i].streamId = stream.id;
+ bufRets[i].streamId = stream.v3_2.id;
bufRets[i].val.buffers(std::move(tmpRetBuffers));
}
@@ -1430,7 +1497,7 @@
for (const auto& buf : buffers) {
bool found = false;
for (size_t idx = 0; idx < mOutstandingBufferIds.size(); idx++) {
- if (mStreams[idx].id == buf.streamId &&
+ if (mStreams[idx].v3_2.id == buf.streamId &&
mOutstandingBufferIds[idx].count(buf.bufferId) == 1) {
mOutstandingBufferIds[idx].erase(buf.bufferId);
// TODO: check do we need to close/delete native handle or assume we have enough
@@ -4157,7 +4224,7 @@
ASSERT_TRUE(resultQueueRet.isOk());
InFlightRequest inflightReq = {static_cast<ssize_t> (halStreamConfig.streams.size()), false,
- supportsPartialResults, partialResultCount, resultQueue};
+ supportsPartialResults, partialResultCount, physicalIds, resultQueue};
std::vector<hidl_handle> graphicBuffers;
graphicBuffers.reserve(halStreamConfig.streams.size());
@@ -4236,7 +4303,7 @@
request.v3_2.outputBuffers[0].buffer = nullptr;
mInflightMap.clear();
inflightReq = {static_cast<ssize_t> (physicalIds.size()), false,
- supportsPartialResults, partialResultCount, resultQueue};
+ supportsPartialResults, partialResultCount, physicalIds, resultQueue};
mInflightMap.add(request.v3_2.frameNumber, &inflightReq);
}
@@ -5315,10 +5382,10 @@
ASSERT_EQ(physicalIds.size(), halConfig.streams.size());
*halStreamConfig = halConfig;
if (*useHalBufManager) {
- hidl_vec<V3_2::Stream> streams(physicalIds.size());
+ hidl_vec<V3_4::Stream> streams(physicalIds.size());
hidl_vec<V3_2::HalStream> halStreams(physicalIds.size());
for (size_t i = 0; i < physicalIds.size(); i++) {
- streams[i] = streams3_4[i].v3_2;
+ streams[i] = streams3_4[i];
halStreams[i] = halConfig.streams[i].v3_3.v3_2;
}
cb->setCurrentStreamConfig(streams, halStreams);
@@ -5493,9 +5560,9 @@
halStreamConfig->streams.resize(1);
halStreamConfig->streams[0] = halConfig.streams[0].v3_3.v3_2;
if (*useHalBufManager) {
- hidl_vec<V3_2::Stream> streams(1);
+ hidl_vec<V3_4::Stream> streams(1);
hidl_vec<V3_2::HalStream> halStreams(1);
- streams[0] = stream3_2;
+ streams[0] = config3_4.streams[0];
halStreams[0] = halConfig.streams[0].v3_3.v3_2;
cb->setCurrentStreamConfig(streams, halStreams);
}
@@ -6148,13 +6215,44 @@
android::hardware::graphics::allocator::V2_0::IAllocator::getService();
sp<android::hardware::graphics::allocator::V3_0::IAllocator> allocatorV3 =
android::hardware::graphics::allocator::V3_0::IAllocator::getService();
+ sp<android::hardware::graphics::allocator::V4_0::IAllocator> allocatorV4 =
+ android::hardware::graphics::allocator::V4_0::IAllocator::getService();
+ sp<android::hardware::graphics::mapper::V4_0::IMapper> mapperV4 =
+ android::hardware::graphics::mapper::V4_0::IMapper::getService();
sp<android::hardware::graphics::mapper::V3_0::IMapper> mapperV3 =
android::hardware::graphics::mapper::V3_0::IMapper::getService();
sp<android::hardware::graphics::mapper::V2_0::IMapper> mapper =
android::hardware::graphics::mapper::V2_0::IMapper::getService();
::android::hardware::hidl_vec<uint32_t> descriptor;
- if (mapperV3 != nullptr && allocatorV3 != nullptr) {
+ if (mapperV4 != nullptr && allocatorV4 != nullptr) {
+ android::hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo descriptorInfo{};
+ descriptorInfo.width = width;
+ descriptorInfo.height = height;
+ descriptorInfo.layerCount = 1;
+ descriptorInfo.format =
+ static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
+ descriptorInfo.usage = usage;
+
+ auto ret = mapperV4->createDescriptor(
+ descriptorInfo, [&descriptor](android::hardware::graphics::mapper::V4_0::Error err,
+ ::android::hardware::hidl_vec<uint32_t> desc) {
+ ASSERT_EQ(err, android::hardware::graphics::mapper::V4_0::Error::NONE);
+ descriptor = desc;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ ret = allocatorV4->allocate(
+ descriptor, 1u,
+ [&](android::hardware::graphics::mapper::V4_0::Error err, uint32_t /*stride*/,
+ const ::android::hardware::hidl_vec<::android::hardware::hidl_handle>&
+ buffers) {
+ ASSERT_EQ(android::hardware::graphics::mapper::V4_0::Error::NONE, err);
+ ASSERT_EQ(buffers.size(), 1u);
+ *buffer_handle = buffers[0];
+ });
+ ASSERT_TRUE(ret.isOk());
+ } else if (mapperV3 != nullptr && allocatorV3 != nullptr) {
android::hardware::graphics::mapper::V3_0::IMapper::BufferDescriptorInfo descriptorInfo {};
descriptorInfo.width = width;
descriptorInfo.height = height;
diff --git a/current.txt b/current.txt
index fbb9752..c7b0d9e 100644
--- a/current.txt
+++ b/current.txt
@@ -572,6 +572,7 @@
cfa81f229b69f9011c58f48264fcb552447430fe68610eac514e811e65bc306a android.hardware.wifi.supplicant@1.2::types
# ABI preserving changes to HALs during Android R
+2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types
b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
ad431c8de51c07934a068e3043d8dd0537ac4d3158627706628b123f42df48dc android.hardware.neuralnetworks@1.0::IPreparedModel
aafcc10cf04ab247e86d4582586c71c6b4c2b8c479241ffa7fe37deb659fc942 android.hardware.neuralnetworks@1.2::IPreparedModel
diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp
index 88b1a8b..cdc0f35 100644
--- a/graphics/composer/2.1/utils/vts/Android.bp
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -27,12 +27,14 @@
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@3.0-vts",
+ "android.hardware.graphics.mapper@4.0-vts",
],
export_static_lib_headers: [
"VtsHalHidlTargetTestBase",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@3.0-vts",
+ "android.hardware.graphics.mapper@4.0-vts",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index c5d5823..a0745ce 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -317,11 +317,16 @@
Gralloc::Gralloc() {
[this] {
- ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+ ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>("default", "default",
/*errOnFailure=*/false));
- if (mGralloc3->getAllocator() == nullptr || mGralloc3->getMapper() == nullptr) {
- mGralloc3 = nullptr;
- ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+ if (mGralloc4->getAllocator() == nullptr || mGralloc4->getMapper() == nullptr) {
+ mGralloc4 = nullptr;
+ ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+ /*errOnFailure=*/false));
+ if (mGralloc3->getAllocator() == nullptr || mGralloc3->getMapper() == nullptr) {
+ mGralloc3 = nullptr;
+ ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+ }
}
}();
}
@@ -329,7 +334,15 @@
const native_handle_t* Gralloc::allocate(uint32_t width, uint32_t height, uint32_t layerCount,
PixelFormat format, uint64_t usage, bool import,
uint32_t* outStride) {
- if (mGralloc3) {
+ if (mGralloc4) {
+ IMapper4::BufferDescriptorInfo info{};
+ info.width = width;
+ info.height = height;
+ info.layerCount = layerCount;
+ info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
+ info.usage = usage;
+ return mGralloc4->allocate(info, import, outStride);
+ } else if (mGralloc3) {
IMapper3::BufferDescriptorInfo info{};
info.width = width;
info.height = height;
@@ -350,7 +363,17 @@
void* Gralloc::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
const AccessRegion& accessRegionRect, int acquireFence) {
- if (mGralloc3) {
+ if (mGralloc4) {
+ IMapper4::Rect accessRegion;
+ accessRegion.left = accessRegionRect.left;
+ accessRegion.top = accessRegionRect.top;
+ accessRegion.width = accessRegionRect.width;
+ accessRegion.height = accessRegionRect.height;
+ int32_t bytesPerPixel;
+ int32_t bytesPerStride;
+ return mGralloc4->lock(bufferHandle, cpuUsage, accessRegion, acquireFence, &bytesPerPixel,
+ &bytesPerStride);
+ } else if (mGralloc3) {
IMapper3::Rect accessRegion;
accessRegion.left = accessRegionRect.left;
accessRegion.top = accessRegionRect.top;
@@ -371,7 +394,9 @@
}
int Gralloc::unlock(const native_handle_t* bufferHandle) {
- if (mGralloc3) {
+ if (mGralloc4) {
+ return mGralloc4->unlock(bufferHandle);
+ } else if (mGralloc3) {
return mGralloc3->unlock(bufferHandle);
} else {
return mGralloc2->unlock(bufferHandle);
@@ -379,7 +404,9 @@
}
void Gralloc::freeBuffer(const native_handle_t* bufferHandle) {
- if (mGralloc3) {
+ if (mGralloc4) {
+ mGralloc4->freeBuffer(bufferHandle);
+ } else if (mGralloc3) {
mGralloc3->freeBuffer(bufferHandle);
} else {
mGralloc2->freeBuffer(bufferHandle);
diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
index 7811048..4294657 100644
--- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
@@ -27,6 +27,7 @@
#include <composer-vts/2.1/TestCommandReader.h>
#include <mapper-vts/2.0/MapperVts.h>
#include <mapper-vts/3.0/MapperVts.h>
+#include <mapper-vts/4.0/MapperVts.h>
#include <utils/StrongPointer.h>
#include "gtest/gtest.h"
@@ -44,8 +45,10 @@
using android::hardware::graphics::common::V1_0::PixelFormat;
using IMapper2 = android::hardware::graphics::mapper::V2_0::IMapper;
using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper;
using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc;
using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc;
+using Gralloc4 = android::hardware::graphics::mapper::V4_0::vts::Gralloc;
class ComposerClient;
@@ -153,6 +156,7 @@
protected:
std::shared_ptr<Gralloc2> mGralloc2 = nullptr;
std::shared_ptr<Gralloc3> mGralloc3 = nullptr;
+ std::shared_ptr<Gralloc4> mGralloc4 = nullptr;
};
} // namespace vts
diff --git a/graphics/composer/2.1/vts/functional/Android.bp b/graphics/composer/2.1/vts/functional/Android.bp
index d54da60..799ca91 100644
--- a/graphics/composer/2.1/vts/functional/Android.bp
+++ b/graphics/composer/2.1/vts/functional/Android.bp
@@ -27,12 +27,17 @@
static_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.allocator@4.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.0-vts",
+ "android.hardware.graphics.mapper@2.1",
+ "android.hardware.graphics.mapper@2.1-vts",
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@3.0-vts",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hardware.graphics.mapper@4.0-vts",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index fa5ace6..5d2f65d 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -22,6 +22,7 @@
#include <composer-vts/2.1/TestCommandReader.h>
#include <mapper-vts/2.0/MapperVts.h>
#include <mapper-vts/3.0/MapperVts.h>
+#include <mapper-vts/4.0/MapperVts.h>
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index 1754a43..5432882 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -34,6 +34,10 @@
"libmath",
"libnativewindow",
"librenderengine",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@3.0-vts",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hardware.graphics.mapper@4.0-vts",
],
export_static_lib_headers: [
"VtsHalHidlTargetTestBase",
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index a380fc0..93b67f0 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -182,17 +182,23 @@
Gralloc::Gralloc() {
[this] {
- ALOGD("Attempting to initialize gralloc3");
- ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+ ALOGD("Attempting to initialize gralloc4");
+ ASSERT_NO_FATAL_FAILURE(mGralloc4 = std::make_shared<Gralloc4>("default", "default",
/*errOnFailure=*/false));
- if (mGralloc3->getMapper() == nullptr || mGralloc3->getAllocator() == nullptr) {
- mGralloc3 = nullptr;
- ALOGD("Failed to initialize gralloc3, initializing gralloc2_1");
- mGralloc2_1 = std::make_shared<Gralloc2_1>(/*errOnFailure*/ false);
- if (!mGralloc2_1->getMapper()) {
- mGralloc2_1 = nullptr;
- ALOGD("Failed to initialize gralloc2_1, initializing gralloc2");
- ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+ if (mGralloc4->getMapper() == nullptr || mGralloc4->getAllocator() == nullptr) {
+ mGralloc4 = nullptr;
+ ALOGD("Failed to initialize gralloc4, initializing gralloc3");
+ ASSERT_NO_FATAL_FAILURE(mGralloc3 = std::make_shared<Gralloc3>("default", "default",
+ /*errOnFailure=*/false));
+ if (mGralloc3->getMapper() == nullptr || mGralloc3->getAllocator() == nullptr) {
+ mGralloc3 = nullptr;
+ ALOGD("Failed to initialize gralloc3, initializing gralloc2_1");
+ mGralloc2_1 = std::make_shared<Gralloc2_1>(/*errOnFailure*/ false);
+ if (!mGralloc2_1->getMapper()) {
+ mGralloc2_1 = nullptr;
+ ALOGD("Failed to initialize gralloc2_1, initializing gralloc2");
+ ASSERT_NO_FATAL_FAILURE(mGralloc2 = std::make_shared<Gralloc2>());
+ }
}
}
}();
@@ -201,7 +207,15 @@
bool Gralloc::validateBufferSize(const native_handle_t* bufferHandle, uint32_t width,
uint32_t height, uint32_t layerCount, PixelFormat format,
uint64_t usage, uint32_t stride) {
- if (mGralloc3) {
+ if (mGralloc4) {
+ IMapper4::BufferDescriptorInfo info{};
+ info.width = width;
+ info.height = height;
+ info.layerCount = layerCount;
+ info.format = static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(format);
+ info.usage = usage;
+ return mGralloc4->validateBufferSize(bufferHandle, info, stride);
+ } else if (mGralloc3) {
IMapper3::BufferDescriptorInfo info{};
info.width = width;
info.height = height;
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index 8fa9b7b..5d22305 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -44,9 +44,11 @@
using common::V1_1::RenderIntent;
using IMapper2_1 = android::hardware::graphics::mapper::V2_1::IMapper;
using IMapper3 = android::hardware::graphics::mapper::V3_0::IMapper;
+using IMapper4 = android::hardware::graphics::mapper::V4_0::IMapper;
using Gralloc2 = android::hardware::graphics::mapper::V2_0::vts::Gralloc;
using Gralloc2_1 = android::hardware::graphics::mapper::V2_1::vts::Gralloc;
using Gralloc3 = android::hardware::graphics::mapper::V3_0::vts::Gralloc;
+using Gralloc4 = android::hardware::graphics::mapper::V4_0::vts::Gralloc;
class ComposerClient;
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index 25b827e..2872880 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -39,6 +39,7 @@
static_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.allocator@4.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.1-vts",
@@ -50,6 +51,8 @@
"android.hardware.graphics.mapper@2.1-vts",
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@3.0-vts",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hardware.graphics.mapper@4.0-vts",
"librenderengine"
],
header_libs: [
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
index 2766638..965c8fe 100644
--- a/graphics/composer/2.3/vts/functional/Android.bp
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -29,6 +29,7 @@
static_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.allocator@4.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.composer@2.2",
@@ -41,6 +42,8 @@
"android.hardware.graphics.mapper@2.1-vts",
"android.hardware.graphics.mapper@3.0",
"android.hardware.graphics.mapper@3.0-vts",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hardware.graphics.mapper@4.0-vts",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.4/vts/functional/Android.bp b/graphics/composer/2.4/vts/functional/Android.bp
index d437f24..6ee7873 100644
--- a/graphics/composer/2.4/vts/functional/Android.bp
+++ b/graphics/composer/2.4/vts/functional/Android.bp
@@ -27,6 +27,8 @@
],
static_libs: [
"android.hardware.graphics.allocator@2.0",
+ "android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.allocator@4.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.composer@2.2",
@@ -38,6 +40,11 @@
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@2.1",
+ "android.hardware.graphics.mapper@2.1-vts",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@3.0-vts",
+ "android.hardware.graphics.mapper@4.0",
+ "android.hardware.graphics.mapper@4.0-vts",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 293c50c..9e6cce7 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -4339,75 +4339,61 @@
*
* This test checks that if rollback protection is implemented, DeleteKey invalidates a formerly
* valid key blob.
- *
- * TODO(swillden): Update to incorporate changes in rollback resistance semantics.
*/
TEST_F(KeyDeletionTest, DeleteKey) {
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(2048, 65537)
- .Digest(Digest::NONE)
- .Padding(PaddingMode::NONE)
- .Authorization(TAG_NO_AUTH_REQUIRED)));
+ auto error = GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_ROLLBACK_RESISTANCE));
+ ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
// Delete must work if rollback protection is implemented
- AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
- bool rollback_protected = hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE);
+ if (error == ErrorCode::OK) {
+ AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+ ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
- if (rollback_protected) {
ASSERT_EQ(ErrorCode::OK, DeleteKey(true /* keep key blob */));
- } else {
- auto delete_result = DeleteKey(true /* keep key blob */);
- ASSERT_TRUE(delete_result == ErrorCode::OK | delete_result == ErrorCode::UNIMPLEMENTED);
- }
- string message = "12345678901234567890123456789012";
- AuthorizationSet begin_out_params;
-
- if (rollback_protected) {
+ string message = "12345678901234567890123456789012";
+ AuthorizationSet begin_out_params;
EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
Begin(KeyPurpose::SIGN, key_blob_,
AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
&begin_out_params, &op_handle_));
- } else {
- EXPECT_EQ(ErrorCode::OK,
- Begin(KeyPurpose::SIGN, key_blob_,
- AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
- &begin_out_params, &op_handle_));
+ AbortIfNeeded();
+ key_blob_ = HidlBuf();
}
- AbortIfNeeded();
- key_blob_ = HidlBuf();
}
/**
* KeyDeletionTest.DeleteInvalidKey
*
- * This test checks that the HAL excepts invalid key blobs.
- *
- * TODO(swillden): Update to incorporate changes in rollback resistance semantics.
+ * This test checks that the HAL excepts invalid key blobs..
*/
TEST_F(KeyDeletionTest, DeleteInvalidKey) {
// Generate key just to check if rollback protection is implemented
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(2048, 65537)
- .Digest(Digest::NONE)
- .Padding(PaddingMode::NONE)
- .Authorization(TAG_NO_AUTH_REQUIRED)));
+ auto error = GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_ROLLBACK_RESISTANCE));
+ ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
// Delete must work if rollback protection is implemented
- AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
- bool rollback_protected = hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE);
+ if (error == ErrorCode::OK) {
+ AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+ ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
- // Delete the key we don't care about the result at this point.
- DeleteKey();
+ // Delete the key we don't care about the result at this point.
+ DeleteKey();
- // Now create an invalid key blob and delete it.
- key_blob_ = HidlBuf("just some garbage data which is not a valid key blob");
+ // Now create an invalid key blob and delete it.
+ key_blob_ = HidlBuf("just some garbage data which is not a valid key blob");
- if (rollback_protected) {
ASSERT_EQ(ErrorCode::OK, DeleteKey());
- } else {
- auto delete_result = DeleteKey();
- ASSERT_TRUE(delete_result == ErrorCode::OK | delete_result == ErrorCode::UNIMPLEMENTED);
}
}
@@ -4421,39 +4407,34 @@
* device has been wiped manually (e.g., fastboot flashall -w), and new FBE/FDE keys have
* been provisioned. Use this test only on dedicated testing devices that have no valuable
* credentials stored in Keystore/Keymaster.
- *
- * TODO(swillden): Update to incorporate changes in rollback resistance semantics.
*/
TEST_F(KeyDeletionTest, DeleteAllKeys) {
if (!arm_deleteAllKeys) return;
- ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
- .RsaSigningKey(2048, 65537)
- .Digest(Digest::NONE)
- .Padding(PaddingMode::NONE)
- .Authorization(TAG_NO_AUTH_REQUIRED)));
+ auto error = GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_ROLLBACK_RESISTANCE));
+ ASSERT_TRUE(error == ErrorCode::ROLLBACK_RESISTANCE_UNAVAILABLE || error == ErrorCode::OK);
// Delete must work if rollback protection is implemented
- AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
- bool rollback_protected = hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE);
+ if (error == ErrorCode::OK) {
+ AuthorizationSet hardwareEnforced(key_characteristics_.hardwareEnforced);
+ ASSERT_TRUE(hardwareEnforced.Contains(TAG_ROLLBACK_RESISTANCE));
- ASSERT_EQ(ErrorCode::OK, DeleteAllKeys());
+ ASSERT_EQ(ErrorCode::OK, DeleteAllKeys());
- string message = "12345678901234567890123456789012";
- AuthorizationSet begin_out_params;
+ string message = "12345678901234567890123456789012";
+ AuthorizationSet begin_out_params;
- if (rollback_protected) {
EXPECT_EQ(ErrorCode::INVALID_KEY_BLOB,
Begin(KeyPurpose::SIGN, key_blob_,
AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
&begin_out_params, &op_handle_));
- } else {
- EXPECT_EQ(ErrorCode::OK,
- Begin(KeyPurpose::SIGN, key_blob_,
- AuthorizationSetBuilder().Digest(Digest::NONE).Padding(PaddingMode::NONE),
- &begin_out_params, &op_handle_));
+ AbortIfNeeded();
+ key_blob_ = HidlBuf();
}
- AbortIfNeeded();
- key_blob_ = HidlBuf();
}
using UpgradeKeyTest = KeymasterHidlTest;
diff --git a/media/omx/1.0/vts/functional/README.md b/media/omx/1.0/vts/functional/README.md
index acffc42..274b30d 100644
--- a/media/omx/1.0/vts/functional/README.md
+++ b/media/omx/1.0/vts/functional/README.md
@@ -18,17 +18,17 @@
usage:
-VtsHalMediaOmxV1\_0TargetAudioDecTest -I default -C <comp name> -R audio_decoder.<comp class> -P /sdcard/media/
+VtsHalMediaOmxV1\_0TargetAudioDecTest -I default -C <comp name> -R audio_decoder.<comp class> -P /data/local/tmp/media/
-VtsHalMediaOmxV1\_0TargetAudioEncTest -I default -C <comp name> -R audio_encoder.<comp class> -P /sdcard/media/
+VtsHalMediaOmxV1\_0TargetAudioEncTest -I default -C <comp name> -R audio_encoder.<comp class> -P /data/local/tmp/media/
#### video :
This folder includes test fixtures associated with testing video encoder and decoder components such as simple encoding of a raw clip or decoding of an elementary stream, end of stream test, timestamp deviations test, flush test and so on. These tests are aimed towards testing the plugin that connects the component to the omx core.
usage:
-VtsHalMediaOmxV1\_0TargetVideoDecTest -I default -C <comp name> -R video_decoder.<comp class> -P /sdcard/media/
+VtsHalMediaOmxV1\_0TargetVideoDecTest -I default -C <comp name> -R video_decoder.<comp class> -P /data/local/tmp/media/
-VtsHalMediaOmxV1\_0TargetVideoEncTest -I default -C <comp name> -R video_encoder.<comp class> -P /sdcard/media/
+VtsHalMediaOmxV1\_0TargetVideoEncTest -I default -C <comp name> -R video_encoder.<comp class> -P /data/local/tmp/media/
-While tesing audio/video encoder, decoder components, test fixtures require input files. These input are files are present in the folder 'res'. Before running the tests all the files in 'res' have to be placed in '/media/sdcard/' or a path of your choice and this path needs to be provided as an argument to the test application
\ No newline at end of file
+While tesing audio/video encoder, decoder components, test fixtures require input files. These input are files are present in the folder 'res'. Before running the tests all the files in 'res' have to be placed in '/data/local/tmp/media' or a path of your choice and this path needs to be provided as an argument to the test application
diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
index 08af26b..ac077a3 100644
--- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
+++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
@@ -408,7 +408,7 @@
public:
virtual void registerTestServices() override { registerTestService<IOmx>(); }
- ComponentTestEnvironment() : res("/sdcard/media/") {}
+ ComponentTestEnvironment() : res("/data/local/tmp/media/") {}
void setComponent(const char* _component) { component = _component; }
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index a8406de..abff213 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -32,12 +32,11 @@
"android.hidl.memory@1.0",
"libgmock",
"libhidlmemory",
+ "libneuralnetworks_generated_test_harness",
"libneuralnetworks_utils",
],
header_libs: [
"libneuralnetworks_headers",
- "libneuralnetworks_generated_test_harness_headers",
- "libneuralnetworks_generated_tests",
],
}
@@ -60,13 +59,12 @@
"android.hidl.memory@1.0",
"libgmock",
"libhidlmemory",
+ "libneuralnetworks_generated_test_harness",
"libneuralnetworks_utils",
"VtsHalNeuralNetworksV1_0_utils",
],
header_libs: [
"libneuralnetworks_headers",
- "libneuralnetworks_generated_test_harness_headers",
- "libneuralnetworks_generated_tests",
],
test_suites: ["general-tests"],
}
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index 40d2f4c..0fd9947 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -15,6 +15,7 @@
*/
#include "GeneratedTestHarness.h"
+
#include "1.0/Callbacks.h"
#include "1.0/Utils.h"
#include "MemoryUtils.h"
@@ -28,6 +29,7 @@
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
+#include <gtest/gtest.h>
#include <iostream>
namespace android {
@@ -36,6 +38,7 @@
namespace V1_0 {
namespace generated_tests {
+using namespace test_helper;
using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
using ::android::hardware::neuralnetworks::V1_0::IDevice;
using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
@@ -45,137 +48,111 @@
using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
using ::android::hardware::neuralnetworks::V1_0::implementation::PreparedModelCallback;
using ::android::hidl::memory::V1_0::IMemory;
-using ::test_helper::compare;
-using ::test_helper::filter;
-using ::test_helper::for_all;
-using ::test_helper::MixedTyped;
-using ::test_helper::MixedTypedExample;
-using ::test_helper::resize_accordingly;
+
+Model createModel(const TestModel& testModel) {
+ // Model operands.
+ hidl_vec<Operand> operands(testModel.operands.size());
+ size_t constCopySize = 0, constRefSize = 0;
+ for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+ const auto& op = testModel.operands[i];
+
+ DataLocation loc = {};
+ if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
+ loc = {.poolIndex = 0,
+ .offset = static_cast<uint32_t>(constCopySize),
+ .length = static_cast<uint32_t>(op.data.size())};
+ constCopySize += op.data.alignedSize();
+ } else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
+ loc = {.poolIndex = 0,
+ .offset = static_cast<uint32_t>(constRefSize),
+ .length = static_cast<uint32_t>(op.data.size())};
+ constRefSize += op.data.alignedSize();
+ }
+
+ operands[i] = {.type = static_cast<OperandType>(op.type),
+ .dimensions = op.dimensions,
+ .numberOfConsumers = op.numberOfConsumers,
+ .scale = op.scale,
+ .zeroPoint = op.zeroPoint,
+ .lifetime = static_cast<OperandLifeTime>(op.lifetime),
+ .location = loc};
+ }
+
+ // Model operations.
+ hidl_vec<Operation> operations(testModel.operations.size());
+ std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(),
+ [](const TestOperation& op) -> Operation {
+ return {.type = static_cast<OperationType>(op.type),
+ .inputs = op.inputs,
+ .outputs = op.outputs};
+ });
+
+ // Constant copies.
+ hidl_vec<uint8_t> operandValues(constCopySize);
+ for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+ const auto& op = testModel.operands[i];
+ if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
+ const uint8_t* begin = op.data.get<uint8_t>();
+ const uint8_t* end = begin + op.data.size();
+ std::copy(begin, end, operandValues.data() + operands[i].location.offset);
+ }
+ }
+
+ // Shared memory.
+ hidl_vec<hidl_memory> pools;
+ if (constRefSize > 0) {
+ hidl_vec_push_back(&pools, nn::allocateSharedMemory(constRefSize));
+ CHECK_NE(pools[0].size(), 0u);
+
+ // load data
+ sp<IMemory> mappedMemory = mapMemory(pools[0]);
+ CHECK(mappedMemory.get() != nullptr);
+ uint8_t* mappedPtr =
+ reinterpret_cast<uint8_t*>(static_cast<void*>(mappedMemory->getPointer()));
+ CHECK(mappedPtr != nullptr);
+
+ for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+ const auto& op = testModel.operands[i];
+ if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
+ const uint8_t* begin = op.data.get<uint8_t>();
+ const uint8_t* end = begin + op.data.size();
+ std::copy(begin, end, mappedPtr + operands[i].location.offset);
+ }
+ }
+ }
+
+ return {.operands = std::move(operands),
+ .operations = std::move(operations),
+ .inputIndexes = testModel.inputIndexes,
+ .outputIndexes = testModel.outputIndexes,
+ .operandValues = std::move(operandValues),
+ .pools = std::move(pools)};
+}
// Top level driver for models and examples generated by test_generator.py
// Test driver for those generated from ml/nn/runtime/test/spec
-void EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
- const std::vector<MixedTypedExample>& examples, float fpAtol,
- float fpRtol) {
- const uint32_t INPUT = 0;
- const uint32_t OUTPUT = 1;
+void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel) {
+ const Request request = createRequest(testModel);
- int example_no = 1;
- for (auto& example : examples) {
- SCOPED_TRACE(example_no++);
- const MixedTyped& inputs = example.operands.first;
- const MixedTyped& golden = example.operands.second;
+ // Launch execution.
+ sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+ Return<ErrorStatus> executionLaunchStatus = preparedModel->execute(request, executionCallback);
+ ASSERT_TRUE(executionLaunchStatus.isOk());
+ EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
- CHECK(inputs.float16Operands.empty()) << "float16 is not supported in 1.0";
+ // Retrieve execution status.
+ executionCallback->wait();
+ ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus());
- std::vector<RequestArgument> inputs_info, outputs_info;
- uint32_t inputSize = 0, outputSize = 0;
- // This function only partially specifies the metadata (vector of RequestArguments).
- // The contents are copied over below.
- for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
- if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
- RequestArgument arg = {
- .location = {.poolIndex = INPUT,
- .offset = 0,
- .length = static_cast<uint32_t>(s)},
- .dimensions = {},
- };
- RequestArgument arg_empty = {
- .hasNoValue = true,
- };
- inputs_info[index] = s ? arg : arg_empty;
- inputSize += s;
- });
- // Compute offset for inputs 1 and so on
- {
- size_t offset = 0;
- for (auto& i : inputs_info) {
- if (!i.hasNoValue) i.location.offset = offset;
- offset += i.location.length;
- }
- }
+ // Retrieve execution results.
+ const std::vector<TestBuffer> outputs = getOutputBuffers(request);
- MixedTyped test; // holding test results
-
- // Go through all outputs, initialize RequestArgument descriptors
- resize_accordingly(golden, test);
- for_all(golden, [&outputs_info, &outputSize](int index, auto, auto s) {
- if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
- RequestArgument arg = {
- .location = {.poolIndex = OUTPUT,
- .offset = 0,
- .length = static_cast<uint32_t>(s)},
- .dimensions = {},
- };
- outputs_info[index] = arg;
- outputSize += s;
- });
- // Compute offset for outputs 1 and so on
- {
- size_t offset = 0;
- for (auto& i : outputs_info) {
- i.location.offset = offset;
- offset += i.location.length;
- }
- }
- std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
- nn::allocateSharedMemory(outputSize)};
- ASSERT_NE(0ull, pools[INPUT].size());
- ASSERT_NE(0ull, pools[OUTPUT].size());
-
- // load data
- sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
- sp<IMemory> outputMemory = mapMemory(pools[OUTPUT]);
- ASSERT_NE(nullptr, inputMemory.get());
- ASSERT_NE(nullptr, outputMemory.get());
- char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
- char* outputPtr = reinterpret_cast<char*>(static_cast<void*>(outputMemory->getPointer()));
- ASSERT_NE(nullptr, inputPtr);
- ASSERT_NE(nullptr, outputPtr);
- inputMemory->update();
- outputMemory->update();
-
- // Go through all inputs, copy the values
- for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
- char* begin = (char*)p;
- char* end = begin + s;
- // TODO: handle more than one input
- std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
- });
-
- inputMemory->commit();
- outputMemory->commit();
-
- const Request request = {.inputs = inputs_info, .outputs = outputs_info, .pools = pools};
-
- // launch execution
- sp<ExecutionCallback> executionCallback = new ExecutionCallback();
- ASSERT_NE(nullptr, executionCallback.get());
- Return<ErrorStatus> executionLaunchStatus =
- preparedModel->execute(request, executionCallback);
- ASSERT_TRUE(executionLaunchStatus.isOk());
- EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
-
- // retrieve execution status
- executionCallback->wait();
- ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus());
-
- // validate results
- outputMemory->read();
- copy_back(&test, outputs_info, outputPtr);
- outputMemory->commit();
- // Filter out don't cares
- MixedTyped filtered_golden = filter(golden, is_ignored);
- MixedTyped filtered_test = filter(test, is_ignored);
-
- // We want "close-enough" results for float
- compare(filtered_golden, filtered_test, fpAtol, fpRtol);
- }
+ // We want "close-enough" results.
+ checkResults(testModel, outputs);
}
-void Execute(const sp<IDevice>& device, std::function<Model(void)> create_model,
- std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples) {
- Model model = create_model();
+void Execute(const sp<IDevice>& device, const TestModel& testModel) {
+ Model model = createModel(testModel);
// see if service can handle model
bool fullySupportsModel = false;
@@ -190,7 +167,6 @@
// launch prepare model
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
- ASSERT_NE(nullptr, preparedModelCallback.get());
Return<ErrorStatus> prepareLaunchStatus = device->prepareModel(model, preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk());
ASSERT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(prepareLaunchStatus));
@@ -213,8 +189,7 @@
EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
ASSERT_NE(nullptr, preparedModel.get());
- float fpAtol = 1e-5f, fpRtol = 5.0f * 1.1920928955078125e-7f;
- EvaluatePreparedModel(preparedModel, is_ignored, examples, fpAtol, fpRtol);
+ EvaluatePreparedModel(preparedModel, testModel);
}
} // namespace generated_tests
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
index 337eb0f..5d22158 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
@@ -26,10 +26,9 @@
namespace V1_0 {
namespace generated_tests {
-using ::test_helper::MixedTypedExample;
+Model createModel(const ::test_helper::TestModel& testModel);
-void Execute(const sp<V1_0::IDevice>& device, std::function<V1_0::Model(void)> create_model,
- std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples);
+void Execute(const sp<V1_0::IDevice>& device, const ::test_helper::TestModel& testModel);
} // namespace generated_tests
} // namespace V1_0
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTests.h b/neuralnetworks/1.0/vts/functional/GeneratedTests.h
index 5cabf68..9528905 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTests.h
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTests.h
@@ -14,20 +14,11 @@
* limitations under the License.
*/
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
+#include "1.0/Utils.h"
#include "GeneratedTestHarness.h"
-#include "MemoryUtils.h"
#include "TestHarness.h"
#include "VtsHalNeuralnetworks.h"
-namespace android::hardware::neuralnetworks::V1_0::vts::functional {
-
-std::vector<Request> createRequests(const std::vector<::test_helper::MixedTypedExample>& examples);
-
-} // namespace android::hardware::neuralnetworks::V1_0::vts::functional
-
namespace android::hardware::neuralnetworks::V1_0::generated_tests {
using namespace android::hardware::neuralnetworks::V1_0::vts::functional;
diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp
index 521e524..5aa2751 100644
--- a/neuralnetworks/1.0/vts/functional/Utils.cpp
+++ b/neuralnetworks/1.0/vts/functional/Utils.cpp
@@ -14,45 +14,108 @@
* limitations under the License.
*/
-#include "GeneratedTestHarness.h"
+#include "1.0/Utils.h"
+
+#include "MemoryUtils.h"
#include "TestHarness.h"
+#include <android-base/logging.h>
#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <hidlmemory/mapping.h>
-#include <cstring>
-#include <map>
+#include <algorithm>
#include <vector>
namespace android {
namespace hardware {
namespace neuralnetworks {
+using namespace test_helper;
+using ::android::hardware::neuralnetworks::V1_0::DataLocation;
+using ::android::hardware::neuralnetworks::V1_0::Request;
using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
-using ::test_helper::for_each;
-using ::test_helper::MixedTyped;
+using ::android::hidl::memory::V1_0::IMemory;
-template <typename T>
-void copy_back_(std::map<int, std::vector<T>>* dst, const std::vector<RequestArgument>& ra,
- char* src) {
- for_each<T>(*dst, [&ra, src](int index, std::vector<T>& m) {
- ASSERT_EQ(m.size(), ra[index].location.length / sizeof(T));
- char* begin = src + ra[index].location.offset;
- memcpy(m.data(), begin, ra[index].location.length);
- });
+constexpr uint32_t kInputPoolIndex = 0;
+constexpr uint32_t kOutputPoolIndex = 1;
+
+Request createRequest(const TestModel& testModel) {
+ // Model inputs.
+ hidl_vec<RequestArgument> inputs(testModel.inputIndexes.size());
+ size_t inputSize = 0;
+ for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
+ const auto& op = testModel.operands[testModel.inputIndexes[i]];
+ if (op.data.size() == 0) {
+ // Omitted input.
+ inputs[i] = {.hasNoValue = true};
+ } else {
+ DataLocation loc = {.poolIndex = kInputPoolIndex,
+ .offset = static_cast<uint32_t>(inputSize),
+ .length = static_cast<uint32_t>(op.data.size())};
+ inputSize += op.data.alignedSize();
+ inputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
+ }
+ }
+
+ // Model outputs.
+ hidl_vec<RequestArgument> outputs(testModel.outputIndexes.size());
+ size_t outputSize = 0;
+ for (uint32_t i = 0; i < testModel.outputIndexes.size(); i++) {
+ const auto& op = testModel.operands[testModel.outputIndexes[i]];
+
+ // In the case of zero-sized output, we should at least provide a one-byte buffer.
+ // This is because zero-sized tensors are only supported internally to the driver, or
+ // reported in output shapes. It is illegal for the client to pre-specify a zero-sized
+ // tensor as model output. Otherwise, we will have two semantic conflicts:
+ // - "Zero dimension" conflicts with "unspecified dimension".
+ // - "Omitted operand buffer" conflicts with "zero-sized operand buffer".
+ size_t bufferSize = std::max<size_t>(op.data.size(), 1);
+
+ DataLocation loc = {.poolIndex = kOutputPoolIndex,
+ .offset = static_cast<uint32_t>(outputSize),
+ .length = static_cast<uint32_t>(bufferSize)};
+ outputSize += op.data.size() == 0 ? TestBuffer::kAlignment : op.data.alignedSize();
+ outputs[i] = {.hasNoValue = false, .location = loc, .dimensions = {}};
+ }
+
+ // 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);
+
+ // Copy input data to the memory pool.
+ for (uint32_t i = 0; i < testModel.inputIndexes.size(); i++) {
+ const auto& op = testModel.operands[testModel.inputIndexes[i]];
+ if (op.data.size() > 0) {
+ const uint8_t* begin = op.data.get<uint8_t>();
+ const uint8_t* end = begin + op.data.size();
+ std::copy(begin, end, inputPtr + inputs[i].location.offset);
+ }
+ }
+
+ return {.inputs = std::move(inputs), .outputs = std::move(outputs), .pools = std::move(pools)};
}
-void copy_back(MixedTyped* dst, const std::vector<RequestArgument>& ra, char* src) {
- copy_back_(&dst->float32Operands, ra, src);
- copy_back_(&dst->int32Operands, ra, src);
- copy_back_(&dst->quant8AsymmOperands, ra, src);
- copy_back_(&dst->quant16SymmOperands, ra, src);
- copy_back_(&dst->float16Operands, ra, src);
- copy_back_(&dst->bool8Operands, ra, src);
- copy_back_(&dst->quant8ChannelOperands, ra, src);
- copy_back_(&dst->quant16AsymmOperands, ra, src);
- copy_back_(&dst->quant8SymmOperands, ra, src);
- static_assert(9 == MixedTyped::kNumTypes,
- "Number of types in MixedTyped changed, but copy_back function wasn't updated");
+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);
+
+ // Copy out output results.
+ std::vector<TestBuffer> outputBuffers;
+ for (const auto& output : request.outputs) {
+ outputBuffers.emplace_back(output.location.length, outputPtr + output.location.offset);
+ }
+
+ return outputBuffers;
}
} // namespace neuralnetworks
diff --git a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
index 058eb25..d62365c 100644
--- a/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.0/vts/functional/ValidateRequest.cpp
@@ -16,13 +16,7 @@
#define LOG_TAG "neuralnetworks_hidl_hal_test"
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
#include "1.0/Callbacks.h"
-#include "MemoryUtils.h"
-#include "TestHarness.h"
#include "VtsHalNeuralnetworks.h"
namespace android {
@@ -33,10 +27,6 @@
namespace functional {
using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
-using ::android::hidl::memory::V1_0::IMemory;
-using test_helper::for_all;
-using test_helper::MixedTyped;
-using test_helper::MixedTypedExample;
///////////////////////// UTILITY FUNCTIONS /////////////////////////
@@ -102,103 +92,10 @@
///////////////////////////// ENTRY POINT //////////////////////////////////
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples) {
- const uint32_t INPUT = 0;
- const uint32_t OUTPUT = 1;
-
- std::vector<Request> requests;
-
- for (const MixedTypedExample& example : examples) {
- const MixedTyped& inputs = example.operands.first;
- const MixedTyped& outputs = example.operands.second;
-
- std::vector<RequestArgument> inputs_info, outputs_info;
- uint32_t inputSize = 0, outputSize = 0;
-
- // This function only partially specifies the metadata (vector of RequestArguments).
- // The contents are copied over below.
- for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
- if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
- RequestArgument arg = {
- .location = {.poolIndex = INPUT,
- .offset = 0,
- .length = static_cast<uint32_t>(s)},
- .dimensions = {},
- };
- RequestArgument arg_empty = {
- .hasNoValue = true,
- };
- inputs_info[index] = s ? arg : arg_empty;
- inputSize += s;
- });
- // Compute offset for inputs 1 and so on
- {
- size_t offset = 0;
- for (auto& i : inputs_info) {
- if (!i.hasNoValue) i.location.offset = offset;
- offset += i.location.length;
- }
- }
-
- // Go through all outputs, initialize RequestArgument descriptors
- for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) {
- if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
- RequestArgument arg = {
- .location = {.poolIndex = OUTPUT,
- .offset = 0,
- .length = static_cast<uint32_t>(s)},
- .dimensions = {},
- };
- outputs_info[index] = arg;
- outputSize += s;
- });
- // Compute offset for outputs 1 and so on
- {
- size_t offset = 0;
- for (auto& i : outputs_info) {
- i.location.offset = offset;
- offset += i.location.length;
- }
- }
- std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
- nn::allocateSharedMemory(outputSize)};
- if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
- return {};
- }
-
- // map pool
- sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
- if (inputMemory == nullptr) {
- return {};
- }
- char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
- if (inputPtr == nullptr) {
- return {};
- }
-
- // initialize pool
- inputMemory->update();
- for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
- char* begin = (char*)p;
- char* end = begin + s;
- // TODO: handle more than one input
- std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
- });
- inputMemory->commit();
-
- requests.push_back({.inputs = inputs_info, .outputs = outputs_info, .pools = pools});
- }
-
- return requests;
-}
-
-void ValidationTest::validateRequests(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests) {
- // validate each request
- for (const Request& request : requests) {
- removeInputTest(preparedModel, request);
- removeOutputTest(preparedModel, request);
- }
+void ValidationTest::validateRequest(const sp<IPreparedModel>& preparedModel,
+ const Request& request) {
+ removeInputTest(preparedModel, request);
+ removeOutputTest(preparedModel, request);
}
} // namespace functional
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
index 95b7ad3..626deac 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
@@ -121,7 +121,7 @@
::testing::VtsHalHidlTargetTestBase::TearDown();
}
-void ValidationTest::validateEverything(const Model& model, const std::vector<Request>& requests) {
+void ValidationTest::validateEverything(const Model& model, const Request& request) {
validateModel(model);
// create IPreparedModel
@@ -131,7 +131,7 @@
return;
}
- validateRequests(preparedModel, requests);
+ validateRequest(preparedModel, request);
}
} // namespace functional
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
index c32a91d..3765314 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
@@ -63,12 +63,11 @@
// Tag for the validation tests
class ValidationTest : public NeuralnetworksHidlTest {
protected:
- void validateEverything(const Model& model, const std::vector<Request>& request);
+ void validateEverything(const Model& model, const Request& request);
private:
void validateModel(const Model& model);
- void validateRequests(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests);
+ void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request);
};
// Tag for the generated tests
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 b270c20..2955b6e 100644
--- a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
+++ b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
@@ -26,8 +26,11 @@
namespace hardware {
namespace neuralnetworks {
-void copy_back(::test_helper::MixedTyped* dst, const std::vector<V1_0::RequestArgument>& ra,
- char* src);
+// Create HIDL Request from the TestModel struct.
+V1_0::Request createRequest(const ::test_helper::TestModel& testModel);
+
+// After execution, copy out output results from the output memory pool.
+std::vector<::test_helper::TestBuffer> getOutputBuffers(const V1_0::Request& request);
// 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/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index 1b31008..86002d2 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -34,13 +34,12 @@
"android.hidl.memory@1.0",
"libgmock",
"libhidlmemory",
+ "libneuralnetworks_generated_test_harness",
"libneuralnetworks_utils",
"VtsHalNeuralNetworksV1_0_utils",
],
header_libs: [
"libneuralnetworks_headers",
- "libneuralnetworks_generated_test_harness_headers",
- "libneuralnetworks_generated_tests",
],
test_suites: ["general-tests"],
}
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
index e7d59ec..73eeb93 100644
--- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
@@ -24,6 +24,7 @@
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
+#include <gtest/gtest.h>
#include <iostream>
#include "1.0/Callbacks.h"
@@ -37,8 +38,13 @@
namespace V1_1 {
namespace generated_tests {
+using namespace test_helper;
+using ::android::hardware::neuralnetworks::V1_0::DataLocation;
using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
using ::android::hardware::neuralnetworks::V1_0::IPreparedModel;
+using ::android::hardware::neuralnetworks::V1_0::Operand;
+using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
+using ::android::hardware::neuralnetworks::V1_0::OperandType;
using ::android::hardware::neuralnetworks::V1_0::Request;
using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
@@ -47,144 +53,112 @@
using ::android::hardware::neuralnetworks::V1_1::IDevice;
using ::android::hardware::neuralnetworks::V1_1::Model;
using ::android::hidl::memory::V1_0::IMemory;
-using ::test_helper::compare;
-using ::test_helper::filter;
-using ::test_helper::for_all;
-using ::test_helper::MixedTyped;
-using ::test_helper::MixedTypedExample;
-using ::test_helper::resize_accordingly;
+
+Model createModel(const TestModel& testModel) {
+ // Model operands.
+ hidl_vec<Operand> operands(testModel.operands.size());
+ size_t constCopySize = 0, constRefSize = 0;
+ for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+ const auto& op = testModel.operands[i];
+
+ DataLocation loc = {};
+ if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
+ loc = {.poolIndex = 0,
+ .offset = static_cast<uint32_t>(constCopySize),
+ .length = static_cast<uint32_t>(op.data.size())};
+ constCopySize += op.data.alignedSize();
+ } else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
+ loc = {.poolIndex = 0,
+ .offset = static_cast<uint32_t>(constRefSize),
+ .length = static_cast<uint32_t>(op.data.size())};
+ constRefSize += op.data.alignedSize();
+ }
+
+ operands[i] = {.type = static_cast<OperandType>(op.type),
+ .dimensions = op.dimensions,
+ .numberOfConsumers = op.numberOfConsumers,
+ .scale = op.scale,
+ .zeroPoint = op.zeroPoint,
+ .lifetime = static_cast<OperandLifeTime>(op.lifetime),
+ .location = loc};
+ }
+
+ // Model operations.
+ hidl_vec<Operation> operations(testModel.operations.size());
+ std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(),
+ [](const TestOperation& op) -> Operation {
+ return {.type = static_cast<OperationType>(op.type),
+ .inputs = op.inputs,
+ .outputs = op.outputs};
+ });
+
+ // Constant copies.
+ hidl_vec<uint8_t> operandValues(constCopySize);
+ for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+ const auto& op = testModel.operands[i];
+ if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
+ const uint8_t* begin = op.data.get<uint8_t>();
+ const uint8_t* end = begin + op.data.size();
+ std::copy(begin, end, operandValues.data() + operands[i].location.offset);
+ }
+ }
+
+ // Shared memory.
+ hidl_vec<hidl_memory> pools;
+ if (constRefSize > 0) {
+ hidl_vec_push_back(&pools, nn::allocateSharedMemory(constRefSize));
+ CHECK_NE(pools[0].size(), 0u);
+
+ // load data
+ sp<IMemory> mappedMemory = mapMemory(pools[0]);
+ CHECK(mappedMemory.get() != nullptr);
+ uint8_t* mappedPtr =
+ reinterpret_cast<uint8_t*>(static_cast<void*>(mappedMemory->getPointer()));
+ CHECK(mappedPtr != nullptr);
+
+ for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+ const auto& op = testModel.operands[i];
+ if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
+ const uint8_t* begin = op.data.get<uint8_t>();
+ const uint8_t* end = begin + op.data.size();
+ std::copy(begin, end, mappedPtr + operands[i].location.offset);
+ }
+ }
+ }
+
+ return {.operands = std::move(operands),
+ .operations = std::move(operations),
+ .inputIndexes = testModel.inputIndexes,
+ .outputIndexes = testModel.outputIndexes,
+ .operandValues = std::move(operandValues),
+ .pools = std::move(pools),
+ .relaxComputationFloat32toFloat16 = testModel.isRelaxed};
+}
// Top level driver for models and examples generated by test_generator.py
// Test driver for those generated from ml/nn/runtime/test/spec
-void EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
- const std::vector<MixedTypedExample>& examples,
- bool hasRelaxedFloat32Model, float fpAtol, float fpRtol) {
- const uint32_t INPUT = 0;
- const uint32_t OUTPUT = 1;
+void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel) {
+ const Request request = createRequest(testModel);
- int example_no = 1;
- for (auto& example : examples) {
- SCOPED_TRACE(example_no++);
- const MixedTyped& inputs = example.operands.first;
- const MixedTyped& golden = example.operands.second;
+ // Launch execution.
+ sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+ Return<ErrorStatus> executionLaunchStatus = preparedModel->execute(request, executionCallback);
+ ASSERT_TRUE(executionLaunchStatus.isOk());
+ EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
- const bool hasFloat16Inputs = !inputs.float16Operands.empty();
- if (hasRelaxedFloat32Model || hasFloat16Inputs) {
- // TODO: Adjust the error limit based on testing.
- // If in relaxed mode, set the absolute tolerance to be 5ULP of FP16.
- fpAtol = 5.0f * 0.0009765625f;
- // Set the relative tolerance to be 5ULP of the corresponding FP precision.
- fpRtol = 5.0f * 0.0009765625f;
- }
+ // Retrieve execution status.
+ executionCallback->wait();
+ ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus());
- std::vector<RequestArgument> inputs_info, outputs_info;
- uint32_t inputSize = 0, outputSize = 0;
- // This function only partially specifies the metadata (vector of RequestArguments).
- // The contents are copied over below.
- for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
- if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
- RequestArgument arg = {
- .location = {.poolIndex = INPUT,
- .offset = 0,
- .length = static_cast<uint32_t>(s)},
- .dimensions = {},
- };
- RequestArgument arg_empty = {
- .hasNoValue = true,
- };
- inputs_info[index] = s ? arg : arg_empty;
- inputSize += s;
- });
- // Compute offset for inputs 1 and so on
- {
- size_t offset = 0;
- for (auto& i : inputs_info) {
- if (!i.hasNoValue) i.location.offset = offset;
- offset += i.location.length;
- }
- }
+ // Retrieve execution results.
+ const std::vector<TestBuffer> outputs = getOutputBuffers(request);
- MixedTyped test; // holding test results
-
- // Go through all outputs, initialize RequestArgument descriptors
- resize_accordingly(golden, test);
- for_all(golden, [&outputs_info, &outputSize](int index, auto, auto s) {
- if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
- RequestArgument arg = {
- .location = {.poolIndex = OUTPUT,
- .offset = 0,
- .length = static_cast<uint32_t>(s)},
- .dimensions = {},
- };
- outputs_info[index] = arg;
- outputSize += s;
- });
- // Compute offset for outputs 1 and so on
- {
- size_t offset = 0;
- for (auto& i : outputs_info) {
- i.location.offset = offset;
- offset += i.location.length;
- }
- }
- std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
- nn::allocateSharedMemory(outputSize)};
- ASSERT_NE(0ull, pools[INPUT].size());
- ASSERT_NE(0ull, pools[OUTPUT].size());
-
- // load data
- sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
- sp<IMemory> outputMemory = mapMemory(pools[OUTPUT]);
- ASSERT_NE(nullptr, inputMemory.get());
- ASSERT_NE(nullptr, outputMemory.get());
- char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
- char* outputPtr = reinterpret_cast<char*>(static_cast<void*>(outputMemory->getPointer()));
- ASSERT_NE(nullptr, inputPtr);
- ASSERT_NE(nullptr, outputPtr);
- inputMemory->update();
- outputMemory->update();
-
- // Go through all inputs, copy the values
- for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
- char* begin = (char*)p;
- char* end = begin + s;
- // TODO: handle more than one input
- std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
- });
-
- inputMemory->commit();
- outputMemory->commit();
-
- const Request request = {.inputs = inputs_info, .outputs = outputs_info, .pools = pools};
-
- // launch execution
- sp<ExecutionCallback> executionCallback = new ExecutionCallback();
- ASSERT_NE(nullptr, executionCallback.get());
- Return<ErrorStatus> executionLaunchStatus =
- preparedModel->execute(request, executionCallback);
- ASSERT_TRUE(executionLaunchStatus.isOk());
- EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
-
- // retrieve execution status
- executionCallback->wait();
- ASSERT_EQ(ErrorStatus::NONE, executionCallback->getStatus());
-
- // validate results
- outputMemory->read();
- copy_back(&test, outputs_info, outputPtr);
- outputMemory->commit();
- // Filter out don't cares
- MixedTyped filtered_golden = filter(golden, is_ignored);
- MixedTyped filtered_test = filter(test, is_ignored);
-
- // We want "close-enough" results for float
- compare(filtered_golden, filtered_test, fpAtol, fpRtol);
- }
+ // We want "close-enough" results.
+ checkResults(testModel, outputs);
}
-void Execute(const sp<IDevice>& device, std::function<Model(void)> create_model,
- std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples) {
- Model model = create_model();
+void Execute(const sp<IDevice>& device, const TestModel& testModel) {
+ Model model = createModel(testModel);
// see if service can handle model
bool fullySupportsModel = false;
@@ -199,7 +173,6 @@
// launch prepare model
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
- ASSERT_NE(nullptr, preparedModelCallback.get());
Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_1(
model, ExecutionPreference::FAST_SINGLE_ANSWER, preparedModelCallback);
ASSERT_TRUE(prepareLaunchStatus.isOk());
@@ -223,8 +196,7 @@
EXPECT_EQ(ErrorStatus::NONE, prepareReturnStatus);
ASSERT_NE(nullptr, preparedModel.get());
- EvaluatePreparedModel(preparedModel, is_ignored, examples,
- model.relaxComputationFloat32toFloat16, 1e-5f, 1e-5f);
+ EvaluatePreparedModel(preparedModel, testModel);
}
} // namespace generated_tests
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
index 64b88dd..56fc825 100644
--- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
@@ -18,9 +18,6 @@
#define ANDROID_HARDWARE_NEURALNETWORKS_V1_1_GENERATED_TEST_HARNESS_H
#include <android/hardware/neuralnetworks/1.1/IDevice.h>
-#include <android/hardware/neuralnetworks/1.1/types.h>
-#include <functional>
-#include <vector>
#include "TestHarness.h"
namespace android {
@@ -29,9 +26,9 @@
namespace V1_1 {
namespace generated_tests {
-void Execute(const sp<V1_1::IDevice>& device, std::function<V1_1::Model(void)> create_model,
- std::function<bool(int)> is_ignored,
- const std::vector<::test_helper::MixedTypedExample>& examples);
+Model createModel(const ::test_helper::TestModel& testModel);
+
+void Execute(const sp<V1_1::IDevice>& device, const ::test_helper::TestModel& testModel);
} // namespace generated_tests
} // namespace V1_1
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTests.h b/neuralnetworks/1.1/vts/functional/GeneratedTests.h
index 80442bf..a55213d 100644
--- a/neuralnetworks/1.1/vts/functional/GeneratedTests.h
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTests.h
@@ -14,20 +14,11 @@
* limitations under the License.
*/
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
+#include "1.0/Utils.h"
#include "GeneratedTestHarness.h"
-#include "MemoryUtils.h"
#include "TestHarness.h"
#include "VtsHalNeuralnetworks.h"
-namespace android::hardware::neuralnetworks::V1_1::vts::functional {
-
-std::vector<Request> createRequests(const std::vector<::test_helper::MixedTypedExample>& examples);
-
-} // namespace android::hardware::neuralnetworks::V1_1::vts::functional
-
namespace android::hardware::neuralnetworks::V1_1::generated_tests {
using namespace android::hardware::neuralnetworks::V1_1::vts::functional;
diff --git a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
index c549728..757bee9 100644
--- a/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.1/vts/functional/ValidateRequest.cpp
@@ -16,14 +16,8 @@
#define LOG_TAG "neuralnetworks_hidl_hal_test"
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
#include "1.0/Callbacks.h"
#include "1.0/Utils.h"
-#include "MemoryUtils.h"
-#include "TestHarness.h"
#include "VtsHalNeuralnetworks.h"
namespace android {
@@ -35,13 +29,8 @@
using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
using ::android::hardware::neuralnetworks::V1_0::Request;
-using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
using ::android::hardware::neuralnetworks::V1_0::implementation::ExecutionCallback;
using ::android::hardware::neuralnetworks::V1_1::IPreparedModel;
-using ::android::hidl::memory::V1_0::IMemory;
-using ::test_helper::for_all;
-using ::test_helper::MixedTyped;
-using ::test_helper::MixedTypedExample;
///////////////////////// UTILITY FUNCTIONS /////////////////////////
@@ -87,103 +76,10 @@
///////////////////////////// ENTRY POINT //////////////////////////////////
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples) {
- const uint32_t INPUT = 0;
- const uint32_t OUTPUT = 1;
-
- std::vector<Request> requests;
-
- for (auto& example : examples) {
- const MixedTyped& inputs = example.operands.first;
- const MixedTyped& outputs = example.operands.second;
-
- std::vector<RequestArgument> inputs_info, outputs_info;
- uint32_t inputSize = 0, outputSize = 0;
-
- // This function only partially specifies the metadata (vector of RequestArguments).
- // The contents are copied over below.
- for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
- if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
- RequestArgument arg = {
- .location = {.poolIndex = INPUT,
- .offset = 0,
- .length = static_cast<uint32_t>(s)},
- .dimensions = {},
- };
- RequestArgument arg_empty = {
- .hasNoValue = true,
- };
- inputs_info[index] = s ? arg : arg_empty;
- inputSize += s;
- });
- // Compute offset for inputs 1 and so on
- {
- size_t offset = 0;
- for (auto& i : inputs_info) {
- if (!i.hasNoValue) i.location.offset = offset;
- offset += i.location.length;
- }
- }
-
- // Go through all outputs, initialize RequestArgument descriptors
- for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) {
- if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
- RequestArgument arg = {
- .location = {.poolIndex = OUTPUT,
- .offset = 0,
- .length = static_cast<uint32_t>(s)},
- .dimensions = {},
- };
- outputs_info[index] = arg;
- outputSize += s;
- });
- // Compute offset for outputs 1 and so on
- {
- size_t offset = 0;
- for (auto& i : outputs_info) {
- i.location.offset = offset;
- offset += i.location.length;
- }
- }
- std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
- nn::allocateSharedMemory(outputSize)};
- if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
- return {};
- }
-
- // map pool
- sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
- if (inputMemory == nullptr) {
- return {};
- }
- char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
- if (inputPtr == nullptr) {
- return {};
- }
-
- // initialize pool
- inputMemory->update();
- for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
- char* begin = (char*)p;
- char* end = begin + s;
- // TODO: handle more than one input
- std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
- });
- inputMemory->commit();
-
- requests.push_back({.inputs = inputs_info, .outputs = outputs_info, .pools = pools});
- }
-
- return requests;
-}
-
-void ValidationTest::validateRequests(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests) {
- // validate each request
- for (const Request& request : requests) {
- removeInputTest(preparedModel, request);
- removeOutputTest(preparedModel, request);
- }
+void ValidationTest::validateRequest(const sp<IPreparedModel>& preparedModel,
+ const Request& request) {
+ removeInputTest(preparedModel, request);
+ removeOutputTest(preparedModel, request);
}
} // namespace functional
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
index 12bdd3f..b3b15fa 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
@@ -122,7 +122,7 @@
::testing::VtsHalHidlTargetTestBase::TearDown();
}
-void ValidationTest::validateEverything(const Model& model, const std::vector<Request>& requests) {
+void ValidationTest::validateEverything(const Model& model, const Request& request) {
validateModel(model);
// create IPreparedModel
@@ -132,7 +132,7 @@
return;
}
- validateRequests(preparedModel, requests);
+ validateRequest(preparedModel, request);
}
} // namespace functional
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
index 3156784..2d6a20c 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
@@ -72,12 +72,11 @@
// Tag for the validation tests
class ValidationTest : public NeuralnetworksHidlTest {
protected:
- void validateEverything(const Model& model, const std::vector<Request>& request);
+ void validateEverything(const Model& model, const Request& request);
private:
void validateModel(const Model& model);
- void validateRequests(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests);
+ void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request);
};
// Tag for the generated tests
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 301ca5d..e14430f 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -37,13 +37,12 @@
"android.hidl.memory@1.0",
"libgmock",
"libhidlmemory",
+ "libneuralnetworks_generated_test_harness",
"libneuralnetworks_utils",
"VtsHalNeuralNetworksV1_0_utils",
],
header_libs: [
"libneuralnetworks_headers",
- "libneuralnetworks_generated_test_harness_headers",
- "libneuralnetworks_generated_tests",
],
test_suites: ["general-tests"],
}
@@ -75,8 +74,8 @@
srcs: [
"BasicTests.cpp",
":VtsHalNeuralNetworksV1_2_all_generated_V1_2_tests",
+ ":VtsHalNeuralNetworksV1_2_mobilenets",
"CompilationCachingTests.cpp",
- ":VtsHalNeuralNetworksV1_2_mobilenets", // CompilationCachingTests depend on MobileNets.
"ValidateBurst.cpp",
],
}
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 5907646..8747fb3 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -35,22 +35,14 @@
#include "Utils.h"
#include "VtsHalNeuralnetworks.h"
-namespace android::hardware::neuralnetworks::V1_2 {
+// Forward declaration of the mobilenet generated test models in
+// frameworks/ml/nn/runtime/test/generated/.
namespace generated_tests::mobilenet_224_gender_basic_fixed {
-Model createTestModel();
+const ::test_helper::TestModel& get_test_model();
} // namespace generated_tests::mobilenet_224_gender_basic_fixed
-} // namespace android::hardware::neuralnetworks::V1_2
-
-namespace generated_tests::mobilenet_224_gender_basic_fixed {
-std::vector<test_helper::MixedTypedExample>& get_examples();
-} // namespace generated_tests::mobilenet_224_gender_basic_fixed
-
-namespace android::hardware::neuralnetworks::V1_2::generated_tests::mobilenet_quantized {
-Model createTestModel();
-} // namespace android::hardware::neuralnetworks::V1_2::generated_tests::mobilenet_quantized
namespace generated_tests::mobilenet_quantized {
-std::vector<test_helper::MixedTypedExample>& get_examples();
+const ::test_helper::TestModel& get_test_model();
} // namespace generated_tests::mobilenet_quantized
namespace android {
@@ -60,49 +52,23 @@
namespace vts {
namespace functional {
+using namespace test_helper;
using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference;
using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
using ::android::hidl::memory::V1_0::IMemory;
using ::android::nn::allocateSharedMemory;
-using ::test_helper::MixedTypedExample;
namespace float32_model {
-constexpr auto createTestModel = ::android::hardware::neuralnetworks::V1_2::generated_tests::
- mobilenet_224_gender_basic_fixed::createTestModel;
-constexpr auto get_examples = ::generated_tests::mobilenet_224_gender_basic_fixed::get_examples;
-
-// MixedTypedExample is defined in frameworks/ml/nn/tools/test_generator/include/TestHarness.h.
-// This function assumes the operation is always ADD.
-std::vector<MixedTypedExample> getLargeModelExamples(uint32_t len) {
- float outputValue = 1.0f + static_cast<float>(len);
- return {{.operands = {
- // Input
- {.operandDimensions = {{0, {1}}}, .float32Operands = {{0, {1.0f}}}},
- // Output
- {.operandDimensions = {{0, {1}}}, .float32Operands = {{0, {outputValue}}}}}}};
-}
+constexpr auto get_test_model = ::generated_tests::mobilenet_224_gender_basic_fixed::get_test_model;
} // namespace float32_model
namespace quant8_model {
-constexpr auto createTestModel = ::android::hardware::neuralnetworks::V1_2::generated_tests::
- mobilenet_quantized::createTestModel;
-constexpr auto get_examples = ::generated_tests::mobilenet_quantized::get_examples;
-
-// MixedTypedExample is defined in frameworks/ml/nn/tools/test_generator/include/TestHarness.h.
-// This function assumes the operation is always ADD.
-std::vector<MixedTypedExample> getLargeModelExamples(uint32_t len) {
- uint8_t outputValue = 1 + static_cast<uint8_t>(len);
- return {{.operands = {// Input
- {.operandDimensions = {{0, {1}}}, .quant8AsymmOperands = {{0, {1}}}},
- // Output
- {.operandDimensions = {{0, {1}}},
- .quant8AsymmOperands = {{0, {outputValue}}}}}}};
-}
+constexpr auto get_test_model = ::generated_tests::mobilenet_quantized::get_test_model;
} // namespace quant8_model
@@ -155,39 +121,34 @@
// [1] [1] [1] [1]
//
// This function assumes the operation is either ADD or MUL.
-template <typename CppType, OperandType operandType>
-Model createLargeTestModelImpl(OperationType op, uint32_t len) {
- EXPECT_TRUE(op == OperationType::ADD || op == OperationType::MUL);
+template <typename CppType, TestOperandType operandType>
+TestModel createLargeTestModelImpl(TestOperationType op, uint32_t len) {
+ EXPECT_TRUE(op == TestOperationType::ADD || op == TestOperationType::MUL);
// Model operations and operands.
- std::vector<Operation> operations(len);
- std::vector<Operand> operands(len * 2 + 2);
-
- // The constant buffer pool. This contains the activation scalar, followed by the
- // per-operation constant operands.
- std::vector<uint8_t> operandValues(sizeof(int32_t) + len * sizeof(CppType));
+ std::vector<TestOperation> operations(len);
+ std::vector<TestOperand> operands(len * 2 + 2);
// The activation scalar, value = 0.
operands[0] = {
- .type = OperandType::INT32,
+ .type = TestOperandType::INT32,
.dimensions = {},
.numberOfConsumers = len,
.scale = 0.0f,
.zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0, .offset = 0, .length = sizeof(int32_t)},
+ .lifetime = TestOperandLifeTime::CONSTANT_COPY,
+ .data = TestBuffer::createFromVector<int32_t>({0}),
};
- memset(operandValues.data(), 0, sizeof(int32_t));
// The buffer value of the constant second operand. The logical value is always 1.0f.
CppType bufferValue;
// The scale of the first and second operand.
float scale1, scale2;
- if (operandType == OperandType::TENSOR_FLOAT32) {
+ if (operandType == TestOperandType::TENSOR_FLOAT32) {
bufferValue = 1.0f;
scale1 = 0.0f;
scale2 = 0.0f;
- } else if (op == OperationType::ADD) {
+ } else if (op == TestOperationType::ADD) {
bufferValue = 1;
scale1 = 1.0f;
scale2 = 1.0f;
@@ -211,9 +172,9 @@
.numberOfConsumers = 1,
.scale = scale1,
.zeroPoint = 0,
- .lifetime = (i == 0 ? OperandLifeTime::MODEL_INPUT
- : OperandLifeTime::TEMPORARY_VARIABLE),
- .location = {},
+ .lifetime = (i == 0 ? TestOperandLifeTime::MODEL_INPUT
+ : TestOperandLifeTime::TEMPORARY_VARIABLE),
+ .data = (i == 0 ? TestBuffer::createFromVector<CppType>({1}) : TestBuffer()),
};
// The second operation input, value = 1.
@@ -223,13 +184,9 @@
.numberOfConsumers = 1,
.scale = scale2,
.zeroPoint = 0,
- .lifetime = OperandLifeTime::CONSTANT_COPY,
- .location = {.poolIndex = 0,
- .offset = static_cast<uint32_t>(i * sizeof(CppType) + sizeof(int32_t)),
- .length = sizeof(CppType)},
+ .lifetime = TestOperandLifeTime::CONSTANT_COPY,
+ .data = TestBuffer::createFromVector<CppType>({bufferValue}),
};
- memcpy(operandValues.data() + sizeof(int32_t) + i * sizeof(CppType), &bufferValue,
- sizeof(CppType));
// The operation. All operations share the same activation scalar.
// The output operand is created as an input in the next iteration of the loop, in the case
@@ -242,6 +199,10 @@
};
}
+ // For TestOperationType::ADD, output = 1 + 1 * len = len + 1
+ // For TestOperationType::MUL, output = 1 * 1 ^ len = 1
+ CppType outputResult = static_cast<CppType>(op == TestOperationType::ADD ? len + 1u : 1u);
+
// The model output.
operands.back() = {
.type = operandType,
@@ -249,21 +210,16 @@
.numberOfConsumers = 0,
.scale = scale1,
.zeroPoint = 0,
- .lifetime = OperandLifeTime::MODEL_OUTPUT,
- .location = {},
+ .lifetime = TestOperandLifeTime::MODEL_OUTPUT,
+ .data = TestBuffer::createFromVector<CppType>({outputResult}),
};
- const std::vector<uint32_t> inputIndexes = {1};
- const std::vector<uint32_t> outputIndexes = {len * 2 + 1};
- const std::vector<hidl_memory> pools = {};
-
return {
- .operands = operands,
- .operations = operations,
- .inputIndexes = inputIndexes,
- .outputIndexes = outputIndexes,
- .operandValues = operandValues,
- .pools = pools,
+ .operands = std::move(operands),
+ .operations = std::move(operations),
+ .inputIndexes = {1},
+ .outputIndexes = {len * 2 + 1},
+ .isRelaxed = false,
};
}
@@ -332,35 +288,21 @@
// Model and examples creators. According to kOperandType, the following methods will return
// either float32 model/examples or the quant8 variant.
- Model createTestModel() {
+ TestModel createTestModel() {
if (kOperandType == OperandType::TENSOR_FLOAT32) {
- return float32_model::createTestModel();
+ return float32_model::get_test_model();
} else {
- return quant8_model::createTestModel();
+ return quant8_model::get_test_model();
}
}
- std::vector<MixedTypedExample> get_examples() {
+ TestModel createLargeTestModel(OperationType op, uint32_t len) {
if (kOperandType == OperandType::TENSOR_FLOAT32) {
- return float32_model::get_examples();
+ return createLargeTestModelImpl<float, TestOperandType::TENSOR_FLOAT32>(
+ static_cast<TestOperationType>(op), len);
} else {
- return quant8_model::get_examples();
- }
- }
-
- Model createLargeTestModel(OperationType op, uint32_t len) {
- if (kOperandType == OperandType::TENSOR_FLOAT32) {
- return createLargeTestModelImpl<float, OperandType::TENSOR_FLOAT32>(op, len);
- } else {
- return createLargeTestModelImpl<uint8_t, OperandType::TENSOR_QUANT8_ASYMM>(op, len);
- }
- }
-
- std::vector<MixedTypedExample> getLargeModelExamples(uint32_t len) {
- if (kOperandType == OperandType::TENSOR_FLOAT32) {
- return float32_model::getLargeModelExamples(len);
- } else {
- return quant8_model::getLargeModelExamples(len);
+ return createLargeTestModelImpl<uint8_t, TestOperandType::TENSOR_QUANT8_ASYMM>(
+ static_cast<TestOperationType>(op), len);
}
}
@@ -482,8 +424,9 @@
TEST_P(CompilationCachingTest, CacheSavingAndRetrieval) {
// Create test HIDL model and compile.
- const Model testModel = createTestModel();
- if (checkEarlyTermination(testModel)) return;
+ const TestModel& testModel = createTestModel();
+ const Model model = generated_tests::createModel(testModel);
+ if (checkEarlyTermination(model)) return;
sp<IPreparedModel> preparedModel = nullptr;
// Save the compilation to cache.
@@ -491,7 +434,7 @@
hidl_vec<hidl_handle> modelCache, dataCache;
createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
- saveModelToCache(testModel, modelCache, dataCache);
+ saveModelToCache(model, modelCache, dataCache);
}
// Retrieve preparedModel from cache.
@@ -516,15 +459,15 @@
}
// Execute and verify results.
- generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(),
- testModel.relaxComputationFloat32toFloat16,
+ generated_tests::EvaluatePreparedModel(preparedModel, testModel,
/*testDynamicOutputShape=*/false);
}
TEST_P(CompilationCachingTest, CacheSavingAndRetrievalNonZeroOffset) {
// Create test HIDL model and compile.
- const Model testModel = createTestModel();
- if (checkEarlyTermination(testModel)) return;
+ const TestModel& testModel = createTestModel();
+ const Model model = generated_tests::createModel(testModel);
+ if (checkEarlyTermination(model)) return;
sp<IPreparedModel> preparedModel = nullptr;
// Save the compilation to cache.
@@ -545,7 +488,7 @@
write(dataCache[i].getNativeHandle()->data[0], &dummyBytes, sizeof(dummyBytes)),
sizeof(dummyBytes));
}
- saveModelToCache(testModel, modelCache, dataCache);
+ saveModelToCache(model, modelCache, dataCache);
}
// Retrieve preparedModel from cache.
@@ -579,15 +522,15 @@
}
// Execute and verify results.
- generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; }, get_examples(),
- testModel.relaxComputationFloat32toFloat16,
+ generated_tests::EvaluatePreparedModel(preparedModel, testModel,
/*testDynamicOutputShape=*/false);
}
TEST_P(CompilationCachingTest, SaveToCacheInvalidNumCache) {
// Create test HIDL model and compile.
- const Model testModel = createTestModel();
- if (checkEarlyTermination(testModel)) return;
+ const TestModel& testModel = createTestModel();
+ const Model model = generated_tests::createModel(testModel);
+ if (checkEarlyTermination(model)) return;
// Test with number of model cache files greater than mNumModelCache.
{
@@ -598,12 +541,10 @@
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
mModelCache.pop_back();
sp<IPreparedModel> preparedModel = nullptr;
- saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+ saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
- get_examples(),
- testModel.relaxComputationFloat32toFloat16,
+ generated_tests::EvaluatePreparedModel(preparedModel, testModel,
/*testDynamicOutputShape=*/false);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
@@ -625,12 +566,10 @@
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
mModelCache.push_back(tmp);
sp<IPreparedModel> preparedModel = nullptr;
- saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+ saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
- get_examples(),
- testModel.relaxComputationFloat32toFloat16,
+ generated_tests::EvaluatePreparedModel(preparedModel, testModel,
/*testDynamicOutputShape=*/false);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
@@ -651,12 +590,10 @@
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
mDataCache.pop_back();
sp<IPreparedModel> preparedModel = nullptr;
- saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+ saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
- get_examples(),
- testModel.relaxComputationFloat32toFloat16,
+ generated_tests::EvaluatePreparedModel(preparedModel, testModel,
/*testDynamicOutputShape=*/false);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
@@ -678,12 +615,10 @@
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
mDataCache.push_back(tmp);
sp<IPreparedModel> preparedModel = nullptr;
- saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+ saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
- get_examples(),
- testModel.relaxComputationFloat32toFloat16,
+ generated_tests::EvaluatePreparedModel(preparedModel, testModel,
/*testDynamicOutputShape=*/false);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
@@ -698,15 +633,16 @@
TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumCache) {
// Create test HIDL model and compile.
- const Model testModel = createTestModel();
- if (checkEarlyTermination(testModel)) return;
+ const TestModel& testModel = createTestModel();
+ const Model model = generated_tests::createModel(testModel);
+ if (checkEarlyTermination(model)) return;
// Save the compilation to cache.
{
hidl_vec<hidl_handle> modelCache, dataCache;
createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
- saveModelToCache(testModel, modelCache, dataCache);
+ saveModelToCache(model, modelCache, dataCache);
}
// Test with number of model cache files greater than mNumModelCache.
@@ -778,8 +714,9 @@
TEST_P(CompilationCachingTest, SaveToCacheInvalidNumFd) {
// Create test HIDL model and compile.
- const Model testModel = createTestModel();
- if (checkEarlyTermination(testModel)) return;
+ const TestModel& testModel = createTestModel();
+ const Model model = generated_tests::createModel(testModel);
+ if (checkEarlyTermination(model)) return;
// Go through each handle in model cache, test with NumFd greater than 1.
for (uint32_t i = 0; i < mNumModelCache; i++) {
@@ -790,12 +727,10 @@
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
mModelCache[i].pop_back();
sp<IPreparedModel> preparedModel = nullptr;
- saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+ saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
- get_examples(),
- testModel.relaxComputationFloat32toFloat16,
+ generated_tests::EvaluatePreparedModel(preparedModel, testModel,
/*testDynamicOutputShape=*/false);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
@@ -817,12 +752,10 @@
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
mModelCache[i].push_back(tmp);
sp<IPreparedModel> preparedModel = nullptr;
- saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+ saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
- get_examples(),
- testModel.relaxComputationFloat32toFloat16,
+ generated_tests::EvaluatePreparedModel(preparedModel, testModel,
/*testDynamicOutputShape=*/false);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
@@ -843,12 +776,10 @@
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
mDataCache[i].pop_back();
sp<IPreparedModel> preparedModel = nullptr;
- saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+ saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
- get_examples(),
- testModel.relaxComputationFloat32toFloat16,
+ generated_tests::EvaluatePreparedModel(preparedModel, testModel,
/*testDynamicOutputShape=*/false);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
@@ -870,12 +801,10 @@
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
mDataCache[i].push_back(tmp);
sp<IPreparedModel> preparedModel = nullptr;
- saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+ saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
- get_examples(),
- testModel.relaxComputationFloat32toFloat16,
+ generated_tests::EvaluatePreparedModel(preparedModel, testModel,
/*testDynamicOutputShape=*/false);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
@@ -890,15 +819,16 @@
TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidNumFd) {
// Create test HIDL model and compile.
- const Model testModel = createTestModel();
- if (checkEarlyTermination(testModel)) return;
+ const TestModel& testModel = createTestModel();
+ const Model model = generated_tests::createModel(testModel);
+ if (checkEarlyTermination(model)) return;
// Save the compilation to cache.
{
hidl_vec<hidl_handle> modelCache, dataCache;
createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
- saveModelToCache(testModel, modelCache, dataCache);
+ saveModelToCache(model, modelCache, dataCache);
}
// Go through each handle in model cache, test with NumFd greater than 1.
@@ -970,8 +900,9 @@
TEST_P(CompilationCachingTest, SaveToCacheInvalidAccessMode) {
// Create test HIDL model and compile.
- const Model testModel = createTestModel();
- if (checkEarlyTermination(testModel)) return;
+ const TestModel& testModel = createTestModel();
+ const Model model = generated_tests::createModel(testModel);
+ if (checkEarlyTermination(model)) return;
std::vector<AccessMode> modelCacheMode(mNumModelCache, AccessMode::READ_WRITE);
std::vector<AccessMode> dataCacheMode(mNumDataCache, AccessMode::READ_WRITE);
@@ -983,12 +914,10 @@
createCacheHandles(mDataCache, dataCacheMode, &dataCache);
modelCacheMode[i] = AccessMode::READ_WRITE;
sp<IPreparedModel> preparedModel = nullptr;
- saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+ saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
- get_examples(),
- testModel.relaxComputationFloat32toFloat16,
+ generated_tests::EvaluatePreparedModel(preparedModel, testModel,
/*testDynamicOutputShape=*/false);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
@@ -1008,12 +937,10 @@
createCacheHandles(mDataCache, dataCacheMode, &dataCache);
dataCacheMode[i] = AccessMode::READ_WRITE;
sp<IPreparedModel> preparedModel = nullptr;
- saveModelToCache(testModel, modelCache, dataCache, &preparedModel);
+ saveModelToCache(model, modelCache, dataCache, &preparedModel);
ASSERT_NE(preparedModel, nullptr);
// Execute and verify results.
- generated_tests::EvaluatePreparedModel(preparedModel, [](int) { return false; },
- get_examples(),
- testModel.relaxComputationFloat32toFloat16,
+ generated_tests::EvaluatePreparedModel(preparedModel, testModel,
/*testDynamicOutputShape=*/false);
// Check if prepareModelFromCache fails.
preparedModel = nullptr;
@@ -1028,8 +955,9 @@
TEST_P(CompilationCachingTest, PrepareModelFromCacheInvalidAccessMode) {
// Create test HIDL model and compile.
- const Model testModel = createTestModel();
- if (checkEarlyTermination(testModel)) return;
+ const TestModel& testModel = createTestModel();
+ const Model model = generated_tests::createModel(testModel);
+ if (checkEarlyTermination(model)) return;
std::vector<AccessMode> modelCacheMode(mNumModelCache, AccessMode::READ_WRITE);
std::vector<AccessMode> dataCacheMode(mNumDataCache, AccessMode::READ_WRITE);
@@ -1038,7 +966,7 @@
hidl_vec<hidl_handle> modelCache, dataCache;
createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
- saveModelToCache(testModel, modelCache, dataCache);
+ saveModelToCache(model, modelCache, dataCache);
}
// Go through each handle in model cache, test with invalid access mode.
@@ -1106,12 +1034,14 @@
if (!mIsCachingSupported) return;
// Create test models and check if fully supported by the service.
- const Model testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
- if (checkEarlyTermination(testModelMul)) return;
- const Model testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
- if (checkEarlyTermination(testModelAdd)) return;
+ const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
+ const Model modelMul = generated_tests::createModel(testModelMul);
+ if (checkEarlyTermination(modelMul)) return;
+ const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
+ const Model modelAdd = generated_tests::createModel(testModelAdd);
+ if (checkEarlyTermination(modelAdd)) return;
- // Save the testModelMul compilation to cache.
+ // Save the modelMul compilation to cache.
auto modelCacheMul = mModelCache;
for (auto& cache : modelCacheMul) {
cache[0].append("_mul");
@@ -1120,15 +1050,15 @@
hidl_vec<hidl_handle> modelCache, dataCache;
createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache);
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
- saveModelToCache(testModelMul, modelCache, dataCache);
+ saveModelToCache(modelMul, modelCache, dataCache);
}
- // Use a different token for testModelAdd.
+ // Use a different token for modelAdd.
mToken[0]++;
// This test is probabilistic, so we run it multiple times.
for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
- // Save the testModelAdd compilation to cache.
+ // Save the modelAdd compilation to cache.
{
hidl_vec<hidl_handle> modelCache, dataCache;
createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
@@ -1136,7 +1066,7 @@
// Spawn a thread to copy the cache content concurrently while saving to cache.
std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache));
- saveModelToCache(testModelAdd, modelCache, dataCache);
+ saveModelToCache(modelAdd, modelCache, dataCache);
thread.join();
}
@@ -1155,11 +1085,8 @@
ASSERT_EQ(preparedModel, nullptr);
} else {
ASSERT_NE(preparedModel, nullptr);
- generated_tests::EvaluatePreparedModel(
- preparedModel, [](int) { return false; },
- getLargeModelExamples(kLargeModelSize),
- testModelAdd.relaxComputationFloat32toFloat16,
- /*testDynamicOutputShape=*/false);
+ generated_tests::EvaluatePreparedModel(preparedModel, testModelAdd,
+ /*testDynamicOutputShape=*/false);
}
}
}
@@ -1169,12 +1096,14 @@
if (!mIsCachingSupported) return;
// Create test models and check if fully supported by the service.
- const Model testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
- if (checkEarlyTermination(testModelMul)) return;
- const Model testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
- if (checkEarlyTermination(testModelAdd)) return;
+ const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
+ const Model modelMul = generated_tests::createModel(testModelMul);
+ if (checkEarlyTermination(modelMul)) return;
+ const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
+ const Model modelAdd = generated_tests::createModel(testModelAdd);
+ if (checkEarlyTermination(modelAdd)) return;
- // Save the testModelMul compilation to cache.
+ // Save the modelMul compilation to cache.
auto modelCacheMul = mModelCache;
for (auto& cache : modelCacheMul) {
cache[0].append("_mul");
@@ -1183,20 +1112,20 @@
hidl_vec<hidl_handle> modelCache, dataCache;
createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache);
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
- saveModelToCache(testModelMul, modelCache, dataCache);
+ saveModelToCache(modelMul, modelCache, dataCache);
}
- // Use a different token for testModelAdd.
+ // Use a different token for modelAdd.
mToken[0]++;
// This test is probabilistic, so we run it multiple times.
for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
- // Save the testModelAdd compilation to cache.
+ // Save the modelAdd compilation to cache.
{
hidl_vec<hidl_handle> modelCache, dataCache;
createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
- saveModelToCache(testModelAdd, modelCache, dataCache);
+ saveModelToCache(modelAdd, modelCache, dataCache);
}
// Retrieve preparedModel from cache.
@@ -1218,11 +1147,8 @@
ASSERT_EQ(preparedModel, nullptr);
} else {
ASSERT_NE(preparedModel, nullptr);
- generated_tests::EvaluatePreparedModel(
- preparedModel, [](int) { return false; },
- getLargeModelExamples(kLargeModelSize),
- testModelAdd.relaxComputationFloat32toFloat16,
- /*testDynamicOutputShape=*/false);
+ generated_tests::EvaluatePreparedModel(preparedModel, testModelAdd,
+ /*testDynamicOutputShape=*/false);
}
}
}
@@ -1232,12 +1158,14 @@
if (!mIsCachingSupported) return;
// Create test models and check if fully supported by the service.
- const Model testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
- if (checkEarlyTermination(testModelMul)) return;
- const Model testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
- if (checkEarlyTermination(testModelAdd)) return;
+ const TestModel testModelMul = createLargeTestModel(OperationType::MUL, kLargeModelSize);
+ const Model modelMul = generated_tests::createModel(testModelMul);
+ if (checkEarlyTermination(modelMul)) return;
+ const TestModel testModelAdd = createLargeTestModel(OperationType::ADD, kLargeModelSize);
+ const Model modelAdd = generated_tests::createModel(testModelAdd);
+ if (checkEarlyTermination(modelAdd)) return;
- // Save the testModelMul compilation to cache.
+ // Save the modelMul compilation to cache.
auto modelCacheMul = mModelCache;
for (auto& cache : modelCacheMul) {
cache[0].append("_mul");
@@ -1246,21 +1174,21 @@
hidl_vec<hidl_handle> modelCache, dataCache;
createCacheHandles(modelCacheMul, AccessMode::READ_WRITE, &modelCache);
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
- saveModelToCache(testModelMul, modelCache, dataCache);
+ saveModelToCache(modelMul, modelCache, dataCache);
}
- // Use a different token for testModelAdd.
+ // Use a different token for modelAdd.
mToken[0]++;
- // Save the testModelAdd compilation to cache.
+ // Save the modelAdd compilation to cache.
{
hidl_vec<hidl_handle> modelCache, dataCache;
createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
- saveModelToCache(testModelAdd, modelCache, dataCache);
+ saveModelToCache(modelAdd, modelCache, dataCache);
}
- // Replace the model cache of testModelAdd with testModelMul.
+ // Replace the model cache of modelAdd with modelMul.
copyCacheFiles(modelCacheMul, mModelCache);
// Retrieve the preparedModel from cache, expect failure.
@@ -1336,15 +1264,16 @@
// The modifier accepts one pointer argument "skip" as the returning value, indicating
// whether the test should be skipped or not.
void testCorruptedCache(ExpectedResult expected, std::function<void(bool*)> modifier) {
- const Model testModel = createTestModel();
- if (checkEarlyTermination(testModel)) return;
+ const TestModel& testModel = createTestModel();
+ const Model model = generated_tests::createModel(testModel);
+ if (checkEarlyTermination(model)) return;
// Save the compilation to cache.
{
hidl_vec<hidl_handle> modelCache, dataCache;
createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
- saveModelToCache(testModel, modelCache, dataCache);
+ saveModelToCache(model, modelCache, dataCache);
}
bool skip = false;
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
index 82cc73d..1dcebbe 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
@@ -31,7 +31,10 @@
#include <android/hidl/memory/1.0/IMemory.h>
#include <hidlmemory/mapping.h>
+#include <gtest/gtest.h>
+#include <algorithm>
#include <iostream>
+#include <numeric>
#include "1.0/Utils.h"
#include "1.2/Callbacks.h"
@@ -46,7 +49,10 @@
namespace V1_2 {
namespace generated_tests {
+using namespace test_helper;
+using ::android::hardware::neuralnetworks::V1_0::DataLocation;
using ::android::hardware::neuralnetworks::V1_0::ErrorStatus;
+using ::android::hardware::neuralnetworks::V1_0::OperandLifeTime;
using ::android::hardware::neuralnetworks::V1_0::Request;
using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
using ::android::hardware::neuralnetworks::V1_1::ExecutionPreference;
@@ -60,29 +66,122 @@
using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
using ::android::hardware::neuralnetworks::V1_2::implementation::PreparedModelCallback;
using ::android::hidl::memory::V1_0::IMemory;
-using ::test_helper::compare;
-using ::test_helper::expectMultinomialDistributionWithinTolerance;
-using ::test_helper::filter;
-using ::test_helper::for_all;
-using ::test_helper::for_each;
-using ::test_helper::MixedTyped;
-using ::test_helper::MixedTypedExample;
-using ::test_helper::resize_accordingly;
using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>;
-static bool isZeroSized(const MixedTyped& example, uint32_t index) {
- for (auto i : example.operandDimensions.at(index)) {
- if (i == 0) return true;
+enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
+
+Model createModel(const TestModel& testModel) {
+ // Model operands.
+ hidl_vec<Operand> operands(testModel.operands.size());
+ size_t constCopySize = 0, constRefSize = 0;
+ for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+ const auto& op = testModel.operands[i];
+
+ DataLocation loc = {};
+ if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
+ loc = {.poolIndex = 0,
+ .offset = static_cast<uint32_t>(constCopySize),
+ .length = static_cast<uint32_t>(op.data.size())};
+ constCopySize += op.data.alignedSize();
+ } else if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
+ loc = {.poolIndex = 0,
+ .offset = static_cast<uint32_t>(constRefSize),
+ .length = static_cast<uint32_t>(op.data.size())};
+ constRefSize += op.data.alignedSize();
+ }
+
+ Operand::ExtraParams extraParams;
+ if (op.type == TestOperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) {
+ extraParams.channelQuant(SymmPerChannelQuantParams{
+ .scales = op.channelQuant.scales, .channelDim = op.channelQuant.channelDim});
+ }
+
+ operands[i] = {.type = static_cast<OperandType>(op.type),
+ .dimensions = op.dimensions,
+ .numberOfConsumers = op.numberOfConsumers,
+ .scale = op.scale,
+ .zeroPoint = op.zeroPoint,
+ .lifetime = static_cast<OperandLifeTime>(op.lifetime),
+ .location = loc,
+ .extraParams = std::move(extraParams)};
}
- return false;
+
+ // Model operations.
+ hidl_vec<Operation> operations(testModel.operations.size());
+ std::transform(testModel.operations.begin(), testModel.operations.end(), operations.begin(),
+ [](const TestOperation& op) -> Operation {
+ return {.type = static_cast<OperationType>(op.type),
+ .inputs = op.inputs,
+ .outputs = op.outputs};
+ });
+
+ // Constant copies.
+ hidl_vec<uint8_t> operandValues(constCopySize);
+ for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+ const auto& op = testModel.operands[i];
+ if (op.lifetime == TestOperandLifeTime::CONSTANT_COPY) {
+ const uint8_t* begin = op.data.get<uint8_t>();
+ const uint8_t* end = begin + op.data.size();
+ std::copy(begin, end, operandValues.data() + operands[i].location.offset);
+ }
+ }
+
+ // Shared memory.
+ hidl_vec<hidl_memory> pools = {};
+ if (constRefSize > 0) {
+ hidl_vec_push_back(&pools, nn::allocateSharedMemory(constRefSize));
+ CHECK_NE(pools[0].size(), 0u);
+
+ // load data
+ sp<IMemory> mappedMemory = mapMemory(pools[0]);
+ CHECK(mappedMemory.get() != nullptr);
+ uint8_t* mappedPtr =
+ reinterpret_cast<uint8_t*>(static_cast<void*>(mappedMemory->getPointer()));
+ CHECK(mappedPtr != nullptr);
+
+ for (uint32_t i = 0; i < testModel.operands.size(); i++) {
+ const auto& op = testModel.operands[i];
+ if (op.lifetime == TestOperandLifeTime::CONSTANT_REFERENCE) {
+ const uint8_t* begin = op.data.get<uint8_t>();
+ const uint8_t* end = begin + op.data.size();
+ std::copy(begin, end, mappedPtr + operands[i].location.offset);
+ }
+ }
+ }
+
+ return {.operands = std::move(operands),
+ .operations = std::move(operations),
+ .inputIndexes = testModel.inputIndexes,
+ .outputIndexes = testModel.outputIndexes,
+ .operandValues = std::move(operandValues),
+ .pools = std::move(pools),
+ .relaxComputationFloat32toFloat16 = testModel.isRelaxed};
}
-static Return<ErrorStatus> ExecutePreparedModel(sp<IPreparedModel>& preparedModel,
+static bool isOutputSizeGreaterThanOne(const TestModel& testModel, uint32_t index) {
+ const auto byteSize = testModel.operands[testModel.outputIndexes[index]].data.size();
+ return byteSize > 1u;
+}
+
+static void makeOutputInsufficientSize(uint32_t outputIndex, Request* request) {
+ auto& length = request->outputs[outputIndex].location.length;
+ ASSERT_GT(length, 1u);
+ length -= 1u;
+}
+
+static void makeOutputDimensionsUnspecified(Model* model) {
+ for (auto i : model->outputIndexes) {
+ auto& dims = model->operands[i].dimensions;
+ std::fill(dims.begin(), dims.end(), 0);
+ }
+}
+
+static Return<ErrorStatus> ExecutePreparedModel(const sp<IPreparedModel>& preparedModel,
const Request& request, MeasureTiming measure,
sp<ExecutionCallback>& callback) {
return preparedModel->execute_1_2(request, measure, callback);
}
-static Return<ErrorStatus> ExecutePreparedModel(sp<IPreparedModel>& preparedModel,
+static Return<ErrorStatus> ExecutePreparedModel(const sp<IPreparedModel>& preparedModel,
const Request& request, MeasureTiming measure,
hidl_vec<OutputShape>* outputShapes,
Timing* timing) {
@@ -105,294 +204,168 @@
return ::android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true);
}
enum class Executor { ASYNC, SYNC, BURST };
-enum class OutputType { FULLY_SPECIFIED, UNSPECIFIED, INSUFFICIENT };
-const float kDefaultAtol = 1e-5f;
-const float kDefaultRtol = 1e-5f;
-void EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
- const std::vector<MixedTypedExample>& examples,
- bool hasRelaxedFloat32Model, float fpAtol, float fpRtol,
+
+void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
Executor executor, MeasureTiming measure, OutputType outputType) {
- const uint32_t INPUT = 0;
- const uint32_t OUTPUT = 1;
+ // If output0 does not have size larger than one byte, we can not test with insufficient buffer.
+ if (outputType == OutputType::INSUFFICIENT && !isOutputSizeGreaterThanOne(testModel, 0)) {
+ return;
+ }
- int example_no = 1;
- for (auto& example : examples) {
- SCOPED_TRACE(example_no++);
- const MixedTyped& inputs = example.operands.first;
- const MixedTyped& golden = example.operands.second;
+ Request request = createRequest(testModel);
+ if (outputType == OutputType::INSUFFICIENT) {
+ makeOutputInsufficientSize(/*outputIndex=*/0, &request);
+ }
- const bool hasFloat16Inputs = !inputs.float16Operands.empty();
- if (hasRelaxedFloat32Model || hasFloat16Inputs) {
- // TODO: Adjust the error limit based on testing.
- // If in relaxed mode, set the absolute tolerance to be 5ULP of FP16.
- fpAtol = 5.0f * 0.0009765625f;
- // Set the relative tolerance to be 5ULP of the corresponding FP precision.
- fpRtol = 5.0f * 0.0009765625f;
+ ErrorStatus executionStatus;
+ hidl_vec<OutputShape> outputShapes;
+ Timing timing;
+ switch (executor) {
+ case Executor::ASYNC: {
+ SCOPED_TRACE("asynchronous");
+
+ // launch execution
+ sp<ExecutionCallback> executionCallback = new ExecutionCallback();
+ Return<ErrorStatus> executionLaunchStatus =
+ ExecutePreparedModel(preparedModel, request, measure, executionCallback);
+ ASSERT_TRUE(executionLaunchStatus.isOk());
+ EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
+
+ // retrieve execution status
+ executionCallback->wait();
+ executionStatus = executionCallback->getStatus();
+ outputShapes = executionCallback->getOutputShapes();
+ timing = executionCallback->getTiming();
+
+ break;
}
+ case Executor::SYNC: {
+ SCOPED_TRACE("synchronous");
- std::vector<RequestArgument> inputs_info, outputs_info;
- uint32_t inputSize = 0, outputSize = 0;
- // This function only partially specifies the metadata (vector of RequestArguments).
- // The contents are copied over below.
- for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
- if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
- RequestArgument arg = {
- .location = {.poolIndex = INPUT,
- .offset = 0,
- .length = static_cast<uint32_t>(s)},
- .dimensions = {},
- };
- RequestArgument arg_empty = {
- .hasNoValue = true,
- };
- inputs_info[index] = s ? arg : arg_empty;
- inputSize += s;
- });
- // Compute offset for inputs 1 and so on
- {
- size_t offset = 0;
- for (auto& i : inputs_info) {
- if (!i.hasNoValue) i.location.offset = offset;
- offset += i.location.length;
+ // execute
+ Return<ErrorStatus> executionReturnStatus =
+ ExecutePreparedModel(preparedModel, request, measure, &outputShapes, &timing);
+ ASSERT_TRUE(executionReturnStatus.isOk());
+ executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
+
+ break;
+ }
+ case Executor::BURST: {
+ SCOPED_TRACE("burst");
+
+ // create burst
+ const std::shared_ptr<::android::nn::ExecutionBurstController> controller =
+ CreateBurst(preparedModel);
+ ASSERT_NE(nullptr, controller.get());
+
+ // create memory keys
+ std::vector<intptr_t> keys(request.pools.size());
+ for (size_t i = 0; i < keys.size(); ++i) {
+ keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
}
- }
- MixedTyped test; // holding test results
+ // execute burst
+ std::tie(executionStatus, outputShapes, timing) =
+ controller->compute(request, measure, keys);
- // Go through all outputs, initialize RequestArgument descriptors
- resize_accordingly(golden, test);
- bool sizeLargerThanOne = true;
- for_all(golden, [&golden, &outputs_info, &outputSize, &outputType, &sizeLargerThanOne](
- int index, auto, auto s) {
- if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
- if (index == 0) {
- // On OutputType::INSUFFICIENT, set the output operand with index 0 with
- // buffer size one byte less than needed.
- if (outputType == OutputType::INSUFFICIENT) {
- if (s > 1 && !isZeroSized(golden, index)) {
- s -= 1;
- } else {
- sizeLargerThanOne = false;
- }
- }
- }
- RequestArgument arg = {
- .location = {.poolIndex = OUTPUT,
- .offset = 0,
- .length = static_cast<uint32_t>(s)},
- .dimensions = {},
- };
- outputs_info[index] = arg;
- outputSize += s;
- });
- // If output0 does not have size larger than one byte,
- // we can not provide an insufficient buffer
- if (!sizeLargerThanOne && outputType == OutputType::INSUFFICIENT) return;
- // Compute offset for outputs 1 and so on
- {
- size_t offset = 0;
- for (auto& i : outputs_info) {
- i.location.offset = offset;
- offset += i.location.length;
- }
- }
- std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
- nn::allocateSharedMemory(outputSize)};
- ASSERT_NE(0ull, pools[INPUT].size());
- ASSERT_NE(0ull, pools[OUTPUT].size());
-
- // load data
- sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
- sp<IMemory> outputMemory = mapMemory(pools[OUTPUT]);
- ASSERT_NE(nullptr, inputMemory.get());
- ASSERT_NE(nullptr, outputMemory.get());
- char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
- char* outputPtr = reinterpret_cast<char*>(static_cast<void*>(outputMemory->getPointer()));
- ASSERT_NE(nullptr, inputPtr);
- ASSERT_NE(nullptr, outputPtr);
- inputMemory->update();
- outputMemory->update();
-
- // Go through all inputs, copy the values
- for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
- char* begin = (char*)p;
- char* end = begin + s;
- // TODO: handle more than one input
- std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
- });
-
- inputMemory->commit();
- outputMemory->commit();
-
- const Request request = {.inputs = inputs_info, .outputs = outputs_info, .pools = pools};
-
- ErrorStatus executionStatus;
- hidl_vec<OutputShape> outputShapes;
- Timing timing;
- switch (executor) {
- case Executor::ASYNC: {
- SCOPED_TRACE("asynchronous");
-
- // launch execution
- sp<ExecutionCallback> executionCallback = new ExecutionCallback();
- ASSERT_NE(nullptr, executionCallback.get());
- Return<ErrorStatus> executionLaunchStatus =
- ExecutePreparedModel(preparedModel, request, measure, executionCallback);
- ASSERT_TRUE(executionLaunchStatus.isOk());
- EXPECT_EQ(ErrorStatus::NONE, static_cast<ErrorStatus>(executionLaunchStatus));
-
- // retrieve execution status
- executionCallback->wait();
- executionStatus = executionCallback->getStatus();
- outputShapes = executionCallback->getOutputShapes();
- timing = executionCallback->getTiming();
-
- break;
- }
- case Executor::SYNC: {
- SCOPED_TRACE("synchronous");
-
- // execute
- Return<ErrorStatus> executionReturnStatus = ExecutePreparedModel(
- preparedModel, request, measure, &outputShapes, &timing);
- ASSERT_TRUE(executionReturnStatus.isOk());
- executionStatus = static_cast<ErrorStatus>(executionReturnStatus);
-
- break;
- }
- case Executor::BURST: {
- SCOPED_TRACE("burst");
-
- // create burst
- const std::shared_ptr<::android::nn::ExecutionBurstController> controller =
- CreateBurst(preparedModel);
- ASSERT_NE(nullptr, controller.get());
-
- // create memory keys
- std::vector<intptr_t> keys(request.pools.size());
- for (size_t i = 0; i < keys.size(); ++i) {
- keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
- }
-
- // execute burst
- std::tie(executionStatus, outputShapes, timing) =
- controller->compute(request, measure, keys);
-
- break;
- }
- }
-
- if (outputType != OutputType::FULLY_SPECIFIED &&
- executionStatus == ErrorStatus::GENERAL_FAILURE) {
- LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
- "execute model that it does not support.";
- std::cout << "[ ] Early termination of test because vendor service cannot "
- "execute model that it does not support."
- << std::endl;
- GTEST_SKIP();
- }
- if (measure == MeasureTiming::NO) {
- EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
- EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
- } else {
- if (timing.timeOnDevice != UINT64_MAX && timing.timeInDriver != UINT64_MAX) {
- EXPECT_LE(timing.timeOnDevice, timing.timeInDriver);
- }
- }
-
- switch (outputType) {
- case OutputType::FULLY_SPECIFIED:
- // 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);
- ASSERT_TRUE(outputShapes.size() == 0 ||
- outputShapes.size() == test.operandDimensions.size());
- break;
- case OutputType::UNSPECIFIED:
- // If the model output operands are not fully specified, outputShapes must have
- // the same number of elements as the number of outputs.
- ASSERT_EQ(ErrorStatus::NONE, executionStatus);
- ASSERT_EQ(outputShapes.size(), test.operandDimensions.size());
- break;
- case OutputType::INSUFFICIENT:
- ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
- ASSERT_EQ(outputShapes.size(), test.operandDimensions.size());
- ASSERT_FALSE(outputShapes[0].isSufficient);
- return;
- }
- // Go through all outputs, overwrite output dimensions with returned output shapes
- if (outputShapes.size() > 0) {
- for_each<uint32_t>(test.operandDimensions,
- [&outputShapes](int idx, std::vector<uint32_t>& dim) {
- dim = outputShapes[idx].dimensions;
- });
- }
-
- // validate results
- outputMemory->read();
- copy_back(&test, outputs_info, outputPtr);
- outputMemory->commit();
- // Filter out don't cares
- MixedTyped filtered_golden = filter(golden, is_ignored);
- MixedTyped filtered_test = filter(test, is_ignored);
-
- // We want "close-enough" results for float
- compare(filtered_golden, filtered_test, fpAtol, fpRtol);
-
- if (example.expectedMultinomialDistributionTolerance > 0) {
- expectMultinomialDistributionWithinTolerance(test, example);
+ break;
}
}
-}
-void EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
- const std::vector<MixedTypedExample>& examples,
- bool hasRelaxedFloat32Model, Executor executor, MeasureTiming measure,
- OutputType outputType) {
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model, kDefaultAtol,
- kDefaultRtol, executor, measure, outputType);
+
+ if (outputType != OutputType::FULLY_SPECIFIED &&
+ executionStatus == ErrorStatus::GENERAL_FAILURE) {
+ LOG(INFO) << "NN VTS: Early termination of test because vendor service cannot "
+ "execute model that it does not support.";
+ std::cout << "[ ] Early termination of test because vendor service cannot "
+ "execute model that it does not support."
+ << std::endl;
+ GTEST_SKIP();
+ }
+ if (measure == MeasureTiming::NO) {
+ EXPECT_EQ(UINT64_MAX, timing.timeOnDevice);
+ EXPECT_EQ(UINT64_MAX, timing.timeInDriver);
+ } else {
+ if (timing.timeOnDevice != UINT64_MAX && timing.timeInDriver != UINT64_MAX) {
+ EXPECT_LE(timing.timeOnDevice, timing.timeInDriver);
+ }
+ }
+
+ switch (outputType) {
+ case OutputType::FULLY_SPECIFIED:
+ // 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);
+ ASSERT_TRUE(outputShapes.size() == 0 ||
+ outputShapes.size() == testModel.outputIndexes.size());
+ break;
+ case OutputType::UNSPECIFIED:
+ // If the model output operands are not fully specified, outputShapes must have
+ // the same number of elements as the number of outputs.
+ ASSERT_EQ(ErrorStatus::NONE, executionStatus);
+ ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size());
+ break;
+ case OutputType::INSUFFICIENT:
+ ASSERT_EQ(ErrorStatus::OUTPUT_INSUFFICIENT_SIZE, executionStatus);
+ ASSERT_EQ(outputShapes.size(), testModel.outputIndexes.size());
+ ASSERT_FALSE(outputShapes[0].isSufficient);
+ return;
+ }
+
+ // Go through all outputs, check returned output shapes.
+ for (uint32_t i = 0; i < outputShapes.size(); i++) {
+ EXPECT_TRUE(outputShapes[i].isSufficient);
+ const auto& expect = testModel.operands[testModel.outputIndexes[i]].dimensions;
+ const std::vector<uint32_t> actual = outputShapes[i].dimensions;
+ EXPECT_EQ(expect, actual);
+ }
+
+ // Retrieve execution results.
+ const std::vector<TestBuffer> outputs = getOutputBuffers(request);
+
+ // We want "close-enough" results.
+ checkResults(testModel, outputs);
}
-void EvaluatePreparedModel(sp<IPreparedModel>& preparedModel, std::function<bool(int)> is_ignored,
- const std::vector<MixedTypedExample>& examples,
- bool hasRelaxedFloat32Model, bool testDynamicOutputShape) {
+void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel, const TestModel& testModel,
+ bool testDynamicOutputShape) {
if (testDynamicOutputShape) {
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::ASYNC, MeasureTiming::NO, OutputType::UNSPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::SYNC, MeasureTiming::NO, OutputType::UNSPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::BURST, MeasureTiming::NO, OutputType::UNSPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::ASYNC, MeasureTiming::YES, OutputType::UNSPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::SYNC, MeasureTiming::YES, OutputType::UNSPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::BURST, MeasureTiming::YES, OutputType::UNSPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::ASYNC, MeasureTiming::NO, OutputType::INSUFFICIENT);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::SYNC, MeasureTiming::NO, OutputType::INSUFFICIENT);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::BURST, MeasureTiming::NO, OutputType::INSUFFICIENT);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::ASYNC, MeasureTiming::YES, OutputType::INSUFFICIENT);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::SYNC, MeasureTiming::YES, OutputType::INSUFFICIENT);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::BURST, MeasureTiming::YES, OutputType::INSUFFICIENT);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
+ OutputType::UNSPECIFIED);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
+ OutputType::UNSPECIFIED);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
+ OutputType::UNSPECIFIED);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
+ OutputType::UNSPECIFIED);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
+ OutputType::UNSPECIFIED);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
+ OutputType::UNSPECIFIED);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
+ OutputType::INSUFFICIENT);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
+ OutputType::INSUFFICIENT);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
+ OutputType::INSUFFICIENT);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
+ OutputType::INSUFFICIENT);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
+ OutputType::INSUFFICIENT);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
+ OutputType::INSUFFICIENT);
} else {
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::ASYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::SYNC, MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::BURST, MeasureTiming::NO, OutputType::FULLY_SPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::ASYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::SYNC, MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
- EvaluatePreparedModel(preparedModel, is_ignored, examples, hasRelaxedFloat32Model,
- Executor::BURST, MeasureTiming::YES, OutputType::FULLY_SPECIFIED);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::NO,
+ OutputType::FULLY_SPECIFIED);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::NO,
+ OutputType::FULLY_SPECIFIED);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::NO,
+ OutputType::FULLY_SPECIFIED);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::ASYNC, MeasureTiming::YES,
+ OutputType::FULLY_SPECIFIED);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::SYNC, MeasureTiming::YES,
+ OutputType::FULLY_SPECIFIED);
+ EvaluatePreparedModel(preparedModel, testModel, Executor::BURST, MeasureTiming::YES,
+ OutputType::FULLY_SPECIFIED);
}
}
@@ -411,7 +384,6 @@
// launch prepare model
sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback();
- ASSERT_NE(nullptr, preparedModelCallback.get());
Return<ErrorStatus> prepareLaunchStatus = device->prepareModel_1_2(
model, ExecutionPreference::FAST_SINGLE_ANSWER, hidl_vec<hidl_handle>(),
hidl_vec<hidl_handle>(), HidlToken(), preparedModelCallback);
@@ -438,17 +410,18 @@
ASSERT_NE(nullptr, preparedModel->get());
}
-void Execute(const sp<IDevice>& device, std::function<Model(void)> create_model,
- std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples,
- bool testDynamicOutputShape) {
- Model model = create_model();
+void Execute(const sp<IDevice>& device, const TestModel& testModel, bool testDynamicOutputShape) {
+ Model model = createModel(testModel);
+ if (testDynamicOutputShape) {
+ makeOutputDimensionsUnspecified(&model);
+ }
+
sp<IPreparedModel> preparedModel = nullptr;
PrepareModel(device, model, &preparedModel);
if (preparedModel == nullptr) {
GTEST_SKIP();
}
- EvaluatePreparedModel(preparedModel, is_ignored, examples,
- model.relaxComputationFloat32toFloat16, testDynamicOutputShape);
+ EvaluatePreparedModel(preparedModel, testModel, testDynamicOutputShape);
}
} // namespace generated_tests
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
index 0ecbe7e..de45242 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
@@ -30,18 +30,15 @@
namespace V1_2 {
namespace generated_tests {
-using ::test_helper::MixedTypedExample;
+Model createModel(const ::test_helper::TestModel& testModel);
void PrepareModel(const sp<V1_2::IDevice>& device, const V1_2::Model& model,
sp<V1_2::IPreparedModel>* preparedModel);
-void EvaluatePreparedModel(sp<V1_2::IPreparedModel>& preparedModel,
- std::function<bool(int)> is_ignored,
- const std::vector<MixedTypedExample>& examples,
- bool hasRelaxedFloat32Model, bool testDynamicOutputShape);
+void EvaluatePreparedModel(const sp<V1_2::IPreparedModel>& preparedModel,
+ const ::test_helper::TestModel& testModel, bool testDynamicOutputShape);
-void Execute(const sp<V1_2::IDevice>& device, std::function<V1_2::Model(void)> create_model,
- std::function<bool(int)> is_ignored, const std::vector<MixedTypedExample>& examples,
+void Execute(const sp<V1_2::IDevice>& device, const ::test_helper::TestModel& testModel,
bool testDynamicOutputShape = false);
} // namespace generated_tests
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTests.h b/neuralnetworks/1.2/vts/functional/GeneratedTests.h
index 9842036..a723609 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTests.h
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTests.h
@@ -14,21 +14,11 @@
* limitations under the License.
*/
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
+#include "1.0/Utils.h"
#include "GeneratedTestHarness.h"
-#include "MemoryUtils.h"
#include "TestHarness.h"
-#include "Utils.h"
#include "VtsHalNeuralnetworks.h"
-namespace android::hardware::neuralnetworks::V1_2::vts::functional {
-
-std::vector<Request> createRequests(const std::vector<::test_helper::MixedTypedExample>& examples);
-
-} // namespace android::hardware::neuralnetworks::V1_2::vts::functional
-
namespace android::hardware::neuralnetworks::V1_2::generated_tests {
using namespace ::android::hardware::neuralnetworks::V1_2::vts::functional;
diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
index 4d6bdbb..94603fb 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
@@ -239,7 +239,7 @@
///////////////////////// BURST VALIATION TESTS ////////////////////////////////////
static void validateBurstSerialization(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests) {
+ const Request& request) {
// create burst
std::unique_ptr<RequestChannelSender> sender;
std::unique_ptr<ResultChannelReceiver> receiver;
@@ -250,35 +250,32 @@
ASSERT_NE(nullptr, receiver.get());
ASSERT_NE(nullptr, context.get());
- // validate each request
- for (const Request& request : requests) {
- // load memory into callback slots
- std::vector<intptr_t> keys;
- keys.reserve(request.pools.size());
- std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys),
- [](const auto& pool) { return reinterpret_cast<intptr_t>(&pool); });
- const std::vector<int32_t> slots = callback->getSlots(request.pools, keys);
+ // load memory into callback slots
+ std::vector<intptr_t> keys;
+ keys.reserve(request.pools.size());
+ std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys),
+ [](const auto& pool) { return reinterpret_cast<intptr_t>(&pool); });
+ const std::vector<int32_t> slots = callback->getSlots(request.pools, keys);
- // ensure slot std::numeric_limits<int32_t>::max() doesn't exist (for
- // subsequent slot validation testing)
- ASSERT_TRUE(std::all_of(slots.begin(), slots.end(), [](int32_t slot) {
- return slot != std::numeric_limits<int32_t>::max();
- }));
+ // ensure slot std::numeric_limits<int32_t>::max() doesn't exist (for
+ // subsequent slot validation testing)
+ ASSERT_TRUE(std::all_of(slots.begin(), slots.end(), [](int32_t slot) {
+ return slot != std::numeric_limits<int32_t>::max();
+ }));
- // serialize the request
- const auto serialized = ::android::nn::serialize(request, MeasureTiming::YES, slots);
+ // serialize the request
+ const auto serialized = ::android::nn::serialize(request, MeasureTiming::YES, slots);
- // validations
- removeDatumTest(sender.get(), receiver.get(), serialized);
- addDatumTest(sender.get(), receiver.get(), serialized);
- mutateDatumTest(sender.get(), receiver.get(), serialized);
- }
+ // validations
+ removeDatumTest(sender.get(), receiver.get(), serialized);
+ addDatumTest(sender.get(), receiver.get(), serialized);
+ mutateDatumTest(sender.get(), receiver.get(), serialized);
}
// This test validates that when the Result message size exceeds length of the
// result FMQ, the service instance gracefully fails and returns an error.
static void validateBurstFmqLength(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests) {
+ const Request& request) {
// create regular burst
std::shared_ptr<ExecutionBurstController> controllerRegular;
ASSERT_NO_FATAL_FAILURE(createBurstWithResultChannelLength(
@@ -291,35 +288,32 @@
preparedModel, kExecutionBurstChannelSmallLength, &controllerSmall));
ASSERT_NE(nullptr, controllerSmall.get());
- // validate each request
- for (const Request& request : requests) {
- // load memory into callback slots
- std::vector<intptr_t> keys(request.pools.size());
- for (size_t i = 0; i < keys.size(); ++i) {
- keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
- }
-
- // collect serialized result by running regular burst
- const auto [statusRegular, outputShapesRegular, timingRegular] =
- controllerRegular->compute(request, MeasureTiming::NO, keys);
-
- // skip test if regular burst output isn't useful for testing a failure
- // caused by having too small of a length for the result FMQ
- const std::vector<FmqResultDatum> serialized =
- ::android::nn::serialize(statusRegular, outputShapesRegular, timingRegular);
- if (statusRegular != ErrorStatus::NONE ||
- serialized.size() <= kExecutionBurstChannelSmallLength) {
- continue;
- }
-
- // by this point, execution should fail because the result channel isn't
- // large enough to return the serialized result
- const auto [statusSmall, outputShapesSmall, timingSmall] =
- controllerSmall->compute(request, MeasureTiming::NO, keys);
- EXPECT_NE(ErrorStatus::NONE, statusSmall);
- EXPECT_EQ(0u, outputShapesSmall.size());
- EXPECT_TRUE(badTiming(timingSmall));
+ // load memory into callback slots
+ std::vector<intptr_t> keys(request.pools.size());
+ for (size_t i = 0; i < keys.size(); ++i) {
+ keys[i] = reinterpret_cast<intptr_t>(&request.pools[i]);
}
+
+ // collect serialized result by running regular burst
+ const auto [statusRegular, outputShapesRegular, timingRegular] =
+ controllerRegular->compute(request, MeasureTiming::NO, keys);
+
+ // skip test if regular burst output isn't useful for testing a failure
+ // caused by having too small of a length for the result FMQ
+ const std::vector<FmqResultDatum> serialized =
+ ::android::nn::serialize(statusRegular, outputShapesRegular, timingRegular);
+ if (statusRegular != ErrorStatus::NONE ||
+ serialized.size() <= kExecutionBurstChannelSmallLength) {
+ return;
+ }
+
+ // by this point, execution should fail because the result channel isn't
+ // large enough to return the serialized result
+ const auto [statusSmall, outputShapesSmall, timingSmall] =
+ controllerSmall->compute(request, MeasureTiming::NO, keys);
+ EXPECT_NE(ErrorStatus::NONE, statusSmall);
+ EXPECT_EQ(0u, outputShapesSmall.size());
+ EXPECT_TRUE(badTiming(timingSmall));
}
static bool isSanitized(const FmqResultDatum& datum) {
@@ -367,7 +361,7 @@
}
static void validateBurstSanitized(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests) {
+ const Request& request) {
// create burst
std::unique_ptr<RequestChannelSender> sender;
std::unique_ptr<ResultChannelReceiver> receiver;
@@ -378,35 +372,32 @@
ASSERT_NE(nullptr, receiver.get());
ASSERT_NE(nullptr, context.get());
- // validate each request
- for (const Request& request : requests) {
- // load memory into callback slots
- std::vector<intptr_t> keys;
- keys.reserve(request.pools.size());
- std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys),
- [](const auto& pool) { return reinterpret_cast<intptr_t>(&pool); });
- const std::vector<int32_t> slots = callback->getSlots(request.pools, keys);
+ // load memory into callback slots
+ std::vector<intptr_t> keys;
+ keys.reserve(request.pools.size());
+ std::transform(request.pools.begin(), request.pools.end(), std::back_inserter(keys),
+ [](const auto& pool) { return reinterpret_cast<intptr_t>(&pool); });
+ const std::vector<int32_t> slots = callback->getSlots(request.pools, keys);
- // send valid request
- ASSERT_TRUE(sender->send(request, MeasureTiming::YES, slots));
+ // send valid request
+ ASSERT_TRUE(sender->send(request, MeasureTiming::YES, slots));
- // receive valid result
- auto serialized = receiver->getPacketBlocking();
- ASSERT_TRUE(serialized.has_value());
+ // receive valid result
+ auto serialized = receiver->getPacketBlocking();
+ ASSERT_TRUE(serialized.has_value());
- // sanitize result
- ASSERT_TRUE(std::all_of(serialized->begin(), serialized->end(), isSanitized))
- << "The result serialized data is not properly sanitized";
- }
+ // sanitize result
+ ASSERT_TRUE(std::all_of(serialized->begin(), serialized->end(), isSanitized))
+ << "The result serialized data is not properly sanitized";
}
///////////////////////////// ENTRY POINT //////////////////////////////////
void ValidationTest::validateBurst(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests) {
- ASSERT_NO_FATAL_FAILURE(validateBurstSerialization(preparedModel, requests));
- ASSERT_NO_FATAL_FAILURE(validateBurstFmqLength(preparedModel, requests));
- ASSERT_NO_FATAL_FAILURE(validateBurstSanitized(preparedModel, requests));
+ const Request& request) {
+ ASSERT_NO_FATAL_FAILURE(validateBurstSerialization(preparedModel, request));
+ ASSERT_NO_FATAL_FAILURE(validateBurstFmqLength(preparedModel, request));
+ ASSERT_NO_FATAL_FAILURE(validateBurstSanitized(preparedModel, request));
}
} // namespace functional
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
index cf5905f..13d45e4 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -16,14 +16,9 @@
#define LOG_TAG "neuralnetworks_hidl_hal_test"
-#include <android-base/logging.h>
-#include <android/hidl/memory/1.0/IMemory.h>
-#include <hidlmemory/mapping.h>
-
#include "1.0/Utils.h"
#include "1.2/Callbacks.h"
#include "ExecutionBurstController.h"
-#include "MemoryUtils.h"
#include "TestHarness.h"
#include "Utils.h"
#include "VtsHalNeuralnetworks.h"
@@ -35,12 +30,7 @@
namespace vts {
namespace functional {
-using ::android::hardware::neuralnetworks::V1_0::RequestArgument;
using ::android::hardware::neuralnetworks::V1_2::implementation::ExecutionCallback;
-using ::android::hidl::memory::V1_0::IMemory;
-using test_helper::for_all;
-using test_helper::MixedTyped;
-using test_helper::MixedTypedExample;
///////////////////////// UTILITY FUNCTIONS /////////////////////////
@@ -161,119 +151,23 @@
///////////////////////////// ENTRY POINT //////////////////////////////////
-std::vector<Request> createRequests(const std::vector<MixedTypedExample>& examples) {
- const uint32_t INPUT = 0;
- const uint32_t OUTPUT = 1;
-
- std::vector<Request> requests;
-
- for (auto& example : examples) {
- const MixedTyped& inputs = example.operands.first;
- const MixedTyped& outputs = example.operands.second;
-
- std::vector<RequestArgument> inputs_info, outputs_info;
- uint32_t inputSize = 0, outputSize = 0;
-
- // This function only partially specifies the metadata (vector of RequestArguments).
- // The contents are copied over below.
- for_all(inputs, [&inputs_info, &inputSize](int index, auto, auto s) {
- if (inputs_info.size() <= static_cast<size_t>(index)) inputs_info.resize(index + 1);
- RequestArgument arg = {
- .location = {.poolIndex = INPUT,
- .offset = 0,
- .length = static_cast<uint32_t>(s)},
- .dimensions = {},
- };
- RequestArgument arg_empty = {
- .hasNoValue = true,
- };
- inputs_info[index] = s ? arg : arg_empty;
- inputSize += s;
- });
- // Compute offset for inputs 1 and so on
- {
- size_t offset = 0;
- for (auto& i : inputs_info) {
- if (!i.hasNoValue) i.location.offset = offset;
- offset += i.location.length;
- }
- }
-
- // Go through all outputs, initialize RequestArgument descriptors
- for_all(outputs, [&outputs_info, &outputSize](int index, auto, auto s) {
- if (outputs_info.size() <= static_cast<size_t>(index)) outputs_info.resize(index + 1);
- RequestArgument arg = {
- .location = {.poolIndex = OUTPUT,
- .offset = 0,
- .length = static_cast<uint32_t>(s)},
- .dimensions = {},
- };
- outputs_info[index] = arg;
- outputSize += s;
- });
- // Compute offset for outputs 1 and so on
- {
- size_t offset = 0;
- for (auto& i : outputs_info) {
- i.location.offset = offset;
- offset += i.location.length;
- }
- }
- std::vector<hidl_memory> pools = {nn::allocateSharedMemory(inputSize),
- nn::allocateSharedMemory(outputSize)};
- if (pools[INPUT].size() == 0 || pools[OUTPUT].size() == 0) {
- return {};
- }
-
- // map pool
- sp<IMemory> inputMemory = mapMemory(pools[INPUT]);
- if (inputMemory == nullptr) {
- return {};
- }
- char* inputPtr = reinterpret_cast<char*>(static_cast<void*>(inputMemory->getPointer()));
- if (inputPtr == nullptr) {
- return {};
- }
-
- // initialize pool
- inputMemory->update();
- for_all(inputs, [&inputs_info, inputPtr](int index, auto p, auto s) {
- char* begin = (char*)p;
- char* end = begin + s;
- // TODO: handle more than one input
- std::copy(begin, end, inputPtr + inputs_info[index].location.offset);
- });
- inputMemory->commit();
-
- requests.push_back({.inputs = inputs_info, .outputs = outputs_info, .pools = pools});
- }
-
- return requests;
-}
-
-void ValidationTest::validateRequests(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests) {
- // validate each request
- for (const Request& request : requests) {
- removeInputTest(preparedModel, request);
- removeOutputTest(preparedModel, request);
- }
+void ValidationTest::validateRequest(const sp<IPreparedModel>& preparedModel,
+ const Request& request) {
+ removeInputTest(preparedModel, request);
+ removeOutputTest(preparedModel, request);
}
void ValidationTest::validateRequestFailure(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests) {
- for (const Request& request : requests) {
- SCOPED_TRACE("Expecting request to fail [executeSynchronously]");
- Return<void> executeStatus = preparedModel->executeSynchronously(
- request, MeasureTiming::NO,
- [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes,
- const Timing& timing) {
- ASSERT_NE(ErrorStatus::NONE, error);
- EXPECT_EQ(outputShapes.size(), 0);
- EXPECT_TRUE(badTiming(timing));
- });
- ASSERT_TRUE(executeStatus.isOk());
- }
+ const Request& request) {
+ SCOPED_TRACE("Expecting request to fail [executeSynchronously]");
+ Return<void> executeStatus = preparedModel->executeSynchronously(
+ request, MeasureTiming::NO,
+ [](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes, const Timing& timing) {
+ ASSERT_NE(ErrorStatus::NONE, error);
+ EXPECT_EQ(outputShapes.size(), 0);
+ EXPECT_TRUE(badTiming(timing));
+ });
+ ASSERT_TRUE(executeStatus.isOk());
}
} // namespace functional
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
index bd24edc..eb52110 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
@@ -126,7 +126,7 @@
::testing::VtsHalHidlTargetTestBase::TearDown();
}
-void ValidationTest::validateEverything(const Model& model, const std::vector<Request>& requests) {
+void ValidationTest::validateEverything(const Model& model, const Request& request) {
validateModel(model);
// create IPreparedModel
@@ -136,11 +136,11 @@
return;
}
- validateRequests(preparedModel, requests);
- validateBurst(preparedModel, requests);
+ validateRequest(preparedModel, request);
+ validateBurst(preparedModel, request);
}
-void ValidationTest::validateFailure(const Model& model, const std::vector<Request>& requests) {
+void ValidationTest::validateFailure(const Model& model, const Request& request) {
// TODO: Should this always succeed?
// What if the invalid input is part of the model (i.e., a parameter).
validateModel(model);
@@ -151,7 +151,7 @@
return;
}
- validateRequestFailure(preparedModel, requests);
+ validateRequestFailure(preparedModel, request);
}
sp<IPreparedModel> getPreparedModel_1_2(
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
index 90dfe25..e76ad7b 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
@@ -68,20 +68,16 @@
sp<IDevice> device;
};
-// Tag for the validation tests
class ValidationTest : public NeuralnetworksHidlTest {
protected:
- void validateEverything(const Model& model, const std::vector<Request>& requests);
- void validateFailure(const Model& model, const std::vector<Request>& requests);
+ void validateEverything(const Model& model, const Request& request);
+ void validateFailure(const Model& model, const Request& request);
private:
void validateModel(const Model& model);
- void validateRequests(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests);
- void validateRequestFailure(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests);
- void validateBurst(const sp<IPreparedModel>& preparedModel,
- const std::vector<Request>& requests);
+ void validateRequest(const sp<IPreparedModel>& preparedModel, const Request& request);
+ void validateRequestFailure(const sp<IPreparedModel>& preparedModel, const Request& request);
+ void validateBurst(const sp<IPreparedModel>& preparedModel, const Request& request);
};
// Tag for the generated tests
diff --git a/tv/tuner/1.0/Android.bp b/tv/tuner/1.0/Android.bp
index b54413d..986518b 100644
--- a/tv/tuner/1.0/Android.bp
+++ b/tv/tuner/1.0/Android.bp
@@ -8,6 +8,9 @@
},
srcs: [
"types.hal",
+ "IDemux.hal",
+ "IDemuxCallback.hal",
+ "IDescrambler.hal",
"IFrontend.hal",
"IFrontendCallback.hal",
"ITuner.hal",
diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal
new file mode 100644
index 0000000..938bc44
--- /dev/null
+++ b/tv/tuner/1.0/IDemux.hal
@@ -0,0 +1,37 @@
+package android.hardware.tv.tuner@1.0;
+
+import IDemuxCallback;
+
+/**
+ * Demultiplexer(Demux) takes a single multiplexed input and splits it into
+ * one or more output.
+ *
+ */
+interface IDemux {
+
+ /**
+ * Set a frontend resource as data input of the demux
+ *
+ * It is used by the client to specify a hardware frontend as data source of
+ * this demux instance. A demux instance can have only one data source.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ setFrontendDataSource(FrontendId frontendId) generates (Result result);
+
+ /**
+ * Close the Demux instance
+ *
+ * It is used by the client to release the demux instance. HAL clear
+ * underneath resource. client mustn't access the instance any more.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ close() generates (Result result);
+};
+
diff --git a/tv/tuner/1.0/IDemuxCallback.hal b/tv/tuner/1.0/IDemuxCallback.hal
new file mode 100644
index 0000000..c67c5f2
--- /dev/null
+++ b/tv/tuner/1.0/IDemuxCallback.hal
@@ -0,0 +1,11 @@
+package android.hardware.tv.tuner@1.0;
+
+interface IDemuxCallback {
+ /**
+ * Notify the client that a new filter event happened.
+ *
+ * @param filterEvent a demux filter event.
+ */
+ oneway onFilterEvent(DemuxFilterEvent filterEvent);
+};
+
diff --git a/tv/tuner/1.0/IDescrambler.hal b/tv/tuner/1.0/IDescrambler.hal
new file mode 100644
index 0000000..4d6cf3c
--- /dev/null
+++ b/tv/tuner/1.0/IDescrambler.hal
@@ -0,0 +1,35 @@
+package android.hardware.tv.tuner@1.0;
+
+/**
+ * Descrambler is used to descramble input data.
+ *
+ */
+interface IDescrambler {
+
+ /**
+ * Set a demux as source of the descrambler
+ *
+ * It is used by the client to specify a demux as source of this
+ * descrambler. A descrambler instance can have only one source, and
+ * this method can be only called once.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * INVALID_STATE if failed for wrong state.
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ setDemuxSource(DemuxId demuxId) generates (Result result);
+
+ /**
+ * Release the descrambler instance
+ *
+ * It is used by the client to release the descrambler instance. HAL clear
+ * underneath resource. client mustn't access the instance any more.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNKNOWN_ERROR if failed for other reasons.
+ */
+ close() generates (Result result);
+};
+
diff --git a/tv/tuner/1.0/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal
index 05cee91..f7237ba 100644
--- a/tv/tuner/1.0/IFrontend.hal
+++ b/tv/tuner/1.0/IFrontend.hal
@@ -18,15 +18,16 @@
import IFrontendCallback;
/**
- * A Tuner Frontend is used to tune to a frequency and lock signal. It provide
- * live data feed to Tuner Demux interface.
+ * A Tuner Frontend is used to tune to a frequency and lock signal.
+ *
+ * IFrontend provides a bit stream to the Tuner Demux interface.
*/
interface IFrontend {
/**
- * Set the callback
+ * Set the frontend callback.
*
- * It is used by the client to receive events from the Frontend.
- * Only one callback for one Frontend instance is supported. The callback
+ * IFrontendCallback is used by the client to receive events from the Frontend.
+ * Only one callback per IFrontend instance is supported. The callback
* will be replaced if it's set again.
*
* @param callback Callback object to pass Frontend events to the system.
@@ -40,14 +41,14 @@
setCallback(IFrontendCallback callback) generates (Result result);
/**
- * Tuning Frontend
+ * Tunes the frontend to using the settings given.
*
- * It is used by the client to lock a frequency by providing signal
- * delivery information. If previous tuning isn't completed, this call must
- * stop previous tuning, and start a new tuning. Tune is a async call.
- * LOCKED or NO_SIGNAL eventi is sent back to caller through callback.
+ * This locks the frontend to a frequency by providing signal
+ * delivery information. If previous tuning isn't completed, this call MUST
+ * stop previous tuning, and start a new tuning.
+ * Tune is an async call, with LOCKED or NO_SIGNAL events sent via callback.
*
- * @param settings Signal delivery information which frontend can use to
+ * @param settings Signal delivery information the frontend uses to
* search and lock the signal.
*
* @return result Result status of the operation.
@@ -58,9 +59,10 @@
tune(FrontendSettings settings) generates (Result result);
/**
- * Stop the tuning
+ * Stops a previous tuning.
*
- * It is used by the client to stop a previous tuning.
+ * If the method completes successfully the frontend is no longer tuned and no data
+ * will be sent to attached demuxes.
*
* @return result Result status of the operation.
* SUCCESS if successfully stop tuning.
@@ -69,10 +71,10 @@
stopTune() generates (Result result);
/**
- * Release the Frontend instance
+ * Releases the Frontend instance
*
- * It is used by the client to release the frontend instance. HAL clear
- * underneath resource. client mustn't access the instance any more.
+ * Associated resources are released. close may be called more than once.
+ * Calls to any other method after this will return an error
*
* @return result Result status of the operation.
* SUCCESS if successful,
diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal
index 5a5f547..61a9d63 100644
--- a/tv/tuner/1.0/ITuner.hal
+++ b/tv/tuner/1.0/ITuner.hal
@@ -16,6 +16,8 @@
package android.hardware.tv.tuner@1.0;
+import IDemux;
+import IDescrambler;
import IFrontend;
/**
@@ -48,5 +50,30 @@
openFrontendById(FrontendId frontendId)
generates (Result result, IFrontend frontend);
-};
+ /**
+ * Create a new instance of Demux.
+ *
+ * It is used by the client to create a Demux instance.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNKNOWN_ERROR if creation failed for other reasons.
+ * @return demuxId newly created demux id.
+ * @return demux the newly created demux interface.
+ */
+ openDemux()
+ generates (Result result, DemuxId demuxId, IDemux demux);
+ /**
+ * Create a new instance of Descrambler.
+ *
+ * It is used by the client to create a Descrambler instance.
+ *
+ * @return result Result status of the operation.
+ * SUCCESS if successful,
+ * UNKNOWN_ERROR if creation failed for other reasons.
+ * @return descrambler the newly created descrambler interface.
+ */
+ openDescrambler()
+ generates (Result result, IDescrambler descrambler);
+};
diff --git a/tv/tuner/1.0/default/Android.bp b/tv/tuner/1.0/default/Android.bp
index cc8d1f5..21c9f1b 100644
--- a/tv/tuner/1.0/default/Android.bp
+++ b/tv/tuner/1.0/default/Android.bp
@@ -5,6 +5,8 @@
relative_install_path: "hw",
srcs: [
"Frontend.cpp",
+ "Descrambler.cpp",
+ "Demux.cpp",
"Tuner.cpp",
"service.cpp",
],
diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp
new file mode 100644
index 0000000..6f7c68b
--- /dev/null
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.tuner@1.0-Demux"
+
+#include "Demux.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Demux::Demux(uint32_t demuxId) {
+ mDemuxId = demuxId;
+}
+
+Demux::~Demux() {}
+
+Return<Result> Demux::setFrontendDataSource(uint32_t frontendId) {
+ ALOGV("%s", __FUNCTION__);
+
+ mSourceFrontendId = frontendId;
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Demux::close() {
+ ALOGV("%s", __FUNCTION__);
+
+ return Result::SUCCESS;
+ ;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h
new file mode 100644
index 0000000..52f3933
--- /dev/null
+++ b/tv/tuner/1.0/default/Demux.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_DEMUX_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_DEMUX_H_
+
+#include <android/hardware/tv/tuner/1.0/IDemux.h>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tv::tuner::V1_0::IDemux;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+class Demux : public IDemux {
+ public:
+ Demux(uint32_t demuxId);
+
+ virtual Return<Result> setFrontendDataSource(uint32_t frontendId) override;
+
+ virtual Return<Result> close() override;
+
+ private:
+ virtual ~Demux();
+ uint32_t mDemuxId;
+ uint32_t mSourceFrontendId;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_TUNER_V1_0_DEMUX_H_
diff --git a/tv/tuner/1.0/default/Descrambler.cpp b/tv/tuner/1.0/default/Descrambler.cpp
new file mode 100644
index 0000000..1af1a2c
--- /dev/null
+++ b/tv/tuner/1.0/default/Descrambler.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.tv.tuner@1.0-Descrambler"
+
+#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
+#include <utils/Log.h>
+
+#include "Descrambler.h"
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Descrambler::Descrambler() {}
+
+Descrambler::~Descrambler() {}
+
+Return<Result> Descrambler::setDemuxSource(uint32_t demuxId) {
+ ALOGV("%s", __FUNCTION__);
+ if (mDemuxSet) {
+ ALOGW("[ WARN ] Descrambler has already been set with a demux id %d", mSourceDemuxId);
+ return Result::INVALID_STATE;
+ }
+ mDemuxSet = true;
+ mSourceDemuxId = demuxId;
+
+ return Result::SUCCESS;
+}
+
+Return<Result> Descrambler::close() {
+ ALOGV("%s", __FUNCTION__);
+ mDemuxSet = false;
+
+ return Result::SUCCESS;
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
diff --git a/tv/tuner/1.0/default/Descrambler.h b/tv/tuner/1.0/default/Descrambler.h
new file mode 100644
index 0000000..2ec8412
--- /dev/null
+++ b/tv/tuner/1.0/default/Descrambler.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_TV_TUNER_V1_0_DESCRAMBLER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_DESCRAMBLER_H_
+
+#include <android/hardware/tv/tuner/1.0/IDescrambler.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tv::tuner::V1_0::IDescrambler;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+class Descrambler : public IDescrambler {
+ public:
+ Descrambler();
+
+ virtual Return<Result> setDemuxSource(uint32_t demuxId) override;
+
+ virtual Return<Result> close() override;
+
+ private:
+ virtual ~Descrambler();
+ uint32_t mSourceDemuxId;
+ bool mDemuxSet = false;
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace tuner
+} // namespace tv
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TV_TUNER_V1_DESCRAMBLER_H_
diff --git a/tv/tuner/1.0/default/OWNERS b/tv/tuner/1.0/default/OWNERS
new file mode 100644
index 0000000..1b3d095
--- /dev/null
+++ b/tv/tuner/1.0/default/OWNERS
@@ -0,0 +1,4 @@
+nchalko@google.com
+amyjojo@google.com
+shubang@google.com
+quxiangfang@google.com
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index 67ec754..68b3436 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -19,6 +19,8 @@
#include "Tuner.h"
#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
#include <utils/Log.h>
+#include "Demux.h"
+#include "Descrambler.h"
#include "Frontend.h"
namespace android {
@@ -28,6 +30,8 @@
namespace V1_0 {
namespace implementation {
+using ::android::hardware::tv::tuner::V1_0::DemuxId;
+
Tuner::Tuner() {
// Static Frontends array to maintain local frontends information
// Array index matches their FrontendId in the default impl
@@ -71,6 +75,26 @@
return Void();
}
+Return<void> Tuner::openDemux(openDemux_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ DemuxId demuxId = mLastUsedId + 1;
+ mLastUsedId += 1;
+ sp<IDemux> demux = new Demux(demuxId);
+
+ _hidl_cb(Result::SUCCESS, demuxId, demux);
+ return Void();
+}
+
+Return<void> Tuner::openDescrambler(openDescrambler_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ sp<IDescrambler> descrambler = new Descrambler();
+
+ _hidl_cb(Result::SUCCESS, descrambler);
+ return Void();
+}
+
} // namespace implementation
} // namespace V1_0
} // namespace tuner
diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h
index 2152c89..12e9594 100644
--- a/tv/tuner/1.0/default/Tuner.h
+++ b/tv/tuner/1.0/default/Tuner.h
@@ -37,12 +37,19 @@
virtual Return<void> openFrontendById(uint32_t frontendId,
openFrontendById_cb _hidl_cb) override;
+ virtual Return<void> openDemux(openDemux_cb _hidl_cb) override;
+
+ virtual Return<void> openDescrambler(openDescrambler_cb _hidl_cb) override;
+
private:
virtual ~Tuner();
// Static mFrontends array to maintain local frontends information
vector<sp<Frontend>> mFrontends;
// To maintain how many Frontends we have
int mFrontendSize;
+ // The last used demux id. Initial value is -1.
+ // First used id will be 0.
+ int mLastUsedId = -1;
};
} // namespace implementation
diff --git a/tv/tuner/1.0/default/service.cpp b/tv/tuner/1.0/default/service.cpp
index 581d269..c360fcf 100644
--- a/tv/tuner/1.0/default/service.cpp
+++ b/tv/tuner/1.0/default/service.cpp
@@ -46,8 +46,8 @@
android::sp<ITuner> service = new Tuner();
android::status_t status;
if (kLazyService) {
- auto serviceRegistrar = std::make_shared<LazyServiceRegistrar>();
- status = serviceRegistrar->registerService(service);
+ auto serviceRegistrar = LazyServiceRegistrar::getInstance();
+ status = serviceRegistrar.registerService(service);
} else {
status = service->registerAsService();
}
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 1ca7fda..3fa9641 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -137,3 +137,53 @@
*/
LOST_LOCK,
};
+
+/* Demux ID is used to associate with a hardware demux resource. */
+typedef uint32_t DemuxId;
+
+/* Filter ID is used to associate with a hardware filter resource. */
+typedef uint32_t DemuxFilterId;
+
+/**
+ * Filter Type according to ISO/IEC 13818-1
+ */
+@export
+enum DemuxFilterType : uint32_t {
+ /**
+ * A filter to filter section data out from input stream.
+ */
+ SECTION,
+ /**
+ * A filter to filter PES data out from input stream.
+ */
+ PES,
+ /**
+ * A filter to filter TS payload out from input stream.
+ */
+ TS,
+ /**
+ * A filter to filter Audio Metadata out from input stream.
+ */
+ AUDIO,
+ /**
+ * A filter to filter Vidoe Metadata out from input stream.
+ */
+ VIDEO,
+ /**
+ * A filter to set PCR channel from input stream.
+ */
+ PCR,
+ /**
+ * A filter to filter data directly to output buffer for record.
+ */
+ RECORD,
+};
+
+/**
+ * Filter Event.
+ */
+struct DemuxFilterEvent {
+ DemuxFilterId filterId;
+ DemuxFilterType filterType;
+};
+
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 4840a02..c652944 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -19,6 +19,9 @@
#include <VtsHalHidlTargetTestBase.h>
#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
+#include <android/hardware/tv/tuner/1.0/IDemux.h>
+#include <android/hardware/tv/tuner/1.0/IDemuxCallback.h>
+#include <android/hardware/tv/tuner/1.0/IDescrambler.h>
#include <android/hardware/tv/tuner/1.0/IFrontend.h>
#include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
#include <android/hardware/tv/tuner/1.0/ITuner.h>
@@ -52,6 +55,9 @@
using android::hardware::tv::tuner::V1_0::FrontendId;
using android::hardware::tv::tuner::V1_0::FrontendInnerFec;
using android::hardware::tv::tuner::V1_0::FrontendSettings;
+using android::hardware::tv::tuner::V1_0::IDemux;
+using android::hardware::tv::tuner::V1_0::IDemuxCallback;
+using android::hardware::tv::tuner::V1_0::IDescrambler;
using android::hardware::tv::tuner::V1_0::IFrontend;
using android::hardware::tv::tuner::V1_0::IFrontendCallback;
using android::hardware::tv::tuner::V1_0::ITuner;
@@ -146,11 +152,19 @@
sp<IFrontend> mFrontend;
sp<FrontendCallback> mFrontendCallback;
+ sp<IDescrambler> mDescrambler;
+ sp<IDemux> mDemux;
+ uint32_t mDemuxId;
::testing::AssertionResult createFrontend(int32_t frontendId);
::testing::AssertionResult tuneFrontend(int32_t frontendId);
::testing::AssertionResult stopTuneFrontend(int32_t frontendId);
::testing::AssertionResult closeFrontend(int32_t frontendId);
+ ::testing::AssertionResult createDemux();
+ ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId);
+ ::testing::AssertionResult closeDemux();
+ ::testing::AssertionResult createDescrambler();
+ ::testing::AssertionResult closeDescrambler();
};
::testing::AssertionResult TunerHidlTest::createFrontend(int32_t frontendId) {
@@ -215,6 +229,78 @@
return ::testing::AssertionResult(status == Result::SUCCESS);
}
+::testing::AssertionResult TunerHidlTest::createDemux() {
+ Result status;
+
+ mService->openDemux([&](Result result, uint32_t demuxId, const sp<IDemux>& demux) {
+ mDemux = demux;
+ mDemuxId = demuxId;
+ status = result;
+ });
+ return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::createDemuxWithFrontend(int32_t frontendId) {
+ Result status;
+
+ if (createDemux() == ::testing::AssertionFailure()) {
+ return ::testing::AssertionFailure();
+ }
+
+ if (createFrontend(frontendId) == ::testing::AssertionFailure()) {
+ return ::testing::AssertionFailure();
+ }
+
+ status = mDemux->setFrontendDataSource(frontendId);
+
+ return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::closeDemux() {
+ Result status;
+ if (createDemux() == ::testing::AssertionFailure()) {
+ return ::testing::AssertionFailure();
+ }
+
+ status = mDemux->close();
+ return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::createDescrambler() {
+ Result status;
+
+ mService->openDescrambler([&](Result result, const sp<IDescrambler>& descrambler) {
+ mDescrambler = descrambler;
+ status = result;
+ });
+ if (status != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+
+ if (createDemux() == ::testing::AssertionFailure()) {
+ return ::testing::AssertionFailure();
+ }
+
+ status = mDescrambler->setDemuxSource(mDemuxId);
+ if (status != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+
+ // Test if demux source can be set more than once.
+ status = mDescrambler->setDemuxSource(mDemuxId);
+ return ::testing::AssertionResult(status == Result::INVALID_STATE);
+}
+
+::testing::AssertionResult TunerHidlTest::closeDescrambler() {
+ Result status;
+ if (createDescrambler() == ::testing::AssertionFailure()) {
+ return ::testing::AssertionFailure();
+ }
+
+ status = mDescrambler->close();
+ return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
TEST_F(TunerHidlTest, CreateFrontend) {
Result status;
hidl_vec<FrontendId> feIds;
@@ -295,6 +381,50 @@
}
}
+TEST_F(TunerHidlTest, CreateDemux) {
+ description("Create Demux");
+
+ ASSERT_TRUE(createDemux());
+}
+
+TEST_F(TunerHidlTest, CreateDemuxWithFrontend) {
+ Result status;
+ hidl_vec<FrontendId> feIds;
+
+ description("Create Demux with Frontend");
+ mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+ status = result;
+ feIds = frontendIds;
+ });
+
+ if (feIds.size() == 0) {
+ ALOGW("[ WARN ] Frontend isn't available");
+ return;
+ }
+
+ for (size_t i = 0; i < feIds.size(); i++) {
+ ASSERT_TRUE(createDemuxWithFrontend(feIds[i]));
+ }
+}
+
+TEST_F(TunerHidlTest, CloseDemux) {
+ description("Close Demux");
+
+ ASSERT_TRUE(closeDemux());
+}
+
+TEST_F(TunerHidlTest, CreateDescrambler) {
+ description("Create Descrambler");
+
+ ASSERT_TRUE(createDescrambler());
+}
+
+TEST_F(TunerHidlTest, CloseDescrambler) {
+ description("Close Descrambler");
+
+ ASSERT_TRUE(closeDescrambler());
+}
+
} // namespace
int main(int argc, char** argv) {