Add support for new gralloc HAL versions

am: df6e2b70ae

Change-Id: Iea28b01046e9094a28d538119e5acdf845385f6f
This commit is contained in:
Brian Duddie
2019-08-02 19:40:42 -07:00
committed by android-build-merger
6 changed files with 250 additions and 225 deletions

View File

@@ -24,7 +24,10 @@ cc_test {
],
static_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
"android.hardware.sensors@1.0",
"VtsHalSensorsTargetTestUtils",
],

View File

@@ -24,7 +24,10 @@ cc_test {
],
static_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
"android.hardware.sensors@1.0",
"android.hardware.sensors@2.0",
"libfmq",

View File

@@ -31,7 +31,10 @@ cc_library_static {
],
static_libs: [
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
"android.hardware.sensors@1.0",
"VtsHalHidlTargetTestBase",
],

View File

@@ -16,206 +16,262 @@
#include "GrallocWrapper.h"
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <android/hardware/graphics/mapper/2.1/IMapper.h>
#include <android/hardware/graphics/mapper/3.0/IMapper.h>
#include <utils/Log.h>
#include <cinttypes>
#include <type_traits>
using IAllocator2 = ::android::hardware::graphics::allocator::V2_0::IAllocator;
using IAllocator3 = ::android::hardware::graphics::allocator::V3_0::IAllocator;
using IMapper2 = ::android::hardware::graphics::mapper::V2_0::IMapper;
using IMapper2_1 = ::android::hardware::graphics::mapper::V2_1::IMapper;
using IMapper3 = ::android::hardware::graphics::mapper::V3_0::IMapper;
using Error2 = ::android::hardware::graphics::mapper::V2_0::Error;
using Error3 = ::android::hardware::graphics::mapper::V3_0::Error;
using ::android::hardware::graphics::common::V1_0::BufferUsage;
using ::android::hardware::graphics::common::V1_0::PixelFormat;
// This is a typedef to the same underlying type across v2.0 and v3.0
using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
namespace android {
GrallocWrapper::GrallocWrapper() {
init();
// Since we use the same APIs across allocator/mapper HALs but they have major
// version differences (meaning they are not related through inheritance), we
// create a common interface abstraction for the IAllocator + IMapper combination
// (major versions need to match in the current HALs, e.g. IAllocator 3.0 needs to
// be paired with IMapper 3.0, so these are tied together)
class IGrallocHalWrapper {
public:
virtual ~IGrallocHalWrapper() = default;
// IAllocator
virtual std::string dumpDebugInfo() = 0;
virtual native_handle_t* allocate(uint32_t size) = 0;
virtual void freeBuffer(native_handle_t* bufferHandle) = 0;
// IMapper
virtual void* lock(native_handle_t* bufferHandle) = 0;
virtual void unlock(native_handle_t* bufferHandle) = 0;
};
namespace {
bool failed(Error2 error) {
return (error != Error2::NONE);
}
bool failed(Error3 error) {
return (error != Error3::NONE);
}
void GrallocWrapper::init() {
mAllocator = allocator2::IAllocator::getService();
if (mAllocator == nullptr) {
ALOGE("Failed to get allocator service");
}
mMapper = mapper2::IMapper::getService();
if (mMapper == nullptr) {
ALOGE("Failed to get mapper service");
} else if (mMapper->isRemote()) {
ALOGE("Mapper is not in passthrough mode");
}
}
GrallocWrapper::~GrallocWrapper() {
for (auto bufferHandle : mClonedBuffers) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
native_handle_close(buffer);
native_handle_delete(buffer);
}
mClonedBuffers.clear();
for (auto bufferHandle : mImportedBuffers) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
if (mMapper->freeBuffer(buffer) != mapper2::Error::NONE) {
ALOGE("Failed to free buffer %p", buffer);
// Since all the type and function names are the same for the things we use across the major HAL
// versions, we use template magic to avoid repeating ourselves.
template <typename AllocatorT, typename MapperT>
class GrallocHalWrapper : public IGrallocHalWrapper {
public:
GrallocHalWrapper(const sp<AllocatorT>& allocator, const sp<MapperT>& mapper)
: mAllocator(allocator), mMapper(mapper) {
if (mapper->isRemote()) {
ALOGE("Mapper is in passthrough mode");
}
}
mImportedBuffers.clear();
}
sp<allocator2::IAllocator> GrallocWrapper::getAllocator() const {
return mAllocator;
}
virtual std::string dumpDebugInfo() override;
virtual native_handle_t* allocate(uint32_t size) override;
virtual void freeBuffer(native_handle_t* bufferHandle) override;
std::string GrallocWrapper::dumpDebugInfo() {
virtual void* lock(native_handle_t* bufferHandle) override;
virtual void unlock(native_handle_t* bufferHandle) override;
private:
static constexpr uint64_t kBufferUsage =
static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::CPU_READ_OFTEN);
sp<AllocatorT> mAllocator;
sp<MapperT> mMapper;
BufferDescriptor getDescriptor(uint32_t size);
native_handle_t* importBuffer(const hidl_handle& rawHandle);
};
template <typename AllocatorT, typename MapperT>
std::string GrallocHalWrapper<AllocatorT, MapperT>::dumpDebugInfo() {
std::string debugInfo;
mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
mAllocator->dumpDebugInfo([&](const hidl_string& tmpDebugInfo) { debugInfo = tmpDebugInfo; });
return debugInfo;
}
const native_handle_t* GrallocWrapper::cloneBuffer(const hardware::hidl_handle& rawHandle) {
const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
template <typename AllocatorT, typename MapperT>
native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::allocate(uint32_t size) {
constexpr uint32_t kBufferCount = 1;
BufferDescriptor descriptor = getDescriptor(size);
native_handle_t* bufferHandle = nullptr;
if (bufferHandle) {
mClonedBuffers.insert(bufferHandle);
}
auto callback = [&](auto error, uint32_t /*stride*/, const hidl_vec<hidl_handle>& buffers) {
if (failed(error)) {
ALOGE("Failed to allocate buffer: %" PRId32, static_cast<int32_t>(error));
} else if (buffers.size() != kBufferCount) {
ALOGE("Invalid buffer array size (got %zu, expected %" PRIu32 ")", buffers.size(),
kBufferCount);
} else {
bufferHandle = importBuffer(buffers[0]);
}
};
mAllocator->allocate(descriptor, kBufferCount, callback);
return bufferHandle;
}
std::vector<const native_handle_t*> GrallocWrapper::allocate(
const mapper2::BufferDescriptor& descriptor, uint32_t count, bool import, uint32_t* outStride) {
std::vector<const native_handle_t*> bufferHandles;
bufferHandles.reserve(count);
mAllocator->allocate(descriptor, count,
[&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
if (mapper2::Error::NONE != tmpError) {
ALOGE("Failed to allocate buffers");
}
if (count != tmpBuffers.size()) {
ALOGE("Invalid buffer array");
}
for (uint32_t i = 0; i < count; i++) {
if (import) {
bufferHandles.push_back(importBuffer(tmpBuffers[i]));
} else {
bufferHandles.push_back(cloneBuffer(tmpBuffers[i]));
}
}
if (outStride) {
*outStride = tmpStride;
}
});
return bufferHandles;
template <typename AllocatorT, typename MapperT>
void GrallocHalWrapper<AllocatorT, MapperT>::freeBuffer(native_handle_t* bufferHandle) {
auto error = mMapper->freeBuffer(bufferHandle);
if (!error.isOk() || failed(error)) {
ALOGE("Failed to free buffer %p", bufferHandle);
}
}
const native_handle_t* GrallocWrapper::allocate(
const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo, bool import,
uint32_t* outStride) {
mapper2::BufferDescriptor descriptor = createDescriptor(descriptorInfo);
auto buffers = allocate(descriptor, 1, import, outStride);
return buffers[0];
}
template <typename AllocatorT, typename MapperT>
BufferDescriptor GrallocHalWrapper<AllocatorT, MapperT>::getDescriptor(uint32_t size) {
typename MapperT::BufferDescriptorInfo descriptorInfo = {
.width = size,
.height = 1,
.layerCount = 1,
.usage = kBufferUsage,
.format = static_cast<decltype(descriptorInfo.format)>(PixelFormat::BLOB),
};
sp<mapper2::IMapper> GrallocWrapper::getMapper() const {
return mMapper;
}
mapper2::BufferDescriptor GrallocWrapper::createDescriptor(
const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo) {
mapper2::BufferDescriptor descriptor;
mMapper->createDescriptor(descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
if (tmpError != mapper2::Error::NONE) {
ALOGE("Failed to create descriptor");
BufferDescriptor descriptor;
auto callback = [&](auto error, const BufferDescriptor& tmpDescriptor) {
if (failed(error)) {
ALOGE("Failed to create descriptor: %" PRId32, static_cast<int32_t>(error));
} else {
descriptor = tmpDescriptor;
}
descriptor = tmpDescriptor;
});
};
mMapper->createDescriptor(descriptorInfo, callback);
return descriptor;
}
const native_handle_t* GrallocWrapper::importBuffer(const hardware::hidl_handle& rawHandle) {
const native_handle_t* bufferHandle = nullptr;
mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
if (tmpError != mapper2::Error::NONE) {
ALOGE("Failed to import buffer %p", rawHandle.getNativeHandle());
}
bufferHandle = static_cast<const native_handle_t*>(tmpBuffer);
});
template <typename AllocatorT, typename MapperT>
native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::importBuffer(
const hidl_handle& rawHandle) {
native_handle_t* bufferHandle = nullptr;
if (bufferHandle) {
mImportedBuffers.insert(bufferHandle);
}
mMapper->importBuffer(rawHandle, [&](auto error, void* tmpBuffer) {
if (failed(error)) {
ALOGE("Failed to import buffer %p: %" PRId32, rawHandle.getNativeHandle(),
static_cast<int32_t>(error));
} else {
bufferHandle = static_cast<native_handle_t*>(tmpBuffer);
}
});
return bufferHandle;
}
void GrallocWrapper::freeBuffer(const native_handle_t* bufferHandle) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
if (mImportedBuffers.erase(bufferHandle)) {
mapper2::Error error = mMapper->freeBuffer(buffer);
if (error != mapper2::Error::NONE) {
ALOGE("Failed to free %p", buffer);
}
} else {
mClonedBuffers.erase(bufferHandle);
native_handle_close(buffer);
native_handle_delete(buffer);
}
}
void* GrallocWrapper::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
const mapper2::IMapper::Rect& accessRegion, int acquireFence) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
hardware::hidl_handle acquireFenceHandle;
if (acquireFence >= 0) {
auto h = native_handle_init(acquireFenceStorage, 1, 0);
h->data[0] = acquireFence;
acquireFenceHandle = h;
}
template <typename AllocatorT, typename MapperT>
void* GrallocHalWrapper<AllocatorT, MapperT>::lock(native_handle_t* bufferHandle) {
// Per the HAL, all-zeros Rect means the entire buffer
typename MapperT::Rect accessRegion = {};
hidl_handle acquireFenceHandle; // No fence needed, already safe to lock
void* data = nullptr;
mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
[&](const auto& tmpError, const auto& tmpData) {
if (tmpError != mapper2::Error::NONE) {
ALOGE("Failed to lock buffer %p", buffer);
mMapper->lock(bufferHandle, kBufferUsage, accessRegion, acquireFenceHandle,
[&](auto error, void* tmpData, ...) { // V3_0 passes extra args we don't use
if (failed(error)) {
ALOGE("Failed to lock buffer %p: %" PRId32, bufferHandle,
static_cast<int32_t>(error));
} else {
data = tmpData;
}
data = tmpData;
});
if (acquireFence >= 0) {
close(acquireFence);
}
return data;
}
int GrallocWrapper::unlock(const native_handle_t* bufferHandle) {
auto buffer = const_cast<native_handle_t*>(bufferHandle);
int releaseFence = -1;
mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
if (tmpError != mapper2::Error::NONE) {
ALOGE("Failed to unlock buffer %p", buffer);
}
auto fenceHandle = tmpReleaseFence.getNativeHandle();
if (fenceHandle) {
if (fenceHandle->numInts != 0) {
ALOGE("Invalid fence handle %p", fenceHandle);
}
if (fenceHandle->numFds == 1) {
releaseFence = dup(fenceHandle->data[0]);
if (releaseFence < 0) {
ALOGE("Failed to dup fence fd");
}
} else {
if (fenceHandle->numFds != 0) {
ALOGE("Invalid fence handle %p", fenceHandle);
}
}
template <typename AllocatorT, typename MapperT>
void GrallocHalWrapper<AllocatorT, MapperT>::unlock(native_handle_t* bufferHandle) {
mMapper->unlock(bufferHandle, [&](auto error, const hidl_handle& /*releaseFence*/) {
if (failed(error)) {
ALOGE("Failed to unlock buffer %p: %" PRId32, bufferHandle,
static_cast<int32_t>(error));
}
});
}
return releaseFence;
} // anonymous namespace
GrallocWrapper::GrallocWrapper() {
sp<IAllocator3> allocator3 = IAllocator3::getService();
sp<IMapper3> mapper3 = IMapper3::getService();
if (allocator3 != nullptr && mapper3 != nullptr) {
mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
new GrallocHalWrapper<IAllocator3, IMapper3>(allocator3, mapper3));
} else {
ALOGD("Graphics HALs 3.0 not found (allocator %d mapper %d), falling back to 2.x",
(allocator3 != nullptr), (mapper3 != nullptr));
sp<IAllocator2> allocator2 = IAllocator2::getService();
sp<IMapper2> mapper2 = IMapper2_1::getService();
if (mapper2 == nullptr) {
mapper2 = IMapper2::getService();
}
if (allocator2 != nullptr && mapper2 != nullptr) {
mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
new GrallocHalWrapper<IAllocator2, IMapper2>(allocator2, mapper2));
} else {
ALOGE("Couldn't open 2.x/3.0 graphics HALs (2.x allocator %d mapper %d)",
(allocator2 != nullptr), (mapper2 != nullptr));
}
}
}
GrallocWrapper::~GrallocWrapper() {
for (auto bufferHandle : mAllocatedBuffers) {
mGrallocHal->unlock(bufferHandle);
mGrallocHal->freeBuffer(bufferHandle);
}
mAllocatedBuffers.clear();
}
std::string GrallocWrapper::dumpDebugInfo() {
return mGrallocHal->dumpDebugInfo();
}
std::pair<native_handle_t*, void*> GrallocWrapper::allocate(uint32_t size) {
native_handle_t* bufferHandle = mGrallocHal->allocate(size);
void* buffer = nullptr;
if (bufferHandle) {
buffer = mGrallocHal->lock(bufferHandle);
if (buffer) {
mAllocatedBuffers.insert(bufferHandle);
} else {
mGrallocHal->freeBuffer(bufferHandle);
bufferHandle = nullptr;
}
}
return std::make_pair<>(bufferHandle, buffer);
}
void GrallocWrapper::freeBuffer(native_handle_t* bufferHandle) {
if (mAllocatedBuffers.erase(bufferHandle)) {
mGrallocHal->unlock(bufferHandle);
mGrallocHal->freeBuffer(bufferHandle);
}
}
} // namespace android

View File

@@ -119,32 +119,13 @@ SensorsTestSharedMemory::SensorsTestSharedMemory(SharedMemType type, size_t size
}
case SharedMemType::GRALLOC: {
mGrallocWrapper = std::make_unique<::android::GrallocWrapper>();
if (mGrallocWrapper->getAllocator() == nullptr ||
mGrallocWrapper->getMapper() == nullptr) {
if (!mGrallocWrapper->isInitialized()) {
break;
}
using android::hardware::graphics::common::V1_0::BufferUsage;
using android::hardware::graphics::common::V1_0::PixelFormat;
mapper2::IMapper::BufferDescriptorInfo buf_desc_info = {
.width = static_cast<uint32_t>(size),
.height = 1,
.layerCount = 1,
.usage = static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA |
BufferUsage::CPU_READ_OFTEN),
.format = PixelFormat::BLOB};
handle = const_cast<native_handle_t*>(mGrallocWrapper->allocate(buf_desc_info));
if (handle != nullptr) {
mapper2::IMapper::Rect region{0, 0, static_cast<int32_t>(buf_desc_info.width),
static_cast<int32_t>(buf_desc_info.height)};
buffer = static_cast<char*>(
mGrallocWrapper->lock(handle, buf_desc_info.usage, region, /*fence=*/-1));
if (buffer != nullptr) {
break;
}
mGrallocWrapper->freeBuffer(handle);
handle = nullptr;
}
std::pair<native_handle_t*, void*> buf = mGrallocWrapper->allocate(size);
handle = buf.first;
buffer = static_cast<char*>(buf.second);
break;
}
default:
@@ -175,9 +156,7 @@ SensorsTestSharedMemory::~SensorsTestSharedMemory() {
}
case SharedMemType::GRALLOC: {
if (mSize != 0) {
mGrallocWrapper->unlock(mNativeHandle);
mGrallocWrapper->freeBuffer(mNativeHandle);
mNativeHandle = nullptr;
mSize = 0;
}

View File

@@ -14,66 +14,47 @@
* limitations under the License.
*/
#ifndef GRALLO_WRAPPER_H_
#define GRALLO_WRAPPER_H_
#pragma once
#include <utils/NativeHandle.h>
#include <memory>
#include <string>
#include <unordered_set>
#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
namespace allocator2 = ::android::hardware::graphics::allocator::V2_0;
namespace mapper2 = ::android::hardware::graphics::mapper::V2_0;
#include <utility>
namespace android {
// Modified from hardware/interfaces/graphics/mapper/2.0/vts/functional/
class IGrallocHalWrapper;
// Reference: hardware/interfaces/graphics/mapper/2.0/vts/functional/
class GrallocWrapper {
public:
GrallocWrapper();
~GrallocWrapper();
sp<allocator2::IAllocator> getAllocator() const;
sp<mapper2::IMapper> getMapper() const;
// After constructing this object, this function must be called to check the result. If it
// returns false, other methods are not safe to call.
bool isInitialized() const { return (mGrallocHal != nullptr); };
std::string dumpDebugInfo();
// When import is false, this simply calls IAllocator::allocate. When import
// is true, the returned buffers are also imported into the mapper.
//
// Either case, the returned buffers must be freed with freeBuffer.
std::vector<const native_handle_t*> allocate(const mapper2::BufferDescriptor& descriptor,
uint32_t count, bool import = true,
uint32_t* outStride = nullptr);
const native_handle_t* allocate(const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo,
bool import = true, uint32_t* outStride = nullptr);
// Allocates a gralloc buffer suitable for direct channel sensors usage with the given size.
// The buffer should be freed using freeBuffer when it's not needed anymore; otherwise it'll
// be freed when this object is destroyed.
// Returns a handle to the buffer, and a CPU-accessible pointer for reading. On failure, both
// will be set to nullptr.
std::pair<native_handle_t*, void*> allocate(uint32_t size);
mapper2::BufferDescriptor createDescriptor(
const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo);
// Releases a gralloc buffer previously returned by allocate()
void freeBuffer(native_handle_t* bufferHandle);
const native_handle_t* importBuffer(const hardware::hidl_handle& rawHandle);
void freeBuffer(const native_handle_t* bufferHandle);
// We use fd instead of hardware::hidl_handle in these functions to pass fences
// in and out of the mapper. The ownership of the fd is always transferred
// with each of these functions.
void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
const mapper2::IMapper::Rect& accessRegion, int acquireFence);
int unlock(const native_handle_t* bufferHandle);
private:
void init();
const native_handle_t* cloneBuffer(const hardware::hidl_handle& rawHandle);
sp<allocator2::IAllocator> mAllocator;
sp<mapper2::IMapper> mMapper;
private:
std::unique_ptr<IGrallocHalWrapper> mGrallocHal;
// Keep track of all cloned and imported handles. When a test fails with
// ASSERT_*, the destructor will free the handles for the test.
std::unordered_set<const native_handle_t*> mClonedBuffers;
std::unordered_set<const native_handle_t*> mImportedBuffers;
std::unordered_set<native_handle_t*> mAllocatedBuffers;
};
} // namespace android
#endif // GRALLO_WRAPPER_H_