Add HidlMemoryCache and mapMemory(memory_block)
The HidlMemoryCache is a singleton class which provides cache for
sp<IMemory>. It works as an abstraction layer on top of the
IMapper. It supports, but is not limited to, the Ashmem type
HidlMemory.
Bug: 69640640
Test: hidl_test/internal master/sailfish
Change-Id: I69cca18dbdda532eaae409ee9372b3080f7d58dd
diff --git a/libhidlcache/HidlMemoryCache.cpp b/libhidlcache/HidlMemoryCache.cpp
new file mode 100644
index 0000000..6f9c25c
--- /dev/null
+++ b/libhidlcache/HidlMemoryCache.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2016 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 "HidlMemoryCache"
+#include "HidlMemoryCache.h"
+#include <android/hidl/memory/1.0/IMemory.h>
+#include <android/hidl/memory/token/1.0/IMemoryToken.h>
+#include <hidlmemory/mapping.h>
+#include <sys/mman.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+
+using IMemoryToken = ::android::hidl::memory::token::V1_0::IMemoryToken;
+using IMemory = ::android::hidl::memory::V1_0::IMemory;
+
+class IMemoryDecorator : public virtual IMemory {
+ public:
+ IMemoryDecorator(sp<IMemory> heap) : mHeap(heap) {}
+ virtual ~IMemoryDecorator(){};
+ Return<void> update() override { return mHeap->update(); }
+ Return<void> read() override { return mHeap->read(); };
+ Return<void> updateRange(uint64_t start, uint64_t length) override {
+ return mHeap->updateRange(start, length);
+ }
+ Return<void> readRange(uint64_t start, uint64_t length) override {
+ return mHeap->readRange(start, length);
+ }
+ Return<void> commit() override { return mHeap->commit(); }
+
+ Return<void*> getPointer() override { return mHeap->getPointer(); }
+ Return<uint64_t> getSize() override { return mHeap->getSize(); }
+
+ protected:
+ sp<IMemory> mHeap;
+};
+
+class IMemoryCacheable : public virtual IMemoryDecorator {
+ public:
+ IMemoryCacheable(sp<IMemory> heap, sp<IMemoryToken> key) : IMemoryDecorator(heap), mKey(key) {}
+ virtual ~IMemoryCacheable() { HidlMemoryCache::getInstance()->flush(mKey); }
+
+ protected:
+ sp<IMemoryToken> mKey;
+};
+
+class IMemoryBlock : public virtual IMemoryDecorator {
+ public:
+ IMemoryBlock(sp<IMemory> heap, uint64_t size, uint64_t offset)
+ : IMemoryDecorator(heap), mSize(size), mOffset(offset), mHeapSize(heap->getSize()) {}
+ bool validRange(uint64_t start, uint64_t length) {
+ return (start + length < mSize) && (start + length >= start) &&
+ (mOffset + mSize < mHeapSize);
+ }
+ Return<void> readRange(uint64_t start, uint64_t length) {
+ if (!validRange(start, length)) {
+ ALOGE("IMemoryBlock::readRange: out of range");
+ Status status;
+ status.setException(Status::EX_ILLEGAL_ARGUMENT, "out of range");
+ return Return<void>(status);
+ }
+ return mHeap->readRange(mOffset + start, length);
+ }
+ Return<void> updateRange(uint64_t start, uint64_t length) override {
+ if (!validRange(start, length)) {
+ ALOGE("IMemoryBlock::updateRange: out of range");
+ return Void();
+ }
+ return mHeap->updateRange(mOffset + start, length);
+ }
+ Return<uint64_t> getSize() override { return mSize; }
+ Return<void*> getPointer() override {
+ void* p = mHeap->getPointer();
+ return (static_cast<char*>(p) + mOffset);
+ }
+
+ protected:
+ uint64_t mSize;
+ uint64_t mOffset;
+ uint64_t mHeapSize;
+};
+
+sp<HidlMemoryCache> HidlMemoryCache::getInstance() {
+ static sp<HidlMemoryCache> instance = new HidlMemoryCache();
+ return instance;
+}
+
+sp<IMemory> HidlMemoryCache::fillLocked(const sp<IMemoryToken>& key) {
+ sp<IMemory> memory = nullptr;
+ Return<void> ret = key->get(
+ [&](const hidl_memory& mem) { memory = new IMemoryCacheable(mapMemory(mem), key); });
+ if (!ret.isOk()) {
+ ALOGE("HidlMemoryCache::fill: cannot IMemoryToken::get.");
+ return nullptr;
+ }
+ mCached[key] = memory;
+ return memory;
+}
+
+sp<IMemory> HidlMemoryCache::map(const MemoryBlock& memblk) {
+ sp<IMemoryToken> token = memblk.token;
+ sp<IMemory> heap = fetch(token);
+ if (heap == nullptr) {
+ return nullptr;
+ }
+ return new IMemoryBlock(heap, memblk.size, memblk.offset);
+}
+
+} // namespace hardware
+} // namespace android