Merge changes from topic "Tuner HAL demux and descrambler"
* changes:
Tuner HAL VTS for Demux and Descrambler Interface.
Tuner HAL default implementation for Demux and Descrambler Interface.
Add Demux and Descrambler interface to Tuner HAL Test: Manual bug: 135709729
diff --git a/automotive/evs/1.1/IEvsCamera.hal b/automotive/evs/1.1/IEvsCamera.hal
index d4263b7..21ca79e 100644
--- a/automotive/evs/1.1/IEvsCamera.hal
+++ b/automotive/evs/1.1/IEvsCamera.hal
@@ -17,6 +17,7 @@
package android.hardware.automotive.evs@1.1;
import @1.0::IEvsCamera;
+import @1.0::IEvsDisplay;
import @1.0::EvsResult;
import IEvsCameraStream;
@@ -71,6 +72,23 @@
*/
setMaster() generates (EvsResult result);
+ /**
+ * Sets to be a master client forcibly.
+ *
+ * The client, which owns the display, has a high priority and can take over
+ * a master role from other clients without the display.
+ *
+ * @param display IEvsDisplay handle. If a given display is in either
+ * NOT_VISIBLE, VISIBLE_ON_NEXT_FRAME, or VISIBLE state, the
+ * calling client is considered as the high priority client
+ * and therefore allowed to take over a master role from
+ * existing master client.
+ *
+ * @return result EvsResult::OK if a master role is granted.
+ * EvsResult::INVALID_ARG if a given display handle is null
+ * or in valid states.
+ */
+ forceMaster(IEvsDisplay display) generates (EvsResult result);
/**
* Retires from a master client role.
diff --git a/automotive/evs/1.1/default/EvsCamera.cpp b/automotive/evs/1.1/default/EvsCamera.cpp
index ae293b6..2d55566 100644
--- a/automotive/evs/1.1/default/EvsCamera.cpp
+++ b/automotive/evs/1.1/default/EvsCamera.cpp
@@ -264,6 +264,12 @@
return EvsResult::OK;
}
+Return<EvsResult> EvsCamera::forceMaster(const sp<IEvsDisplay>& ) {
+ // Default implementation does not expect multiple subscribers and therefore
+ // return a success code always.
+ return EvsResult::OK;
+}
+
Return<EvsResult> EvsCamera::unsetMaster() {
// Default implementation does not expect multiple subscribers and therefore
diff --git a/automotive/evs/1.1/default/EvsCamera.h b/automotive/evs/1.1/default/EvsCamera.h
index 6cb1cfb..47a3164 100644
--- a/automotive/evs/1.1/default/EvsCamera.h
+++ b/automotive/evs/1.1/default/EvsCamera.h
@@ -20,6 +20,7 @@
#include <android/hardware/automotive/evs/1.1/types.h>
#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <android/hardware/automotive/evs/1.0/IEvsDisplay.h>
#include <ui/GraphicBuffer.h>
#include <thread>
@@ -30,6 +31,7 @@
using IEvsCameraStream_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCameraStream;
using ::android::hardware::automotive::evs::V1_0::EvsResult;
using ::android::hardware::automotive::evs::V1_0::CameraDesc;
+using ::android::hardware::automotive::evs::V1_0::IEvsDisplay;
namespace android {
@@ -61,6 +63,7 @@
Return<EvsResult> resumeVideoStream() override;
Return<EvsResult> doneWithFrame_1_1(const BufferDesc_1_1& buffer) override;
Return<EvsResult> setMaster() override;
+ Return<EvsResult> forceMaster(const sp<IEvsDisplay>& display) override;
Return<EvsResult> unsetMaster() override;
Return<void> setParameter(CameraParam id, int32_t value,
setParameter_cb _hidl_cb) override;
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.cpp b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
index a39346b..1627689 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.cpp
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.cpp
@@ -21,11 +21,14 @@
#include <stdio.h>
#include <string.h>
+#include <chrono>
#include <android/log.h>
#include <cutils/native_handle.h>
#include <ui/GraphicBuffer.h>
+using namespace std::chrono_literals;
+
FrameHandler::FrameHandler(android::sp <IEvsCamera> pCamera, CameraDesc cameraInfo,
android::sp <IEvsDisplay> pDisplay,
BufferControlFlag mode) :
@@ -148,7 +151,7 @@
ALOGD("Camera parameter 0x%X is changed to 0x%X",
mLatestEventDesc.payload[0], mLatestEventDesc.payload[1]);
} else {
- ALOGD("Received an event 0x%X", mLatestEventDesc.aType);
+ ALOGD("Received an event %s", eventToString(mLatestEventDesc.aType));
}
mLock.unlock();
mEventSignal.notify_all();
@@ -339,19 +342,42 @@
}
}
-void FrameHandler::waitForEvent(const InfoEventType aTargetEvent,
+bool FrameHandler::waitForEvent(const InfoEventType aTargetEvent,
InfoEventDesc &eventDesc) {
// Wait until we get an expected parameter change event.
std::unique_lock<std::mutex> lock(mLock);
- mEventSignal.wait(lock, [this, aTargetEvent, &eventDesc](){
- bool flag = mLatestEventDesc.aType == aTargetEvent;
- if (flag) {
- eventDesc.aType = mLatestEventDesc.aType;
- eventDesc.payload[0] = mLatestEventDesc.payload[0];
- eventDesc.payload[1] = mLatestEventDesc.payload[1];
- }
+ auto now = std::chrono::system_clock::now();
+ bool result = mEventSignal.wait_until(lock, now + 5s,
+ [this, aTargetEvent, &eventDesc](){
+ bool flag = mLatestEventDesc.aType == aTargetEvent;
+ if (flag) {
+ eventDesc.aType = mLatestEventDesc.aType;
+ eventDesc.payload[0] = mLatestEventDesc.payload[0];
+ eventDesc.payload[1] = mLatestEventDesc.payload[1];
+ }
- return flag;
- });
+ return flag;
+ }
+ );
+
+ return !result;
}
+const char *FrameHandler::eventToString(const InfoEventType aType) {
+ switch (aType) {
+ case InfoEventType::STREAM_STARTED:
+ return "STREAM_STARTED";
+ case InfoEventType::STREAM_STOPPED:
+ return "STREAM_STOPPED";
+ case InfoEventType::FRAME_DROPPED:
+ return "FRAME_DROPPED";
+ case InfoEventType::TIMEOUT:
+ return "TIMEOUT";
+ case InfoEventType::PARAMETER_CHANGED:
+ return "PARAMETER_CHANGED";
+ case InfoEventType::MASTER_RELEASED:
+ return "MASTER_RELEASED";
+ default:
+ return "Unknown";
+ }
+}
diff --git a/automotive/evs/1.1/vts/functional/FrameHandler.h b/automotive/evs/1.1/vts/functional/FrameHandler.h
index c5faecd..7f87cb4 100644
--- a/automotive/evs/1.1/vts/functional/FrameHandler.h
+++ b/automotive/evs/1.1/vts/functional/FrameHandler.h
@@ -67,7 +67,7 @@
bool isRunning();
void waitForFrameCount(unsigned frameCount);
- void waitForEvent(const InfoEventType aTargetEvent,
+ bool waitForEvent(const InfoEventType aTargetEvent,
InfoEventDesc &eventDesc);
void getFramesCounters(unsigned* received, unsigned* displayed);
void getFrameDimension(unsigned* width, unsigned* height);
@@ -79,6 +79,7 @@
// Local implementation details
bool copyBufferContents(const BufferDesc_1_0& tgtBuffer, const BufferDesc_1_1& srcBuffer);
+ const char *eventToString(const InfoEventType aType);
// Values initialized as startup
android::sp <IEvsCamera> mCamera;
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index 0d88c07..a6e4881 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -935,6 +935,132 @@
}
+/*
+ * HighPriorityCameraClient:
+ * EVS client, which owns the display, is priortized and therefore can take over
+ * a master role from other EVS clients without the display.
+ */
+TEST_F(EvsHidlTest, HighPriorityCameraClient) {
+ ALOGI("Starting HighPriorityCameraClient test");
+
+ // Get the camera list
+ loadCameraList();
+
+ // Request exclusive access to the EVS display
+ sp<IEvsDisplay> pDisplay = pEnumerator->openDisplay();
+ ASSERT_NE(pDisplay, nullptr);
+
+ // Test each reported camera
+ for (auto&& cam: cameraInfo) {
+ // Create two clients
+ sp<IEvsCamera_1_1> pCam0 =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam0, nullptr);
+
+ sp<IEvsCamera_1_1> pCam1 =
+ IEvsCamera_1_1::castFrom(pEnumerator->openCamera(cam.cameraId))
+ .withDefault(nullptr);
+ ASSERT_NE(pCam1, nullptr);
+
+ // Set up a frame receiver object which will fire up its own thread.
+ sp<FrameHandler> frameHandler0 = new FrameHandler(pCam0, cam,
+ pDisplay,
+ FrameHandler::eAutoReturn);
+ sp<FrameHandler> frameHandler1 = new FrameHandler(pCam1, cam,
+ nullptr,
+ FrameHandler::eAutoReturn);
+
+ // Activate the display
+ pDisplay->setDisplayState(DisplayState::VISIBLE_ON_NEXT_FRAME);
+
+ // Start the camera's video stream
+ ASSERT_TRUE(frameHandler0->startStream());
+ ASSERT_TRUE(frameHandler1->startStream());
+
+ // Ensure the stream starts
+ frameHandler0->waitForFrameCount(1);
+ frameHandler1->waitForFrameCount(1);
+
+ // Client 1 becomes a master and programs a brightness.
+ EvsResult result = EvsResult::OK;
+ int32_t val0 = 100;
+ int32_t val1 = 0;
+
+ result = pCam1->setMaster();
+ ASSERT_TRUE(result == EvsResult::OK);
+
+ pCam1->setParameter(CameraParam::BRIGHTNESS, val0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_TRUE(result == EvsResult::OK ||
+ result == EvsResult::INVALID_ARG);
+
+
+ // Verify a change notification
+ InfoEventDesc aNotification = {};
+ if (result == EvsResult::OK) {
+ bool timeout =
+ frameHandler0->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
+ ASSERT_FALSE(timeout) << "Expected event does not arrive";
+ ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
+ InfoEventType::PARAMETER_CHANGED);
+ ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+ CameraParam::BRIGHTNESS);
+ ASSERT_EQ(val1,
+ static_cast<int32_t>(aNotification.payload[1]));
+ }
+
+ // Client 0 steals a master role
+ ASSERT_EQ(EvsResult::OK, pCam0->forceMaster(pDisplay));
+
+ frameHandler1->waitForEvent(InfoEventType::MASTER_RELEASED, aNotification);
+ ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
+ InfoEventType::MASTER_RELEASED);
+
+ // Client 0 programs a brightness
+ val0 = 50;
+ val1 = 0;
+ pCam0->setParameter(CameraParam::BRIGHTNESS, val0,
+ [&result, &val1](auto status, auto effectiveValue) {
+ result = status;
+ val1 = effectiveValue;
+ });
+ ASSERT_TRUE(result == EvsResult::OK ||
+ result == EvsResult::INVALID_ARG);
+
+ // Verify a change notification
+ if (result == EvsResult::OK) {
+ bool timeout =
+ frameHandler1->waitForEvent(InfoEventType::PARAMETER_CHANGED, aNotification);
+ ASSERT_FALSE(timeout) << "Expected event does not arrive";
+ ASSERT_EQ(static_cast<InfoEventType>(aNotification.aType),
+ InfoEventType::PARAMETER_CHANGED);
+ ASSERT_EQ(static_cast<CameraParam>(aNotification.payload[0]),
+ CameraParam::BRIGHTNESS);
+ ASSERT_EQ(val1,
+ static_cast<int32_t>(aNotification.payload[1]));
+ }
+
+ // Turn off the display (yes, before the stream stops -- it should be handled)
+ pDisplay->setDisplayState(DisplayState::NOT_VISIBLE);
+
+ // Shut down the streamer
+ frameHandler0->shutdown();
+ frameHandler1->shutdown();
+
+ // Explicitly release the camera
+ pEnumerator->closeCamera(pCam0);
+ pEnumerator->closeCamera(pCam1);
+ }
+
+ // Explicitly release the display
+ pEnumerator->closeDisplay(pDisplay);
+}
+
+
int main(int argc, char** argv) {
::testing::AddGlobalTestEnvironment(EvsHidlEnvironment::Instance());
::testing::InitGoogleTest(&argc, argv);
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/camera/provider/2.5/default/service.cpp b/camera/provider/2.5/default/service.cpp
index 604215d..ec30cbc 100644
--- a/camera/provider/2.5/default/service.cpp
+++ b/camera/provider/2.5/default/service.cpp
@@ -49,8 +49,8 @@
status_t status;
if (kLazyService) {
- auto serviceRegistrar = std::make_shared<::android::hardware::LazyServiceRegistrar>();
- status = serviceRegistrar->registerService(provider, "legacy/0");
+ auto serviceRegistrar = ::android::hardware::LazyServiceRegistrar::getInstance();
+ status = serviceRegistrar.registerService(provider, "legacy/0");
} else {
status = provider->registerAsService("legacy/0");
}
diff --git a/cas/1.1/default/service.cpp b/cas/1.1/default/service.cpp
index 9625303..bf0e159 100644
--- a/cas/1.1/default/service.cpp
+++ b/cas/1.1/default/service.cpp
@@ -46,8 +46,8 @@
android::sp<IMediaCasService> service = new MediaCasService();
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/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/default/Android.bp b/graphics/composer/2.1/default/Android.bp
index 63accff..c4feae5 100644
--- a/graphics/composer/2.1/default/Android.bp
+++ b/graphics/composer/2.1/default/Android.bp
@@ -9,8 +9,7 @@
],
shared_libs: [
"android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.composer@2.1-resources",
"libbase",
"libcutils",
"libfmq",
diff --git a/graphics/composer/2.1/utils/hal/Android.bp b/graphics/composer/2.1/utils/hal/Android.bp
index 7a501fc..ea3666d 100644
--- a/graphics/composer/2.1/utils/hal/Android.bp
+++ b/graphics/composer/2.1/utils/hal/Android.bp
@@ -19,14 +19,12 @@
vendor_available: true,
shared_libs: [
"android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.composer@2.1-resources",
"libhardware", // TODO remove hwcomposer2.h dependency
],
export_shared_lib_headers: [
"android.hardware.graphics.composer@2.1",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.composer@2.1-resources",
"libhardware",
],
header_libs: [
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
index 095189f..47ead41 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerClient.h
@@ -27,7 +27,7 @@
#include <android/hardware/graphics/composer/2.1/IComposerClient.h>
#include <composer-hal/2.1/ComposerCommandEngine.h>
#include <composer-hal/2.1/ComposerHal.h>
-#include <composer-hal/2.1/ComposerResources.h>
+#include <composer-resources/2.1/ComposerResources.h>
#include <log/log.h>
namespace android {
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
index d87110a..53b9202 100644
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
+++ b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerCommandEngine.h
@@ -24,7 +24,7 @@
#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
#include <composer-hal/2.1/ComposerHal.h>
-#include <composer-hal/2.1/ComposerResources.h>
+#include <composer-resources/2.1/ComposerResources.h>
// TODO remove hwcomposer_defs.h dependency
#include <hardware/hwcomposer_defs.h>
#include <log/log.h>
@@ -195,7 +195,7 @@
bool closeFence = true;
const native_handle_t* clientTarget;
- ComposerResources::ReplacedBufferHandle replacedClientTarget;
+ ComposerResources::ReplacedHandle replacedClientTarget(true);
auto err = mResources->getDisplayClientTarget(mCurrentDisplay, slot, useCache, rawHandle,
&clientTarget, &replacedClientTarget);
if (err == Error::NONE) {
@@ -226,7 +226,7 @@
bool closeFence = true;
const native_handle_t* outputBuffer;
- ComposerResources::ReplacedBufferHandle replacedOutputBuffer;
+ ComposerResources::ReplacedHandle replacedOutputBuffer(true);
auto err = mResources->getDisplayOutputBuffer(mCurrentDisplay, slot, useCache, rawhandle,
&outputBuffer, &replacedOutputBuffer);
if (err == Error::NONE) {
@@ -369,7 +369,7 @@
bool closeFence = true;
const native_handle_t* buffer;
- ComposerResources::ReplacedBufferHandle replacedBuffer;
+ ComposerResources::ReplacedHandle replacedBuffer(true);
auto err = mResources->getLayerBuffer(mCurrentDisplay, mCurrentLayer, slot, useCache,
rawHandle, &buffer, &replacedBuffer);
if (err == Error::NONE) {
@@ -489,7 +489,7 @@
auto rawHandle = readHandle();
const native_handle_t* stream;
- ComposerResources::ReplacedStreamHandle replacedStream;
+ ComposerResources::ReplacedHandle replacedStream(false);
auto err = mResources->getLayerSidebandStream(mCurrentDisplay, mCurrentLayer, rawHandle,
&stream, &replacedStream);
if (err == Error::NONE) {
diff --git a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h b/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
deleted file mode 100644
index 18d184e..0000000
--- a/graphics/composer/2.1/utils/hal/include/composer-hal/2.1/ComposerResources.h
+++ /dev/null
@@ -1,592 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#ifndef LOG_TAG
-#warning "ComposerResources.h included without LOG_TAG"
-#endif
-
-#include <memory>
-#include <mutex>
-#include <unordered_map>
-#include <vector>
-
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <android/hardware/graphics/mapper/3.0/IMapper.h>
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace composer {
-namespace V2_1 {
-namespace hal {
-
-// wrapper for IMapper to import buffers and sideband streams
-class ComposerHandleImporter {
- public:
- bool init() {
- mMapper3 = mapper::V3_0::IMapper::getService();
- if (mMapper3) {
- return true;
- }
- ALOGD_IF(!mMapper3, "failed to get mapper 3.0 service, falling back to mapper 2.0");
-
- mMapper2 = mapper::V2_0::IMapper::getService();
- ALOGE_IF(!mMapper2, "failed to get mapper 2.0 service");
-
- return mMapper2 != nullptr;
- }
-
- Error importBuffer(const native_handle_t* rawHandle, const native_handle_t** outBufferHandle) {
- if (!rawHandle || (!rawHandle->numFds && !rawHandle->numInts)) {
- *outBufferHandle = nullptr;
- return Error::NONE;
- }
-
- const native_handle_t* bufferHandle;
- if (mMapper2) {
- mapper::V2_0::Error error;
- mMapper2->importBuffer(
- rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
- error = tmpError;
- bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
- });
- if (error != mapper::V2_0::Error::NONE) {
- return Error::NO_RESOURCES;
- }
- }
- if (mMapper3) {
- mapper::V3_0::Error error;
- mMapper3->importBuffer(
- rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
- error = tmpError;
- bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
- });
- if (error != mapper::V3_0::Error::NONE) {
- return Error::NO_RESOURCES;
- }
- }
-
- *outBufferHandle = bufferHandle;
- return Error::NONE;
- }
-
- void freeBuffer(const native_handle_t* bufferHandle) {
- if (bufferHandle) {
- if (mMapper2) {
- mMapper2->freeBuffer(
- static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
- } else if (mMapper3) {
- mMapper3->freeBuffer(
- static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
- }
- }
- }
-
- Error importStream(const native_handle_t* rawHandle, const native_handle_t** outStreamHandle) {
- const native_handle_t* streamHandle = nullptr;
- if (rawHandle) {
- streamHandle = native_handle_clone(rawHandle);
- if (!streamHandle) {
- return Error::NO_RESOURCES;
- }
- }
-
- *outStreamHandle = streamHandle;
- return Error::NONE;
- }
-
- void freeStream(const native_handle_t* streamHandle) {
- if (streamHandle) {
- native_handle_close(streamHandle);
- native_handle_delete(const_cast<native_handle_t*>(streamHandle));
- }
- }
-
- private:
- sp<mapper::V2_0::IMapper> mMapper2;
- sp<mapper::V3_0::IMapper> mMapper3;
-};
-
-class ComposerHandleCache {
- public:
- enum class HandleType {
- INVALID,
- BUFFER,
- STREAM,
- };
-
- ComposerHandleCache(ComposerHandleImporter& importer, HandleType type, uint32_t cacheSize)
- : mImporter(importer), mHandleType(type), mHandles(cacheSize, nullptr) {}
-
- // must be initialized later with initCache
- ComposerHandleCache(ComposerHandleImporter& importer) : mImporter(importer) {}
-
- ~ComposerHandleCache() {
- switch (mHandleType) {
- case HandleType::BUFFER:
- for (auto handle : mHandles) {
- mImporter.freeBuffer(handle);
- }
- break;
- case HandleType::STREAM:
- for (auto handle : mHandles) {
- mImporter.freeStream(handle);
- }
- break;
- default:
- break;
- }
- }
-
- ComposerHandleCache(const ComposerHandleCache&) = delete;
- ComposerHandleCache& operator=(const ComposerHandleCache&) = delete;
-
- bool initCache(HandleType type, uint32_t cacheSize) {
- // already initialized
- if (mHandleType != HandleType::INVALID) {
- return false;
- }
-
- mHandleType = type;
- mHandles.resize(cacheSize, nullptr);
-
- return true;
- }
-
- Error lookupCache(uint32_t slot, const native_handle_t** outHandle) {
- if (slot >= 0 && slot < mHandles.size()) {
- *outHandle = mHandles[slot];
- return Error::NONE;
- } else {
- return Error::BAD_PARAMETER;
- }
- }
-
- Error updateCache(uint32_t slot, const native_handle_t* handle,
- const native_handle** outReplacedHandle) {
- if (slot >= 0 && slot < mHandles.size()) {
- auto& cachedHandle = mHandles[slot];
- *outReplacedHandle = cachedHandle;
- cachedHandle = handle;
- return Error::NONE;
- } else {
- return Error::BAD_PARAMETER;
- }
- }
-
- // when fromCache is true, look up in the cache; otherwise, update the cache
- Error getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
- const native_handle_t** outHandle, const native_handle** outReplacedHandle) {
- if (fromCache) {
- *outReplacedHandle = nullptr;
- return lookupCache(slot, outHandle);
- } else {
- *outHandle = inHandle;
- return updateCache(slot, inHandle, outReplacedHandle);
- }
- }
-
- private:
- ComposerHandleImporter& mImporter;
- HandleType mHandleType = HandleType::INVALID;
- std::vector<const native_handle_t*> mHandles;
-};
-
-// layer resource
-class ComposerLayerResource {
- public:
- ComposerLayerResource(ComposerHandleImporter& importer, uint32_t bufferCacheSize)
- : mBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, bufferCacheSize),
- mSidebandStreamCache(importer, ComposerHandleCache::HandleType::STREAM, 1) {}
-
- virtual ~ComposerLayerResource() = default;
-
- Error getBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
- const native_handle_t** outHandle, const native_handle** outReplacedHandle) {
- return mBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
- }
-
- Error getSidebandStream(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
- const native_handle_t** outHandle,
- const native_handle** outReplacedHandle) {
- return mSidebandStreamCache.getHandle(slot, fromCache, inHandle, outHandle,
- outReplacedHandle);
- }
-
- protected:
- ComposerHandleCache mBufferCache;
- ComposerHandleCache mSidebandStreamCache;
-};
-
-// display resource
-class ComposerDisplayResource {
- public:
- enum class DisplayType {
- PHYSICAL,
- VIRTUAL,
- };
-
- virtual ~ComposerDisplayResource() = default;
-
- ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
- uint32_t outputBufferCacheSize)
- : mType(type),
- mClientTargetCache(importer),
- mOutputBufferCache(importer, ComposerHandleCache::HandleType::BUFFER,
- outputBufferCacheSize),
- mMustValidate(true) {}
-
- bool initClientTargetCache(uint32_t cacheSize) {
- return mClientTargetCache.initCache(ComposerHandleCache::HandleType::BUFFER, cacheSize);
- }
-
- bool isVirtual() const { return mType == DisplayType::VIRTUAL; }
-
- Error getClientTarget(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
- const native_handle_t** outHandle,
- const native_handle** outReplacedHandle) {
- return mClientTargetCache.getHandle(slot, fromCache, inHandle, outHandle,
- outReplacedHandle);
- }
-
- Error getOutputBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
- const native_handle_t** outHandle,
- const native_handle** outReplacedHandle) {
- return mOutputBufferCache.getHandle(slot, fromCache, inHandle, outHandle,
- outReplacedHandle);
- }
-
- bool addLayer(Layer layer, std::unique_ptr<ComposerLayerResource> layerResource) {
- auto result = mLayerResources.emplace(layer, std::move(layerResource));
- return result.second;
- }
-
- bool removeLayer(Layer layer) { return mLayerResources.erase(layer) > 0; }
-
- ComposerLayerResource* findLayerResource(Layer layer) {
- auto layerIter = mLayerResources.find(layer);
- if (layerIter == mLayerResources.end()) {
- return nullptr;
- }
-
- return layerIter->second.get();
- }
-
- std::vector<Layer> getLayers() const {
- std::vector<Layer> layers;
- layers.reserve(mLayerResources.size());
- for (const auto& layerKey : mLayerResources) {
- layers.push_back(layerKey.first);
- }
- return layers;
- }
-
- void setMustValidateState(bool mustValidate) { mMustValidate = mustValidate; }
-
- bool mustValidate() const { return mMustValidate; }
-
- protected:
- const DisplayType mType;
- ComposerHandleCache mClientTargetCache;
- ComposerHandleCache mOutputBufferCache;
- bool mMustValidate;
-
- std::unordered_map<Layer, std::unique_ptr<ComposerLayerResource>> mLayerResources;
-};
-
-class ComposerResources {
- private:
- template <bool isBuffer>
- class ReplacedHandle;
-
- public:
- static std::unique_ptr<ComposerResources> create() {
- auto resources = std::make_unique<ComposerResources>();
- return resources->init() ? std::move(resources) : nullptr;
- }
-
- ComposerResources() = default;
- virtual ~ComposerResources() = default;
-
- bool init() { return mImporter.init(); }
-
- using RemoveDisplay =
- std::function<void(Display display, bool isVirtual, const std::vector<Layer>& layers)>;
- void clear(RemoveDisplay removeDisplay) {
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- for (const auto& displayKey : mDisplayResources) {
- Display display = displayKey.first;
- const ComposerDisplayResource& displayResource = *displayKey.second;
- removeDisplay(display, displayResource.isVirtual(), displayResource.getLayers());
- }
- mDisplayResources.clear();
- }
-
- Error addPhysicalDisplay(Display display) {
- auto displayResource =
- createDisplayResource(ComposerDisplayResource::DisplayType::PHYSICAL, 0);
-
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- auto result = mDisplayResources.emplace(display, std::move(displayResource));
- return result.second ? Error::NONE : Error::BAD_DISPLAY;
- }
-
- Error addVirtualDisplay(Display display, uint32_t outputBufferCacheSize) {
- auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::VIRTUAL,
- outputBufferCacheSize);
-
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- auto result = mDisplayResources.emplace(display, std::move(displayResource));
- return result.second ? Error::NONE : Error::BAD_DISPLAY;
- }
-
- Error removeDisplay(Display display) {
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- return mDisplayResources.erase(display) > 0 ? Error::NONE : Error::BAD_DISPLAY;
- }
-
- Error setDisplayClientTargetCacheSize(Display display, uint32_t clientTargetCacheSize) {
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
- if (!displayResource) {
- return Error::BAD_DISPLAY;
- }
-
- return displayResource->initClientTargetCache(clientTargetCacheSize) ? Error::NONE
- : Error::BAD_PARAMETER;
- }
-
- Error addLayer(Display display, Layer layer, uint32_t bufferCacheSize) {
- auto layerResource = createLayerResource(bufferCacheSize);
-
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
- if (!displayResource) {
- return Error::BAD_DISPLAY;
- }
-
- return displayResource->addLayer(layer, std::move(layerResource)) ? Error::NONE
- : Error::BAD_LAYER;
- }
-
- Error removeLayer(Display display, Layer layer) {
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
- if (!displayResource) {
- return Error::BAD_DISPLAY;
- }
-
- return displayResource->removeLayer(layer) ? Error::NONE : Error::BAD_LAYER;
- }
-
- using ReplacedBufferHandle = ReplacedHandle<true>;
- using ReplacedStreamHandle = ReplacedHandle<false>;
-
- Error getDisplayClientTarget(Display display, uint32_t slot, bool fromCache,
- const native_handle_t* rawHandle,
- const native_handle_t** outBufferHandle,
- ReplacedBufferHandle* outReplacedBuffer) {
- return getHandle<Cache::CLIENT_TARGET>(display, 0, slot, fromCache, rawHandle,
- outBufferHandle, outReplacedBuffer);
- }
-
- Error getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache,
- const native_handle_t* rawHandle,
- const native_handle_t** outBufferHandle,
- ReplacedBufferHandle* outReplacedBuffer) {
- return getHandle<Cache::OUTPUT_BUFFER>(display, 0, slot, fromCache, rawHandle,
- outBufferHandle, outReplacedBuffer);
- }
-
- Error getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache,
- const native_handle_t* rawHandle, const native_handle_t** outBufferHandle,
- ReplacedBufferHandle* outReplacedBuffer) {
- return getHandle<Cache::LAYER_BUFFER>(display, layer, slot, fromCache, rawHandle,
- outBufferHandle, outReplacedBuffer);
- }
-
- Error getLayerSidebandStream(Display display, Layer layer, const native_handle_t* rawHandle,
- const native_handle_t** outStreamHandle,
- ReplacedStreamHandle* outReplacedStream) {
- return getHandle<Cache::LAYER_SIDEBAND_STREAM>(display, layer, 0, false, rawHandle,
- outStreamHandle, outReplacedStream);
- }
-
- void setDisplayMustValidateState(Display display, bool mustValidate) {
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- auto* displayResource = findDisplayResourceLocked(display);
- if (displayResource) {
- displayResource->setMustValidateState(mustValidate);
- }
- }
-
- bool mustValidateDisplay(Display display) {
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
- auto* displayResource = findDisplayResourceLocked(display);
- if (displayResource) {
- return displayResource->mustValidate();
- }
- return false;
- }
-
- protected:
- virtual std::unique_ptr<ComposerDisplayResource> createDisplayResource(
- ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) {
- return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
- }
-
- virtual std::unique_ptr<ComposerLayerResource> createLayerResource(uint32_t bufferCacheSize) {
- return std::make_unique<ComposerLayerResource>(mImporter, bufferCacheSize);
- }
-
- ComposerDisplayResource* findDisplayResourceLocked(Display display) {
- auto iter = mDisplayResources.find(display);
- if (iter == mDisplayResources.end()) {
- return nullptr;
- }
- return iter->second.get();
- }
-
- ComposerHandleImporter mImporter;
-
- std::mutex mDisplayResourcesMutex;
- std::unordered_map<Display, std::unique_ptr<ComposerDisplayResource>> mDisplayResources;
-
- private:
- enum class Cache {
- CLIENT_TARGET,
- OUTPUT_BUFFER,
- LAYER_BUFFER,
- LAYER_SIDEBAND_STREAM,
- };
-
- // When a buffer in the cache is replaced by a new one, we must keep it
- // alive until it has been replaced in ComposerHal.
- template <bool isBuffer>
- class ReplacedHandle {
- public:
- ReplacedHandle() = default;
- ReplacedHandle(const ReplacedHandle&) = delete;
- ReplacedHandle& operator=(const ReplacedHandle&) = delete;
-
- ~ReplacedHandle() { reset(); }
-
- void reset(ComposerHandleImporter* importer = nullptr,
- const native_handle_t* handle = nullptr) {
- if (mHandle) {
- if (isBuffer) {
- mImporter->freeBuffer(mHandle);
- } else {
- mImporter->freeStream(mHandle);
- }
- }
-
- mImporter = importer;
- mHandle = handle;
- }
-
- private:
- ComposerHandleImporter* mImporter = nullptr;
- const native_handle_t* mHandle = nullptr;
- };
-
- template <Cache cache, bool isBuffer>
- Error getHandle(Display display, Layer layer, uint32_t slot, bool fromCache,
- const native_handle_t* rawHandle, const native_handle_t** outHandle,
- ReplacedHandle<isBuffer>* outReplacedHandle) {
- Error error;
-
- // import the raw handle (or ignore raw handle when fromCache is true)
- const native_handle_t* importedHandle = nullptr;
- if (!fromCache) {
- error = (isBuffer) ? mImporter.importBuffer(rawHandle, &importedHandle)
- : mImporter.importStream(rawHandle, &importedHandle);
- if (error != Error::NONE) {
- return error;
- }
- }
-
- std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
-
- // find display/layer resource
- const bool needLayerResource =
- (cache == Cache::LAYER_BUFFER || cache == Cache::LAYER_SIDEBAND_STREAM);
- ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
- ComposerLayerResource* layerResource = (displayResource && needLayerResource)
- ? displayResource->findLayerResource(layer)
- : nullptr;
-
- // lookup or update cache
- const native_handle_t* replacedHandle = nullptr;
- if (displayResource && (!needLayerResource || layerResource)) {
- switch (cache) {
- case Cache::CLIENT_TARGET:
- error = displayResource->getClientTarget(slot, fromCache, importedHandle,
- outHandle, &replacedHandle);
- break;
- case Cache::OUTPUT_BUFFER:
- error = displayResource->getOutputBuffer(slot, fromCache, importedHandle,
- outHandle, &replacedHandle);
- break;
- case Cache::LAYER_BUFFER:
- error = layerResource->getBuffer(slot, fromCache, importedHandle, outHandle,
- &replacedHandle);
- break;
- case Cache::LAYER_SIDEBAND_STREAM:
- error = layerResource->getSidebandStream(slot, fromCache, importedHandle,
- outHandle, &replacedHandle);
- break;
- default:
- error = Error::BAD_PARAMETER;
- break;
- }
-
- if (error != Error::NONE) {
- ALOGW("invalid cache %d slot %d", int(cache), int(slot));
- }
- } else if (!displayResource) {
- error = Error::BAD_DISPLAY;
- } else {
- error = Error::BAD_LAYER;
- }
-
- // clean up on errors
- if (error != Error::NONE) {
- if (!fromCache) {
- if (isBuffer) {
- mImporter.freeBuffer(importedHandle);
- } else {
- mImporter.freeStream(importedHandle);
- }
- }
- return error;
- }
-
- outReplacedHandle->reset(&mImporter, replacedHandle);
-
- return Error::NONE;
- }
-};
-
-} // namespace hal
-} // namespace V2_1
-} // namespace composer
-} // namespace graphics
-} // namespace hardware
-} // namespace android
diff --git a/graphics/composer/2.1/utils/resources/Android.bp b/graphics/composer/2.1/utils/resources/Android.bp
new file mode 100644
index 0000000..ed827fe
--- /dev/null
+++ b/graphics/composer/2.1/utils/resources/Android.bp
@@ -0,0 +1,51 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+ name: "android.hardware.graphics.composer@2.1-resources",
+ defaults: ["hidl_defaults"],
+ vendor_available: true,
+ shared_libs: [
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
+ "libcutils",
+ "libhardware", // TODO remove hwcomposer2.h dependency
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ ],
+ header_libs: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ ],
+ export_header_lib_headers: [
+ "android.hardware.graphics.composer@2.1-command-buffer",
+ ],
+ export_include_dirs: ["include"],
+ srcs: [
+ "ComposerResources.cpp",
+ ],
+}
diff --git a/graphics/composer/2.1/utils/resources/ComposerResources.cpp b/graphics/composer/2.1/utils/resources/ComposerResources.cpp
new file mode 100644
index 0000000..21f6035
--- /dev/null
+++ b/graphics/composer/2.1/utils/resources/ComposerResources.cpp
@@ -0,0 +1,503 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ComposerResources"
+
+#include "composer-resources/2.1/ComposerResources.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace hal {
+
+bool ComposerHandleImporter::init() {
+ mMapper4 = mapper::V4_0::IMapper::getService();
+ if (mMapper4) {
+ return true;
+ }
+ ALOGI_IF(!mMapper4, "failed to get mapper 4.0 service, falling back to mapper 3.0");
+
+ mMapper3 = mapper::V3_0::IMapper::getService();
+ if (mMapper3) {
+ return true;
+ }
+ ALOGI_IF(!mMapper3, "failed to get mapper 3.0 service, falling back to mapper 2.0");
+
+ mMapper2 = mapper::V2_0::IMapper::getService();
+ ALOGE_IF(!mMapper2, "failed to get mapper 2.0 service");
+
+ return mMapper2 != nullptr;
+}
+
+Error ComposerHandleImporter::importBuffer(const native_handle_t* rawHandle,
+ const native_handle_t** outBufferHandle) {
+ if (!rawHandle || (!rawHandle->numFds && !rawHandle->numInts)) {
+ *outBufferHandle = nullptr;
+ return Error::NONE;
+ }
+
+ const native_handle_t* bufferHandle;
+ if (mMapper2) {
+ mapper::V2_0::Error error;
+ mMapper2->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
+ error = tmpError;
+ bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
+ });
+ if (error != mapper::V2_0::Error::NONE) {
+ return Error::NO_RESOURCES;
+ }
+ }
+ if (mMapper3) {
+ mapper::V3_0::Error error;
+ mMapper3->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
+ error = tmpError;
+ bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
+ });
+ if (error != mapper::V3_0::Error::NONE) {
+ return Error::NO_RESOURCES;
+ }
+ }
+ if (mMapper4) {
+ mapper::V4_0::Error error;
+ mMapper4->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) {
+ error = tmpError;
+ bufferHandle = static_cast<const native_handle_t*>(tmpBufferHandle);
+ });
+ if (error != mapper::V4_0::Error::NONE) {
+ return Error::NO_RESOURCES;
+ }
+ }
+
+ *outBufferHandle = bufferHandle;
+ return Error::NONE;
+}
+
+void ComposerHandleImporter::freeBuffer(const native_handle_t* bufferHandle) {
+ if (bufferHandle) {
+ if (mMapper2) {
+ mMapper2->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
+ } else if (mMapper3) {
+ mMapper3->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
+ } else if (mMapper4) {
+ mMapper4->freeBuffer(static_cast<void*>(const_cast<native_handle_t*>(bufferHandle)));
+ }
+ }
+}
+
+Error ComposerHandleImporter::importStream(const native_handle_t* rawHandle,
+ const native_handle_t** outStreamHandle) {
+ const native_handle_t* streamHandle = nullptr;
+ if (rawHandle) {
+ streamHandle = native_handle_clone(rawHandle);
+ if (!streamHandle) {
+ return Error::NO_RESOURCES;
+ }
+ }
+
+ *outStreamHandle = streamHandle;
+ return Error::NONE;
+}
+
+void ComposerHandleImporter::freeStream(const native_handle_t* streamHandle) {
+ if (streamHandle) {
+ native_handle_close(streamHandle);
+ native_handle_delete(const_cast<native_handle_t*>(streamHandle));
+ }
+}
+
+ComposerHandleCache::ComposerHandleCache(ComposerHandleImporter& importer, HandleType type,
+ uint32_t cacheSize)
+ : mImporter(importer), mHandleType(type), mHandles(cacheSize, nullptr) {}
+
+// must be initialized later with initCache
+ComposerHandleCache::ComposerHandleCache(ComposerHandleImporter& importer) : mImporter(importer) {}
+
+ComposerHandleCache::~ComposerHandleCache() {
+ switch (mHandleType) {
+ case HandleType::BUFFER:
+ for (auto handle : mHandles) {
+ mImporter.freeBuffer(handle);
+ }
+ break;
+ case HandleType::STREAM:
+ for (auto handle : mHandles) {
+ mImporter.freeStream(handle);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool ComposerHandleCache::initCache(HandleType type, uint32_t cacheSize) {
+ // already initialized
+ if (mHandleType != HandleType::INVALID) {
+ return false;
+ }
+
+ mHandleType = type;
+ mHandles.resize(cacheSize, nullptr);
+
+ return true;
+}
+
+Error ComposerHandleCache::lookupCache(uint32_t slot, const native_handle_t** outHandle) {
+ if (slot >= 0 && slot < mHandles.size()) {
+ *outHandle = mHandles[slot];
+ return Error::NONE;
+ } else {
+ return Error::BAD_PARAMETER;
+ }
+}
+
+Error ComposerHandleCache::updateCache(uint32_t slot, const native_handle_t* handle,
+ const native_handle** outReplacedHandle) {
+ if (slot >= 0 && slot < mHandles.size()) {
+ auto& cachedHandle = mHandles[slot];
+ *outReplacedHandle = cachedHandle;
+ cachedHandle = handle;
+ return Error::NONE;
+ } else {
+ return Error::BAD_PARAMETER;
+ }
+}
+
+// when fromCache is true, look up in the cache; otherwise, update the cache
+Error ComposerHandleCache::getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ if (fromCache) {
+ *outReplacedHandle = nullptr;
+ return lookupCache(slot, outHandle);
+ } else {
+ *outHandle = inHandle;
+ return updateCache(slot, inHandle, outReplacedHandle);
+ }
+}
+
+ComposerLayerResource::ComposerLayerResource(ComposerHandleImporter& importer,
+ uint32_t bufferCacheSize)
+ : mBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, bufferCacheSize),
+ mSidebandStreamCache(importer, ComposerHandleCache::HandleType::STREAM, 1) {}
+
+Error ComposerLayerResource::getBuffer(uint32_t slot, bool fromCache,
+ const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ return mBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+Error ComposerLayerResource::getSidebandStream(uint32_t slot, bool fromCache,
+ const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ return mSidebandStreamCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+ComposerDisplayResource::ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
+ uint32_t outputBufferCacheSize)
+ : mType(type),
+ mClientTargetCache(importer),
+ mOutputBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, outputBufferCacheSize),
+ mMustValidate(true) {}
+
+bool ComposerDisplayResource::initClientTargetCache(uint32_t cacheSize) {
+ return mClientTargetCache.initCache(ComposerHandleCache::HandleType::BUFFER, cacheSize);
+}
+
+bool ComposerDisplayResource::isVirtual() const {
+ return mType == DisplayType::VIRTUAL;
+}
+
+Error ComposerDisplayResource::getClientTarget(uint32_t slot, bool fromCache,
+ const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ return mClientTargetCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+Error ComposerDisplayResource::getOutputBuffer(uint32_t slot, bool fromCache,
+ const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ return mOutputBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+bool ComposerDisplayResource::addLayer(Layer layer,
+ std::unique_ptr<ComposerLayerResource> layerResource) {
+ auto result = mLayerResources.emplace(layer, std::move(layerResource));
+ return result.second;
+}
+
+bool ComposerDisplayResource::removeLayer(Layer layer) {
+ return mLayerResources.erase(layer) > 0;
+}
+
+ComposerLayerResource* ComposerDisplayResource::findLayerResource(Layer layer) {
+ auto layerIter = mLayerResources.find(layer);
+ if (layerIter == mLayerResources.end()) {
+ return nullptr;
+ }
+
+ return layerIter->second.get();
+}
+
+std::vector<Layer> ComposerDisplayResource::getLayers() const {
+ std::vector<Layer> layers;
+ layers.reserve(mLayerResources.size());
+ for (const auto& layerKey : mLayerResources) {
+ layers.push_back(layerKey.first);
+ }
+ return layers;
+}
+
+void ComposerDisplayResource::setMustValidateState(bool mustValidate) {
+ mMustValidate = mustValidate;
+}
+
+bool ComposerDisplayResource::mustValidate() const {
+ return mMustValidate;
+}
+
+std::unique_ptr<ComposerResources> ComposerResources::create() {
+ auto resources = std::make_unique<ComposerResources>();
+ return resources->init() ? std::move(resources) : nullptr;
+}
+
+bool ComposerResources::init() {
+ return mImporter.init();
+}
+
+void ComposerResources::clear(RemoveDisplay removeDisplay) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ for (const auto& displayKey : mDisplayResources) {
+ Display display = displayKey.first;
+ const ComposerDisplayResource& displayResource = *displayKey.second;
+ removeDisplay(display, displayResource.isVirtual(), displayResource.getLayers());
+ }
+ mDisplayResources.clear();
+}
+
+Error ComposerResources::addPhysicalDisplay(Display display) {
+ auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::PHYSICAL, 0);
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ auto result = mDisplayResources.emplace(display, std::move(displayResource));
+ return result.second ? Error::NONE : Error::BAD_DISPLAY;
+}
+
+Error ComposerResources::addVirtualDisplay(Display display, uint32_t outputBufferCacheSize) {
+ auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::VIRTUAL,
+ outputBufferCacheSize);
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ auto result = mDisplayResources.emplace(display, std::move(displayResource));
+ return result.second ? Error::NONE : Error::BAD_DISPLAY;
+}
+
+Error ComposerResources::removeDisplay(Display display) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ return mDisplayResources.erase(display) > 0 ? Error::NONE : Error::BAD_DISPLAY;
+}
+
+Error ComposerResources::setDisplayClientTargetCacheSize(Display display,
+ uint32_t clientTargetCacheSize) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+ if (!displayResource) {
+ return Error::BAD_DISPLAY;
+ }
+
+ return displayResource->initClientTargetCache(clientTargetCacheSize) ? Error::NONE
+ : Error::BAD_PARAMETER;
+}
+
+Error ComposerResources::addLayer(Display display, Layer layer, uint32_t bufferCacheSize) {
+ auto layerResource = createLayerResource(bufferCacheSize);
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+ if (!displayResource) {
+ return Error::BAD_DISPLAY;
+ }
+
+ return displayResource->addLayer(layer, std::move(layerResource)) ? Error::NONE
+ : Error::BAD_LAYER;
+}
+
+Error ComposerResources::removeLayer(Display display, Layer layer) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+ if (!displayResource) {
+ return Error::BAD_DISPLAY;
+ }
+
+ return displayResource->removeLayer(layer) ? Error::NONE : Error::BAD_LAYER;
+}
+
+Error ComposerResources::getDisplayClientTarget(Display display, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle,
+ const native_handle_t** outBufferHandle,
+ ReplacedHandle* outReplacedBuffer) {
+ return getHandle(display, 0, slot, Cache::CLIENT_TARGET, fromCache, rawHandle, outBufferHandle,
+ outReplacedBuffer);
+}
+
+Error ComposerResources::getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle,
+ const native_handle_t** outBufferHandle,
+ ReplacedHandle* outReplacedBuffer) {
+ return getHandle(display, 0, slot, Cache::OUTPUT_BUFFER, fromCache, rawHandle, outBufferHandle,
+ outReplacedBuffer);
+}
+
+Error ComposerResources::getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle,
+ const native_handle_t** outBufferHandle,
+ ReplacedHandle* outReplacedBuffer) {
+ return getHandle(display, layer, slot, Cache::LAYER_BUFFER, fromCache, rawHandle,
+ outBufferHandle, outReplacedBuffer);
+}
+
+Error ComposerResources::getLayerSidebandStream(Display display, Layer layer,
+ const native_handle_t* rawHandle,
+ const native_handle_t** outStreamHandle,
+ ReplacedHandle* outReplacedStream) {
+ return getHandle(display, layer, 0, Cache::LAYER_SIDEBAND_STREAM, false, rawHandle,
+ outStreamHandle, outReplacedStream);
+}
+
+void ComposerResources::setDisplayMustValidateState(Display display, bool mustValidate) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ auto* displayResource = findDisplayResourceLocked(display);
+ if (displayResource) {
+ displayResource->setMustValidateState(mustValidate);
+ }
+}
+
+bool ComposerResources::mustValidateDisplay(Display display) {
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+ auto* displayResource = findDisplayResourceLocked(display);
+ if (displayResource) {
+ return displayResource->mustValidate();
+ }
+ return false;
+}
+
+std::unique_ptr<ComposerDisplayResource> ComposerResources::createDisplayResource(
+ ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) {
+ return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
+}
+
+std::unique_ptr<ComposerLayerResource> ComposerResources::createLayerResource(
+ uint32_t bufferCacheSize) {
+ return std::make_unique<ComposerLayerResource>(mImporter, bufferCacheSize);
+}
+
+ComposerDisplayResource* ComposerResources::findDisplayResourceLocked(Display display) {
+ auto iter = mDisplayResources.find(display);
+ if (iter == mDisplayResources.end()) {
+ return nullptr;
+ }
+ return iter->second.get();
+}
+
+Error ComposerResources::getHandle(Display display, Layer layer, uint32_t slot, Cache cache,
+ bool fromCache, const native_handle_t* rawHandle,
+ const native_handle_t** outHandle,
+ ReplacedHandle* outReplacedHandle) {
+ Error error;
+
+ // import the raw handle (or ignore raw handle when fromCache is true)
+ const native_handle_t* importedHandle = nullptr;
+ if (!fromCache) {
+ error = (outReplacedHandle->isBuffer())
+ ? mImporter.importBuffer(rawHandle, &importedHandle)
+ : mImporter.importStream(rawHandle, &importedHandle);
+ if (error != Error::NONE) {
+ return error;
+ }
+ }
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+
+ // find display/layer resource
+ const bool needLayerResource = (cache == ComposerResources::Cache::LAYER_BUFFER ||
+ cache == ComposerResources::Cache::LAYER_SIDEBAND_STREAM);
+ ComposerDisplayResource* displayResource = findDisplayResourceLocked(display);
+ ComposerLayerResource* layerResource = (displayResource && needLayerResource)
+ ? displayResource->findLayerResource(layer)
+ : nullptr;
+
+ // lookup or update cache
+ const native_handle_t* replacedHandle = nullptr;
+ if (displayResource && (!needLayerResource || layerResource)) {
+ switch (cache) {
+ case ComposerResources::Cache::CLIENT_TARGET:
+ error = displayResource->getClientTarget(slot, fromCache, importedHandle, outHandle,
+ &replacedHandle);
+ break;
+ case ComposerResources::Cache::OUTPUT_BUFFER:
+ error = displayResource->getOutputBuffer(slot, fromCache, importedHandle, outHandle,
+ &replacedHandle);
+ break;
+ case ComposerResources::Cache::LAYER_BUFFER:
+ error = layerResource->getBuffer(slot, fromCache, importedHandle, outHandle,
+ &replacedHandle);
+ break;
+ case ComposerResources::Cache::LAYER_SIDEBAND_STREAM:
+ error = layerResource->getSidebandStream(slot, fromCache, importedHandle, outHandle,
+ &replacedHandle);
+ break;
+ default:
+ error = Error::BAD_PARAMETER;
+ break;
+ }
+
+ if (error != Error::NONE) {
+ ALOGW("invalid cache %d slot %d", int(cache), int(slot));
+ }
+ } else if (!displayResource) {
+ error = Error::BAD_DISPLAY;
+ } else {
+ error = Error::BAD_LAYER;
+ }
+
+ // clean up on errors
+ if (error != Error::NONE) {
+ if (!fromCache) {
+ if (outReplacedHandle->isBuffer()) {
+ mImporter.freeBuffer(importedHandle);
+ } else {
+ mImporter.freeStream(importedHandle);
+ }
+ }
+ return error;
+ }
+
+ outReplacedHandle->reset(&mImporter, replacedHandle);
+
+ return Error::NONE;
+}
+
+} // namespace hal
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h
new file mode 100644
index 0000000..3738278
--- /dev/null
+++ b/graphics/composer/2.1/utils/resources/include/composer-resources/2.1/ComposerResources.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerResources.h included without LOG_TAG"
+#endif
+
+#include <memory>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+#include <android/hardware/graphics/composer/2.1/types.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 <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_1 {
+namespace hal {
+
+// wrapper for IMapper to import buffers and sideband streams
+class ComposerHandleImporter {
+ public:
+ bool init();
+
+ Error importBuffer(const native_handle_t* rawHandle, const native_handle_t** outBufferHandle);
+ void freeBuffer(const native_handle_t* bufferHandle);
+ Error importStream(const native_handle_t* rawHandle, const native_handle_t** outStreamHandle);
+ void freeStream(const native_handle_t* streamHandle);
+
+ private:
+ sp<mapper::V2_0::IMapper> mMapper2;
+ sp<mapper::V3_0::IMapper> mMapper3;
+ sp<mapper::V4_0::IMapper> mMapper4;
+};
+
+class ComposerHandleCache {
+ public:
+ enum class HandleType {
+ INVALID,
+ BUFFER,
+ STREAM,
+ };
+
+ ComposerHandleCache(ComposerHandleImporter& importer, HandleType type, uint32_t cacheSize);
+
+ // must be initialized later with initCache
+ ComposerHandleCache(ComposerHandleImporter& importer);
+
+ ~ComposerHandleCache();
+
+ ComposerHandleCache(const ComposerHandleCache&) = delete;
+ ComposerHandleCache& operator=(const ComposerHandleCache&) = delete;
+
+ bool initCache(HandleType type, uint32_t cacheSize);
+ Error lookupCache(uint32_t slot, const native_handle_t** outHandle);
+ Error updateCache(uint32_t slot, const native_handle_t* handle,
+ const native_handle** outReplacedHandle);
+
+ // when fromCache is true, look up in the cache; otherwise, update the cache
+ Error getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle, const native_handle** outReplacedHandle);
+
+ private:
+ ComposerHandleImporter& mImporter;
+ HandleType mHandleType = HandleType::INVALID;
+ std::vector<const native_handle_t*> mHandles;
+};
+
+// layer resource
+class ComposerLayerResource {
+ public:
+ ComposerLayerResource(ComposerHandleImporter& importer, uint32_t bufferCacheSize);
+
+ virtual ~ComposerLayerResource() = default;
+
+ Error getBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle, const native_handle** outReplacedHandle);
+ Error getSidebandStream(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle);
+
+ protected:
+ ComposerHandleCache mBufferCache;
+ ComposerHandleCache mSidebandStreamCache;
+};
+
+// display resource
+class ComposerDisplayResource {
+ public:
+ enum class DisplayType {
+ PHYSICAL,
+ VIRTUAL,
+ };
+
+ virtual ~ComposerDisplayResource() = default;
+
+ ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
+ uint32_t outputBufferCacheSize);
+
+ bool initClientTargetCache(uint32_t cacheSize);
+
+ bool isVirtual() const;
+
+ Error getClientTarget(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle);
+
+ Error getOutputBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle);
+
+ bool addLayer(Layer layer, std::unique_ptr<ComposerLayerResource> layerResource);
+ bool removeLayer(Layer layer);
+ ComposerLayerResource* findLayerResource(Layer layer);
+ std::vector<Layer> getLayers() const;
+
+ void setMustValidateState(bool mustValidate);
+
+ bool mustValidate() const;
+
+ protected:
+ const DisplayType mType;
+ ComposerHandleCache mClientTargetCache;
+ ComposerHandleCache mOutputBufferCache;
+ bool mMustValidate;
+
+ std::unordered_map<Layer, std::unique_ptr<ComposerLayerResource>> mLayerResources;
+};
+
+class ComposerResources {
+ public:
+ static std::unique_ptr<ComposerResources> create();
+
+ ComposerResources() = default;
+ virtual ~ComposerResources() = default;
+
+ bool init();
+
+ using RemoveDisplay =
+ std::function<void(Display display, bool isVirtual, const std::vector<Layer>& layers)>;
+ void clear(RemoveDisplay removeDisplay);
+
+ Error addPhysicalDisplay(Display display);
+ Error addVirtualDisplay(Display display, uint32_t outputBufferCacheSize);
+
+ Error removeDisplay(Display display);
+
+ Error setDisplayClientTargetCacheSize(Display display, uint32_t clientTargetCacheSize);
+
+ Error addLayer(Display display, Layer layer, uint32_t bufferCacheSize);
+ Error removeLayer(Display display, Layer layer);
+
+ void setDisplayMustValidateState(Display display, bool mustValidate);
+
+ bool mustValidateDisplay(Display display);
+
+ // When a buffer in the cache is replaced by a new one, we must keep it
+ // alive until it has been replaced in ComposerHal.
+ class ReplacedHandle {
+ public:
+ explicit ReplacedHandle(bool isBuffer) : mIsBuffer(isBuffer) {}
+ ReplacedHandle(const ReplacedHandle&) = delete;
+ ReplacedHandle& operator=(const ReplacedHandle&) = delete;
+
+ ~ReplacedHandle() { reset(); }
+
+ bool isBuffer() { return mIsBuffer; }
+
+ void reset(ComposerHandleImporter* importer = nullptr,
+ const native_handle_t* handle = nullptr) {
+ if (mHandle) {
+ if (mIsBuffer) {
+ mImporter->freeBuffer(mHandle);
+ } else {
+ mImporter->freeStream(mHandle);
+ }
+ }
+
+ mImporter = importer;
+ mHandle = handle;
+ }
+
+ private:
+ bool mIsBuffer;
+ ComposerHandleImporter* mImporter = nullptr;
+ const native_handle_t* mHandle = nullptr;
+ };
+
+ Error getDisplayClientTarget(Display display, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle,
+ const native_handle_t** outBufferHandle,
+ ReplacedHandle* outReplacedBuffer);
+
+ Error getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle,
+ const native_handle_t** outBufferHandle,
+ ReplacedHandle* outReplacedBuffer);
+
+ Error getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache,
+ const native_handle_t* rawHandle, const native_handle_t** outBufferHandle,
+ ReplacedHandle* outReplacedBuffer);
+
+ Error getLayerSidebandStream(Display display, Layer layer, const native_handle_t* rawHandle,
+ const native_handle_t** outStreamHandle,
+ ReplacedHandle* outReplacedStream);
+
+ protected:
+ virtual std::unique_ptr<ComposerDisplayResource> createDisplayResource(
+ ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize);
+
+ virtual std::unique_ptr<ComposerLayerResource> createLayerResource(uint32_t bufferCacheSize);
+
+ ComposerDisplayResource* findDisplayResourceLocked(Display display);
+
+ ComposerHandleImporter mImporter;
+
+ std::mutex mDisplayResourcesMutex;
+ std::unordered_map<Display, std::unique_ptr<ComposerDisplayResource>> mDisplayResources;
+
+ private:
+ enum class Cache {
+ CLIENT_TARGET,
+ OUTPUT_BUFFER,
+ LAYER_BUFFER,
+ LAYER_SIDEBAND_STREAM,
+ };
+
+ Error getHandle(Display display, Layer layer, uint32_t slot, Cache cache, bool fromCache,
+ const native_handle_t* rawHandle, const native_handle_t** outHandle,
+ ReplacedHandle* outReplacedHandle);
+};
+
+} // namespace hal
+} // namespace V2_1
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
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/default/Android.mk b/graphics/composer/2.2/default/Android.mk
index 7dedf61..cb551c6 100644
--- a/graphics/composer/2.2/default/Android.mk
+++ b/graphics/composer/2.2/default/Android.mk
@@ -11,8 +11,8 @@
LOCAL_SHARED_LIBRARIES := \
android.hardware.graphics.composer@2.1 \
android.hardware.graphics.composer@2.2 \
- android.hardware.graphics.mapper@2.0 \
- android.hardware.graphics.mapper@3.0 \
+ android.hardware.graphics.composer@2.1-resources \
+ android.hardware.graphics.composer@2.2-resources \
libbase \
libbinder \
libcutils \
diff --git a/graphics/composer/2.2/utils/hal/Android.bp b/graphics/composer/2.2/utils/hal/Android.bp
index 10dcae4..f334a11 100644
--- a/graphics/composer/2.2/utils/hal/Android.bp
+++ b/graphics/composer/2.2/utils/hal/Android.bp
@@ -19,9 +19,11 @@
vendor_available: true,
shared_libs: [
"android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.2-resources",
],
export_shared_lib_headers: [
"android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.2-resources",
],
header_libs: [
"android.hardware.graphics.composer@2.2-command-buffer",
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
index c760d0a..512d39d 100644
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerClient.h
@@ -24,7 +24,7 @@
#include <composer-hal/2.1/ComposerClient.h>
#include <composer-hal/2.2/ComposerCommandEngine.h>
#include <composer-hal/2.2/ComposerHal.h>
-#include <composer-hal/2.2/ComposerResources.h>
+#include <composer-resources/2.2/ComposerResources.h>
namespace android {
namespace hardware {
@@ -89,7 +89,7 @@
auto resources = static_cast<ComposerResources*>(mResources.get());
const native_handle_t* readbackBuffer;
- ComposerResources::ReplacedBufferHandle replacedReadbackBuffer;
+ ComposerResources::ReplacedHandle replacedReadbackBuffer(true);
error = resources->getDisplayReadbackBuffer(display, buffer.getNativeHandle(),
&readbackBuffer, &replacedReadbackBuffer);
if (error != Error::NONE) {
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
index 97e3a9e..d9f6226 100644
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
+++ b/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerCommandEngine.h
@@ -23,7 +23,7 @@
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
#include <composer-hal/2.1/ComposerCommandEngine.h>
#include <composer-hal/2.2/ComposerHal.h>
-#include <composer-hal/2.2/ComposerResources.h>
+#include <composer-resources/2.2/ComposerResources.h>
namespace android {
namespace hardware {
diff --git a/graphics/composer/2.2/utils/resources/Android.bp b/graphics/composer/2.2/utils/resources/Android.bp
new file mode 100644
index 0000000..752eb81
--- /dev/null
+++ b/graphics/composer/2.2/utils/resources/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+ name: "android.hardware.graphics.composer@2.2-resources",
+ defaults: ["hidl_defaults"],
+ vendor_available: true,
+ shared_libs: [
+ "android.hardware.graphics.composer@2.1-resources",
+ "android.hardware.graphics.composer@2.2",
+ ],
+ export_shared_lib_headers: [
+ "android.hardware.graphics.composer@2.1-resources",
+ "android.hardware.graphics.composer@2.2",
+ ],
+ export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.2/utils/resources/ComposerResources.cpp b/graphics/composer/2.2/utils/resources/ComposerResources.cpp
new file mode 100644
index 0000000..a0610a3
--- /dev/null
+++ b/graphics/composer/2.2/utils/resources/ComposerResources.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ComposerResources 2.2"
+
+#include "composer-resources/2.2/ComposerResources.h"
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace hal {
+
+using V2_1::Display;
+using V2_1::Error;
+using V2_1::Layer;
+using V2_1::hal::ComposerHandleCache;
+using V2_1::hal::ComposerHandleImporter;
+
+Error ComposerDisplayResource::getReadbackBuffer(const native_handle_t* inHandle,
+ const native_handle_t** outHandle,
+ const native_handle** outReplacedHandle) {
+ const uint32_t slot = 0;
+ const bool fromCache = false;
+ return mReadbackBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle);
+}
+
+std::unique_ptr<ComposerResources> ComposerResources::create() {
+ auto resources = std::make_unique<ComposerResources>();
+ return resources->init() ? std::move(resources) : nullptr;
+}
+
+Error ComposerResources::getDisplayReadbackBuffer(Display display, const native_handle_t* rawHandle,
+ const native_handle_t** outHandle,
+ ReplacedHandle* outReplacedHandle) {
+ // import buffer
+ const native_handle_t* importedHandle;
+ Error error = mImporter.importBuffer(rawHandle, &importedHandle);
+ if (error != Error::NONE) {
+ return error;
+ }
+
+ std::lock_guard<std::mutex> lock(mDisplayResourcesMutex);
+
+ auto iter = mDisplayResources.find(display);
+ if (iter == mDisplayResources.end()) {
+ mImporter.freeBuffer(importedHandle);
+ return Error::BAD_DISPLAY;
+ }
+ ComposerDisplayResource& displayResource =
+ *static_cast<ComposerDisplayResource*>(iter->second.get());
+
+ // update cache
+ const native_handle_t* replacedHandle;
+ error = displayResource.getReadbackBuffer(importedHandle, outHandle, &replacedHandle);
+ if (error != Error::NONE) {
+ mImporter.freeBuffer(importedHandle);
+ return error;
+ }
+
+ outReplacedHandle->reset(&mImporter, replacedHandle);
+ return Error::NONE;
+}
+
+} // namespace hal
+} // namespace V2_2
+} // namespace composer
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h b/graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h
similarity index 90%
rename from graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h
rename to graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h
index 85b6651..33012e9 100644
--- a/graphics/composer/2.2/utils/hal/include/composer-hal/2.2/ComposerResources.h
+++ b/graphics/composer/2.2/utils/resources/include/composer-resources/2.2/ComposerResources.h
@@ -20,7 +20,7 @@
#warning "ComposerResources.h included without LOG_TAG"
#endif
-#include <composer-hal/2.1/ComposerResources.h>
+#include <composer-resources/2.1/ComposerResources.h>
namespace android {
namespace hardware {
@@ -33,7 +33,7 @@
using V2_1::hal::ComposerHandleImporter;
class ComposerDisplayResource : public V2_1::hal::ComposerDisplayResource {
- public:
+ public:
ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer,
uint32_t outputBufferCacheSize)
: V2_1::hal::ComposerDisplayResource(type, importer, outputBufferCacheSize),
@@ -47,12 +47,12 @@
outReplacedHandle);
}
- protected:
+ protected:
ComposerHandleCache mReadbackBufferCache;
};
class ComposerResources : public V2_1::hal::ComposerResources {
- public:
+ public:
static std::unique_ptr<ComposerResources> create() {
auto resources = std::make_unique<ComposerResources>();
return resources->init() ? std::move(resources) : nullptr;
@@ -60,7 +60,7 @@
Error getDisplayReadbackBuffer(Display display, const native_handle_t* rawHandle,
const native_handle_t** outHandle,
- ReplacedBufferHandle* outReplacedHandle) {
+ ReplacedHandle* outReplacedHandle) {
// import buffer
const native_handle_t* importedHandle;
Error error = mImporter.importBuffer(rawHandle, &importedHandle);
@@ -76,7 +76,7 @@
return Error::BAD_DISPLAY;
}
ComposerDisplayResource& displayResource =
- *static_cast<ComposerDisplayResource*>(iter->second.get());
+ *static_cast<ComposerDisplayResource*>(iter->second.get());
// update cache
const native_handle_t* replacedHandle;
@@ -90,9 +90,9 @@
return Error::NONE;
}
- protected:
+ protected:
std::unique_ptr<V2_1::hal::ComposerDisplayResource> createDisplayResource(
- ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) override {
+ ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) override {
return std::make_unique<ComposerDisplayResource>(type, mImporter, outputBufferCacheSize);
}
};
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/default/Android.bp b/graphics/composer/2.3/default/Android.bp
index 07afd6c..8103b89 100644
--- a/graphics/composer/2.3/default/Android.bp
+++ b/graphics/composer/2.3/default/Android.bp
@@ -28,8 +28,8 @@
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.composer@2.1-resources",
+ "android.hardware.graphics.composer@2.2-resources",
"libbase",
"libbinder",
"libcutils",
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
index b289b6a..04530d3 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
@@ -21,9 +21,9 @@
#endif
#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
-#include <composer-hal/2.2/ComposerResources.h>
#include <composer-hal/2.3/ComposerCommandEngine.h>
#include <composer-hal/2.3/ComposerHal.h>
+#include <composer-resources/2.2/ComposerResources.h>
namespace android {
namespace hardware {
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
index 1a40d96..329dbed 100644
--- a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
@@ -23,8 +23,8 @@
#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
#include <composer-hal/2.1/ComposerCommandEngine.h>
#include <composer-hal/2.2/ComposerCommandEngine.h>
-#include <composer-hal/2.2/ComposerResources.h>
#include <composer-hal/2.3/ComposerHal.h>
+#include <composer-resources/2.2/ComposerResources.h>
namespace android {
namespace hardware {
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/default/Android.bp b/graphics/composer/2.4/default/Android.bp
index 1bf51e0..a44e687 100644
--- a/graphics/composer/2.4/default/Android.bp
+++ b/graphics/composer/2.4/default/Android.bp
@@ -29,8 +29,8 @@
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3",
"android.hardware.graphics.composer@2.4",
- "android.hardware.graphics.mapper@2.0",
- "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.composer@2.1-resources",
+ "android.hardware.graphics.composer@2.2-resources",
"libbase",
"libbinder",
"libcutils",
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/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/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/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/wifi/1.3/default/service.cpp b/wifi/1.3/default/service.cpp
index fcbc37c..0b41d28 100644
--- a/wifi/1.3/default/service.cpp
+++ b/wifi/1.3/default/service.cpp
@@ -58,7 +58,7 @@
std::make_shared<WifiIfaceUtil>(iface_tool),
std::make_shared<WifiFeatureFlags>());
if (kLazyService) {
- LazyServiceRegistrar registrar;
+ auto registrar = LazyServiceRegistrar::getInstance();
CHECK_EQ(registrar.registerService(service), android::NO_ERROR)
<< "Failed to register wifi HAL";
} else {