/* * Copyright (C) 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. */ #include #include #include "allocator.h" union Params { struct { uint32_t capacity; } data; uint8_t array[0]; Params() : data{0} {} Params(uint32_t size) : data{size} {} }; namespace { struct HandleAshmem : public native_handle_t { HandleAshmem(int ashmemFd, size_t size) : native_handle_t(cHeader), mFds{ ashmemFd }, mInts{ int (size & 0xFFFFFFFF), int((uint64_t(size) >> 32) & 0xFFFFFFFF), kMagic } {} int ashmemFd() const { return mFds.mAshmem; } size_t size() const { return size_t(unsigned(mInts.mSizeLo)) | size_t(uint64_t(unsigned(mInts.mSizeHi)) << 32); } static bool isValid(const native_handle_t * const o); protected: struct { int mAshmem; } mFds; struct { int mSizeLo; int mSizeHi; int mMagic; } mInts; private: enum { kMagic = 'ahm\x00', numFds = sizeof(mFds) / sizeof(int), numInts = sizeof(mInts) / sizeof(int), version = sizeof(native_handle_t) }; const static native_handle_t cHeader; }; const native_handle_t HandleAshmem::cHeader = { HandleAshmem::version, HandleAshmem::numFds, HandleAshmem::numInts, {} }; bool HandleAshmem::isValid(const native_handle_t * const o) { if (!o || memcmp(o, &cHeader, sizeof(cHeader))) { return false; } const HandleAshmem *other = static_cast(o); return other->mInts.mMagic == kMagic; } class AllocationAshmem { private: AllocationAshmem(int ashmemFd, size_t capacity, bool res) : mHandle(ashmemFd, capacity), mInit(res) {} public: static AllocationAshmem *Alloc(size_t size) { constexpr static const char *kAllocationTag = "bufferpool_test"; int ashmemFd = ashmem_create_region(kAllocationTag, size); return new AllocationAshmem(ashmemFd, size, ashmemFd >= 0); } ~AllocationAshmem() { if (mInit) { native_handle_close(&mHandle); } } const HandleAshmem *handle() { return &mHandle; } private: HandleAshmem mHandle; bool mInit; // TODO: mapping and map fd }; struct AllocationDtor { AllocationDtor(const std::shared_ptr &alloc) : mAlloc(alloc) {} void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; } const std::shared_ptr mAlloc; }; } ResultStatus TestBufferPoolAllocator::allocate( const std::vector ¶ms, std::shared_ptr *alloc, size_t *allocSize) { Params ashmemParams; memcpy(&ashmemParams, params.data(), std::min(sizeof(Params), params.size())); std::shared_ptr ashmemAlloc = std::shared_ptr( AllocationAshmem::Alloc(ashmemParams.data.capacity)); if (ashmemAlloc) { BufferPoolAllocation *ptr = new BufferPoolAllocation(ashmemAlloc->handle()); if (ptr) { *alloc = std::shared_ptr(ptr, AllocationDtor(ashmemAlloc)); if (*alloc) { *allocSize = ashmemParams.data.capacity; return ResultStatus::OK; } delete ptr; return ResultStatus::NO_MEMORY; } } return ResultStatus::CRITICAL_ERROR; } bool TestBufferPoolAllocator::compatible(const std::vector &newParams, const std::vector &oldParams) { size_t newSize = newParams.size(); size_t oldSize = oldParams.size(); if (newSize == oldSize) { for (size_t i = 0; i < newSize; ++i) { if (newParams[i] != oldParams[i]) { return false; } } return true; } return false; } bool TestBufferPoolAllocator::Fill(const native_handle_t *handle, const unsigned char val) { if (!HandleAshmem::isValid(handle)) { return false; } const HandleAshmem *o = static_cast(handle); unsigned char *ptr = (unsigned char *)mmap( NULL, o->size(), PROT_READ|PROT_WRITE, MAP_SHARED, o->ashmemFd(), 0); if (ptr != MAP_FAILED) { for (size_t i = 0; i < o->size(); ++i) { ptr[i] = val; } munmap(ptr, o->size()); return true; } return false; } bool TestBufferPoolAllocator::Verify(const native_handle_t *handle, const unsigned char val) { if (!HandleAshmem::isValid(handle)) { return false; } const HandleAshmem *o = static_cast(handle); unsigned char *ptr = (unsigned char *)mmap( NULL, o->size(), PROT_READ, MAP_SHARED, o->ashmemFd(), 0); if (ptr != MAP_FAILED) { bool res = true; for (size_t i = 0; i < o->size(); ++i) { if (ptr[i] != val) { res = false; break; } } munmap(ptr, o->size()); return res; } return false; } void getTestAllocatorParams(std::vector *params) { constexpr static int kAllocationSize = 1024 * 10; Params ashmemParams(kAllocationSize); params->assign(ashmemParams.array, ashmemParams.array + sizeof(ashmemParams)); }