summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSlava Shklyaev <slavash@google.com>2020-11-02 20:00:18 +0000
committerSlava Shklyaev <slavash@google.com>2020-11-20 13:56:52 +0000
commit083da328b8899ce08f63fc564db444669f62b324 (patch)
tree393400e347cac5b974dddc0b93060aef51e2317e
parent72737fc910d8a0f3f96d08bc2eb861551cb84e41 (diff)
downloadml-083da328b8899ce08f63fc564db444669f62b324.tar.gz
Replace native_handle with unique_fd
This change replaces native_handle_t from libutils with a custom type that wraps std::vector<base::unique_fd> and std::vector<int>. Bug: 160669116 Test: NNT_static Change-Id: If4d767b35c2d48cabcb6a9a3436079f6f7d39a13 Merged-In: If4d767b35c2d48cabcb6a9a3436079f6f7d39a13 (cherry picked from commit b3c5d46cd1a7e8c7f4c624d2c24bf721f4d0edb2)
-rw-r--r--nn/common/SharedMemoryAndroid.cpp124
-rw-r--r--nn/common/SharedMemoryHost.cpp57
-rw-r--r--nn/common/TypeUtils.cpp2
-rw-r--r--nn/common/Types.cpp32
-rw-r--r--nn/common/Validation.cpp14
-rw-r--r--nn/common/include/nnapi/IDevice.h8
-rw-r--r--nn/common/include/nnapi/TypeUtils.h2
-rw-r--r--nn/common/include/nnapi/Types.h23
-rw-r--r--nn/common/include/nnapi/Validation.h4
-rw-r--r--nn/runtime/Manager.cpp34
-rw-r--r--nn/runtime/VersionedInterfaces.cpp67
-rw-r--r--nn/runtime/VersionedInterfaces.h14
-rw-r--r--nn/runtime/test/TestVersionedInterfaces.cpp24
13 files changed, 232 insertions, 173 deletions
diff --git a/nn/common/SharedMemoryAndroid.cpp b/nn/common/SharedMemoryAndroid.cpp
index 9baca73c5..18881e04a 100644
--- a/nn/common/SharedMemoryAndroid.cpp
+++ b/nn/common/SharedMemoryAndroid.cpp
@@ -19,12 +19,12 @@
#include <android-base/scopeguard.h>
#include <android/hardware_buffer.h>
#include <android/hidl/allocator/1.0/IAllocator.h>
-#include <cutils/native_handle.h>
#include <hidl/HidlSupport.h>
#include <hidlmemory/mapping.h>
#include <sys/mman.h>
#include <vndk/hardware_buffer.h>
+#include <algorithm>
#include <any>
#include <limits>
#include <memory>
@@ -66,28 +66,74 @@ GeneralResult<hidl_memory> allocateSharedMemory(size_t size) {
return maybeMemory;
}
-Memory createMemory(const hidl_memory& memory) {
- CHECK_LE(memory.size(), std::numeric_limits<uint32_t>::max());
+GeneralResult<hardware::hidl_handle> hidlHandleFromSharedHandle(const SharedHandle& handle) {
+ if (handle == nullptr) {
+ return {};
+ }
- auto* cloned = native_handle_clone(memory.handle());
- auto nativeHandle = ::android::NativeHandle::create(cloned, /*ownsHandle=*/true);
+ std::vector<base::unique_fd> fds;
+ fds.reserve(handle->fds.size());
+ for (const auto& fd : handle->fds) {
+ int dupFd = dup(fd);
+ if (dupFd == -1) {
+ return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd";
+ }
+ fds.emplace_back(dupFd);
+ }
- return {
- .handle = std::move(nativeHandle),
+ native_handle_t* nativeHandle = native_handle_create(handle->fds.size(), handle->ints.size());
+ if (nativeHandle == nullptr) {
+ return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "Failed to create native_handle";
+ }
+ for (size_t i = 0; i < fds.size(); ++i) {
+ nativeHandle->data[i] = fds[i].release();
+ }
+ std::copy(handle->ints.begin(), handle->ints.end(), &nativeHandle->data[nativeHandle->numFds]);
+
+ hardware::hidl_handle hidlHandle;
+ hidlHandle.setTo(nativeHandle, /*shouldOwn=*/true);
+ return hidlHandle;
+}
+
+GeneralResult<SharedHandle> sharedHandleFromNativeHandle(const native_handle_t* handle) {
+ if (handle == nullptr) {
+ return nullptr;
+ }
+
+ std::vector<base::unique_fd> fds;
+ fds.reserve(handle->numFds);
+ for (int i = 0; i < handle->numFds; ++i) {
+ int dupFd = dup(handle->data[i]);
+ if (dupFd == -1) {
+ return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd";
+ }
+ fds.emplace_back(dupFd);
+ }
+
+ std::vector<int> ints(&handle->data[handle->numFds],
+ &handle->data[handle->numFds + handle->numInts]);
+
+ return std::make_shared<const Handle>(Handle{
+ .fds = std::move(fds),
+ .ints = std::move(ints),
+ });
+}
+
+GeneralResult<Memory> createMemory(const hidl_memory& memory) {
+ CHECK_LE(memory.size(), std::numeric_limits<uint32_t>::max());
+ return Memory{
+ .handle = NN_TRY(sharedHandleFromNativeHandle(memory.handle())),
.size = static_cast<uint32_t>(memory.size()),
.name = memory.name(),
};
}
-hidl_memory createHidlMemory(const Memory& memory) {
- const auto hidlMemory = hidl_memory(memory.name, memory.handle->handle(), memory.size);
- // Copy memory to force the native_handle_t to be copied.
- auto copiedMemory = hidlMemory;
- return copiedMemory;
+GeneralResult<hidl_memory> createHidlMemory(const Memory& memory) {
+ return hidl_memory(memory.name, NN_TRY(hidlHandleFromSharedHandle(memory.handle)), memory.size);
}
GeneralResult<Mapping> mapAshmem(const Memory& memory) {
- const auto hidlMemory = createHidlMemory(memory);
+ const auto hidlMemory = NN_TRY(createHidlMemory(memory));
const auto mapping = mapMemory(hidlMemory);
if (mapping == nullptr) {
return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "Failed to map memory";
@@ -116,10 +162,10 @@ struct MmapFdMappingContext {
GeneralResult<Mapping> mapMemFd(const Memory& memory) {
const size_t size = memory.size;
- const native_handle_t* handle = memory.handle->handle();
- const int fd = handle->data[0];
- const int prot = handle->data[1];
- const size_t offset = getOffsetFromInts(handle->data[2], handle->data[3]);
+ const SharedHandle& handle = memory.handle;
+ const int fd = handle->fds[0];
+ const int prot = handle->ints[0];
+ const size_t offset = getOffsetFromInts(handle->ints[1], handle->ints[2]);
std::shared_ptr<base::MappedFile> mapping = base::MappedFile::FromFd(fd, offset, size, prot);
if (mapping == nullptr) {
@@ -132,7 +178,7 @@ GeneralResult<Mapping> mapMemFd(const Memory& memory) {
}
GeneralResult<Mapping> mapAhwbBlobMemory(const Memory& memory) {
- const auto* handle = memory.handle->handle();
+ const SharedHandle& handle = memory.handle;
const auto size = memory.size;
const auto format = AHARDWAREBUFFER_FORMAT_BLOB;
const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
@@ -152,7 +198,8 @@ GeneralResult<Mapping> mapAhwbBlobMemory(const Memory& memory) {
AHardwareBuffer* hardwareBuffer = nullptr;
status_t status = AHardwareBuffer_createFromHandle(
- &desc, handle, AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, &hardwareBuffer);
+ &desc, NN_TRY(hidlHandleFromSharedHandle(handle)),
+ AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, &hardwareBuffer);
if (status != NO_ERROR) {
return NN_ERROR(ErrorStatus::GENERAL_FAILURE)
<< "Can't create AHardwareBuffer from handle. Error: " << status;
@@ -196,31 +243,23 @@ GeneralResult<Memory> createSharedMemoryFromFd(size_t size, int prot, int fd, si
}
// Duplicate the file descriptor so the resultant Memory owns its own version.
- int dupfd = dup(fd);
- if (dupfd == -1) {
+ int dupFd = dup(fd);
+ if (dupFd == -1) {
// TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return here?
return NN_ERROR(ErrorStatus::INVALID_ARGUMENT) << "Failed to dup the fd";
}
- // Create a temporary native handle to own the dupfd.
- native_handle_t* nativeHandle = native_handle_create(1, 3);
- if (nativeHandle == nullptr) {
- close(dupfd);
- // TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return here?
- return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "Failed to create native_handle";
- }
+ std::vector<base::unique_fd> fds;
+ fds.emplace_back(dupFd);
const auto [lowOffsetBits, highOffsetBits] = getIntsFromOffset(offset);
- nativeHandle->data[0] = dupfd;
- nativeHandle->data[1] = prot;
- nativeHandle->data[2] = lowOffsetBits;
- nativeHandle->data[3] = highOffsetBits;
-
- // Create a NativeHandle which owns the native handle and fd so that we don't have to manually
- // clean either the native handle or the fd.
- auto ownedHandle = ::android::NativeHandle::create(nativeHandle, /*ownsHandle=*/true);
+ std::vector<int> ints = {prot, lowOffsetBits, highOffsetBits};
- return Memory{.handle = std::move(ownedHandle), .size = size, .name = "mmap_fd"};
+ SharedHandle handle = std::make_shared<const Handle>(Handle{
+ .fds = std::move(fds),
+ .ints = std::move(ints),
+ });
+ return Memory{.handle = std::move(handle), .size = size, .name = "mmap_fd"};
}
GeneralResult<Memory> createSharedMemoryFromHidlMemory(const hardware::hidl_memory& memory) {
@@ -232,19 +271,20 @@ GeneralResult<Memory> createSharedMemoryFromAHWB(const AHardwareBuffer& ahwb) {
AHardwareBuffer_describe(&ahwb, &bufferDesc);
const native_handle_t* handle = AHardwareBuffer_getNativeHandle(&ahwb);
- auto* cloned = native_handle_clone(handle);
- auto nativeHandle = ::android::NativeHandle::create(cloned, /*ownsHandle=*/true);
-
if (bufferDesc.format == AHARDWAREBUFFER_FORMAT_BLOB) {
return Memory{
- .handle = std::move(nativeHandle),
+ .handle = NN_TRY(sharedHandleFromNativeHandle(handle)),
.size = bufferDesc.width,
.name = "hardware_buffer_blob",
};
}
// memory size is not used for non-BLOB AHWB memory.
- return Memory{.handle = std::move(nativeHandle), .size = 0, .name = "hardware_buffer"};
+ return Memory{
+ .handle = NN_TRY(sharedHandleFromNativeHandle(handle)),
+ .size = 0,
+ .name = "hardware_buffer",
+ };
}
GeneralResult<Mapping> map(const Memory& memory) {
diff --git a/nn/common/SharedMemoryHost.cpp b/nn/common/SharedMemoryHost.cpp
index 231977cf7..eeb49075e 100644
--- a/nn/common/SharedMemoryHost.cpp
+++ b/nn/common/SharedMemoryHost.cpp
@@ -23,6 +23,7 @@
#include <limits>
#include <memory>
#include <utility>
+#include <vector>
#include "Result.h"
#include "SharedMemory.h"
@@ -36,7 +37,7 @@ GeneralResult<Mapping> mapAshmem(const Memory& memory) {
CHECK_LE(memory.size, std::numeric_limits<uint32_t>::max());
const auto size = memory.size;
- int fd = memory.handle->handle()->data[0];
+ const int fd = memory.handle->fds[0];
std::shared_ptr<base::MappedFile> mapping =
base::MappedFile::FromFd(fd, /*offset=*/0, size, PROT_READ | PROT_WRITE);
if (mapping == nullptr) {
@@ -54,10 +55,10 @@ struct MmapFdMappingContext {
GeneralResult<Mapping> mapMemFd(const Memory& memory) {
const size_t size = memory.size;
- const native_handle_t* handle = memory.handle->handle();
- const int fd = handle->data[0];
- const int prot = handle->data[1];
- const size_t offset = getOffsetFromInts(handle->data[2], handle->data[3]);
+ const SharedHandle& handle = memory.handle;
+ const int fd = handle->fds[0];
+ const int prot = handle->ints[0];
+ const size_t offset = getOffsetFromInts(handle->ints[1], handle->ints[2]);
std::shared_ptr<base::MappedFile> mapping = base::MappedFile::FromFd(fd, offset, size, prot);
if (mapping == nullptr) {
@@ -78,18 +79,14 @@ GeneralResult<Memory> createSharedMemory(size_t size) {
<< "ashmem_create_region(" << size << ") fails with " << fd;
}
- native_handle_t* handle = native_handle_create(1, 0);
- if (handle == nullptr) {
- // TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return here?
- return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "Failed to create native_handle";
- }
- handle->data[0] = fd;
-
- // Create a NativeHandle which owns the native handle and fd so that we don't have to manually
- // clean either the native handle or the fd.
- auto nativeHandle = ::android::NativeHandle::create(handle, /*ownsHandle=*/true);
+ std::vector<base::unique_fd> fds;
+ fds.emplace_back(fd);
- return Memory{.handle = std::move(nativeHandle), .size = size, .name = "ashmem"};
+ SharedHandle handle = std::make_shared<const Handle>(Handle{
+ .fds = std::move(fds),
+ .ints = {},
+ });
+ return Memory{.handle = std::move(handle), .size = size, .name = "ashmem"};
}
GeneralResult<Memory> createSharedMemoryFromFd(size_t size, int prot, int fd, size_t offset) {
@@ -98,31 +95,23 @@ GeneralResult<Memory> createSharedMemoryFromFd(size_t size, int prot, int fd, si
}
// Duplicate the file descriptor so the resultant Memory owns its own version.
- int dupfd = dup(fd);
- if (dupfd == -1) {
+ int dupFd = dup(fd);
+ if (dupFd == -1) {
// TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return here?
return NN_ERROR(ErrorStatus::INVALID_ARGUMENT) << "Failed to dup the fd";
}
- // Create a temporary native handle to own the dupfd.
- native_handle_t* nativeHandle = native_handle_create(1, 3);
- if (nativeHandle == nullptr) {
- close(dupfd);
- // TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return here?
- return NN_ERROR(ErrorStatus::GENERAL_FAILURE) << "Failed to create native_handle";
- }
+ std::vector<base::unique_fd> fds;
+ fds.emplace_back(dupFd);
const auto [lowOffsetBits, highOffsetBits] = getIntsFromOffset(offset);
- nativeHandle->data[0] = dupfd;
- nativeHandle->data[1] = prot;
- nativeHandle->data[2] = lowOffsetBits;
- nativeHandle->data[3] = highOffsetBits;
-
- // Create a NativeHandle which owns the native handle and fd so that we don't have to manually
- // clean either the native handle or the fd.
- auto ownedHandle = ::android::NativeHandle::create(nativeHandle, /*ownsHandle=*/true);
+ std::vector<int> ints = {prot, lowOffsetBits, highOffsetBits};
- return Memory{.handle = std::move(ownedHandle), .size = size, .name = "mmap_fd"};
+ SharedHandle handle = std::make_shared<const Handle>(Handle{
+ .fds = std::move(fds),
+ .ints = std::move(ints),
+ });
+ return Memory{.handle = std::move(handle), .size = size, .name = "mmap_fd"};
}
GeneralResult<Memory> createSharedMemoryFromHidlMemory(const hardware::hidl_memory& /*memory*/) {
diff --git a/nn/common/TypeUtils.cpp b/nn/common/TypeUtils.cpp
index 6d089bd2a..79d493e14 100644
--- a/nn/common/TypeUtils.cpp
+++ b/nn/common/TypeUtils.cpp
@@ -701,7 +701,7 @@ std::ostream& operator<<(std::ostream& os, const Operation& operation) {
<< ", .outputs=" << operation.outputs << "}";
}
-std::ostream& operator<<(std::ostream& os, const NativeHandle& handle) {
+std::ostream& operator<<(std::ostream& os, const SharedHandle& handle) {
return os << (handle != nullptr ? "<non-empty handle>" : "<empty handle>");
}
diff --git a/nn/common/Types.cpp b/nn/common/Types.cpp
index 17485f442..e2e4cf112 100644
--- a/nn/common/Types.cpp
+++ b/nn/common/Types.cpp
@@ -17,7 +17,6 @@
#include "Types.h"
#include <android-base/logging.h>
-#include <cutils/native_handle.h>
#include <errno.h>
#include <poll.h>
@@ -25,6 +24,7 @@
#include <cstddef>
#include <iterator>
#include <limits>
+#include <memory>
#include <optional>
#include <utility>
#include <vector>
@@ -128,24 +128,32 @@ SyncFence SyncFence::createAsSignaled() {
return SyncFence(nullptr);
}
-Result<SyncFence> SyncFence::create(NativeHandle syncFence) {
- const bool isValid = (syncFence != nullptr && syncFence->handle() != nullptr &&
- syncFence->handle()->numFds == 1 && syncFence->handle()->numInts == 0 &&
- &syncFence->handle()->data[0] != nullptr);
+SyncFence SyncFence::create(base::unique_fd fd) {
+ std::vector<base::unique_fd> fds;
+ fds.push_back(std::move(fd));
+ return SyncFence(std::make_shared<const Handle>(Handle{
+ .fds = std::move(fds),
+ .ints = {},
+ }));
+}
+
+Result<SyncFence> SyncFence::create(SharedHandle syncFence) {
+ const bool isValid =
+ (syncFence != nullptr && syncFence->fds.size() == 1 && syncFence->ints.empty());
if (!isValid) {
return NN_ERROR() << "Invalid sync fence handle passed to SyncFence::create";
}
return SyncFence(std::move(syncFence));
}
-SyncFence::SyncFence(NativeHandle syncFence) : mSyncFence(std::move(syncFence)) {}
+SyncFence::SyncFence(SharedHandle syncFence) : mSyncFence(std::move(syncFence)) {}
SyncFence::FenceState SyncFence::syncWait(OptionalTimeout optionalTimeout) const {
if (mSyncFence == nullptr) {
return FenceState::SIGNALED;
}
- const int fd = mSyncFence->handle()->data[0];
+ const int fd = mSyncFence->fds.front().get();
const int timeout = optionalTimeout.value_or(Timeout{-1}).count();
// This implementation is directly based on the ::sync_wait() implementation.
@@ -182,8 +190,16 @@ SyncFence::FenceState SyncFence::syncWait(OptionalTimeout optionalTimeout) const
return FenceState::UNKNOWN;
}
-NativeHandle SyncFence::getHandle() const {
+SharedHandle SyncFence::getSharedHandle() const {
return mSyncFence;
}
+bool SyncFence::hasFd() const {
+ return mSyncFence != nullptr;
+}
+
+int SyncFence::getFd() const {
+ return mSyncFence == nullptr ? -1 : mSyncFence->fds.front().get();
+}
+
} // namespace android::nn
diff --git a/nn/common/Validation.cpp b/nn/common/Validation.cpp
index d37c447c0..1c939ba40 100644
--- a/nn/common/Validation.cpp
+++ b/nn/common/Validation.cpp
@@ -679,13 +679,15 @@ Result<Version> validateOperations(const std::vector<Operation>& operations,
return version;
}
-Result<Version> validateNativeHandle(const NativeHandle& handle) {
+Result<Version> validateSharedHandle(const SharedHandle& handle) {
NN_VALIDATE(handle != nullptr);
+ NN_VALIDATE(std::all_of(handle->fds.begin(), handle->fds.end(),
+ [](const base::unique_fd& fd) { return fd.ok(); }));
return Version::ANDROID_OC_MR1;
}
Result<Version> validateMemory(const Memory& memory) {
- NN_TRY(validateNativeHandle(memory.handle));
+ NN_TRY(validateSharedHandle(memory.handle));
if (memory.name == "ashmem") {
NN_VALIDATE_NE(memory.size, 0u);
@@ -2571,8 +2573,8 @@ Result<Version> validate(const Extension& extension) {
return validateExtension(extension);
}
-Result<Version> validate(const NativeHandle& handle) {
- return validateNativeHandle(handle);
+Result<Version> validate(const SharedHandle& handle) {
+ return validateSharedHandle(handle);
}
Result<Version> validate(const Memory& memory) {
@@ -2611,8 +2613,8 @@ Result<Version> validate(const std::vector<Extension>& extensions) {
return validateExtensions(extensions);
}
-Result<Version> validate(const std::vector<NativeHandle>& handles) {
- return validateVector(handles, validateNativeHandle);
+Result<Version> validate(const std::vector<SharedHandle>& handles) {
+ return validateVector(handles, validateSharedHandle);
}
Result<Version> validate(const std::vector<BufferRole>& bufferRoles) {
diff --git a/nn/common/include/nnapi/IDevice.h b/nn/common/include/nnapi/IDevice.h
index 9a2e51680..75cf0a523 100644
--- a/nn/common/include/nnapi/IDevice.h
+++ b/nn/common/include/nnapi/IDevice.h
@@ -245,8 +245,8 @@ class IDevice {
*/
virtual GeneralResult<SharedPreparedModel> prepareModel(
const Model& model, ExecutionPreference preference, Priority priority,
- OptionalTimePoint deadline, const std::vector<NativeHandle>& modelCache,
- const std::vector<NativeHandle>& dataCache, const CacheToken& token) const = 0;
+ OptionalTimePoint deadline, const std::vector<SharedHandle>& modelCache,
+ const std::vector<SharedHandle>& dataCache, const CacheToken& token) const = 0;
/**
* Creates a prepared model from cache files for execution.
@@ -301,8 +301,8 @@ class IDevice {
* for execution, otherwise GeneralError.
*/
virtual GeneralResult<SharedPreparedModel> prepareModelFromCache(
- OptionalTimePoint deadline, const std::vector<NativeHandle>& modelCache,
- const std::vector<NativeHandle>& dataCache, const CacheToken& token) const = 0;
+ OptionalTimePoint deadline, const std::vector<SharedHandle>& modelCache,
+ const std::vector<SharedHandle>& dataCache, const CacheToken& token) const = 0;
/**
* Allocates a driver-managed buffer with the properties specified by the descriptor as well as
diff --git a/nn/common/include/nnapi/TypeUtils.h b/nn/common/include/nnapi/TypeUtils.h
index 6b2af916f..b32f78b66 100644
--- a/nn/common/include/nnapi/TypeUtils.h
+++ b/nn/common/include/nnapi/TypeUtils.h
@@ -88,7 +88,7 @@ std::ostream& operator<<(std::ostream& os,
std::ostream& operator<<(std::ostream& os, const Operand::ExtraParams& extraParams);
std::ostream& operator<<(std::ostream& os, const Operand& operand);
std::ostream& operator<<(std::ostream& os, const Operation& operation);
-std::ostream& operator<<(std::ostream& os, const NativeHandle& handle);
+std::ostream& operator<<(std::ostream& os, const SharedHandle& handle);
std::ostream& operator<<(std::ostream& os, const Memory& memory);
std::ostream& operator<<(std::ostream& os, const Model::Subgraph& subgraph);
std::ostream& operator<<(std::ostream& os, const Model::OperandValues& operandValues);
diff --git a/nn/common/include/nnapi/Types.h b/nn/common/include/nnapi/Types.h
index 3b9725d27..5adab6bfa 100644
--- a/nn/common/include/nnapi/Types.h
+++ b/nn/common/include/nnapi/Types.h
@@ -18,8 +18,7 @@
#define ANDROID_FRAMEWORKS_ML_NN_COMMON_NNAPI_TYPES_H
#include <android-base/expected.h>
-#include <utils/NativeHandle.h>
-#include <utils/StrongPointer.h>
+#include <android-base/unique_fd.h>
#include <array>
#include <chrono>
@@ -238,10 +237,15 @@ struct Operand {
ExtraParams extraParams;
};
-using NativeHandle = ::android::sp<::android::NativeHandle>;
+struct Handle {
+ std::vector<base::unique_fd> fds;
+ std::vector<int> ints;
+};
+
+using SharedHandle = std::shared_ptr<const Handle>;
struct Memory {
- NativeHandle handle;
+ SharedHandle handle;
size_t size = 0;
std::string name;
};
@@ -313,7 +317,8 @@ struct Request {
class SyncFence {
public:
static SyncFence createAsSignaled();
- static Result<SyncFence> create(NativeHandle syncFence);
+ static SyncFence create(base::unique_fd fd);
+ static Result<SyncFence> create(SharedHandle syncFence);
// The function syncWait() has the same semantics as the system function
// ::sync_wait(), except that the syncWait() return value is semantically
@@ -329,12 +334,14 @@ class SyncFence {
FenceState syncWait(OptionalTimeout optionalTimeout) const;
- NativeHandle getHandle() const;
+ SharedHandle getSharedHandle() const;
+ bool hasFd() const;
+ int getFd() const;
private:
- explicit SyncFence(NativeHandle syncFence);
+ explicit SyncFence(SharedHandle syncFence);
- NativeHandle mSyncFence;
+ SharedHandle mSyncFence;
};
using Clock = std::chrono::steady_clock;
diff --git a/nn/common/include/nnapi/Validation.h b/nn/common/include/nnapi/Validation.h
index 3eda174f6..ea213bdd8 100644
--- a/nn/common/include/nnapi/Validation.h
+++ b/nn/common/include/nnapi/Validation.h
@@ -42,7 +42,7 @@ Result<Version> validate(const OutputShape& outputShape);
Result<Version> validate(const Timing& timing);
Result<Version> validate(const Capabilities& capabilities);
Result<Version> validate(const Extension& extension);
-Result<Version> validate(const NativeHandle& handle);
+Result<Version> validate(const SharedHandle& handle);
Result<Version> validate(const Memory& memory);
Result<Version> validate(const Model& model);
Result<Version> validate(const BufferDesc& bufferDesc);
@@ -53,7 +53,7 @@ Result<Version> validate(const OptionalTimeoutDuration& optionalTimeoutDuration)
Result<Version> validate(const std::vector<OutputShape>& outputShapes);
Result<Version> validate(const std::vector<Extension>& extensions);
-Result<Version> validate(const std::vector<NativeHandle>& handles);
+Result<Version> validate(const std::vector<SharedHandle>& handles);
Result<Version> validate(const std::vector<BufferRole>& bufferRoles);
// Validate request applied to model.
diff --git a/nn/runtime/Manager.cpp b/nn/runtime/Manager.cpp
index 90d58e490..d977878cd 100644
--- a/nn/runtime/Manager.cpp
+++ b/nn/runtime/Manager.cpp
@@ -432,8 +432,6 @@ std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>, Timing> DriverPreparedM
CHECK(std::all_of(waitFor.begin(), waitFor.end(), [](int fd) { return fd > 0; }));
// Make a copy of the memory tracker as we will append memory pools for pointer arguments.
std::vector<const RuntimeMemory*> localMemories = memories;
- sp<V1_3::IFencedExecutionCallback> executeFencedCallback;
- Timing timing;
// We separate the input & output pools so accelerators only need to copy
// the contents of the input pools. We could also use it to set protection
@@ -443,12 +441,12 @@ std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>, Timing> DriverPreparedM
const auto [n1, inputPtrArgsMemory, inputPtrArgsLocations] =
allocatePointerArgumentsToPool(inputs, &localMemories);
if (n1 != ANEURALNETWORKS_NO_ERROR) {
- return {n1, -1, nullptr, timing};
+ return {n1, -1, nullptr, {}};
}
const auto [n2, outputPtrArgsMemory, outputPtrArgsLocations] =
allocatePointerArgumentsToPool(outputs, &localMemories);
if (n2 != ANEURALNETWORKS_NO_ERROR) {
- return {n2, -1, nullptr, timing};
+ return {n2, -1, nullptr, {}};
}
// Copy the input data that was specified via a pointer.
@@ -475,28 +473,18 @@ std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>, Timing> DriverPreparedM
NNTRACE_FULL_SWITCH(NNTRACE_LAYER_IPC, NNTRACE_PHASE_EXECUTION,
"DriverPreparedModel::executeFenced");
- int n = ANEURALNETWORKS_OP_FAILED;
- hardware::hidl_vec<hardware::hidl_handle> waitForHandles;
- waitForHandles.resize(waitFor.size());
- for (uint32_t i = 0; i < waitFor.size(); i++) {
- native_handle_t* nativeHandle = native_handle_create(1, 0);
- if (nativeHandle == nullptr) {
- LOG(ERROR) << "Failed to create native_handle";
- return {n, -1, nullptr, timing};
- }
- int dupFd = dup(waitFor[i]);
+ std::vector<SyncFence> waitForHandles;
+ waitForHandles.reserve(waitFor.size());
+ for (int fd : waitFor) {
+ int dupFd = dup(fd);
if (dupFd <= 0) {
LOG(ERROR) << "Unable to dup the file descriptor";
- return {n, -1, nullptr, timing};
+ return {ANEURALNETWORKS_OP_FAILED, -1, nullptr, {}};
}
- nativeHandle->data[0] = dupFd;
- hardware::hidl_handle hidlHandle;
- hidlHandle.setTo(nativeHandle, /*shouldOwn=*/true);
- waitForHandles[i] = std::move(hidlHandle);
+ waitForHandles.push_back(SyncFence::create(base::unique_fd(dupFd)));
}
- hardware::hidl_handle syncFence;
- std::tie(n, syncFence, executeFencedCallback, timing) =
+ auto [n, syncFence, executeFencedCallback, timing] =
mPreparedModel->executeFenced(request, waitForHandles, measure, deadline,
loopTimeoutDuration, timeoutDurationAfterFence);
@@ -506,8 +494,8 @@ std::tuple<int, int, sp<V1_3::IFencedExecutionCallback>, Timing> DriverPreparedM
}
int syncFenceFd = -1;
- if (syncFence.getNativeHandle()) {
- syncFenceFd = dup(syncFence.getNativeHandle()->data[0]);
+ if (syncFence.hasFd()) {
+ syncFenceFd = dup(syncFence.getFd());
if (syncFenceFd < 0) {
LOG(ERROR) << "Failed to dup the file descriptor";
return {ANEURALNETWORKS_OP_FAILED, -1, nullptr, timing};
diff --git a/nn/runtime/VersionedInterfaces.cpp b/nn/runtime/VersionedInterfaces.cpp
index fce558c38..8246b623e 100644
--- a/nn/runtime/VersionedInterfaces.cpp
+++ b/nn/runtime/VersionedInterfaces.cpp
@@ -24,6 +24,7 @@
#include <android-base/thread_annotations.h>
#include <cutils/native_handle.h>
#include <fcntl.h>
+#include <nnapi/hal/CommonUtils.h>
#include <algorithm>
#include <chrono>
@@ -416,67 +417,83 @@ static std::pair<V1_3::ErrorStatus, V1_3::Capabilities> getCapabilitiesFunction(
return result;
}
-std::tuple<int, hardware::hidl_handle, sp<V1_3::IFencedExecutionCallback>, Timing>
+std::tuple<int, SyncFence, sp<V1_3::IFencedExecutionCallback>, Timing>
VersionedIPreparedModel::executeFenced(const Request& request,
- const hardware::hidl_vec<hardware::hidl_handle>& waitFor,
- MeasureTiming measure,
+ const std::vector<SyncFence>& waitFor, MeasureTiming measure,
const std::optional<Deadline>& deadline,
const OptionalTimeoutDuration& loopTimeoutDuration,
const OptionalTimeoutDuration& timeoutDurationAfterFence) {
// version 1.3 HAL
- hardware::hidl_handle syncFence;
+ hardware::hidl_handle hidlSyncFence;
sp<V1_3::IFencedExecutionCallback> dispatchCallback;
Timing timing = {UINT64_MAX, UINT64_MAX};
if (mPreparedModelV1_3 != nullptr) {
ErrorStatus errorStatus;
const auto otp = makeTimePoint(deadline);
+ auto waitForHandles = hal::utils::convertSyncFences(waitFor);
+ if (!waitForHandles.has_value()) {
+ LOG(ERROR) << "executeFenced failure: " << waitForHandles.error().message;
+ return std::make_tuple(ANEURALNETWORKS_OP_FAILED, SyncFence::createAsSignaled(),
+ nullptr, timing);
+ }
hardware::Return<void> ret = mPreparedModelV1_3->executeFenced(
- convertToV1_3(request), waitFor, convertToV1_2(measure), convertToV1_3(otp),
- convertToV1_3(loopTimeoutDuration), convertToV1_3(timeoutDurationAfterFence),
- [&syncFence, &errorStatus, &dispatchCallback](
+ convertToV1_3(request), std::move(waitForHandles).value(), convertToV1_2(measure),
+ convertToV1_3(otp), convertToV1_3(loopTimeoutDuration),
+ convertToV1_3(timeoutDurationAfterFence),
+ [&hidlSyncFence, &errorStatus, &dispatchCallback](
V1_3::ErrorStatus error, const hardware::hidl_handle& handle,
const sp<V1_3::IFencedExecutionCallback>& callback) {
- syncFence = handle;
+ hidlSyncFence = handle;
errorStatus = uncheckedConvert(error);
dispatchCallback = callback;
});
if (!ret.isOk()) {
LOG(ERROR) << "executeFenced failure: " << ret.description();
- return std::make_tuple(ANEURALNETWORKS_OP_FAILED, hardware::hidl_handle(nullptr),
+ return std::make_tuple(ANEURALNETWORKS_OP_FAILED, SyncFence::createAsSignaled(),
nullptr, timing);
}
if (errorStatus != ErrorStatus::NONE) {
LOG(ERROR) << "executeFenced returned " << errorStatus;
return std::make_tuple(convertErrorStatusToResultCode(errorStatus),
- hardware::hidl_handle(nullptr), nullptr, timing);
+ SyncFence::createAsSignaled(), nullptr, timing);
}
- return std::make_tuple(ANEURALNETWORKS_NO_ERROR, syncFence, dispatchCallback, timing);
+ auto sharedHandle = hal::utils::sharedHandleFromNativeHandle(hidlSyncFence);
+ if (!sharedHandle.has_value()) {
+ LOG(ERROR) << "executeFenced failure: " << sharedHandle.error().message;
+ return std::make_tuple(ANEURALNETWORKS_OP_FAILED, SyncFence::createAsSignaled(),
+ nullptr, timing);
+ }
+ auto syncFence = sharedHandle.value() == nullptr
+ ? SyncFence::createAsSignaled()
+ : SyncFence::create(std::move(sharedHandle).value());
+ if (!syncFence.has_value()) {
+ LOG(ERROR) << "executeFenced failure: " << syncFence.error();
+ return std::make_tuple(ANEURALNETWORKS_OP_FAILED, SyncFence::createAsSignaled(),
+ nullptr, timing);
+ }
+ return std::make_tuple(ANEURALNETWORKS_NO_ERROR, std::move(syncFence).value(),
+ dispatchCallback, timing);
}
// fallback to synchronous execution if sync_fence is not supported
// first wait for all sync fences to be ready.
LOG(INFO) << "No drivers able to handle sync fences, falling back to regular execution";
- for (const auto& fenceHandle : waitFor) {
- if (!fenceHandle.getNativeHandle()) {
- return std::make_tuple(ANEURALNETWORKS_BAD_DATA, hardware::hidl_handle(nullptr),
- nullptr, timing);
- }
- int syncFd = fenceHandle.getNativeHandle()->data[0];
- if (syncFd <= 0) {
- return std::make_tuple(ANEURALNETWORKS_BAD_DATA, hardware::hidl_handle(nullptr),
- nullptr, timing);
+ for (const auto& fence : waitFor) {
+ if (!fence.hasFd() || fence.getFd() <= 0) {
+ return std::make_tuple(ANEURALNETWORKS_BAD_DATA, SyncFence::createAsSignaled(), nullptr,
+ timing);
}
- auto r = syncWait(syncFd, -1);
- if (r != FenceState::SIGNALED) {
- LOG(ERROR) << "syncWait failed, fd: " << syncFd;
- return std::make_tuple(ANEURALNETWORKS_OP_FAILED, hardware::hidl_handle(nullptr),
+ auto r = fence.syncWait({/* no timeout */});
+ if (r != SyncFence::FenceState::SIGNALED) {
+ LOG(ERROR) << "syncWait failed, fd: " << fence.getFd() << ", state: " << r;
+ return std::make_tuple(ANEURALNETWORKS_OP_FAILED, SyncFence::createAsSignaled(),
nullptr, timing);
}
}
int errorCode;
std::tie(errorCode, std::ignore, timing) =
executeSynchronously(request, measure, deadline, loopTimeoutDuration);
- return std::make_tuple(errorCode, hardware::hidl_handle(nullptr), nullptr, timing);
+ return std::make_tuple(errorCode, SyncFence::createAsSignaled(), nullptr, timing);
}
static std::pair<V1_3::ErrorStatus, V1_3::Capabilities> getCapabilitiesFunction(
diff --git a/nn/runtime/VersionedInterfaces.h b/nn/runtime/VersionedInterfaces.h
index d41dcd3ad..bd7e396bf 100644
--- a/nn/runtime/VersionedInterfaces.h
+++ b/nn/runtime/VersionedInterfaces.h
@@ -754,8 +754,8 @@ class VersionedIPreparedModel {
* all sync fences in waitFor are signaled.
* @return A tuple consisting of:
* - Error code of the dispatch call.
- * - A sync_fence that will be triggered when the task is completed.
- * The sync_fence will be set to error if critical error occurs when doing
+ * - A SyncFence that will be triggered when the task is completed.
+ * The SyncFence will be set to error if critical error occurs when doing
* actual evaluation.
* - A callback can be used to query information like duration
* and detailed runtime error status when the task is completed.
@@ -763,11 +763,11 @@ class VersionedIPreparedModel {
* sync execution. Either IFencedExecutionCallback will be
* returned or optional timing information is returned
*/
- std::tuple<int, hardware::hidl_handle, sp<V1_3::IFencedExecutionCallback>, Timing>
- executeFenced(const Request& request, const hardware::hidl_vec<hardware::hidl_handle>& waitFor,
- MeasureTiming measure, const std::optional<Deadline>& deadline,
- const OptionalTimeoutDuration& loopTimeoutDuration,
- const OptionalTimeoutDuration& timeoutDurationAfterFence);
+ std::tuple<int, SyncFence, sp<V1_3::IFencedExecutionCallback>, Timing> executeFenced(
+ const Request& request, const std::vector<SyncFence>& waitFor, MeasureTiming measure,
+ const std::optional<Deadline>& deadline,
+ const OptionalTimeoutDuration& loopTimeoutDuration,
+ const OptionalTimeoutDuration& timeoutDurationAfterFence);
private:
friend class VersionedIDevice;
diff --git a/nn/runtime/test/TestVersionedInterfaces.cpp b/nn/runtime/test/TestVersionedInterfaces.cpp
index b4f32bcde..4187029f9 100644
--- a/nn/runtime/test/TestVersionedInterfaces.cpp
+++ b/nn/runtime/test/TestVersionedInterfaces.cpp
@@ -2182,7 +2182,7 @@ TEST_F(VersionedIPreparedModelV1_0Test, executeFenced) {
// verify success
EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode);
- EXPECT_EQ(nullptr, syncFence.getNativeHandle());
+ EXPECT_EQ(nullptr, syncFence.getSharedHandle());
EXPECT_EQ(nullptr, dispatchCallback.get());
EXPECT_EQ(kNoTiming, timing);
}
@@ -2198,7 +2198,7 @@ TEST_F(VersionedIPreparedModelV1_1Test, executeFenced) {
// verify success
EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode);
- EXPECT_EQ(nullptr, syncFence.getNativeHandle());
+ EXPECT_EQ(nullptr, syncFence.getSharedHandle());
EXPECT_EQ(nullptr, dispatchCallback.get());
EXPECT_EQ(kNoTiming, timing);
}
@@ -2214,7 +2214,7 @@ TEST_F(VersionedIPreparedModelV1_2Test, executeFenced) {
// verify success
EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode);
- EXPECT_EQ(nullptr, syncFence.getNativeHandle());
+ EXPECT_EQ(nullptr, syncFence.getSharedHandle());
EXPECT_EQ(nullptr, dispatchCallback.get());
EXPECT_EQ(kNoTiming, timing);
}
@@ -2235,7 +2235,7 @@ TEST_F(VersionedIPreparedModelV1_3Test, executeFenced) {
// verify success
EXPECT_EQ(ANEURALNETWORKS_NO_ERROR, resultCode);
- EXPECT_NE(nullptr, syncFence.getNativeHandle());
+ EXPECT_NE(nullptr, syncFence.getSharedHandle());
EXPECT_NE(nullptr, dispatchCallback.get());
EXPECT_EQ(kNoTiming, timing);
}
@@ -2494,7 +2494,7 @@ TEST_F(VersionedIPreparedModelV1_0Test, executeFencedFailure) {
// verify failure
EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode);
- EXPECT_EQ(nullptr, syncFence.getNativeHandle());
+ EXPECT_EQ(nullptr, syncFence.getSharedHandle());
EXPECT_EQ(nullptr, dispatchCallback.get());
EXPECT_EQ(kNoTiming, timing);
}
@@ -2511,7 +2511,7 @@ TEST_F(VersionedIPreparedModelV1_1Test, executeFencedFailure) {
// verify failure
EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode);
- EXPECT_EQ(nullptr, syncFence.getNativeHandle());
+ EXPECT_EQ(nullptr, syncFence.getSharedHandle());
EXPECT_EQ(nullptr, dispatchCallback.get());
EXPECT_EQ(kNoTiming, timing);
}
@@ -2528,7 +2528,7 @@ TEST_F(VersionedIPreparedModelV1_2Test, executeFencedFailure) {
// verify failure
EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode);
- EXPECT_EQ(nullptr, syncFence.getNativeHandle());
+ EXPECT_EQ(nullptr, syncFence.getSharedHandle());
EXPECT_EQ(nullptr, dispatchCallback.get());
EXPECT_EQ(kNoTiming, timing);
}
@@ -2550,7 +2550,7 @@ TEST_F(VersionedIPreparedModelV1_3Test, executeFencedFailure) {
// verify failure
EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode);
- EXPECT_EQ(nullptr, syncFence.getNativeHandle());
+ EXPECT_EQ(nullptr, syncFence.getSharedHandle());
EXPECT_EQ(nullptr, dispatchCallback.get());
EXPECT_EQ(kNoTiming, timing);
}
@@ -2759,7 +2759,7 @@ TEST_F(VersionedIPreparedModelV1_0Test, executeFencedTransportFailure) {
// verify failure
EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode);
- EXPECT_EQ(nullptr, syncFence.getNativeHandle());
+ EXPECT_EQ(nullptr, syncFence.getSharedHandle());
EXPECT_EQ(nullptr, dispatchCallback.get());
EXPECT_EQ(kNoTiming, timing);
}
@@ -2776,7 +2776,7 @@ TEST_F(VersionedIPreparedModelV1_1Test, executeFencedTransportFailure) {
// verify failure
EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode);
- EXPECT_EQ(nullptr, syncFence.getNativeHandle());
+ EXPECT_EQ(nullptr, syncFence.getSharedHandle());
EXPECT_EQ(nullptr, dispatchCallback.get());
EXPECT_EQ(kNoTiming, timing);
}
@@ -2793,7 +2793,7 @@ TEST_F(VersionedIPreparedModelV1_2Test, executeFencedTransportFailure) {
// verify failure
EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode);
- EXPECT_EQ(nullptr, syncFence.getNativeHandle());
+ EXPECT_EQ(nullptr, syncFence.getSharedHandle());
EXPECT_EQ(nullptr, dispatchCallback.get());
EXPECT_EQ(kNoTiming, timing);
}
@@ -2810,7 +2810,7 @@ TEST_F(VersionedIPreparedModelV1_3Test, executeFencedTransportFailure) {
// verify failure
EXPECT_EQ(ANEURALNETWORKS_OP_FAILED, resultCode);
- EXPECT_EQ(nullptr, syncFence.getNativeHandle());
+ EXPECT_EQ(nullptr, syncFence.getSharedHandle());
EXPECT_EQ(nullptr, dispatchCallback.get());
EXPECT_EQ(kNoTiming, timing);
}