1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "HidlMemoryCache"
18 #include "HidlMemoryCache.h"
19 #include <android/hidl/memory/1.0/IMemory.h>
20 #include <android/hidl/memory/token/1.0/IMemoryToken.h>
21 #include <hidlmemory/mapping.h>
22 #include <sys/mman.h>
23 #include <utils/Log.h>
24
25 namespace android {
26 namespace hardware {
27
28 using IMemoryToken = ::android::hidl::memory::token::V1_0::IMemoryToken;
29 using IMemory = ::android::hidl::memory::V1_0::IMemory;
30
31 class IMemoryDecorator : public virtual IMemory {
32 public:
IMemoryDecorator(sp<IMemory> heap)33 IMemoryDecorator(sp<IMemory> heap) : mHeap(heap) {}
~IMemoryDecorator()34 virtual ~IMemoryDecorator(){};
update()35 Return<void> update() override { return mHeap->update(); }
read()36 Return<void> read() override { return mHeap->read(); };
updateRange(uint64_t start,uint64_t length)37 Return<void> updateRange(uint64_t start, uint64_t length) override {
38 return mHeap->updateRange(start, length);
39 }
readRange(uint64_t start,uint64_t length)40 Return<void> readRange(uint64_t start, uint64_t length) override {
41 return mHeap->readRange(start, length);
42 }
commit()43 Return<void> commit() override { return mHeap->commit(); }
44
getPointer()45 Return<void*> getPointer() override { return mHeap->getPointer(); }
getSize()46 Return<uint64_t> getSize() override { return mHeap->getSize(); }
47
48 protected:
49 sp<IMemory> mHeap;
50 };
51
52 class IMemoryCacheable : public virtual IMemoryDecorator {
53 public:
IMemoryCacheable(sp<IMemory> heap,sp<IMemoryToken> key)54 IMemoryCacheable(sp<IMemory> heap, sp<IMemoryToken> key) : IMemoryDecorator(heap), mKey(key) {}
~IMemoryCacheable()55 virtual ~IMemoryCacheable() { HidlMemoryCache::getInstance()->flush(mKey); }
56
57 protected:
58 sp<IMemoryToken> mKey;
59 };
60
61 class IMemoryBlock : public virtual IMemoryDecorator {
62 public:
IMemoryBlock(sp<IMemory> heap,uint64_t size,uint64_t offset)63 IMemoryBlock(sp<IMemory> heap, uint64_t size, uint64_t offset)
64 : IMemoryDecorator(heap), mSize(size), mOffset(offset), mHeapSize(heap->getSize()) {}
validRange(uint64_t start,uint64_t length)65 bool validRange(uint64_t start, uint64_t length) {
66 return (start + length < mSize) && (start + length >= start) &&
67 (mOffset + mSize < mHeapSize);
68 }
readRange(uint64_t start,uint64_t length)69 Return<void> readRange(uint64_t start, uint64_t length) {
70 if (!validRange(start, length)) {
71 ALOGE("IMemoryBlock::readRange: out of range");
72 Status status;
73 status.setException(Status::EX_ILLEGAL_ARGUMENT, "out of range");
74 return Return<void>(status);
75 }
76 return mHeap->readRange(mOffset + start, length);
77 }
updateRange(uint64_t start,uint64_t length)78 Return<void> updateRange(uint64_t start, uint64_t length) override {
79 if (!validRange(start, length)) {
80 ALOGE("IMemoryBlock::updateRange: out of range");
81 return Void();
82 }
83 return mHeap->updateRange(mOffset + start, length);
84 }
getSize()85 Return<uint64_t> getSize() override { return mSize; }
getPointer()86 Return<void*> getPointer() override {
87 void* p = mHeap->getPointer();
88 return (static_cast<char*>(p) + mOffset);
89 }
90
91 protected:
92 uint64_t mSize;
93 uint64_t mOffset;
94 uint64_t mHeapSize;
95 };
96
getInstance()97 sp<HidlMemoryCache> HidlMemoryCache::getInstance() {
98 static sp<HidlMemoryCache> instance = new HidlMemoryCache();
99 return instance;
100 }
101
fillLocked(const sp<IMemoryToken> & key)102 sp<IMemory> HidlMemoryCache::fillLocked(const sp<IMemoryToken>& key) {
103 sp<IMemory> memory = nullptr;
104 Return<void> ret = key->get(
105 [&](const hidl_memory& mem) { memory = new IMemoryCacheable(mapMemory(mem), key); });
106 if (!ret.isOk()) {
107 ALOGE("HidlMemoryCache::fill: cannot IMemoryToken::get.");
108 return nullptr;
109 }
110 mCached[key] = memory;
111 return memory;
112 }
113
map(const MemoryBlock & memblk)114 sp<IMemory> HidlMemoryCache::map(const MemoryBlock& memblk) {
115 sp<IMemoryToken> token = memblk.token;
116 sp<IMemory> heap = fetch(token);
117 if (heap == nullptr) {
118 return nullptr;
119 }
120 return new IMemoryBlock(heap, memblk.size, memblk.offset);
121 }
122
123 } // namespace hardware
124 } // namespace android
125